* [PATCH v2 09/11] fblog: register console driver
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com>
We want to print the kernel log to all FBs so we need a console driver.
This registers the driver on startup and writes all messages to all
registered fblog instances.
We cannot share a console buffer between FBs because they might have
different resolutions. Therefore, we create one buffer per object. We
destroy the buffer during close() so we do not waste memory if it is not
used.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/video/console/fblog.c | 150 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 150 insertions(+)
diff --git a/drivers/video/console/fblog.c b/drivers/video/console/fblog.c
index fd1f3d6..e447f98 100644
--- a/drivers/video/console/fblog.c
+++ b/drivers/video/console/fblog.c
@@ -23,11 +23,34 @@
* all fblog instances before running other graphics applications.
*/
+#include <linux/console.h>
#include <linux/device.h>
#include <linux/fb.h>
#include <linux/module.h>
#include <linux/mutex.h>
+/**
+ * struct fblog_buf: Console text buffer
+ *
+ * Each framebuffer has its own text buffer which contains all characters that
+ * are currently printed on screen. The buffers might have different sizes and
+ * can be resized during runtime. When the buffer content changes, we redraw the
+ * screen.
+ *
+ * width: Width of buffer in characters
+ * height: Height of buffer in characters
+ * lines: Array of lines
+ * pos_x: Cursor x-position
+ * pos_y: Cursor y-position
+ */
+struct fblog_buf {
+ size_t width;
+ size_t height;
+ u16 **lines;
+ size_t pos_x;
+ size_t pos_y;
+};
+
enum fblog_flags {
FBLOG_KILLED,
FBLOG_OPEN,
@@ -40,6 +63,7 @@ struct fblog_fb {
struct fb_info *info;
struct device dev;
struct mutex lock;
+ struct fblog_buf buf;
};
static DEFINE_MUTEX(fblog_registration_lock);
@@ -47,6 +71,107 @@ static struct fblog_fb *fblog_fbs[FB_MAX];
static bool active = 1;
#define to_fblog_dev(_d) container_of(_d, struct fblog_fb, dev)
+#define FBLOG_STR(x) x, sizeof(x) - 1
+
+static void fblog_buf_resize(struct fblog_buf *buf, size_t width,
+ size_t height)
+{
+ u16 **lines = NULL;
+ size_t i, j, minw, minh;
+
+ if (buf->height = height && buf->width = width)
+ return;
+
+ if (width && height) {
+ lines = kzalloc(height * sizeof(char*), GFP_KERNEL);
+ if (!lines)
+ return;
+
+ for (i = 0; i < height; ++i) {
+ lines[i] = kzalloc(width * sizeof(u16), GFP_KERNEL);
+ if (!lines[i]) {
+ while (i--)
+ kfree(lines[i]);
+ return;
+ }
+ }
+
+ /* copy old lines */
+ minw = min(width, buf->width);
+ minh = min(height, buf->height);
+ if (height >= buf->height)
+ i = 0;
+ else
+ i = buf->height - height;
+
+ for (j = 0; j < minh; ++i, ++j)
+ memcpy(lines[j], buf->lines[i], minw * sizeof(u16));
+ } else {
+ width = 0;
+ height = 0;
+ }
+
+ for (i = 0; i < buf->height; ++i)
+ kfree(buf->lines[i]);
+ kfree(buf->lines);
+
+ buf->lines = lines;
+ buf->width = width;
+ buf->height = height;
+}
+
+static void fblog_buf_deinit(struct fblog_buf *buf)
+{
+ fblog_buf_resize(buf, 0, 0);
+}
+
+static void fblog_buf_rotate(struct fblog_buf *buf)
+{
+ u16 *line;
+
+ if (!buf->height)
+ return;
+
+ line = buf->lines[0];
+ memset(line, 0, sizeof(u16) * buf->width);
+
+ memmove(buf->lines, &buf->lines[1], sizeof(char*) * (buf->height - 1));
+ buf->lines[buf->height - 1] = line;
+}
+
+static void fblog_buf_write(struct fblog_buf *buf, const char *str, size_t len)
+{
+ char c;
+
+ if (!buf->height)
+ return;
+
+ while (len--) {
+ c = *str++;
+
+ if (c = 0)
+ c = '?';
+
+ if (c = '\n') {
+ buf->pos_x = 0;
+ if (++buf->pos_y >= buf->height) {
+ buf->pos_y = buf->height - 1;
+ fblog_buf_rotate(buf);
+ }
+ } else {
+ if (buf->pos_x >= buf->width) {
+ buf->pos_x = 0;
+ ++buf->pos_y;
+ }
+ if (buf->pos_y >= buf->height) {
+ buf->pos_y = buf->height - 1;
+ fblog_buf_rotate(buf);
+ }
+
+ buf->lines[buf->pos_y][buf->pos_x++] = c;
+ }
+ }
+}
static int fblog_open(struct fblog_fb *fb, bool locked)
{
@@ -80,6 +205,8 @@ static int fblog_open(struct fblog_fb *fb, bool locked)
if (!locked)
mutex_unlock(&fb->info->lock);
+ fblog_buf_resize(&fb->buf, 80, 24);
+ fblog_buf_write(&fb->buf, FBLOG_STR("Framebuffer log initialized\n"));
set_bit(FBLOG_OPEN, &fb->flags);
mutex_unlock(&fb->lock);
return 0;
@@ -111,6 +238,7 @@ static void fblog_close(struct fblog_fb *fb, bool kill_dev, bool locked)
mutex_unlock(&fb->info->lock);
clear_bit(FBLOG_OPEN, &fb->flags);
+ fblog_buf_deinit(&fb->buf);
}
if (kill_dev)
@@ -368,6 +496,26 @@ static struct notifier_block fblog_notifier = {
.notifier_call = fblog_event,
};
+static void fblog_con_write(struct console *con, const char *buf,
+ unsigned int len)
+{
+ int i;
+
+ mutex_lock(&fblog_registration_lock);
+ for (i = 0; i < FB_MAX; ++i) {
+ if (fblog_fbs[i]) {
+ fblog_buf_write(&fblog_fbs[i]->buf, buf, len);
+ }
+ }
+ mutex_unlock(&fblog_registration_lock);
+}
+
+static struct console fblog_con_driver = {
+ .name = "fblog",
+ .write = fblog_con_write,
+ .flags = CON_PRINTBUFFER | CON_ENABLED,
+};
+
static int __init fblog_init(void)
{
int ret;
@@ -379,6 +527,7 @@ static int __init fblog_init(void)
}
fblog_scan();
+ register_console(&fblog_con_driver);
return 0;
}
@@ -388,6 +537,7 @@ static void __exit fblog_exit(void)
unsigned int i;
struct fb_info *info;
+ unregister_console(&fblog_con_driver);
fb_unregister_client(&fblog_notifier);
for (i = 0; i < FB_MAX; ++i) {
--
1.7.11.1
^ permalink raw reply related
* [PATCH v2 10/11] fblog: draw console to framebuffers
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com>
If not disabled or suspended, we now blit the console data to each
framebuffer. We only redraw on changes to avoid consuming too much CPU
power.
This isn't optimized for speed, currently. However, fblog is mainly used
for debugging purposes so this can be optimized later.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/video/console/fblog.c | 107 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 106 insertions(+), 1 deletion(-)
diff --git a/drivers/video/console/fblog.c b/drivers/video/console/fblog.c
index e447f98..d6e4fe2 100644
--- a/drivers/video/console/fblog.c
+++ b/drivers/video/console/fblog.c
@@ -26,8 +26,11 @@
#include <linux/console.h>
#include <linux/device.h>
#include <linux/fb.h>
+#include <linux/font.h>
+#include <linux/kd.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include "fbdraw.h"
/**
* struct fblog_buf: Console text buffer
@@ -64,6 +67,7 @@ struct fblog_fb {
struct device dev;
struct mutex lock;
struct fblog_buf buf;
+ struct console_font font;
};
static DEFINE_MUTEX(fblog_registration_lock);
@@ -173,9 +177,65 @@ static void fblog_buf_write(struct fblog_buf *buf, const char *str, size_t len)
}
}
+static void fblog_redraw_clear(struct fblog_fb *fb)
+{
+ struct fb_fillrect region;
+ struct fb_info *info = fb->info;
+
+ region.color = 0;
+ region.dx = 0;
+ region.dy = 0;
+ region.width = info->var.xres;
+ region.height = info->var.yres;
+ region.rop = ROP_COPY;
+
+ info->fbops->fb_fillrect(info, ®ion);
+}
+
+static void fblog_redraw(struct fblog_fb *fb)
+{
+ size_t i;
+
+ mutex_lock(&fb->lock);
+ if (!test_bit(FBLOG_OPEN, &fb->flags) ||
+ test_bit(FBLOG_SUSPENDED, &fb->flags) ||
+ test_bit(FBLOG_BLANKED, &fb->flags)) {
+ mutex_unlock(&fb->lock);
+ return;
+ }
+
+ fblog_redraw_clear(fb);
+
+ for (i = 0; i < fb->buf.height; ++i) {
+ fbdraw_font(fb->info, &fb->font, false, 0, i, 7, 0, 0,
+ fb->buf.lines[i], fb->buf.width);
+ }
+
+ mutex_unlock(&fb->lock);
+}
+
+static void fblog_refresh(struct fblog_fb *fb)
+{
+ unsigned int width, height;
+
+ mutex_lock(&fb->lock);
+ if (test_bit(FBLOG_OPEN, &fb->flags)) {
+ width = fb->info->var.xres / fb->font.width;
+ height = fb->info->var.yres / fb->font.height;
+ fblog_buf_resize(&fb->buf, width, height);
+ }
+ mutex_unlock(&fb->lock);
+
+ fblog_redraw(fb);
+}
+
static int fblog_open(struct fblog_fb *fb, bool locked)
{
int ret;
+ struct fb_var_screeninfo var;
+ const struct fb_videomode *mode;
+ unsigned int width, height;
+ const struct font_desc *font;
mutex_lock(&fb->lock);
@@ -189,6 +249,13 @@ static int fblog_open(struct fblog_fb *fb, bool locked)
goto unlock;
}
+ font = get_default_font(var.xres, var.yres, fb->info->pixmap.blit_x,
+ fb->info->pixmap.blit_y);
+ if (!font) {
+ ret = -ENODEV;
+ goto unlock;
+ }
+
if (!locked)
mutex_lock(&fb->info->lock);
@@ -202,13 +269,25 @@ static int fblog_open(struct fblog_fb *fb, bool locked)
goto out_unref;
}
+ var = fb->info->var;
+ mode = fb_find_best_mode(&var, &fb->info->modelist);
+ var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
+ fb_set_var(fb->info, &var);
+
+ fb->font.width = font->width;
+ fb->font.height = font->height;
+ fb->font.data = (void*)font->data;
+
if (!locked)
mutex_unlock(&fb->info->lock);
- fblog_buf_resize(&fb->buf, 80, 24);
+ width = var.xres / fb->font.width;
+ height = var.yres / fb->font.height;
+ fblog_buf_resize(&fb->buf, width, height);
fblog_buf_write(&fb->buf, FBLOG_STR("Framebuffer log initialized\n"));
set_bit(FBLOG_OPEN, &fb->flags);
mutex_unlock(&fb->lock);
+ fblog_redraw(fb);
return 0;
out_unref:
@@ -449,6 +528,31 @@ static int fblog_event(struct notifier_block *self, unsigned long action,
else
set_bit(FBLOG_BLANKED, &fb->flags);
break;
+ case FB_EVENT_MODE_DELETE:
+ /* This is sent when a video mode is removed. The current video
+ * mode is never removed! The console lock is held while this is
+ * called. */
+ /* fallthrough */
+ case FB_EVENT_NEW_MODELIST:
+ /* This is sent when the modelist got changed. The console-lock
+ * is held and we should reset the mode. */
+ /* fallthrough */
+ case FB_EVENT_MODE_CHANGE_ALL:
+ /* This is the same as below but notifies us that the user used
+ * the FB_ACTIVATE_ALL flag when setting the video mode. */
+ /* fallthrough */
+ case FB_EVENT_MODE_CHANGE:
+ /* This is called when the _user_ changes the video mode via
+ * ioctls. It is not sent, when the kernel changes the mode
+ * internally. This callback is called inside fb_set_var() so
+ * the console lock is held. */
+ mutex_lock(&fblog_registration_lock);
+ fb = fblog_fbs[info->node];
+ mutex_unlock(&fblog_registration_lock);
+
+ if (fb)
+ fblog_refresh(fb);
+ break;
}
return 0;
@@ -505,6 +609,7 @@ static void fblog_con_write(struct console *con, const char *buf,
for (i = 0; i < FB_MAX; ++i) {
if (fblog_fbs[i]) {
fblog_buf_write(&fblog_fbs[i]->buf, buf, len);
+ fblog_redraw(fblog_fbs[i]);
}
}
mutex_unlock(&fblog_registration_lock);
--
1.7.11.1
^ permalink raw reply related
* [PATCH v2 11/11] MAINTAINERS: add fblog entry
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com>
Add myself as maintainer for the fblog driver to the MAINTAINERS file.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
MAINTAINERS | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index ae8fe46..249b02a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2854,6 +2854,12 @@ F: drivers/video/
F: include/video/
F: include/linux/fb.h
+FRAMEBUFFER LOG DRIVER
+M: David Herrmann <dh.herrmann@googlemail.com>
+L: linux-serial@vger.kernel.org
+S: Maintained
+F: drivers/video/console/fblog.c
+
FREESCALE DMA DRIVER
M: Li Yang <leoli@freescale.com>
M: Zhang Wei <zw@zh-kernel.org>
--
1.7.11.1
^ permalink raw reply related
* Re: [PATCH RESEND] video: w100fb: Reduce sleep mode battery discharge
From: Florian Tobias Schandinat @ 2012-07-08 22:01 UTC (permalink / raw)
To: Paul Parsons
Cc: mreimer, philipp.zabel, linux-kernel, linux-fbdev@vger.kernel.org
In-Reply-To: <20120603103355.3845gmx1@mx072.gmx.net>
On 06/03/2012 10:33 AM, Paul Parsons wrote:
> In 2006 and 2007 the handhelds.org kernel w100fb driver was patched to
> reduce sleep mode battery discharge. Unfortunately those two patches
> never migrated to the mainline kernel.
>
> Fortunately the function affected - w100_suspend() - has not changed
> since; thus those patches still apply cleanly.
>
> Applying those patches to linux-3.4-rc3 running on an HP iPAQ hx4700
> reduces the sleep mode battery discharge from approximately 26 mA to
> approximately 11 mA.
>
> This patch combines those two patches into a single unified patch.
>
> Signed-off-by: Paul Parsons <lost.distance@yahoo.com>
> Cc: Matt Reimer <mreimer@sdgsystems.com>
> Cc: Philipp Zabel <philipp.zabel@gmail.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
>
> Many thanks to Matt Reimer for suggesting this.
>
> The seeming demise of handhelds.org has removed any formal patch logs.
> However the patches can still be viewed online:
> 2006 patch:
> http://paste.lisp.org/display/31700
> 2007 patch:
> http://osdir.com/ml/handhelds.linux.kernel/2007-02/msg00020.html
>
> And the fully patched handhelds.org kernel is still available, e.g.:
> http://www.linuxtogo.org/~goxboxlive/htcuniversal/Kernel/linux-2.6.21-hh20.tar.bz2
>
> drivers/video/w100fb.c | 12 ++++++++++++
> 1 files changed, 12 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
> index 90a2e30..2f6b2b8 100644
> --- a/drivers/video/w100fb.c
> +++ b/drivers/video/w100fb.c
> @@ -1567,6 +1567,18 @@ static void w100_suspend(u32 mode)
> val = readl(remapped_regs + mmPLL_CNTL);
> val |= 0x00000004; /* bit2=1 */
> writel(val, remapped_regs + mmPLL_CNTL);
> +
> + writel(0x00000000, remapped_regs + mmLCDD_CNTL1);
> + writel(0x00000000, remapped_regs + mmLCDD_CNTL2);
> + writel(0x00000000, remapped_regs + mmGENLCD_CNTL1);
> + writel(0x00000000, remapped_regs + mmGENLCD_CNTL2);
> + writel(0x00000000, remapped_regs + mmGENLCD_CNTL3);
> +
> + val = readl(remapped_regs + mmMEM_EXT_CNTL);
> + val |= 0xF0000000;
> + val &= ~(0x00000001);
> + writel(val, remapped_regs + mmMEM_EXT_CNTL);
> +
> writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL);
> }
> }
^ permalink raw reply
* Re: [PATCH v2] grvga: Fix error handling issues
From: Florian Tobias Schandinat @ 2012-07-08 22:02 UTC (permalink / raw)
To: Emil Goode; +Cc: linux-fbdev, linux-kernel, kernel-janitors
In-Reply-To: <1340663852-11719-1-git-send-email-emilgoode@gmail.com>
On 06/25/2012 10:37 PM, Emil Goode wrote:
> This patch fixes two problems with the error handling in the
> grvga_probe function and simplifies it making the code
> easier to read.
>
> - If the call to grvga_parse_custom on line 370 fails we use
> the wrong label so that release_mem_region will be called
> without a call to request_mem_region being made.
>
> - If the call to ioremap on line 436 fails we should not try
> to call iounmap in the error handling code.
>
> This patch introduces the following changes:
>
> - Converts request_mem_region into its devm_ equivalent
> which simplifies the otherwise messy clean up code.
>
> - Changes the labels for correct error handling and their
> names to make the code easier to read.
>
> Signed-off-by: Emil Goode <emilgoode@gmail.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> v2: Simplifies the error handling by converting to
> devm_request_mem_region
>
> drivers/video/grvga.c | 47 ++++++++++++++++++++++-------------------------
> 1 file changed, 22 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/video/grvga.c b/drivers/video/grvga.c
> index da066c2..5245f9a 100644
> --- a/drivers/video/grvga.c
> +++ b/drivers/video/grvga.c
> @@ -354,7 +354,7 @@ static int __devinit grvga_probe(struct platform_device *dev)
> */
> if (fb_get_options("grvga", &options)) {
> retval = -ENODEV;
> - goto err;
> + goto free_fb;
> }
>
> if (!options || !*options)
> @@ -370,7 +370,7 @@ static int __devinit grvga_probe(struct platform_device *dev)
> if (grvga_parse_custom(this_opt, &info->var) < 0) {
> dev_err(&dev->dev, "Failed to parse custom mode (%s).\n", this_opt);
> retval = -EINVAL;
> - goto err1;
> + goto free_fb;
> }
> } else if (!strncmp(this_opt, "addr", 4))
> grvga_fix_addr = simple_strtoul(this_opt + 5, NULL, 16);
> @@ -387,10 +387,11 @@ static int __devinit grvga_probe(struct platform_device *dev)
> info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
> info->fix.smem_len = grvga_mem_size;
>
> - if (!request_mem_region(dev->resource[0].start, resource_size(&dev->resource[0]), "grlib-svgactrl regs")) {
> + if (!devm_request_mem_region(&dev->dev, dev->resource[0].start,
> + resource_size(&dev->resource[0]), "grlib-svgactrl regs")) {
> dev_err(&dev->dev, "registers already mapped\n");
> retval = -EBUSY;
> - goto err;
> + goto free_fb;
> }
>
> par->regs = of_ioremap(&dev->resource[0], 0,
> @@ -400,14 +401,14 @@ static int __devinit grvga_probe(struct platform_device *dev)
> if (!par->regs) {
> dev_err(&dev->dev, "failed to map registers\n");
> retval = -ENOMEM;
> - goto err1;
> + goto free_fb;
> }
>
> retval = fb_alloc_cmap(&info->cmap, 256, 0);
> if (retval < 0) {
> dev_err(&dev->dev, "failed to allocate mem with fb_alloc_cmap\n");
> retval = -ENOMEM;
> - goto err2;
> + goto unmap_regs;
> }
>
> if (mode_opt) {
> @@ -415,7 +416,7 @@ static int __devinit grvga_probe(struct platform_device *dev)
> grvga_modedb, sizeof(grvga_modedb), &grvga_modedb[0], 8);
> if (!retval || retval = 4) {
> retval = -EINVAL;
> - goto err3;
> + goto dealloc_cmap;
> }
> }
>
> @@ -427,10 +428,11 @@ static int __devinit grvga_probe(struct platform_device *dev)
>
> physical_start = grvga_fix_addr;
>
> - if (!request_mem_region(physical_start, grvga_mem_size, dev->name)) {
> + if (!devm_request_mem_region(&dev->dev, physical_start,
> + grvga_mem_size, dev->name)) {
> dev_err(&dev->dev, "failed to request memory region\n");
> retval = -ENOMEM;
> - goto err3;
> + goto dealloc_cmap;
> }
>
> virtual_start = (unsigned long) ioremap(physical_start, grvga_mem_size);
> @@ -438,7 +440,7 @@ static int __devinit grvga_probe(struct platform_device *dev)
> if (!virtual_start) {
> dev_err(&dev->dev, "error mapping framebuffer memory\n");
> retval = -ENOMEM;
> - goto err4;
> + goto dealloc_cmap;
> }
> } else { /* Allocate frambuffer memory */
>
> @@ -451,7 +453,7 @@ static int __devinit grvga_probe(struct platform_device *dev)
> "unable to allocate framebuffer memory (%lu bytes)\n",
> grvga_mem_size);
> retval = -ENOMEM;
> - goto err3;
> + goto dealloc_cmap;
> }
>
> physical_start = dma_map_single(&dev->dev, (void *)virtual_start, grvga_mem_size, DMA_TO_DEVICE);
> @@ -484,7 +486,7 @@ static int __devinit grvga_probe(struct platform_device *dev)
> retval = register_framebuffer(info);
> if (retval < 0) {
> dev_err(&dev->dev, "failed to register framebuffer\n");
> - goto err4;
> + goto free_mem;
> }
>
> __raw_writel(physical_start, &par->regs->fb_pos);
> @@ -493,21 +495,18 @@ static int __devinit grvga_probe(struct platform_device *dev)
>
> return 0;
>
> -err4:
> +free_mem:
> dev_set_drvdata(&dev->dev, NULL);
> - if (grvga_fix_addr) {
> - release_mem_region(physical_start, grvga_mem_size);
> + if (grvga_fix_addr)
> iounmap((void *)virtual_start);
> - } else
> + else
> kfree((void *)virtual_start);
> -err3:
> +dealloc_cmap:
> fb_dealloc_cmap(&info->cmap);
> -err2:
> +unmap_regs:
> of_iounmap(&dev->resource[0], par->regs,
> resource_size(&dev->resource[0]));
> -err1:
> - release_mem_region(dev->resource[0].start, resource_size(&dev->resource[0]));
> -err:
> +free_fb:
> framebuffer_release(info);
>
> return retval;
> @@ -524,12 +523,10 @@ static int __devexit grvga_remove(struct platform_device *device)
>
> of_iounmap(&device->resource[0], par->regs,
> resource_size(&device->resource[0]));
> - release_mem_region(device->resource[0].start, resource_size(&device->resource[0]));
>
> - if (!par->fb_alloced) {
> - release_mem_region(info->fix.smem_start, info->fix.smem_len);
> + if (!par->fb_alloced)
> iounmap(info->screen_base);
> - } else
> + else
> kfree((void *)info->screen_base);
>
> framebuffer_release(info);
^ permalink raw reply
* Re: [PATCH] [resend] s3fb: Add Virge/MX (86C260)
From: Florian Tobias Schandinat @ 2012-07-08 22:03 UTC (permalink / raw)
To: Ondrej Zary; +Cc: Ondrej Zajicek, linux-fbdev, Kernel development list
In-Reply-To: <201207061512.11975.linux@rainbow-software.org>
On 07/06/2012 01:12 PM, Ondrej Zary wrote:
> Add support for Virge/MX (86C260) chip. Although this is a laptop chip,
> there's an AGP card with this chip too.
>
> Tested with AGP card, will probably not work correctly with laptops.
> DDC does not work on this card (even in DOS or Windows).
>
> Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
Applied.
Thanks,
Florian Tobias Schandinat
>
> --- a/drivers/video/s3fb.c
> +++ b/drivers/video/s3fb.c
> @@ -84,7 +84,7 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
> "S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX",
> "S3 Virge/GX2", "S3 Virge/GX2+", "",
> "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X",
> - "S3 Trio3D"};
> + "S3 Trio3D", "S3 Virge/MX"};
>
> #define CHIP_UNKNOWN 0x00
> #define CHIP_732_TRIO32 0x01
> @@ -105,6 +105,7 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
> #define CHIP_362_TRIO3D_2X 0x11
> #define CHIP_368_TRIO3D_2X 0x12
> #define CHIP_365_TRIO3D 0x13
> +#define CHIP_260_VIRGE_MX 0x14
>
> #define CHIP_XXX_TRIO 0x80
> #define CHIP_XXX_TRIO64V2_DXGX 0x81
> @@ -280,7 +281,8 @@ static int __devinit s3fb_setup_ddc_bus(struct fb_info *info)
> */
> /* vga_wseq(par->state.vgabase, 0x08, 0x06); - not needed, already unlocked */
> if (par->chip = CHIP_357_VIRGE_GX2 ||
> - par->chip = CHIP_359_VIRGE_GX2P)
> + par->chip = CHIP_359_VIRGE_GX2P ||
> + par->chip = CHIP_260_VIRGE_MX)
> svga_wseq_mask(par->state.vgabase, 0x0d, 0x01, 0x03);
> else
> svga_wseq_mask(par->state.vgabase, 0x0d, 0x00, 0x03);
> @@ -487,7 +489,8 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock)
> par->chip = CHIP_359_VIRGE_GX2P ||
> par->chip = CHIP_360_TRIO3D_1X ||
> par->chip = CHIP_362_TRIO3D_2X ||
> - par->chip = CHIP_368_TRIO3D_2X) {
> + par->chip = CHIP_368_TRIO3D_2X ||
> + par->chip = CHIP_260_VIRGE_MX) {
> vga_wseq(par->state.vgabase, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */
> vga_wseq(par->state.vgabase, 0x29, r >> 2); /* remaining highest bit of r */
> } else
> @@ -690,7 +693,8 @@ static int s3fb_set_par(struct fb_info *info)
> par->chip != CHIP_359_VIRGE_GX2P &&
> par->chip != CHIP_360_TRIO3D_1X &&
> par->chip != CHIP_362_TRIO3D_2X &&
> - par->chip != CHIP_368_TRIO3D_2X) {
> + par->chip != CHIP_368_TRIO3D_2X &&
> + par->chip != CHIP_260_VIRGE_MX) {
> vga_wcrt(par->state.vgabase, 0x54, 0x18); /* M parameter */
> vga_wcrt(par->state.vgabase, 0x60, 0xff); /* N parameter */
> vga_wcrt(par->state.vgabase, 0x61, 0xff); /* L parameter */
> @@ -739,7 +743,8 @@ static int s3fb_set_par(struct fb_info *info)
> par->chip = CHIP_368_TRIO3D_2X ||
> par->chip = CHIP_365_TRIO3D ||
> par->chip = CHIP_375_VIRGE_DX ||
> - par->chip = CHIP_385_VIRGE_GX) {
> + par->chip = CHIP_385_VIRGE_GX ||
> + par->chip = CHIP_260_VIRGE_MX) {
> dbytes = info->var.xres * ((bpp+7)/8);
> vga_wcrt(par->state.vgabase, 0x91, (dbytes + 7) / 8);
> vga_wcrt(par->state.vgabase, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80);
> @@ -751,7 +756,8 @@ static int s3fb_set_par(struct fb_info *info)
> par->chip = CHIP_359_VIRGE_GX2P ||
> par->chip = CHIP_360_TRIO3D_1X ||
> par->chip = CHIP_362_TRIO3D_2X ||
> - par->chip = CHIP_368_TRIO3D_2X)
> + par->chip = CHIP_368_TRIO3D_2X ||
> + par->chip = CHIP_260_VIRGE_MX)
> vga_wcrt(par->state.vgabase, 0x34, 0x00);
> else /* enable Data Transfer Position Control (DTPC) */
> vga_wcrt(par->state.vgabase, 0x34, 0x10);
> @@ -807,7 +813,8 @@ static int s3fb_set_par(struct fb_info *info)
> par->chip = CHIP_359_VIRGE_GX2P ||
> par->chip = CHIP_360_TRIO3D_1X ||
> par->chip = CHIP_362_TRIO3D_2X ||
> - par->chip = CHIP_368_TRIO3D_2X)
> + par->chip = CHIP_368_TRIO3D_2X ||
> + par->chip = CHIP_260_VIRGE_MX)
> svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
> else {
> svga_wcrt_mask(par->state.vgabase, 0x67, 0x10, 0xF0);
> @@ -837,7 +844,8 @@ static int s3fb_set_par(struct fb_info *info)
> par->chip != CHIP_359_VIRGE_GX2P &&
> par->chip != CHIP_360_TRIO3D_1X &&
> par->chip != CHIP_362_TRIO3D_2X &&
> - par->chip != CHIP_368_TRIO3D_2X)
> + par->chip != CHIP_368_TRIO3D_2X &&
> + par->chip != CHIP_260_VIRGE_MX)
> hmul = 2;
> }
> break;
> @@ -864,7 +872,8 @@ static int s3fb_set_par(struct fb_info *info)
> par->chip != CHIP_359_VIRGE_GX2P &&
> par->chip != CHIP_360_TRIO3D_1X &&
> par->chip != CHIP_362_TRIO3D_2X &&
> - par->chip != CHIP_368_TRIO3D_2X)
> + par->chip != CHIP_368_TRIO3D_2X &&
> + par->chip != CHIP_260_VIRGE_MX)
> hmul = 2;
> }
> break;
> @@ -1208,7 +1217,8 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
> break;
> }
> } else if (par->chip = CHIP_357_VIRGE_GX2 ||
> - par->chip = CHIP_359_VIRGE_GX2P) {
> + par->chip = CHIP_359_VIRGE_GX2P ||
> + par->chip = CHIP_260_VIRGE_MX) {
> switch ((regval & 0xC0) >> 6) {
> case 1: /* 4MB */
> info->screen_size = 4 << 20;
> @@ -1515,6 +1525,7 @@ static struct pci_device_id s3_devices[] __devinitdata = {
> {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P},
> {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X},
> {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8904), .driver_data = CHIP_365_TRIO3D},
> + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8C01), .driver_data = CHIP_260_VIRGE_MX},
>
> {0, 0, 0, 0, 0, 0, 0}
> };
>
^ permalink raw reply
* Re: [PATCH v2 09/11] fblog: register console driver
From: Joe Perches @ 2012-07-08 22:09 UTC (permalink / raw)
To: David Herrmann
Cc: linux-serial, linux-kernel, florianschandinat, linux-fbdev,
gregkh, alan, bonbons
In-Reply-To: <1341784614-2797-10-git-send-email-dh.herrmann@googlemail.com>
On Sun, 2012-07-08 at 23:56 +0200, David Herrmann wrote:
> We want to print the kernel log to all FBs so we need a console driver.
> This registers the driver on startup and writes all messages to all
> registered fblog instances.
Hi David. Trivia only:
> diff --git a/drivers/video/console/fblog.c b/drivers/video/console/fblog.c
[]
> @@ -47,6 +71,107 @@ static struct fblog_fb *fblog_fbs[FB_MAX];
> static bool active = 1;
>
> #define to_fblog_dev(_d) container_of(_d, struct fblog_fb, dev)
> +#define FBLOG_STR(x) x, sizeof(x) - 1
That's a rather ugly macro.
> +static void fblog_buf_resize(struct fblog_buf *buf, size_t width,
> + size_t height)
> +{
> + u16 **lines = NULL;
> + size_t i, j, minw, minh;
> +
> + if (buf->height = height && buf->width = width)
> + return;
> +
> + if (width && height) {
> + lines = kzalloc(height * sizeof(char*), GFP_KERNEL);
sizeof(char *) is a bit more kernel style like.
^ permalink raw reply
* Re: [PATCH 0/2] OMAPDSS: PM runtime fixes for 3.5-rc
From: Florian Tobias Schandinat @ 2012-07-08 22:10 UTC (permalink / raw)
To: Archit Taneja
Cc: tomi.valkeinen, jaswinder.singh, jw, linux-fbdev, linux-omap
In-Reply-To: <1341405829-16964-1-git-send-email-archit@ti.com>
Hi Archit,
On 07/04/2012 12:43 PM, Archit Taneja wrote:
> Hi Florian,
>
> These are 2 fixes which Tomi had intended to push for the coming rcs. He is
> currently on vacation and asked me to post the patches on his behalf.
>
> The first patch ensures that system suspend doesn't break on OMAP if DSS is
> enabled. The second patch prevents some warning backtraces when the kernel is
> not built with PM runtime.
>
> Could you please queue these for the upcoming rc?
as you sent me those patches you should have added your Signed-off-by as
well, I added it.
Also the first patch of this series contained 2 coding style issues
related to braces that checkpatch complained about and also differed
from the coding style used in those files, I fixed those as well.
I applied both patches.
Thanks,
Florian Tobias Schandinat
>
> Thanks,
> Archit
>
> Tomi Valkeinen (2):
> OMAPDSS: Use PM notifiers for system suspend
> OMAPDSS: fix warnings if CONFIG_PM_RUNTIME=n
>
> drivers/video/omap2/dss/core.c | 45 +++++++++++++++++++++++++--------------
> drivers/video/omap2/dss/dispc.c | 2 +-
> drivers/video/omap2/dss/dsi.c | 2 +-
> drivers/video/omap2/dss/dss.c | 2 +-
> drivers/video/omap2/dss/hdmi.c | 2 +-
> drivers/video/omap2/dss/rfbi.c | 2 +-
> drivers/video/omap2/dss/venc.c | 2 +-
> 7 files changed, 35 insertions(+), 22 deletions(-)
>
^ permalink raw reply
* Re: [PATCH v2 05/11] fblog: register one fblog object per framebuffer
From: Joe Perches @ 2012-07-08 22:13 UTC (permalink / raw)
To: David Herrmann
Cc: linux-serial, linux-kernel, florianschandinat, linux-fbdev,
gregkh, alan, bonbons
In-Reply-To: <1341784614-2797-6-git-send-email-dh.herrmann@googlemail.com>
On Sun, 2012-07-08 at 23:56 +0200, David Herrmann wrote:
>
Hi David. Trivial comments only:
> diff --git a/drivers/video/console/fblog.c b/drivers/video/console/fblog.c
[]
> @@ -23,15 +23,204 @@
> * all fblog instances before running other graphics applications.
> */
Please add
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
before any #include and...
> static int __init fblog_init(void)
> {
> + int ret;
> +
> + ret = fb_register_client(&fblog_notifier);
> + if (ret) {
> + pr_err("fblog: cannot register framebuffer notifier");
Missing newline, pr_fmt would add module name.
pr_err("cannot register framebuffer notifier\n");
^ permalink raw reply
* [PATCH] pwm_backlight: pass correct brightness to callback
From: Alexandre Courbot @ 2012-07-09 4:21 UTC (permalink / raw)
To: Thierry Reding; +Cc: linux-kernel, linux-fbdev, Alexandre Courbot
pwm_backlight_update_status calls two callbacks before and after
applying the new PWM settings. However, the brightness scale is
completely changed in between if brightness levels are used. This patch
ensures that both callbacks are passed brightness values of the same
meaning.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
drivers/video/backlight/pwm_bl.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 057389d..dd4d24d 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -39,6 +39,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
{
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
int brightness = bl->props.brightness;
+ int pwm_brightness;
int max = bl->props.max_brightness;
if (bl->props.power != FB_BLANK_UNBLANK)
@@ -55,13 +56,14 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
pwm_disable(pb->pwm);
} else {
if (pb->levels) {
- brightness = pb->levels[brightness];
+ pwm_brightness = pb->levels[brightness];
max = pb->levels[max];
- }
+ } else
+ pwm_brightness = brightness;
- brightness = pb->lth_brightness +
- (brightness * (pb->period - pb->lth_brightness) / max);
- pwm_config(pb->pwm, brightness, pb->period);
+ pwm_brightness = pb->lth_brightness +
+ (pwm_brightness * (pb->period - pb->lth_brightness) / max);
+ pwm_config(pb->pwm, pwm_brightness, pb->period);
pwm_enable(pb->pwm);
}
--
1.7.11.1
^ permalink raw reply related
* Re: [PATCH] pwm_backlight: pass correct brightness to callback
From: Thierry Reding @ 2012-07-09 5:10 UTC (permalink / raw)
To: Alexandre Courbot; +Cc: linux-kernel, linux-fbdev
In-Reply-To: <1341807700-7103-1-git-send-email-acourbot@nvidia.com>
[-- Attachment #1: Type: text/plain, Size: 2141 bytes --]
On Mon, Jul 09, 2012 at 01:21:40PM +0900, Alexandre Courbot wrote:
> pwm_backlight_update_status calls two callbacks before and after
> applying the new PWM settings. However, the brightness scale is
> completely changed in between if brightness levels are used. This patch
> ensures that both callbacks are passed brightness values of the same
> meaning.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
> drivers/video/backlight/pwm_bl.c | 12 +++++++-----
> 1 file changed, 7 insertions(+), 5 deletions(-)
I had to actually read this patch a number of times and then realized I
was completely missing the context. Looking at the whole function makes
it more obvious what you mean.
However I think it'd be much clearer if we just passed the value of
bl->props.brightness into the callbacks, that way we can avoid the
additional variable.
Thierry
>
> diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
> index 057389d..dd4d24d 100644
> --- a/drivers/video/backlight/pwm_bl.c
> +++ b/drivers/video/backlight/pwm_bl.c
> @@ -39,6 +39,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
> {
> struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
> int brightness = bl->props.brightness;
> + int pwm_brightness;
> int max = bl->props.max_brightness;
>
> if (bl->props.power != FB_BLANK_UNBLANK)
> @@ -55,13 +56,14 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
> pwm_disable(pb->pwm);
> } else {
> if (pb->levels) {
> - brightness = pb->levels[brightness];
> + pwm_brightness = pb->levels[brightness];
> max = pb->levels[max];
> - }
> + } else
> + pwm_brightness = brightness;
>
> - brightness = pb->lth_brightness +
> - (brightness * (pb->period - pb->lth_brightness) / max);
> - pwm_config(pb->pwm, brightness, pb->period);
> + pwm_brightness = pb->lth_brightness +
> + (pwm_brightness * (pb->period - pb->lth_brightness) / max);
> + pwm_config(pb->pwm, pwm_brightness, pb->period);
> pwm_enable(pb->pwm);
> }
>
> --
> 1.7.11.1
>
>
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* RE: [PATCH] pwm_backlight: pass correct brightness to callback
From: Jingoo Han @ 2012-07-09 5:11 UTC (permalink / raw)
To: 'Alexandre Courbot', 'Thierry Reding'
Cc: linux-kernel, linux-fbdev, 'Jingoo Han'
In-Reply-To: <1341807700-7103-1-git-send-email-acourbot@nvidia.com>
On Monday, July 09, 2012 1:22 PM, Alexandre Courbot wrote:
> pwm_backlight_update_status calls two callbacks before and after
> applying the new PWM settings. However, the brightness scale is
> completely changed in between if brightness levels are used. This patch
> ensures that both callbacks are passed brightness values of the same
> meaning.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
> drivers/video/backlight/pwm_bl.c | 12 +++++++-----
> 1 file changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
> index 057389d..dd4d24d 100644
> --- a/drivers/video/backlight/pwm_bl.c
> +++ b/drivers/video/backlight/pwm_bl.c
> @@ -39,6 +39,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
> {
> struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
> int brightness = bl->props.brightness;
> + int pwm_brightness;
> int max = bl->props.max_brightness;
>
> if (bl->props.power != FB_BLANK_UNBLANK)
> @@ -55,13 +56,14 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
> pwm_disable(pb->pwm);
> } else {
> if (pb->levels) {
> - brightness = pb->levels[brightness];
> + pwm_brightness = pb->levels[brightness];
> max = pb->levels[max];
> - }
> + } else
> + pwm_brightness = brightness;
Hi Alexandre Courbot,
Please, use braces to keep the Coding Style.
Refer to Documentation/CodingStyle as follow:
169 This does not apply if only one branch of a conditional statement is a single
170 statement; in the latter case use braces in both branches:
171
172 if (condition) {
173 do_this();
174 do_that();
175 } else {
176 otherwise();
177 }
Best regards,
Jingoo Han
>
> - brightness = pb->lth_brightness +
> - (brightness * (pb->period - pb->lth_brightness) / max);
> - pwm_config(pb->pwm, brightness, pb->period);
> + pwm_brightness = pb->lth_brightness +
> + (pwm_brightness * (pb->period - pb->lth_brightness) / max);
> + pwm_config(pb->pwm, pwm_brightness, pb->period);
> pwm_enable(pb->pwm);
> }
>
> --
> 1.7.11.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* RE: [PATCH] pwm-backlight: add regulator and GPIO support
From: Jingoo Han @ 2012-07-09 5:19 UTC (permalink / raw)
To: 'Alex Courbot'
Cc: 'Thierry Reding', 'Sascha Hauer',
'Stephen Warren', 'Mark Brown', linux-tegra,
linux-kernel, linux-fbdev
In-Reply-To: <4FF5BAEE.3020403@wwwdotorg.org>
> -----Original Message-----
> From: linux-fbdev-owner@vger.kernel.org [mailto:linux-fbdev-owner@vger.kernel.org] On Behalf Of Stephen
> Warren
> Sent: Friday, July 06, 2012 1:04 AM
> To: Alex Courbot
> Cc: Thierry Reding; Sascha Hauer; Mark Brown; linux-tegra@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-fbdev@vger.kernel.org
> Subject: Re: [PATCH] pwm-backlight: add regulator and GPIO support
>
> On 07/05/2012 02:12 AM, Alex Courbot wrote:
> > On 07/05/2012 04:57 PM, Thierry Reding wrote:
> >> I agree. Non-DT platforms have always used the callbacks to execute this
> >> kind of code. As you've said before there are situations where it isn't
> >> just about setting a GPIO or enabling a regulator but it also requires a
> >> specific timing. Representing this in the platform data would become
> >> tedious.
> >
> > That will settle the whole issue then.
> >
> >> So I think for the DT case you can parse the power-on and power-off
> >> sequences directly and execute code based on it, while in non-DT cases
> >> the init and exit callbacks should be used instead. I think it even
> >> makes sense to reuse the platform data's init and exit functions in the
> >> DT case and implement the parser/interpreter within those.
> >
> > It totally makes sense indeed.
>
> I don't agree here. It'd be best if non-DT and DT cases worked as
> similarly as possible. Relying on callbacks in one case and
> data-parsed-from-DT in the other isn't consistent with that. After all,
> in the DT case, you parse some data out of the DT and into some data
> structure. In the non-DT case, you can have that data structure passed
> in directly using platform data. Now, there's certainly a need to
> continue to support callbacks for backwards compatibility, at the very
> least temporarily before all clients are converted to the new model, but
> requiring different models rather than simply allowing it seems like a
> bad idea to me.
Hi Alex Courbot,
I couldn't agree with Stephen Warren more.
Could you support DT and non-DT case for backwards compatibility?
Best regards,
Jingoo Han
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] pwm_backlight: pass correct brightness to callback
From: Alex Courbot @ 2012-07-09 5:27 UTC (permalink / raw)
To: Thierry Reding; +Cc: linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org
In-Reply-To: <20120709051001.GA10108@avionic-0098.mockup.avionic-design.de>
On 07/09/2012 02:10 PM, Thierry Reding wrote:
> I had to actually read this patch a number of times and then realized I
> was completely missing the context. Looking at the whole function makes
> it more obvious what you mean.
>
> However I think it'd be much clearer if we just passed the value of
> bl->props.brightness into the callbacks, that way we can avoid the
> additional variable.
This won't work I'm afraid, as brightness can be modified prior to being
passed to the callback function:
if (bl->props.power != FB_BLANK_UNBLANK)
brightness = 0;
if (bl->props.fb_blank != FB_BLANK_UNBLANK)
brightness = 0;
if (pb->notify)
brightness = pb->notify(pb->dev, brightness);
Alex.
^ permalink raw reply
* [PATCHv2] pwm_backlight: pass correct brightness to callback
From: Alexandre Courbot @ 2012-07-09 5:36 UTC (permalink / raw)
To: Thierry Reding; +Cc: linux-kernel, linux-fbdev, Alexandre Courbot
In-Reply-To: <4FFA6BCA.2040101@nvidia.com>
pwm_backlight_update_status calls the notify() and notify_after()
callbacks before and after applying the new PWM settings. However, if
brightness levels are used, the brightness value will be changed from
the index into the levels array to the PWM duty cycle length before
being passed to notify_after(), which results in inconsistent behavior.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
drivers/video/backlight/pwm_bl.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 057389d..6d1d3ea 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -39,6 +39,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
{
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
int brightness = bl->props.brightness;
+ int pwm_brightness;
int max = bl->props.max_brightness;
if (bl->props.power != FB_BLANK_UNBLANK)
@@ -55,13 +56,15 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
pwm_disable(pb->pwm);
} else {
if (pb->levels) {
- brightness = pb->levels[brightness];
+ pwm_brightness = pb->levels[brightness];
max = pb->levels[max];
+ } else {
+ pwm_brightness = brightness;
}
- brightness = pb->lth_brightness +
- (brightness * (pb->period - pb->lth_brightness) / max);
- pwm_config(pb->pwm, brightness, pb->period);
+ pwm_brightness = pb->lth_brightness +
+ (pwm_brightness * (pb->period - pb->lth_brightness) / max);
+ pwm_config(pb->pwm, pwm_brightness, pb->period);
pwm_enable(pb->pwm);
}
--
1.7.11.1
^ permalink raw reply related
* [PATCHv3] pwm_backlight: pass correct brightness to callback
From: Alexandre Courbot @ 2012-07-09 6:04 UTC (permalink / raw)
To: Thierry Reding; +Cc: linux-kernel, linux-fbdev, Alexandre Courbot
In-Reply-To: <4FFA6BCA.2040101@nvidia.com>
pwm_backlight_update_status calls the notify() and notify_after()
callbacks before and after applying the new PWM settings. However, if
brightness levels are used, the brightness value will be changed from
the index into the levels array to the PWM duty cycle length before
being passed to notify_after(), which results in inconsistent behavior.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
drivers/video/backlight/pwm_bl.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 057389d..be48517 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -54,14 +54,17 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
pwm_config(pb->pwm, 0, pb->period);
pwm_disable(pb->pwm);
} else {
+ int duty_cycle;
if (pb->levels) {
- brightness = pb->levels[brightness];
+ duty_cycle = pb->levels[brightness];
max = pb->levels[max];
+ } else {
+ duty_cycle = brightness;
}
- brightness = pb->lth_brightness +
- (brightness * (pb->period - pb->lth_brightness) / max);
- pwm_config(pb->pwm, brightness, pb->period);
+ duty_cycle = pb->lth_brightness +
+ (duty_cycle * (pb->period - pb->lth_brightness) / max);
+ pwm_config(pb->pwm, duty_cycle, pb->period);
pwm_enable(pb->pwm);
}
--
1.7.11.1
^ permalink raw reply related
* [RFC][PATCHv2 0/3] Power sequences interpreter for pwm_backlight
From: Alexandre Courbot @ 2012-07-09 6:08 UTC (permalink / raw)
To: Thierry Reding
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Alexandre Courbot
This is a RFC since this patch largely drifted beyond its original goal
of supporting one GPIO and one regulator for the pwm_backlight driver.
The issue to address is that backlight power sequences, which were
implemented using board-specific callbacks so far, could not be used with
the device tree. This series of patches adds a small power sequence
interpreter that allows to acquire and control regulators, GPIOs, and PWMs
during sequences defined in the device tree. It is easy to use,
low-footprint, and takes care of managing the resources that it acquires.
The implementation is working and should be complete, but documentation is
lacking. Also since the interpreter could be used by other drivers (which
ones?), it may make sense to have it in a better place than
drivers/video/backlight/.
The tegra device tree nodes are just here as an example usage.
Alexandre Courbot (3):
Power sequences interpreter for device tree
pwm-backlight: use power sequences
tegra: add pwm backlight device tree nodes
.../bindings/video/backlight/pwm-backlight.txt | 28 +-
arch/arm/boot/dts/tegra20-ventana.dts | 31 +++
arch/arm/boot/dts/tegra20.dtsi | 2 +-
drivers/video/backlight/Makefile | 2 +-
drivers/video/backlight/power_seq.c | 298 +++++++++++++++++++++
drivers/video/backlight/pwm_bl.c | 212 +++++++++++----
include/linux/power_seq.h | 96 +++++++
include/linux/pwm_backlight.h | 37 ++-
8 files changed, 645 insertions(+), 61 deletions(-)
create mode 100644 drivers/video/backlight/power_seq.c
create mode 100644 include/linux/power_seq.h
--
1.7.11.1
^ permalink raw reply
* [RFC][PATCH V2 1/3] power sequences interpreter for device tree
From: Alexandre Courbot @ 2012-07-09 6:08 UTC (permalink / raw)
To: Thierry Reding
Cc: linux-tegra, linux-kernel, linux-fbdev, devicetree-discuss,
Alexandre Courbot
In-Reply-To: <1341814105-20690-1-git-send-email-acourbot@nvidia.com>
Some device drivers (panel backlights especially) need to follow precise
sequences for powering on and off, involving gpios, regulators, PWMs
with a precise powering order and delays to respect between each steps.
These sequences are board-specific, and do not belong to a particular
driver - therefore they have been performed by board-specific hook
functions to far.
With the advent of the device tree, we cannot rely of board-specific
hooks anymore, but still need a way to implement these sequences in a
portable manner. This patch introduces a simple interpreter that can
execute such power sequences encoded either as platform data or within
the device tree.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
drivers/video/backlight/Makefile | 2 +-
drivers/video/backlight/power_seq.c | 298 ++++++++++++++++++++++++++++++++++++
drivers/video/backlight/pwm_bl.c | 3 +-
include/linux/power_seq.h | 96 ++++++++++++
4 files changed, 397 insertions(+), 2 deletions(-)
create mode 100644 drivers/video/backlight/power_seq.c
create mode 100644 include/linux/power_seq.h
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index a2ac9cf..6bff124 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -28,7 +28,7 @@ obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o
obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o
obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
-obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
+obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o power_seq.o
obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o
obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o
diff --git a/drivers/video/backlight/power_seq.c b/drivers/video/backlight/power_seq.c
new file mode 100644
index 0000000..f54cb7d
--- /dev/null
+++ b/drivers/video/backlight/power_seq.c
@@ -0,0 +1,298 @@
+#include <linux/err.h>
+#include <linux/of_gpio.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/power_seq.h>
+#include <linux/delay.h>
+#include <linux/pwm.h>
+#include <linux/regulator/consumer.h>
+
+#define PWM_SEQ_TYPE(type) [POWER_SEQ_ ## type] = #type
+static const char *pwm_seq_types[] = {
+ PWM_SEQ_TYPE(STOP),
+ PWM_SEQ_TYPE(DELAY),
+ PWM_SEQ_TYPE(REGULATOR),
+ PWM_SEQ_TYPE(PWM),
+ PWM_SEQ_TYPE(GPIO),
+};
+#undef PWM_SEQ_TYPE
+
+static bool power_seq_step_run(struct power_seq_step *step)
+{
+ switch (step->type) {
+ case POWER_SEQ_DELAY:
+ msleep(step->parameter);
+ break;
+ case POWER_SEQ_REGULATOR:
+ if (step->parameter)
+ regulator_enable(step->resource->regulator);
+ else
+ regulator_disable(step->resource->regulator);
+ break;
+ case POWER_SEQ_PWM:
+ if (step->parameter)
+ pwm_enable(step->resource->pwm);
+ else
+ pwm_disable(step->resource->pwm);
+ break;
+ case POWER_SEQ_GPIO:
+ gpio_set_value_cansleep(step->resource->gpio, step->parameter);
+ break;
+ /* should never happen since we verify the data when building it */
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int power_seq_run(power_seq *seq)
+{
+ int err;
+
+ if (!seq) return 0;
+
+ while (seq->type != POWER_SEQ_STOP) {
+ if ((err = power_seq_step_run(seq++))) {
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int of_parse_power_seq_step(struct device *dev, struct property *prop,
+ struct platform_power_seq_step *seq,
+ int max_steps)
+{
+ void *value = prop->value;
+ void *end = prop->value + prop->length;
+ int slen, smax, cpt = 0, i, ret;
+ char tmp_buf[32];
+
+ while (value < end && cpt < max_steps) {
+ smax = value - end;
+ slen = strnlen(value, end - value);
+
+ /* Unterminated string / not a string? */
+ if (slen >= end - value)
+ goto invalid_seq;
+
+ /* Find a matching sequence step type */
+ for (i = 0; i < POWER_SEQ_MAX; i++)
+ if (!strcmp(value, pwm_seq_types[i]))
+ break;
+
+ if (i >= POWER_SEQ_MAX)
+ goto unknown_step;
+
+ value += slen + 1;
+
+ seq[cpt].type = i;
+ switch (seq[cpt].type) {
+ case POWER_SEQ_DELAY:
+ /* integer parameter */
+ seq[cpt].parameter = be32_to_cpup(value);
+ value += sizeof(__be32);
+ break;
+ case POWER_SEQ_REGULATOR:
+ case POWER_SEQ_PWM:
+ case POWER_SEQ_GPIO:
+ /* consumer string */
+ slen = strnlen(value, end - value);
+ if (slen >= end - value)
+ goto invalid_seq;
+ seq[cpt].id = value;
+ value += slen + 1;
+
+ /* parameter */
+ seq[cpt].parameter = be32_to_cpup(value);
+ be32_to_cpup(value);
+ value += sizeof(__be32);
+
+ /* For GPIO we still need to resolve the phandle */
+ if (seq[cpt].type != POWER_SEQ_GPIO)
+ break;
+
+ strncpy(tmp_buf, seq[cpt].id, sizeof(tmp_buf) - 6);
+ tmp_buf[sizeof(tmp_buf) - 6] = 0;
+ strcat(tmp_buf, "-gpios");
+ ret = of_get_named_gpio(dev->of_node, tmp_buf, 0);
+ if (ret >= 0)
+ seq[cpt].value = ret;
+ else {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "cannot get gpio \"%s\"\n",
+ seq[cpt].id);
+ return ret;
+ }
+ default:
+ break;
+ }
+
+ cpt++;
+ }
+
+ if (cpt >= max_steps)
+ return -EOVERFLOW;
+
+ return 0;
+
+invalid_seq:
+ dev_err(dev, "invalid sequence \"%s\"\n", prop->name);
+ return -EINVAL;
+unknown_step:
+ dev_err(dev, "unknown step type \"%s\" in sequence \"%s\"\n",
+ (char *)value, prop->name);
+ return -EINVAL;
+}
+
+#define PWM_SEQ_MAX_LENGTH 16
+platform_power_seq *of_parse_power_seq(struct device *dev,
+ struct device_node *node, char *propname)
+{
+ platform_power_seq *seq = NULL;
+ struct property *prop;
+ int length;
+ int ret;
+
+ prop = of_find_property(node, propname, &length);
+ if (prop && length > 0) {
+ seq = devm_kzalloc(dev, sizeof(*seq) * PWM_SEQ_MAX_LENGTH,
+ GFP_KERNEL);
+ if (!seq)
+ return ERR_PTR(-ENOMEM);
+ /* keep one empty entry for the STOP step */
+ ret = of_parse_power_seq_step(dev, prop, seq,
+ PWM_SEQ_MAX_LENGTH - 1);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ }
+
+ return seq;
+}
+
+static
+struct power_seq_resource * power_seq_find_resource(power_seq_resources *ress,
+ struct platform_power_seq_step *res)
+{
+ struct power_seq_resource *step;
+
+ list_for_each_entry(step, ress, list) {
+ if (step->plat.type != res->type) continue;
+ switch (res->type) {
+ case POWER_SEQ_DELAY:
+ case POWER_SEQ_GPIO:
+ if (step->plat.value = res->value)
+ return step;
+ break;
+ default:
+ if (!strcmp(step->plat.id, res->id))
+ return step;
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+power_seq *power_seq_build(struct device *dev, power_seq_resources *ress,
+ platform_power_seq *pseq)
+{
+ struct power_seq_step *seq = NULL, *ret;
+ struct power_seq_resource *res;
+ int cpt;
+
+ /* first pass to count the number of elements */
+ for (cpt = 0; pseq[cpt].type != POWER_SEQ_STOP; cpt++);
+
+ if (!cpt)
+ return seq;
+
+ /* 1 more for the STOP step */
+ ret = seq = devm_kzalloc(dev, sizeof(*seq) * (cpt + 1), GFP_KERNEL);
+ if (!seq)
+ return ERR_PTR(-ENOMEM);
+
+ for (; pseq->type != POWER_SEQ_STOP; pseq++, seq++) {
+ seq->type = pseq->type;
+
+ switch (pseq->type) {
+ case POWER_SEQ_REGULATOR:
+ case POWER_SEQ_GPIO:
+ case POWER_SEQ_PWM:
+ if (!(res = power_seq_find_resource(ress, pseq))) {
+ /* create resource node */
+ res = devm_kzalloc(dev, sizeof(*res),
+ GFP_KERNEL);
+ if (!res)
+ return ERR_PTR(-ENOMEM);
+ memcpy(&res->plat, pseq, sizeof(*pseq));
+
+ list_add(&res->list, ress);
+ }
+ seq->resource = res;
+ case POWER_SEQ_DELAY:
+ seq->parameter = pseq->parameter;
+ break;
+ default:
+ dev_err(dev, "invalid sequence step type!\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ return ret;
+}
+
+int power_seq_allocate_resources(struct device *dev, power_seq_resources *ress)
+{
+ struct power_seq_resource *res;
+ int err;
+
+ list_for_each_entry(res, ress, list) {
+ switch (res->plat.type) {
+ case POWER_SEQ_REGULATOR:
+ res->regulator = devm_regulator_get(dev, res->plat.id);
+ if (IS_ERR(res->regulator)) {
+ dev_err(dev, "cannot get regulator \"%s\"\n",
+ res->plat.id);
+ return PTR_ERR(res->regulator);
+ }
+ dev_dbg(dev, "got regulator %s\n", res->plat.id);
+ break;
+ case POWER_SEQ_PWM:
+ res->pwm = pwm_get(dev, res->plat.id);
+ if (IS_ERR(res->pwm)) {
+ dev_err(dev, "cannot get pwm \"%s\"\n",
+ res->plat.id);
+ return PTR_ERR(res->pwm);
+ }
+ dev_dbg(dev, "got PWM %s\n", res->plat.id);
+ break;
+ case POWER_SEQ_GPIO:
+ err = devm_gpio_request_one(dev, res->plat.value,
+ GPIOF_OUT_INIT_HIGH, "backlight_gpio");
+ if (err) {
+ dev_err(dev, "cannot get gpio %d\n",
+ res->plat.value);
+ return err;
+ }
+ res->gpio = res->plat.value;
+ dev_dbg(dev, "got GPIO %d\n", res->plat.value);
+ break;
+ default:
+ break;
+ };
+ }
+
+ return 0;
+}
+
+void power_seq_free_resources(power_seq_resources *ress) {
+ struct power_seq_resource *res;
+
+ list_for_each_entry(res, ress, list) {
+ if (res->plat.type = POWER_SEQ_PWM)
+ pwm_put(res->pwm);
+ }
+}
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index be48517..1a38953 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -203,8 +203,9 @@ static int pwm_backlight_probe(struct platform_device *pdev)
if (data->levels) {
max = data->levels[data->max_brightness];
pb->levels = data->levels;
- } else
+ } else {
max = data->max_brightness;
+ }
pb->notify = data->notify;
pb->notify_after = data->notify_after;
diff --git a/include/linux/power_seq.h b/include/linux/power_seq.h
new file mode 100644
index 0000000..7f76270
--- /dev/null
+++ b/include/linux/power_seq.h
@@ -0,0 +1,96 @@
+/*
+ * Simple interpreter for defining power sequences as platform data or device
+ * tree properties. Mainly for use with backlight drivers.
+ */
+
+#ifndef __LINUX_POWER_SEQ_H
+#define __LINUX_POWER_SEQ_H
+
+#include <linux/of.h>
+#include <linux/types.h>
+
+/**
+ * The different kinds of resources that can be controlled during the sequences.
+ */
+typedef enum {
+ POWER_SEQ_STOP = 0,
+ POWER_SEQ_DELAY,
+ POWER_SEQ_REGULATOR,
+ POWER_SEQ_PWM,
+ POWER_SEQ_GPIO,
+ POWER_SEQ_MAX,
+} seq_type;
+
+/**
+ * Describe something to do during the power-up/down sequence.
+ */
+struct platform_power_seq_step {
+ seq_type type;
+ /**
+ * Identify the resource. Steps of type DELAY use value, others name the
+ * consumer to use in id.
+ */
+ union {
+ const char *id;
+ int value;
+ };
+ /**
+ * A value of 0 disables the resource, while a non-zero enables it.
+ * For DELAY steps this contains the delay to wait in milliseconds.
+ */
+ int parameter;
+};
+typedef struct platform_power_seq_step platform_power_seq;
+
+struct power_seq_resource {
+ /* copied from platform data */
+ struct platform_power_seq_step plat;
+ /* resolved resource */
+ union {
+ struct regulator *regulator;
+ struct pwm_device *pwm;
+ int gpio;
+ };
+ /* used to maintain a list of resources used by the driver */
+ struct list_head list;
+};
+typedef struct list_head power_seq_resources;
+
+struct power_seq_step {
+ seq_type type;
+ int parameter;
+ struct power_seq_resource *resource;
+};
+typedef struct power_seq_step power_seq;
+
+/**
+ * Build a platform data sequence from a device tree node. Memory for the
+ * sequence is allocated using devm_kzalloc on dev.
+ */
+platform_power_seq *of_parse_power_seq(struct device *dev,
+ struct device_node *node,
+ char *propname);
+/**
+ * Build a runnable power sequence from platform data, and add the resources
+ * it uses into ress. Memory for the sequence is allocated using devm_kzalloc
+ * on dev.
+ */
+power_seq *power_seq_build(struct device *dev, power_seq_resources *ress,
+ platform_power_seq *pseq);
+/**
+ * Allocate all resources (regulators, PWMs, GPIOs) found by calls to
+ * power_seq_build() for use by dev. Return 0 in case of success, error code
+ * otherwise.
+ */
+int power_seq_allocate_resources(struct device *dev, power_seq_resources *ress);
+/**
+ * Free all the resources previously allocated by power_seq_allocate_resources.
+ */
+void power_seq_free_resources(power_seq_resources *ress);
+/**
+ * Run the given power sequence. Returns 0 on success, error code in case of
+ * failure.
+ */
+int power_seq_run(power_seq *seq);
+
+#endif
--
1.7.11.1
^ permalink raw reply related
* [RFC][PATCH V2 2/3] pwm_backlight: use power sequences
From: Alexandre Courbot @ 2012-07-09 6:08 UTC (permalink / raw)
To: Thierry Reding
Cc: linux-tegra, linux-kernel, linux-fbdev, devicetree-discuss,
Alexandre Courbot
In-Reply-To: <1341814105-20690-1-git-send-email-acourbot@nvidia.com>
Make use of the power sequences specified in the device tree or platform
data, if any.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
.../bindings/video/backlight/pwm-backlight.txt | 28 ++-
drivers/video/backlight/power_seq.c | 44 ++---
drivers/video/backlight/pwm_bl.c | 210 +++++++++++++++------
include/linux/pwm_backlight.h | 37 +++-
4 files changed, 239 insertions(+), 80 deletions(-)
diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
index 1e4fc72..86c9253 100644
--- a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
+++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
@@ -2,7 +2,10 @@ pwm-backlight bindings
Required properties:
- compatible: "pwm-backlight"
- - pwms: OF device-tree PWM specification (see PWM binding[0])
+ - pwms: OF device-tree PWM specification (see PWM binding[0]). Exactly one PWM
+ must be specified
+ - pwm-names: a list of names for the PWM devices specified in the
+ "pwms" property (see PWM binding[0])
- brightness-levels: Array of distinct brightness levels. Typically these
are in the range from 0 to 255, but any range starting at 0 will do.
The actual brightness level (PWM duty cycle) will be interpolated
@@ -10,10 +13,18 @@ Required properties:
last value in the array represents a 100% duty cycle (brightest).
- default-brightness-level: the default brightness level (index into the
array defined by the "brightness-levels" property)
+ - power-on-sequence: Power sequence that will bring the backlight on. This
+ sequence must reference the PWM specified in the pwms property by its
+ name. It can also reference extra GPIOs or regulators, and introduce
+ delays between sequence steps
+ - power-off-sequence: Power sequence that will bring the backlight off. This
+ sequence must reference the PWM specified in the pwms property by its
+ name. It can also reference extra GPIOs or regulators, and introduce
+ delays between sequence steps
Optional properties:
- - pwm-names: a list of names for the PWM devices specified in the
- "pwms" property (see PWM binding[0])
+ - *-supply: a reference to a regulator used within a power sequence
+ - *-gpios: a reference to a GPIO used within a power sequence.
[0]: Documentation/devicetree/bindings/pwm/pwm.txt
@@ -22,7 +33,18 @@ Example:
backlight {
compatible = "pwm-backlight";
pwms = <&pwm 0 5000000>;
+ pwm-names = "backlight";
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <6>;
+ power-supply = <&backlight_reg>;
+ enable-gpios = <&gpio 6 0>;
+ power-on-sequence = "REGULATOR", "power", <1>,
+ "DELAY", <10>,
+ "PWM", "backlight", <1>,
+ "GPIO", "enable", <1>;
+ power-off-sequence = "GPIO", "enable", <0>,
+ "PWM", "backlight", <0>,
+ "DELAY", <10>,
+ "REGULATOR", "power", <0>;
};
diff --git a/drivers/video/backlight/power_seq.c b/drivers/video/backlight/power_seq.c
index f54cb7d..f8737db 100644
--- a/drivers/video/backlight/power_seq.c
+++ b/drivers/video/backlight/power_seq.c
@@ -118,9 +118,9 @@ static int of_parse_power_seq_step(struct device *dev, struct property *prop,
tmp_buf[sizeof(tmp_buf) - 6] = 0;
strcat(tmp_buf, "-gpios");
ret = of_get_named_gpio(dev->of_node, tmp_buf, 0);
- if (ret >= 0)
+ if (ret >= 0) {
seq[cpt].value = ret;
- else {
+ } else {
if (ret != -EPROBE_DEFER)
dev_err(dev, "cannot get gpio \"%s\"\n",
seq[cpt].id);
@@ -218,26 +218,26 @@ power_seq *power_seq_build(struct device *dev, power_seq_resources *ress,
seq->type = pseq->type;
switch (pseq->type) {
- case POWER_SEQ_REGULATOR:
- case POWER_SEQ_GPIO:
- case POWER_SEQ_PWM:
- if (!(res = power_seq_find_resource(ress, pseq))) {
- /* create resource node */
- res = devm_kzalloc(dev, sizeof(*res),
- GFP_KERNEL);
- if (!res)
- return ERR_PTR(-ENOMEM);
- memcpy(&res->plat, pseq, sizeof(*pseq));
-
- list_add(&res->list, ress);
- }
- seq->resource = res;
- case POWER_SEQ_DELAY:
- seq->parameter = pseq->parameter;
- break;
- default:
- dev_err(dev, "invalid sequence step type!\n");
- return ERR_PTR(-EINVAL);
+ case POWER_SEQ_REGULATOR:
+ case POWER_SEQ_GPIO:
+ case POWER_SEQ_PWM:
+ if (!(res = power_seq_find_resource(ress, pseq))) {
+ /* create resource node */
+ res = devm_kzalloc(dev, sizeof(*res),
+ GFP_KERNEL);
+ if (!res)
+ return ERR_PTR(-ENOMEM);
+ memcpy(&res->plat, pseq, sizeof(*pseq));
+
+ list_add(&res->list, ress);
+ }
+ seq->resource = res;
+ case POWER_SEQ_DELAY:
+ seq->parameter = pseq->parameter;
+ break;
+ default:
+ dev_err(dev, "invalid sequence step type!\n");
+ return ERR_PTR(-EINVAL);
}
}
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 1a38953..2936819 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -27,6 +27,12 @@ struct pwm_bl_data {
unsigned int period;
unsigned int lth_brightness;
unsigned int *levels;
+ bool enabled;
+ power_seq_resources resources;
+ power_seq *power_on_seq;
+ power_seq *power_off_seq;
+
+ /* Legacy callbacks */
int (*notify)(struct device *,
int brightness);
void (*notify_after)(struct device *,
@@ -35,6 +41,34 @@ struct pwm_bl_data {
void (*exit)(struct device *);
};
+static void pwm_backlight_on(struct backlight_device *bl)
+{
+ struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+ int ret;
+
+ if (pb->enabled)
+ return;
+
+ if ((ret = power_seq_run(pb->power_on_seq)) < 0)
+ dev_err(&bl->dev, "cannot run power on sequence\n");
+
+ pb->enabled = true;
+}
+
+static void pwm_backlight_off(struct backlight_device *bl)
+{
+ struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+ int ret;
+
+ if (!pb->enabled)
+ return;
+
+ if ((ret = power_seq_run(pb->power_off_seq)) < 0)
+ dev_err(&bl->dev, "cannot run power off sequence\n");
+
+ pb->enabled = false;
+}
+
static int pwm_backlight_update_status(struct backlight_device *bl)
{
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
@@ -51,8 +85,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
brightness = pb->notify(pb->dev, brightness);
if (brightness = 0) {
- pwm_config(pb->pwm, 0, pb->period);
- pwm_disable(pb->pwm);
+ pwm_backlight_off(bl);
} else {
int duty_cycle;
if (pb->levels) {
@@ -144,12 +177,15 @@ static int pwm_backlight_parse_dt(struct device *dev,
data->max_brightness--;
}
- /*
- * TODO: Most users of this driver use a number of GPIOs to control
- * backlight power. Support for specifying these needs to be
- * added.
- */
+ data->power_on_seq = of_parse_power_seq(dev, node, "power-on-sequence");
+ if (IS_ERR(data->power_on_seq))
+ return PTR_ERR(data->power_on_seq);
+ data->power_off_seq = of_parse_power_seq(dev, node,
+ "power-off-sequence");
+ if (IS_ERR(data->power_off_seq))
+ return PTR_ERR(data->power_off_seq);
+ data->use_power_sequences = true;
return 0;
}
@@ -167,37 +203,134 @@ static int pwm_backlight_parse_dt(struct device *dev,
}
#endif
+/**
+ * Construct the power sequences corresponding to the legacy platform data.
+ */
+static int pwm_backlight_legacy_probe(struct platform_device *pdev,
+ struct pwm_bl_data *pb)
+{
+ struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct power_seq_resource *res;
+ struct power_seq_step *step;
+
+ pb->pwm = pwm_get(dev, NULL);
+ if (IS_ERR(pb->pwm)) {
+ dev_warn(dev, "unable to request PWM, trying legacy API\n");
+
+ pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
+ if (IS_ERR(pb->pwm)) {
+ dev_err(dev, "unable to request legacy PWM\n");
+ return PTR_ERR(pb->pwm);
+ }
+ pwm_set_period(pb->pwm, data->pwm_period_ns);
+ }
+
+ pb->notify = data->notify;
+ pb->notify_after = data->notify_after;
+ pb->check_fb = data->check_fb;
+ pb->exit = data->exit;
+ pb->dev = dev;
+
+ /* Now build the resources and sequences corresponding to this PWM */
+ res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
+ if (!res) return -ENOMEM;
+ res->plat.type = POWER_SEQ_PWM;
+ res->plat.id = "pwm-backlight";
+ res->pwm = pb->pwm;
+ list_add(&res->list, &pb->resources);
+
+ /* allocate both power on and off sequences at the same time */
+ step = devm_kzalloc(dev, sizeof(*step) * 4, GFP_KERNEL);
+ if (!step) return -ENOMEM;
+ step->type = POWER_SEQ_PWM;
+ step->resource = res;
+ memcpy(&step[2], &step[0], sizeof(*step));
+ step[0].parameter = 1;
+ pb->power_on_seq = &step[0];
+ pb->power_off_seq = &step[2];
+
+ return 0;
+}
+
static int pwm_backlight_probe(struct platform_device *pdev)
{
struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
struct platform_pwm_backlight_data defdata;
+ struct power_seq_resource *res;
struct backlight_properties props;
struct backlight_device *bl;
struct pwm_bl_data *pb;
unsigned int max;
int ret;
+ pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
+ if (!pb) {
+ dev_err(&pdev->dev, "no memory for state\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&pb->resources);
+
+ /* using new interface or device tree */
if (!data) {
+ /* build platform data from device tree */
ret = pwm_backlight_parse_dt(&pdev->dev, &defdata);
- if (ret < 0) {
+ if (ret = -EPROBE_DEFER) {
+ return ret;
+ } else if (ret < 0) {
dev_err(&pdev->dev, "failed to find platform data\n");
return ret;
}
-
data = &defdata;
}
- if (data->init) {
- ret = data->init(&pdev->dev);
+ if (!data->use_power_sequences) {
+ /* using legacy interface */
+ ret = pwm_backlight_legacy_probe(pdev, pb);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* build sequences and allocate resources from platform data */
+ if (data->power_on_seq) {
+ pb->power_on_seq = power_seq_build(&pdev->dev, &pb->resources,
+ data->power_on_seq);
+ if (IS_ERR(pb->power_on_seq))
+ return PTR_ERR(pb->power_on_seq);
+ }
+ if (data->power_off_seq) {
+ pb->power_off_seq = power_seq_build(&pdev->dev, &pb->resources,
+ data->power_off_seq);
+ if (IS_ERR(pb->power_off_seq))
+ return PTR_ERR(pb->power_off_seq);
+ }
+ ret = power_seq_allocate_resources(&pdev->dev, &pb->resources);
if (ret < 0)
return ret;
+
+ /* we must have exactly one PWM for this driver */
+ list_for_each_entry(res, &pb->resources, list) {
+ if (res->plat.type != POWER_SEQ_PWM)
+ continue;
+ if (pb->pwm) {
+ dev_err(&pdev->dev, "cannot use more than one PWM\n");
+ return -EINVAL;
+ }
+ /* keep the pwm at hand */
+ pb->pwm = res->pwm;
+ }
}
- pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
- if (!pb) {
- dev_err(&pdev->dev, "no memory for state\n");
- ret = -ENOMEM;
- goto err_alloc;
+ /* from here we should have a PWM */
+ if (!pb->pwm) {
+ dev_err(&pdev->dev, "no PWM defined!\n");
+ return -EINVAL;
+ }
+
+ if (data->init) {
+ ret = data->init(&pdev->dev);
+ if (ret < 0)
+ goto err;
}
if (data->levels) {
@@ -207,34 +340,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
max = data->max_brightness;
}
- pb->notify = data->notify;
- pb->notify_after = data->notify_after;
- pb->check_fb = data->check_fb;
- pb->exit = data->exit;
- pb->dev = &pdev->dev;
-
- pb->pwm = pwm_get(&pdev->dev, NULL);
- if (IS_ERR(pb->pwm)) {
- dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
-
- pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
- if (IS_ERR(pb->pwm)) {
- dev_err(&pdev->dev, "unable to request legacy PWM\n");
- ret = PTR_ERR(pb->pwm);
- goto err_alloc;
- }
- }
-
- dev_dbg(&pdev->dev, "got pwm for backlight\n");
-
- /*
- * The DT case will set the pwm_period_ns field to 0 and store the
- * period, parsed from the DT, in the PWM device. For the non-DT case,
- * set the period from platform data.
- */
- if (data->pwm_period_ns > 0)
- pwm_set_period(pb->pwm, data->pwm_period_ns);
-
pb->period = pwm_get_period(pb->pwm);
pb->lth_brightness = data->lth_brightness * (pb->period / max);
@@ -246,20 +351,20 @@ static int pwm_backlight_probe(struct platform_device *pdev)
if (IS_ERR(bl)) {
dev_err(&pdev->dev, "failed to register backlight\n");
ret = PTR_ERR(bl);
- goto err_bl;
+ goto err;
}
bl->props.brightness = data->dft_brightness;
backlight_update_status(bl);
platform_set_drvdata(pdev, bl);
+
return 0;
-err_bl:
- pwm_put(pb->pwm);
-err_alloc:
+err:
if (data->exit)
data->exit(&pdev->dev);
+ power_seq_free_resources(&pb->resources);
return ret;
}
@@ -269,9 +374,9 @@ static int pwm_backlight_remove(struct platform_device *pdev)
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
backlight_device_unregister(bl);
- pwm_config(pb->pwm, 0, pb->period);
- pwm_disable(pb->pwm);
- pwm_put(pb->pwm);
+ pwm_backlight_off(bl);
+ power_seq_free_resources(&pb->resources);
+
if (pb->exit)
pb->exit(&pdev->dev);
return 0;
@@ -285,8 +390,7 @@ static int pwm_backlight_suspend(struct device *dev)
if (pb->notify)
pb->notify(pb->dev, 0);
- pwm_config(pb->pwm, 0, pb->period);
- pwm_disable(pb->pwm);
+ pwm_backlight_off(bl);
if (pb->notify_after)
pb->notify_after(pb->dev, 0);
return 0;
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index 56f4a86..dda267e 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -5,14 +5,47 @@
#define __LINUX_PWM_BACKLIGHT_H
#include <linux/backlight.h>
+#include <linux/power_seq.h>
+/**
+ * Two ways of passing data to the driver can be used:
+ * 1) If not using device tree and use_power_sequences is not set, the legacy
+ * interface is used. power_on_sequence and power_off_sequences are ignored,
+ * and pwm_id and pwm_period_ns can be used to assign a PWM and period to
+ * the backlight. The callback functions will also be called by the driver
+ * at appropriate times.
+ * 2) If use_power_sequences is set, the power sequences should either be NULL
+ * of contain an array of platform_pwm_backlight_seq_step instances
+ * terminated by a full-zero'd one. The described sequences will then be used
+ * for powering the backlight on and off, and the callbacks will not be
+ * called. Instances of resources will be obtained using the get_* functions,
+ * giving id as a consumer name.
+ *
+ * If the device tree is used, the power sequences properties are parsed and
+ * converted to the corresponding power sequences of this structure, which is
+ * passed to the driver with use_power_sequences set to true. See the
+ * pwm-backlight bindings documentation file for more details.
+ */
struct platform_pwm_backlight_data {
- int pwm_id;
unsigned int max_brightness;
unsigned int dft_brightness;
unsigned int lth_brightness;
- unsigned int pwm_period_ns;
unsigned int *levels;
+ /* Set this to true otherwise the legacy interface will be used */
+ bool use_power_sequences;
+ /*
+ * New interface - arrays of steps terminated by a STOP instance, or
+ * NULL if unused.
+ */
+ struct platform_power_seq_step *power_on_seq;
+ struct platform_power_seq_step *power_off_seq;
+ /*
+ * Legacy interface - single PWM and callback methods to control
+ * the power sequence. pwm_id and pwm_period_ns need only be specified
+ * if get_pwm(dev, NULL) will return NULL.
+ */
+ int pwm_id;
+ unsigned int pwm_period_ns;
int (*init)(struct device *dev);
int (*notify)(struct device *dev, int brightness);
void (*notify_after)(struct device *dev, int brightness);
--
1.7.11.1
^ permalink raw reply related
* [RFC][PATCH V2 3/3] tegra: add pwm backlight device tree nodes
From: Alexandre Courbot @ 2012-07-09 6:08 UTC (permalink / raw)
To: Thierry Reding
Cc: linux-tegra, linux-kernel, linux-fbdev, devicetree-discuss,
Alexandre Courbot
In-Reply-To: <1341814105-20690-1-git-send-email-acourbot@nvidia.com>
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
arch/arm/boot/dts/tegra20-ventana.dts | 31 +++++++++++++++++++++++++++++++
arch/arm/boot/dts/tegra20.dtsi | 2 +-
2 files changed, 32 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
index be90544..c67d9e1 100644
--- a/arch/arm/boot/dts/tegra20-ventana.dts
+++ b/arch/arm/boot/dts/tegra20-ventana.dts
@@ -317,6 +317,37 @@
bus-width = <8>;
};
+ backlight {
+ compatible = "pwm-backlight";
+ brightness-levels = <0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240 255>;
+ default-brightness-level = <12>;
+
+ pwms = <&pwm 2 5000000>;
+ pwm-names = "backlight";
+ power-supply = <&backlight_reg>;
+ enable-gpios = <&gpio 28 0>;
+
+ power-on-sequence = "REGULATOR", "power", <1>,
+ "DELAY", <10>,
+ "PWM", "backlight", <1>,
+ "GPIO", "enable", <1>;
+ power-off-sequence = "GPIO", "enable", <0>,
+ "PWM", "backlight", <0>,
+ "DELAY", <10>,
+ "REGULATOR", "power", <0>;
+ };
+
+ backlight_reg: fixedregulator@176 {
+ compatible = "regulator-fixed";
+ regulator-name = "backlight_regulator";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ gpio = <&gpio 176 0>;
+ startup-delay-us = <0>;
+ enable-active-high;
+ regulator-boot-off;
+ };
+
sound {
compatible = "nvidia,tegra-audio-wm8903-ventana",
"nvidia,tegra-audio-wm8903";
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 405d167..67a6cd9 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -123,7 +123,7 @@
status = "disabled";
};
- pwm {
+ pwm: pwm {
compatible = "nvidia,tegra20-pwm";
reg = <0x7000a000 0x100>;
#pwm-cells = <2>;
--
1.7.11.1
^ permalink raw reply related
* Re: [PATCH] pwm-backlight: add regulator and GPIO support
From: Alex Courbot @ 2012-07-09 6:12 UTC (permalink / raw)
To: Jingoo Han
Cc: 'Thierry Reding', 'Sascha Hauer',
'Stephen Warren', 'Mark Brown',
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <00ae01cd5d92$70d1f9f0$5275edd0$%han-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
On 07/09/2012 02:19 PM, Jingoo Han wrote:
> I couldn't agree with Stephen Warren more.
> Could you support DT and non-DT case for backwards compatibility?
Both cases are handled in the new version I just sent. I hope all other
concerns have also been addressed properly. If I forgot something please
ping me.
Alex.
^ permalink raw reply
* Re: [PATCHv3] pwm_backlight: pass correct brightness to callback
From: Thierry Reding @ 2012-07-09 6:30 UTC (permalink / raw)
To: Alexandre Courbot; +Cc: linux-kernel, linux-fbdev
In-Reply-To: <1341813863-18822-1-git-send-email-acourbot@nvidia.com>
[-- Attachment #1: Type: text/plain, Size: 1712 bytes --]
On Mon, Jul 09, 2012 at 03:04:23PM +0900, Alexandre Courbot wrote:
> pwm_backlight_update_status calls the notify() and notify_after()
> callbacks before and after applying the new PWM settings. However, if
> brightness levels are used, the brightness value will be changed from
> the index into the levels array to the PWM duty cycle length before
> being passed to notify_after(), which results in inconsistent behavior.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
> drivers/video/backlight/pwm_bl.c | 11 +++++++----
> 1 file changed, 7 insertions(+), 4 deletions(-)
Applied, with a minor stylistic fixup adding a blank line after the
duty_cycle variable declaration. Thanks.
Thierry
> diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
> index 057389d..be48517 100644
> --- a/drivers/video/backlight/pwm_bl.c
> +++ b/drivers/video/backlight/pwm_bl.c
> @@ -54,14 +54,17 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
> pwm_config(pb->pwm, 0, pb->period);
> pwm_disable(pb->pwm);
> } else {
> + int duty_cycle;
> if (pb->levels) {
> - brightness = pb->levels[brightness];
> + duty_cycle = pb->levels[brightness];
> max = pb->levels[max];
> + } else {
> + duty_cycle = brightness;
> }
>
> - brightness = pb->lth_brightness +
> - (brightness * (pb->period - pb->lth_brightness) / max);
> - pwm_config(pb->pwm, brightness, pb->period);
> + duty_cycle = pb->lth_brightness +
> + (duty_cycle * (pb->period - pb->lth_brightness) / max);
> + pwm_config(pb->pwm, duty_cycle, pb->period);
> pwm_enable(pb->pwm);
> }
>
> --
> 1.7.11.1
>
>
>
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH v2 11/11] MAINTAINERS: add fblog entry
From: Geert Uytterhoeven @ 2012-07-09 7:33 UTC (permalink / raw)
To: David Herrmann
Cc: linux-serial, linux-kernel, florianschandinat, linux-fbdev,
gregkh, alan, bonbons
In-Reply-To: <1341784614-2797-12-git-send-email-dh.herrmann@googlemail.com>
On Sun, Jul 8, 2012 at 11:56 PM, David Herrmann
<dh.herrmann@googlemail.com> wrote:
> Add myself as maintainer for the fblog driver to the MAINTAINERS file.
>
> Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
> ---
> MAINTAINERS | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ae8fe46..249b02a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2854,6 +2854,12 @@ F: drivers/video/
> F: include/video/
> F: include/linux/fb.h
>
> +FRAMEBUFFER LOG DRIVER
> +M: David Herrmann <dh.herrmann@googlemail.com>
> +L: linux-serial@vger.kernel.org
Why linux-serial, and not linux-fbdev?
> +S: Maintained
> +F: drivers/video/console/fblog.c
> +
> FREESCALE DMA DRIVER
> M: Li Yang <leoli@freescale.com>
> M: Zhang Wei <zw@zh-kernel.org>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v2 04/11] fbdev: export get_fb_info()/put_fb_info()
From: Geert Uytterhoeven @ 2012-07-09 7:34 UTC (permalink / raw)
To: David Herrmann
Cc: linux-serial, linux-kernel, florianschandinat, linux-fbdev,
gregkh, alan, bonbons
In-Reply-To: <1341784614-2797-5-git-send-email-dh.herrmann@googlemail.com>
On Sun, Jul 8, 2012 at 11:56 PM, David Herrmann
<dh.herrmann@googlemail.com> wrote:
> --- a/drivers/video/fbmem.c
> +++ b/drivers/video/fbmem.c
> @@ -46,7 +46,7 @@ static DEFINE_MUTEX(registration_lock);
> struct fb_info *registered_fb[FB_MAX] __read_mostly;
> int num_registered_fb __read_mostly;
>
> -static struct fb_info *get_fb_info(unsigned int idx)
> +struct fb_info *get_fb_info(unsigned int idx)
> {
> struct fb_info *fb_info;
>
> @@ -61,14 +61,16 @@ static struct fb_info *get_fb_info(unsigned int idx)
>
> return fb_info;
> }
> +EXPORT_SYMBOL(get_fb_info);
EXPORT_SYMBOL_GPL?
> -static void put_fb_info(struct fb_info *fb_info)
> +void put_fb_info(struct fb_info *fb_info)
> {
> if (!atomic_dec_and_test(&fb_info->count))
> return;
> if (fb_info->fbops->fb_destroy)
> fb_info->fbops->fb_destroy(fb_info);
> }
> +EXPORT_SYMBOL(put_fb_info);
EXPORT_SYMBOL_GPL?
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [RFC][PATCH V2 2/3] pwm_backlight: use power sequences
From: Alex Courbot @ 2012-07-09 7:48 UTC (permalink / raw)
To: Alexandre Courbot
Cc: Thierry Reding,
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
In-Reply-To: <1341814105-20690-3-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Sorry, I just noticed a mistake in this patch I made while merging
another one. The following also needs to be changed, otherwise the
power-on sequence will never be executed:
diff --git a/drivers/video/backlight/pwm_bl.c
b/drivers/video/backlight/pwm_bl.c
index 1a38953..4546d23 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -65,7 +98,7 @@ static int pwm_backlight_update_status(struct
backlight_device *bl)
duty_cycle = pb->lth_brightness +
(duty_cycle * (pb->period - pb->lth_brightness) /
max);
pwm_config(pb->pwm, duty_cycle, pb->period);
- pwm_enable(pb->pwm);
+ pwm_backlight_on(bl);
}
Apologies for the inconvenience.
Alex.
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox