From f3a82170aef72bf57f03e5c154fc94fad54968b1 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Wed, 18 Sep 2013 17:06:05 +0200 Subject: pwm: atmel-tcb: add missing clk source config Clock source changes are never applied to the CMR register. This may lead to wrong period/duty cycle configuration. Signed-off-by: Boris BREZILLON Acked-by: Nicolas Ferre Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index ba6ce01..0266969 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -249,6 +249,8 @@ static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) } } + cmr |= (tcbpwm->div & ATMEL_TC_TCCLKS); + __raw_writel(cmr, regs + ATMEL_TC_REG(group, CMR)); if (index == 0) -- cgit v0.10.2 From ceb12f939809b3445d0b2118d4b07638bb07afa6 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Wed, 18 Sep 2013 17:06:21 +0200 Subject: pwm: atmel-tcb: fix max time computation for slow clk source Use the the tcb counter width to compute the maximum time that can be represented using the slow clock source instead of the static 16 bit width. Signed-off-by: Boris BREZILLON Acked-by: Nicolas Ferre Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 0266969..f3dcd02 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -307,7 +307,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, i = slowclk; rate = 32768; min = div_u64(NSEC_PER_SEC, rate); - max = min << 16; + max = min << tc->tcb_config->counter_width; /* If period is too big return ERANGE error */ if (max < period_ns) -- cgit v0.10.2 From 2a8876cfdf14de557705e2559df99f40058a3b3b Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 27 Sep 2013 16:53:23 +0530 Subject: pwm: imx: Include linux/of.h header 'of_match_ptr' is defined in linux/of.h. Include it explicitly. Signed-off-by: Sachin Kamat Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 2b7c4f8..aa6e5c6 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -16,6 +16,7 @@ #include #include #include +#include #include /* i.MX1 and i.MX21 share the same PWM function block: */ -- cgit v0.10.2 From c3bdfe1f1e4e1e195945c55a2256eba89334d36c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 27 Sep 2013 16:53:24 +0530 Subject: pwm: samsung: Include linux/of.h header 'of_match_ptr' is defined in linux/of.h. Include it explicitly. Signed-off-by: Sachin Kamat Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index fcc8b9a..57eb8cb 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From e852340deef3ce260074d53fbe553c60217c6c5b Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 27 Sep 2013 16:53:25 +0530 Subject: pwm: twl-led: Include linux/of.h header 'of_match_ptr' is defined in linux/of.h. Include it explicitly. Signed-off-by: Sachin Kamat Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c index 29d1bba..b964470 100644 --- a/drivers/pwm/pwm-twl-led.c +++ b/drivers/pwm/pwm-twl-led.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include -- cgit v0.10.2 From ea8eeb1502f20ecada3436ec058f65831b4a0fab Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 27 Sep 2013 16:53:26 +0530 Subject: pwm: twl: Include linux/of.h header 'of_match_ptr' is defined in linux/of.h. Include it explicitly. Signed-off-by: Sachin Kamat Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c index eef9105..b99a50e 100644 --- a/drivers/pwm/pwm-twl.c +++ b/drivers/pwm/pwm-twl.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include -- cgit v0.10.2 From de02cb887cb20d5a7fff5e44acfc67f6fd1ebe0c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 30 Sep 2013 08:56:39 +0530 Subject: pwm: mxs: Remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Acked-by: Shawn Guo Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index c2c5a4f..9475bc7 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -189,7 +189,7 @@ static struct platform_driver mxs_pwm_driver = { .driver = { .name = "mxs-pwm", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(mxs_pwm_dt_ids), + .of_match_table = mxs_pwm_dt_ids, }, .probe = mxs_pwm_probe, .remove = mxs_pwm_remove, -- cgit v0.10.2 From 3cb3b2bfddcdf0bd44b787127b52c2bd1ce9f291 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 30 Sep 2013 08:56:40 +0530 Subject: pwm: lpc32xx: Remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Cc: Alexandre Pereira da Silva Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c index efac99e0..9dc0f9d 100644 --- a/drivers/pwm/pwm-lpc32xx.c +++ b/drivers/pwm/pwm-lpc32xx.c @@ -169,7 +169,7 @@ static struct platform_driver lpc32xx_pwm_driver = { .driver = { .name = "lpc32xx-pwm", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(lpc32xx_pwm_dt_ids), + .of_match_table = lpc32xx_pwm_dt_ids, }, .probe = lpc32xx_pwm_probe, .remove = lpc32xx_pwm_remove, -- cgit v0.10.2 From becbca1390a5147b363a34e238e74cffe65eecc3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 30 Sep 2013 08:56:41 +0530 Subject: pwm: imx: Remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Acked-by: Sascha Hauer Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index aa6e5c6..cc47733 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -297,7 +297,7 @@ static struct platform_driver imx_pwm_driver = { .driver = { .name = "imx-pwm", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(imx_pwm_dt_ids), + .of_match_table = imx_pwm_dt_ids, }, .probe = imx_pwm_probe, .remove = imx_pwm_remove, -- cgit v0.10.2 From faed9c380860d986886e8a8b79b29bb3d1ac2a91 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 13 Oct 2013 18:17:49 +0200 Subject: pwm: don't use devm_pinctrl_get_select_default() in probe Since commit ab78029 (drivers/pinctrl: grab default handles from device core), we can rely on device core for setting the default pins. Compile tested only. Acked-by: Linus Walleij (personally at LCE13) Signed-off-by: Wolfram Sang Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index c2e2e58..4e5c3d1 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "pwm-tipwmss.h" @@ -208,11 +207,6 @@ static int ecap_pwm_probe(struct platform_device *pdev) struct clk *clk; struct ecap_pwm_chip *pc; u16 status; - struct pinctrl *pinctrl; - - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) - dev_warn(&pdev->dev, "unable to select pin group\n"); pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); if (!pc) { diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 084f552..a4d8f51 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "pwm-tipwmss.h" @@ -439,11 +438,6 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev) struct clk *clk; struct ehrpwm_pwm_chip *pc; u16 status; - struct pinctrl *pinctrl; - - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) - dev_warn(&pdev->dev, "unable to select pin group\n"); pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); if (!pc) { -- cgit v0.10.2 From 668e63c6701d486c68b49ffffc0e5b7de1a2e95c Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 7 Oct 2013 11:30:50 +0200 Subject: pwm-backlight: Improve readability Add more blank lines to increase readability. While at it, remove a trailing blank line at the end of the file. Signed-off-by: Thierry Reding diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 1fea627..774bce3 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -269,8 +269,10 @@ static int pwm_backlight_remove(struct platform_device *pdev) backlight_device_unregister(bl); pwm_config(pb->pwm, 0, pb->period); pwm_disable(pb->pwm); + if (pb->exit) pb->exit(&pdev->dev); + return 0; } @@ -282,10 +284,13 @@ 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); + if (pb->notify_after) pb->notify_after(pb->dev, 0); + return 0; } @@ -294,6 +299,7 @@ static int pwm_backlight_resume(struct device *dev) struct backlight_device *bl = dev_get_drvdata(dev); backlight_update_status(bl); + return 0; } #endif @@ -317,4 +323,3 @@ module_platform_driver(pwm_backlight_driver); MODULE_DESCRIPTION("PWM based Backlight Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:pwm-backlight"); - -- cgit v0.10.2 From 62b744a87c1170b339f993aa3cfb22465974816a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 7 Oct 2013 11:32:02 +0200 Subject: pwm-backlight: Refactor backlight power on/off In preparation for adding an optional regulator and enable GPIO to the driver, split the power on and power off sequences into separate functions to reduce code duplication at the multiple call sites. Signed-off-by: Thierry Reding diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 774bce3..ab9d5e6 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -35,6 +35,31 @@ struct pwm_bl_data { void (*exit)(struct device *); }; +static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness, + int max) +{ + int duty_cycle, err; + + if (pb->levels) { + duty_cycle = pb->levels[brightness]; + max = pb->levels[max]; + } else { + duty_cycle = brightness; + } + + duty_cycle = (duty_cycle * (pb->period - pb->lth_brightness) / max) + + pb->lth_brightness; + + pwm_config(pb->pwm, duty_cycle, pb->period); + pwm_enable(pb->pwm); +} + +static void pwm_backlight_power_off(struct pwm_bl_data *pb) +{ + pwm_config(pb->pwm, 0, pb->period); + pwm_disable(pb->pwm); +} + static int pwm_backlight_update_status(struct backlight_device *bl) { struct pwm_bl_data *pb = bl_get_data(bl); @@ -49,24 +74,10 @@ static int pwm_backlight_update_status(struct backlight_device *bl) if (pb->notify) brightness = pb->notify(pb->dev, brightness); - if (brightness == 0) { - pwm_config(pb->pwm, 0, pb->period); - pwm_disable(pb->pwm); - } else { - int duty_cycle; - - if (pb->levels) { - duty_cycle = pb->levels[brightness]; - max = pb->levels[max]; - } else { - duty_cycle = brightness; - } - - 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); - } + if (brightness > 0) + pwm_backlight_power_on(pb, brightness, max); + else + pwm_backlight_power_off(pb); if (pb->notify_after) pb->notify_after(pb->dev, brightness); @@ -267,8 +278,7 @@ static int pwm_backlight_remove(struct platform_device *pdev) struct pwm_bl_data *pb = bl_get_data(bl); backlight_device_unregister(bl); - pwm_config(pb->pwm, 0, pb->period); - pwm_disable(pb->pwm); + pwm_backlight_power_off(pb); if (pb->exit) pb->exit(&pdev->dev); @@ -285,8 +295,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_power_off(pb); if (pb->notify_after) pb->notify_after(pb->dev, 0); -- cgit v0.10.2 From 97c38437115aa0c3fb2d50c488814b503ba529e0 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 2 Oct 2013 18:01:02 +0200 Subject: pwm-backlight: Track enable state Follow up patches will add support for more complex means of powering the backlight on and off such as using a regulator. To prevent calls to the regulator API from becoming unbalanced, keep track of the enabled state internally. Signed-off-by: Thierry Reding diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index ab9d5e6..4053efb 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -27,6 +27,7 @@ struct pwm_bl_data { unsigned int period; unsigned int lth_brightness; unsigned int *levels; + bool enabled; int (*notify)(struct device *, int brightness); void (*notify_after)(struct device *, @@ -40,6 +41,9 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness, { int duty_cycle, err; + if (pb->enabled) + return; + if (pb->levels) { duty_cycle = pb->levels[brightness]; max = pb->levels[max]; @@ -52,12 +56,18 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness, pwm_config(pb->pwm, duty_cycle, pb->period); pwm_enable(pb->pwm); + pb->enabled = true; } static void pwm_backlight_power_off(struct pwm_bl_data *pb) { + if (!pb->enabled) + return; + pwm_config(pb->pwm, 0, pb->period); pwm_disable(pb->pwm); + + pb->enabled = false; } static int pwm_backlight_update_status(struct backlight_device *bl) @@ -216,6 +226,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->check_fb = data->check_fb; pb->exit = data->exit; pb->dev = &pdev->dev; + pb->enabled = false; pb->pwm = devm_pwm_get(&pdev->dev, NULL); if (IS_ERR(pb->pwm)) { -- cgit v0.10.2 From 2b9b1620349e325f184c68cddf3b484499c163c0 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 30 Aug 2013 11:51:22 +0200 Subject: pwm-backlight: Add optional enable GPIO To support a wider variety of backlight setups, introduce an optional enable GPIO. Legacy users of the platform data already have a means of supporting GPIOs by using the .init(), .exit() and .notify() hooks. DT users however cannot use those, so an alternative method is required. In order to ease the introduction of the optional enable GPIO, make it available in the platform data first, so that existing users can be converted. Once that has happened a second patch will add code to make use of it in the driver. Signed-off-by: Thierry Reding diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h index 56f4a86..2de2e27 100644 --- a/include/linux/pwm_backlight.h +++ b/include/linux/pwm_backlight.h @@ -6,6 +6,9 @@ #include +/* TODO: convert to gpiod_*() API once it has been merged */ +#define PWM_BACKLIGHT_GPIO_ACTIVE_LOW (1 << 0) + struct platform_pwm_backlight_data { int pwm_id; unsigned int max_brightness; @@ -13,6 +16,8 @@ struct platform_pwm_backlight_data { unsigned int lth_brightness; unsigned int pwm_period_ns; unsigned int *levels; + int enable_gpio; + unsigned long enable_gpio_flags; int (*init)(struct device *dev); int (*notify)(struct device *dev, int brightness); void (*notify_after)(struct device *dev, int brightness); -- cgit v0.10.2 From d46055af1cc4ba413ae0c3b6f1e6066501f943a0 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 30 Aug 2013 12:13:53 +0200 Subject: ARM: OMAP: Initialize PWM backlight enable_gpio field The GPIO API defines 0 as being a valid GPIO number, so this field needs to be initialized explicitly. Signed-off-by: Thierry Reding diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c index a90375d..5ed2884 100644 --- a/arch/arm/mach-omap2/board-zoom-peripherals.c +++ b/arch/arm/mach-omap2/board-zoom-peripherals.c @@ -227,6 +227,7 @@ static struct platform_pwm_backlight_data zoom_backlight_data = { .max_brightness = 127, .dft_brightness = 127, .pwm_period_ns = 7812500, + .enable_gpio = -1, }; static struct platform_device zoom_backlight_pwm = { -- cgit v0.10.2 From db01120c5f6cb1d8c6533a49b009f08a73852498 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 30 Aug 2013 12:15:24 +0200 Subject: ARM: pxa: Initialize PWM backlight enable_gpio field The GPIO API defines 0 as being a valid GPIO number, so this field needs to be initialized explicitly. A special case is the Palm Tungsten|C board. Since it doesn't use any quirks that would require the existing .init() or .exit() hooks it can simply use the new enable_gpio field. Signed-off-by: Thierry Reding diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c index f942349..584439b 100644 --- a/arch/arm/mach-pxa/cm-x300.c +++ b/arch/arm/mach-pxa/cm-x300.c @@ -310,6 +310,7 @@ static struct platform_pwm_backlight_data cm_x300_backlight_data = { .max_brightness = 100, .dft_brightness = 100, .pwm_period_ns = 10000, + .enable_gpio = -1, }; static struct platform_device cm_x300_backlight_device = { diff --git a/arch/arm/mach-pxa/colibri-pxa270-income.c b/arch/arm/mach-pxa/colibri-pxa270-income.c index 2d4a7b4..3aa2646 100644 --- a/arch/arm/mach-pxa/colibri-pxa270-income.c +++ b/arch/arm/mach-pxa/colibri-pxa270-income.c @@ -189,6 +189,7 @@ static struct platform_pwm_backlight_data income_backlight_data = { .max_brightness = 0x3ff, .dft_brightness = 0x1ff, .pwm_period_ns = 1000000, + .enable_gpio = -1, }; static struct platform_device income_backlight = { diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c index fe2eb83..ab93441 100644 --- a/arch/arm/mach-pxa/ezx.c +++ b/arch/arm/mach-pxa/ezx.c @@ -54,6 +54,7 @@ static struct platform_pwm_backlight_data ezx_backlight_data = { .max_brightness = 1023, .dft_brightness = 1023, .pwm_period_ns = 78770, + .enable_gpio = -1, }; static struct platform_device ezx_backlight_device = { diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c index 133109e..a7c30eb 100644 --- a/arch/arm/mach-pxa/hx4700.c +++ b/arch/arm/mach-pxa/hx4700.c @@ -561,6 +561,7 @@ static struct platform_pwm_backlight_data backlight_data = { .max_brightness = 200, .dft_brightness = 100, .pwm_period_ns = 30923, + .enable_gpio = -1, }; static struct platform_device backlight = { diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c index 1255ee0..9f6ec16 100644 --- a/arch/arm/mach-pxa/lpd270.c +++ b/arch/arm/mach-pxa/lpd270.c @@ -269,6 +269,7 @@ static struct platform_pwm_backlight_data lpd270_backlight_data = { .max_brightness = 1, .dft_brightness = 1, .pwm_period_ns = 78770, + .enable_gpio = -1, }; static struct platform_device lpd270_backlight_device = { diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index f44532f..fab30d6 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -378,6 +378,7 @@ static struct platform_pwm_backlight_data backlight_data = { .max_brightness = 272, .dft_brightness = 100, .pwm_period_ns = 30923, + .enable_gpio = -1, .init = magician_backlight_init, .notify = magician_backlight_notify, .exit = magician_backlight_exit, diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index dd70343..08ccc07 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -338,6 +338,7 @@ static struct platform_pwm_backlight_data mainstone_backlight_data = { .max_brightness = 1023, .dft_brightness = 1023, .pwm_period_ns = 78770, + .enable_gpio = -1, }; static struct platform_device mainstone_backlight_device = { diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c index acc9d3c..f70583f 100644 --- a/arch/arm/mach-pxa/mioa701.c +++ b/arch/arm/mach-pxa/mioa701.c @@ -186,6 +186,7 @@ static struct platform_pwm_backlight_data mioa701_backlight_data = { .max_brightness = 100, .dft_brightness = 50, .pwm_period_ns = 4000 * 1024, /* Fl = 250kHz */ + .enable_gpio = -1, }; /* diff --git a/arch/arm/mach-pxa/palm27x.c b/arch/arm/mach-pxa/palm27x.c index 17d4c53..e54a296 100644 --- a/arch/arm/mach-pxa/palm27x.c +++ b/arch/arm/mach-pxa/palm27x.c @@ -322,6 +322,7 @@ static struct platform_pwm_backlight_data palm27x_backlight_data = { .max_brightness = 0xfe, .dft_brightness = 0x7e, .pwm_period_ns = 3500 * 1024, + .enable_gpio = -1, .init = palm27x_backlight_init, .notify = palm27x_backlight_notify, .exit = palm27x_backlight_exit, diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c index 100b176f..7691c97 100644 --- a/arch/arm/mach-pxa/palmtc.c +++ b/arch/arm/mach-pxa/palmtc.c @@ -166,45 +166,12 @@ static inline void palmtc_keys_init(void) {} * Backlight ******************************************************************************/ #if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE) -static int palmtc_backlight_init(struct device *dev) -{ - int ret; - - ret = gpio_request(GPIO_NR_PALMTC_BL_POWER, "BL POWER"); - if (ret) - goto err; - ret = gpio_direction_output(GPIO_NR_PALMTC_BL_POWER, 1); - if (ret) - goto err2; - - return 0; - -err2: - gpio_free(GPIO_NR_PALMTC_BL_POWER); -err: - return ret; -} - -static int palmtc_backlight_notify(struct device *dev, int brightness) -{ - /* backlight is on when GPIO16 AF0 is high */ - gpio_set_value(GPIO_NR_PALMTC_BL_POWER, brightness); - return brightness; -} - -static void palmtc_backlight_exit(struct device *dev) -{ - gpio_free(GPIO_NR_PALMTC_BL_POWER); -} - static struct platform_pwm_backlight_data palmtc_backlight_data = { .pwm_id = 1, .max_brightness = PALMTC_MAX_INTENSITY, .dft_brightness = PALMTC_MAX_INTENSITY, .pwm_period_ns = PALMTC_PERIOD_NS, - .init = palmtc_backlight_init, - .notify = palmtc_backlight_notify, - .exit = palmtc_backlight_exit, + .enable_gpio = GPIO_NR_PALMTC_BL_POWER, }; static struct platform_device palmtc_backlight = { diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c index 0742721..956fd24 100644 --- a/arch/arm/mach-pxa/palmte2.c +++ b/arch/arm/mach-pxa/palmte2.c @@ -165,6 +165,7 @@ static struct platform_pwm_backlight_data palmte2_backlight_data = { .max_brightness = PALMTE2_MAX_INTENSITY, .dft_brightness = PALMTE2_MAX_INTENSITY, .pwm_period_ns = PALMTE2_PERIOD_NS, + .enable_gpio = -1, .init = palmte2_backlight_init, .notify = palmte2_backlight_notify, .exit = palmte2_backlight_exit, diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c index 3133ba8..9a4e470 100644 --- a/arch/arm/mach-pxa/pcm990-baseboard.c +++ b/arch/arm/mach-pxa/pcm990-baseboard.c @@ -153,6 +153,7 @@ static struct platform_pwm_backlight_data pcm990_backlight_data = { .max_brightness = 1023, .dft_brightness = 1023, .pwm_period_ns = 78770, + .enable_gpio = -1, }; static struct platform_device pcm990_backlight_device = { diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 969b0ba..8386dc3 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -539,6 +539,7 @@ static struct platform_pwm_backlight_data raumfeld_pwm_backlight_data = { .dft_brightness = 100, /* 10000 ns = 10 ms ^= 100 kHz */ .pwm_period_ns = 10000, + .enable_gpio = -1, }; static struct platform_device raumfeld_pwm_backlight_device = { diff --git a/arch/arm/mach-pxa/tavorevb.c b/arch/arm/mach-pxa/tavorevb.c index 4680efe..a71da84 100644 --- a/arch/arm/mach-pxa/tavorevb.c +++ b/arch/arm/mach-pxa/tavorevb.c @@ -175,6 +175,7 @@ static struct platform_pwm_backlight_data tavorevb_backlight_data[] = { .max_brightness = 100, .dft_brightness = 100, .pwm_period_ns = 100000, + .enable_gpio = -1, }, [1] = { /* secondary backlight */ @@ -182,6 +183,7 @@ static struct platform_pwm_backlight_data tavorevb_backlight_data[] = { .max_brightness = 100, .dft_brightness = 100, .pwm_period_ns = 100000, + .enable_gpio = -1, }, }; diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c index 9c363c0..29905b1 100644 --- a/arch/arm/mach-pxa/viper.c +++ b/arch/arm/mach-pxa/viper.c @@ -401,6 +401,7 @@ static struct platform_pwm_backlight_data viper_backlight_data = { .max_brightness = 100, .dft_brightness = 100, .pwm_period_ns = 1000000, + .enable_gpio = -1, .init = viper_backlight_init, .notify = viper_backlight_notify, .exit = viper_backlight_exit, diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c index 2513d8f..e1a121b 100644 --- a/arch/arm/mach-pxa/z2.c +++ b/arch/arm/mach-pxa/z2.c @@ -206,6 +206,7 @@ static struct platform_pwm_backlight_data z2_backlight_data[] = { .max_brightness = 1023, .dft_brightness = 0, .pwm_period_ns = 1260320, + .enable_gpio = -1, }, [1] = { /* LCD Backlight */ @@ -213,6 +214,7 @@ static struct platform_pwm_backlight_data z2_backlight_data[] = { .max_brightness = 1023, .dft_brightness = 512, .pwm_period_ns = 1260320, + .enable_gpio = -1, }, }; diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c index 36cf7cf..77daea4 100644 --- a/arch/arm/mach-pxa/zylonite.c +++ b/arch/arm/mach-pxa/zylonite.c @@ -125,6 +125,7 @@ static struct platform_pwm_backlight_data zylonite_backlight_data = { .max_brightness = 100, .dft_brightness = 100, .pwm_period_ns = 10000, + .enable_gpio = -1, }; static struct platform_device zylonite_backlight_device = { -- cgit v0.10.2 From a63652f1a7b5b04545bfe0ebc9e54f32bde05caf Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 30 Aug 2013 12:19:52 +0200 Subject: ARM: SAMSUNG: Initialize PWM backlight enable_gpio field The GPIO API defines 0 as being a valid GPIO number, so this field needs to be initialized explicitly. Signed-off-by: Thierry Reding diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c index 74dd479..952b6a0 100644 --- a/arch/arm/mach-s3c24xx/mach-h1940.c +++ b/arch/arm/mach-s3c24xx/mach-h1940.c @@ -504,6 +504,7 @@ static struct platform_pwm_backlight_data backlight_data = { .dft_brightness = 50, /* tcnt = 0x31 */ .pwm_period_ns = 36296, + .enable_gpio = -1, .init = h1940_backlight_init, .notify = h1940_backlight_notify, .exit = h1940_backlight_exit, diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c index 206b1f7..034b7fe 100644 --- a/arch/arm/mach-s3c24xx/mach-rx1950.c +++ b/arch/arm/mach-s3c24xx/mach-rx1950.c @@ -522,6 +522,7 @@ static struct platform_pwm_backlight_data rx1950_backlight_data = { .max_brightness = 24, .dft_brightness = 4, .pwm_period_ns = 48000, + .enable_gpio = -1, .init = rx1950_backlight_init, .notify = rx1950_backlight_notify, .exit = rx1950_backlight_exit, diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index eb8e5a1..51d0fcd 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -114,6 +114,7 @@ static struct platform_pwm_backlight_data crag6410_backlight_data = { .max_brightness = 1000, .dft_brightness = 600, .pwm_period_ns = 100000, /* about 1kHz */ + .enable_gpio = -1, }; static struct platform_device crag6410_backlight_device = { diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c index f39569e..7ce417d 100644 --- a/arch/arm/mach-s3c64xx/mach-hmt.c +++ b/arch/arm/mach-s3c64xx/mach-hmt.c @@ -114,6 +114,7 @@ static struct platform_pwm_backlight_data hmt_backlight_data = { .max_brightness = 100 * 256, .dft_brightness = 40 * 256, .pwm_period_ns = 1000000000 / (100 * 256 * 20), + .enable_gpio = -1, .init = hmt_bl_init, .notify = hmt_bl_notify, .exit = hmt_bl_exit, diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c index 86d980b..f3699a9 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq.c +++ b/arch/arm/mach-s3c64xx/mach-smartq.c @@ -151,6 +151,7 @@ static struct platform_pwm_backlight_data smartq_backlight_data = { .max_brightness = 1000, .dft_brightness = 600, .pwm_period_ns = 1000000000 / (1000 * 20), + .enable_gpio = -1, .init = smartq_bl_init, }; diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c index d90b450..0bf5b33 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6410.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c @@ -625,6 +625,7 @@ static struct samsung_bl_gpio_info smdk6410_bl_gpio_info = { static struct platform_pwm_backlight_data smdk6410_bl_data = { .pwm_id = 1, + .enable_gpio = -1, }; static struct s3c_hsotg_plat smdk6410_hsotg_pdata; diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c index 0b00304..9efdcc0 100644 --- a/arch/arm/mach-s5p64x0/mach-smdk6440.c +++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c @@ -223,6 +223,7 @@ static struct samsung_bl_gpio_info smdk6440_bl_gpio_info = { static struct platform_pwm_backlight_data smdk6440_bl_data = { .pwm_id = 1, + .enable_gpio = -1, }; static void __init smdk6440_map_io(void) diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c index 5949296..c3cacc0 100644 --- a/arch/arm/mach-s5p64x0/mach-smdk6450.c +++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c @@ -242,6 +242,7 @@ static struct samsung_bl_gpio_info smdk6450_bl_gpio_info = { static struct platform_pwm_backlight_data smdk6450_bl_data = { .pwm_id = 1, + .enable_gpio = -1, }; static void __init smdk6450_map_io(void) diff --git a/arch/arm/mach-s5pc100/mach-smdkc100.c b/arch/arm/mach-s5pc100/mach-smdkc100.c index 7c57a22..9e256b9 100644 --- a/arch/arm/mach-s5pc100/mach-smdkc100.c +++ b/arch/arm/mach-s5pc100/mach-smdkc100.c @@ -216,6 +216,7 @@ static struct samsung_bl_gpio_info smdkc100_bl_gpio_info = { static struct platform_pwm_backlight_data smdkc100_bl_data = { .pwm_id = 0, + .enable_gpio = -1, }; static void __init smdkc100_map_io(void) diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c index 6d72bb99..f52cc15 100644 --- a/arch/arm/mach-s5pv210/mach-smdkv210.c +++ b/arch/arm/mach-s5pv210/mach-smdkv210.c @@ -279,6 +279,7 @@ static struct samsung_bl_gpio_info smdkv210_bl_gpio_info = { static struct platform_pwm_backlight_data smdkv210_bl_data = { .pwm_id = 3, .pwm_period_ns = 1000, + .enable_gpio = -1, }; static void __init smdkv210_map_io(void) diff --git a/arch/arm/plat-samsung/dev-backlight.c b/arch/arm/plat-samsung/dev-backlight.c index d51f956..be4ad0b 100644 --- a/arch/arm/plat-samsung/dev-backlight.c +++ b/arch/arm/plat-samsung/dev-backlight.c @@ -70,6 +70,7 @@ static struct samsung_bl_drvdata samsung_dfl_bl_data __initdata = { .max_brightness = 255, .dft_brightness = 255, .pwm_period_ns = 78770, + .enable_gpio = -1, .init = samsung_bl_init, .exit = samsung_bl_exit, }, @@ -121,6 +122,10 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info, samsung_bl_data->lth_brightness = bl_data->lth_brightness; if (bl_data->pwm_period_ns) samsung_bl_data->pwm_period_ns = bl_data->pwm_period_ns; + if (bl_data->enable_gpio >= 0) + samsung_bl_data->enable_gpio = bl_data->enable_gpio; + if (bl_data->enable_gpio_flags) + samsung_bl_data->enable_gpio_flags = bl_data->enable_gpio_flags; if (bl_data->init) samsung_bl_data->init = bl_data->init; if (bl_data->notify) -- cgit v0.10.2 From bf4d252a2906df097874926bcfff6a3bcef38491 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 30 Aug 2013 12:21:42 +0200 Subject: ARM: shmobile: Initialize PWM backlight enable_gpio field The GPIO API defines 0 as being a valid GPIO number, so this field needs to be initialized explicitly. Acked-by: Simon Horman Signed-off-by: Thierry Reding diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index 5bd1479..f68634a 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -423,6 +423,7 @@ static struct platform_pwm_backlight_data pwm_backlight_data = { .max_brightness = 255, .dft_brightness = 255, .pwm_period_ns = 33333, /* 30kHz */ + .enable_gpio = -1, }; static struct platform_device pwm_backlight_device = { -- cgit v0.10.2 From 611c86c6de7a58c59b231804ffa19d1b70f6fd90 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 30 Aug 2013 13:30:32 +0200 Subject: unicore32: Initialize PWM backlight enable_gpio field The GPIO API defines 0 as being a valid GPIO number, so this field needs to be initialized explicitly. Signed-off-by: Thierry Reding diff --git a/arch/unicore32/kernel/puv3-nb0916.c b/arch/unicore32/kernel/puv3-nb0916.c index 181108b..0c6618e 100644 --- a/arch/unicore32/kernel/puv3-nb0916.c +++ b/arch/unicore32/kernel/puv3-nb0916.c @@ -54,6 +54,7 @@ static struct platform_pwm_backlight_data nb0916_backlight_data = { .max_brightness = 100, .dft_brightness = 100, .pwm_period_ns = 70 * 1024, + .enable_gpio = -1, }; static struct gpio_keys_button nb0916_gpio_keys[] = { -- cgit v0.10.2 From 8265b2e4e62632b01f998095d1bbda4d281629fe Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 30 Aug 2013 12:32:18 +0200 Subject: pwm-backlight: Use new enable_gpio field Make use of the new enable_gpio field and allow it to be set from DT as well. Now that all legacy users of platform data have been converted to initialize this field to an invalid value, it is safe to use the field from the driver. Signed-off-by: Thierry Reding diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt index 1e4fc72..72810cc 100644 --- a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt +++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt @@ -14,8 +14,11 @@ Required properties: Optional properties: - pwm-names: a list of names for the PWM devices specified in the "pwms" property (see PWM binding[0]) + - enable-gpios: contains a single GPIO specifier for the GPIO which enables + and disables the backlight (see GPIO binding[1]) [0]: Documentation/devicetree/bindings/pwm/pwm.txt +[1]: Documentation/devicetree/bindings/gpio/gpio.txt Example: @@ -25,4 +28,6 @@ Example: brightness-levels = <0 4 8 16 32 64 128 255>; default-brightness-level = <6>; + + enable-gpios = <&gpio 58 0>; }; diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 4053efb..cdef4a3 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -10,6 +10,8 @@ * published by the Free Software Foundation. */ +#include +#include #include #include #include @@ -28,6 +30,8 @@ struct pwm_bl_data { unsigned int lth_brightness; unsigned int *levels; bool enabled; + int enable_gpio; + unsigned long enable_gpio_flags; int (*notify)(struct device *, int brightness); void (*notify_after)(struct device *, @@ -55,6 +59,14 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness, pb->lth_brightness; pwm_config(pb->pwm, duty_cycle, pb->period); + + if (gpio_is_valid(pb->enable_gpio)) { + if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW) + gpio_set_value(pb->enable_gpio, 0); + else + gpio_set_value(pb->enable_gpio, 1); + } + pwm_enable(pb->pwm); pb->enabled = true; } @@ -67,6 +79,13 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb) pwm_config(pb->pwm, 0, pb->period); pwm_disable(pb->pwm); + if (gpio_is_valid(pb->enable_gpio)) { + if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW) + gpio_set_value(pb->enable_gpio, 1); + else + gpio_set_value(pb->enable_gpio, 0); + } + pb->enabled = false; } @@ -119,6 +138,7 @@ static int pwm_backlight_parse_dt(struct device *dev, struct platform_pwm_backlight_data *data) { struct device_node *node = dev->of_node; + enum of_gpio_flags flags; struct property *prop; int length; u32 value; @@ -159,11 +179,13 @@ 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->enable_gpio = of_get_named_gpio_flags(node, "enable-gpios", 0, + &flags); + if (data->enable_gpio == -EPROBE_DEFER) + return -EPROBE_DEFER; + + if (gpio_is_valid(data->enable_gpio) && (flags & OF_GPIO_ACTIVE_LOW)) + data->enable_gpio_flags |= PWM_BACKLIGHT_GPIO_ACTIVE_LOW; return 0; } @@ -221,6 +243,8 @@ static int pwm_backlight_probe(struct platform_device *pdev) } else max = data->max_brightness; + pb->enable_gpio = data->enable_gpio; + pb->enable_gpio_flags = data->enable_gpio_flags; pb->notify = data->notify; pb->notify_after = data->notify_after; pb->check_fb = data->check_fb; @@ -228,6 +252,22 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->dev = &pdev->dev; pb->enabled = false; + if (gpio_is_valid(pb->enable_gpio)) { + unsigned long flags; + + if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW) + flags = GPIOF_OUT_INIT_HIGH; + else + flags = GPIOF_OUT_INIT_LOW; + + ret = gpio_request_one(pb->enable_gpio, flags, "enable"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request GPIO#%d: %d\n", + pb->enable_gpio, ret); + goto err_alloc; + } + } + pb->pwm = devm_pwm_get(&pdev->dev, NULL); if (IS_ERR(pb->pwm)) { dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n"); @@ -236,7 +276,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) if (IS_ERR(pb->pwm)) { dev_err(&pdev->dev, "unable to request legacy PWM\n"); ret = PTR_ERR(pb->pwm); - goto err_alloc; + goto err_gpio; } } @@ -261,7 +301,7 @@ 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_alloc; + goto err_gpio; } if (data->dft_brightness > data->max_brightness) { @@ -277,6 +317,9 @@ static int pwm_backlight_probe(struct platform_device *pdev) platform_set_drvdata(pdev, bl); return 0; +err_gpio: + if (gpio_is_valid(pb->enable_gpio)) + gpio_free(pb->enable_gpio); err_alloc: if (data->exit) data->exit(&pdev->dev); -- cgit v0.10.2 From 22ceeee16eb8f0d04de3ef43a5174fb30ec18af9 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 30 Aug 2013 12:38:34 +0200 Subject: pwm-backlight: Add power supply support Backlights require a power supply to work properly. This commit adds a regulator to power up and power down the backlight. Signed-off-by: Thierry Reding diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt index 72810cc..764db86 100644 --- a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt +++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt @@ -10,6 +10,7 @@ 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-supply: regulator for supply voltage Optional properties: - pwm-names: a list of names for the PWM devices specified in the @@ -29,5 +30,6 @@ Example: brightness-levels = <0 4 8 16 32 64 128 255>; default-brightness-level = <6>; + power-supply = <&vdd_bl_reg>; enable-gpios = <&gpio 58 0>; }; diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index cdef4a3..eec6c98 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -21,6 +21,7 @@ #include #include #include +#include #include struct pwm_bl_data { @@ -30,6 +31,7 @@ struct pwm_bl_data { unsigned int lth_brightness; unsigned int *levels; bool enabled; + struct regulator *power_supply; int enable_gpio; unsigned long enable_gpio_flags; int (*notify)(struct device *, @@ -60,6 +62,10 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness, pwm_config(pb->pwm, duty_cycle, pb->period); + err = regulator_enable(pb->power_supply); + if (err < 0) + dev_err(pb->dev, "failed to enable power supply\n"); + if (gpio_is_valid(pb->enable_gpio)) { if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW) gpio_set_value(pb->enable_gpio, 0); @@ -86,6 +92,7 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb) gpio_set_value(pb->enable_gpio, 0); } + regulator_disable(pb->power_supply); pb->enabled = false; } @@ -268,6 +275,12 @@ static int pwm_backlight_probe(struct platform_device *pdev) } } + pb->power_supply = devm_regulator_get(&pdev->dev, "power"); + if (IS_ERR(pb->power_supply)) { + ret = PTR_ERR(pb->power_supply); + goto err_gpio; + } + pb->pwm = devm_pwm_get(&pdev->dev, NULL); if (IS_ERR(pb->pwm)) { dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n"); -- cgit v0.10.2 From 8f43e18e2769b3b28383903d501b4da29e388aad Mon Sep 17 00:00:00 2001 From: Mike Dunn Date: Sun, 22 Sep 2013 09:59:56 -0700 Subject: pwm-backlight: Allow for non-increasing brightness levels Currently the driver assumes that the values specified in the brightness-levels device tree property increase as they are parsed from left to right. But boards that invert the signal between the PWM output and the backlight will need to specify decreasing brightness-levels. This patch removes the assumption that the last element of the array is the maximum value, and instead searches the array for the maximum value and uses that in the duty cycle calculation. Signed-off-by: Mike Dunn Signed-off-by: Thierry Reding diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index eec6c98..32e96e3 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -34,6 +34,7 @@ struct pwm_bl_data { struct regulator *power_supply; int enable_gpio; unsigned long enable_gpio_flags; + unsigned int scale; int (*notify)(struct device *, int brightness); void (*notify_after)(struct device *, @@ -42,23 +43,20 @@ struct pwm_bl_data { void (*exit)(struct device *); }; -static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness, - int max) +static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness) { + unsigned int lth = pb->lth_brightness; int duty_cycle, err; if (pb->enabled) return; - if (pb->levels) { + if (pb->levels) duty_cycle = pb->levels[brightness]; - max = pb->levels[max]; - } else { + else duty_cycle = brightness; - } - duty_cycle = (duty_cycle * (pb->period - pb->lth_brightness) / max) + - pb->lth_brightness; + duty_cycle = (duty_cycle * (pb->period - lth) / pb->scale) + lth; pwm_config(pb->pwm, duty_cycle, pb->period); @@ -100,7 +98,6 @@ static int pwm_backlight_update_status(struct backlight_device *bl) { struct pwm_bl_data *pb = bl_get_data(bl); int brightness = bl->props.brightness; - int max = bl->props.max_brightness; if (bl->props.power != FB_BLANK_UNBLANK || bl->props.fb_blank != FB_BLANK_UNBLANK || @@ -111,7 +108,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl) brightness = pb->notify(pb->dev, brightness); if (brightness > 0) - pwm_backlight_power_on(pb, brightness, max); + pwm_backlight_power_on(pb, brightness); else pwm_backlight_power_off(pb); @@ -218,7 +215,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) struct backlight_properties props; struct backlight_device *bl; struct pwm_bl_data *pb; - unsigned int max; int ret; if (!data) { @@ -245,10 +241,15 @@ static int pwm_backlight_probe(struct platform_device *pdev) } if (data->levels) { - max = data->levels[data->max_brightness]; + unsigned int i; + + for (i = 0; i <= data->max_brightness; i++) + if (data->levels[i] > pb->scale) + pb->scale = data->levels[i]; + pb->levels = data->levels; } else - max = data->max_brightness; + pb->scale = data->max_brightness; pb->enable_gpio = data->enable_gpio; pb->enable_gpio_flags = data->enable_gpio_flags; @@ -304,7 +305,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) 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); + pb->lth_brightness = data->lth_brightness * (pb->period / pb->scale); memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; -- cgit v0.10.2 From a23086981723570c8952520d9ffaf6995d45f63e Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 15 Oct 2013 18:40:03 -0700 Subject: pwm: add ep93xx PWM support Remove the non-standard EP93xx PWM driver in drivers/misc and add a new driver for the PWM controllers on the EP93xx platform based on the PWM framework. These PWM controllers each support 1 PWM channel with programmable duty cycle, frequency, and polarity inversion. Signed-off-by: H Hartley Sweeten Cc: Ryan Mallon Acked-by: Arnd Bergmann Acked-by: Greg Kroah-Hartman Signed-off-by: Thierry Reding diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 8dacd4c..c43c66a 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -381,19 +381,6 @@ config HMC6352 This driver provides support for the Honeywell HMC6352 compass, providing configuration and heading data via sysfs. -config EP93XX_PWM - tristate "EP93xx PWM support" - depends on ARCH_EP93XX - help - This option enables device driver support for the PWM channels - on the Cirrus EP93xx processors. The EP9307 chip only has one - PWM channel all the others have two, the second channel is an - alternate function of the EGPIO14 pin. A sysfs interface is - provided to control the PWM channels. - - To compile this driver as a module, choose M here: the module will - be called ep93xx_pwm. - config DS1682 tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm" depends on I2C diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index c235d5b..ecccd00 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -33,7 +33,6 @@ obj-$(CONFIG_APDS9802ALS) += apds9802als.o obj-$(CONFIG_ISL29003) += isl29003.o obj-$(CONFIG_ISL29020) += isl29020.o obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o -obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o obj-$(CONFIG_DS1682) += ds1682.o obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o obj-$(CONFIG_C2PORT) += c2port/ diff --git a/drivers/misc/ep93xx_pwm.c b/drivers/misc/ep93xx_pwm.c deleted file mode 100644 index cdb67a9..0000000 --- a/drivers/misc/ep93xx_pwm.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Simple PWM driver for EP93XX - * - * (c) Copyright 2009 Matthieu Crapet - * (c) Copyright 2009 H Hartley Sweeten - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * EP9307 has only one channel: - * - PWMOUT - * - * EP9301/02/12/15 have two channels: - * - PWMOUT - * - PWMOUT1 (alternate function for EGPIO14) - */ - -#include -#include -#include -#include -#include -#include - -#include - -#define EP93XX_PWMx_TERM_COUNT 0x00 -#define EP93XX_PWMx_DUTY_CYCLE 0x04 -#define EP93XX_PWMx_ENABLE 0x08 -#define EP93XX_PWMx_INVERT 0x0C - -#define EP93XX_PWM_MAX_COUNT 0xFFFF - -struct ep93xx_pwm { - void __iomem *mmio_base; - struct clk *clk; - u32 duty_percent; -}; - -/* - * /sys/devices/platform/ep93xx-pwm.N - * /min_freq read-only minimum pwm output frequency - * /max_req read-only maximum pwm output frequency - * /freq read-write pwm output frequency (0 = disable output) - * /duty_percent read-write pwm duty cycle percent (1..99) - * /invert read-write invert pwm output - */ - -static ssize_t ep93xx_pwm_get_min_freq(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct platform_device *pdev = to_platform_device(dev); - struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); - unsigned long rate = clk_get_rate(pwm->clk); - - return sprintf(buf, "%ld\n", rate / (EP93XX_PWM_MAX_COUNT + 1)); -} - -static ssize_t ep93xx_pwm_get_max_freq(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct platform_device *pdev = to_platform_device(dev); - struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); - unsigned long rate = clk_get_rate(pwm->clk); - - return sprintf(buf, "%ld\n", rate / 2); -} - -static ssize_t ep93xx_pwm_get_freq(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct platform_device *pdev = to_platform_device(dev); - struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); - - if (readl(pwm->mmio_base + EP93XX_PWMx_ENABLE) & 0x1) { - unsigned long rate = clk_get_rate(pwm->clk); - u16 term = readl(pwm->mmio_base + EP93XX_PWMx_TERM_COUNT); - - return sprintf(buf, "%ld\n", rate / (term + 1)); - } else { - return sprintf(buf, "disabled\n"); - } -} - -static ssize_t ep93xx_pwm_set_freq(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct platform_device *pdev = to_platform_device(dev); - struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); - long val; - int err; - - err = kstrtol(buf, 10, &val); - if (err) - return -EINVAL; - - if (val == 0) { - writel(0x0, pwm->mmio_base + EP93XX_PWMx_ENABLE); - } else if (val <= (clk_get_rate(pwm->clk) / 2)) { - u32 term, duty; - - val = (clk_get_rate(pwm->clk) / val) - 1; - if (val > EP93XX_PWM_MAX_COUNT) - val = EP93XX_PWM_MAX_COUNT; - if (val < 1) - val = 1; - - term = readl(pwm->mmio_base + EP93XX_PWMx_TERM_COUNT); - duty = ((val + 1) * pwm->duty_percent / 100) - 1; - - /* If pwm is running, order is important */ - if (val > term) { - writel(val, pwm->mmio_base + EP93XX_PWMx_TERM_COUNT); - writel(duty, pwm->mmio_base + EP93XX_PWMx_DUTY_CYCLE); - } else { - writel(duty, pwm->mmio_base + EP93XX_PWMx_DUTY_CYCLE); - writel(val, pwm->mmio_base + EP93XX_PWMx_TERM_COUNT); - } - - if (!readl(pwm->mmio_base + EP93XX_PWMx_ENABLE) & 0x1) - writel(0x1, pwm->mmio_base + EP93XX_PWMx_ENABLE); - } else { - return -EINVAL; - } - - return count; -} - -static ssize_t ep93xx_pwm_get_duty_percent(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct platform_device *pdev = to_platform_device(dev); - struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); - - return sprintf(buf, "%d\n", pwm->duty_percent); -} - -static ssize_t ep93xx_pwm_set_duty_percent(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct platform_device *pdev = to_platform_device(dev); - struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); - long val; - int err; - - err = kstrtol(buf, 10, &val); - if (err) - return -EINVAL; - - if (val > 0 && val < 100) { - u32 term = readl(pwm->mmio_base + EP93XX_PWMx_TERM_COUNT); - u32 duty = ((term + 1) * val / 100) - 1; - - writel(duty, pwm->mmio_base + EP93XX_PWMx_DUTY_CYCLE); - pwm->duty_percent = val; - return count; - } - - return -EINVAL; -} - -static ssize_t ep93xx_pwm_get_invert(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct platform_device *pdev = to_platform_device(dev); - struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); - int inverted = readl(pwm->mmio_base + EP93XX_PWMx_INVERT) & 0x1; - - return sprintf(buf, "%d\n", inverted); -} - -static ssize_t ep93xx_pwm_set_invert(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct platform_device *pdev = to_platform_device(dev); - struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); - long val; - int err; - - err = kstrtol(buf, 10, &val); - if (err) - return -EINVAL; - - if (val == 0) - writel(0x0, pwm->mmio_base + EP93XX_PWMx_INVERT); - else if (val == 1) - writel(0x1, pwm->mmio_base + EP93XX_PWMx_INVERT); - else - return -EINVAL; - - return count; -} - -static DEVICE_ATTR(min_freq, S_IRUGO, ep93xx_pwm_get_min_freq, NULL); -static DEVICE_ATTR(max_freq, S_IRUGO, ep93xx_pwm_get_max_freq, NULL); -static DEVICE_ATTR(freq, S_IWUSR | S_IRUGO, - ep93xx_pwm_get_freq, ep93xx_pwm_set_freq); -static DEVICE_ATTR(duty_percent, S_IWUSR | S_IRUGO, - ep93xx_pwm_get_duty_percent, ep93xx_pwm_set_duty_percent); -static DEVICE_ATTR(invert, S_IWUSR | S_IRUGO, - ep93xx_pwm_get_invert, ep93xx_pwm_set_invert); - -static struct attribute *ep93xx_pwm_attrs[] = { - &dev_attr_min_freq.attr, - &dev_attr_max_freq.attr, - &dev_attr_freq.attr, - &dev_attr_duty_percent.attr, - &dev_attr_invert.attr, - NULL -}; - -static const struct attribute_group ep93xx_pwm_sysfs_files = { - .attrs = ep93xx_pwm_attrs, -}; - -static int ep93xx_pwm_probe(struct platform_device *pdev) -{ - struct ep93xx_pwm *pwm; - struct resource *res; - int ret; - - pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); - if (!pwm) - return -ENOMEM; - - pwm->clk = devm_clk_get(&pdev->dev, "pwm_clk"); - if (IS_ERR(pwm->clk)) - return PTR_ERR(pwm->clk); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pwm->mmio_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pwm->mmio_base)) - return PTR_ERR(pwm->mmio_base); - - ret = ep93xx_pwm_acquire_gpio(pdev); - if (ret) - return ret; - - ret = sysfs_create_group(&pdev->dev.kobj, &ep93xx_pwm_sysfs_files); - if (ret) { - ep93xx_pwm_release_gpio(pdev); - return ret; - } - - pwm->duty_percent = 50; - - /* disable pwm at startup. Avoids zero value. */ - writel(0x0, pwm->mmio_base + EP93XX_PWMx_ENABLE); - writel(EP93XX_PWM_MAX_COUNT, pwm->mmio_base + EP93XX_PWMx_TERM_COUNT); - writel(EP93XX_PWM_MAX_COUNT/2, pwm->mmio_base + EP93XX_PWMx_DUTY_CYCLE); - - clk_enable(pwm->clk); - - platform_set_drvdata(pdev, pwm); - return 0; -} - -static int ep93xx_pwm_remove(struct platform_device *pdev) -{ - struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); - - writel(0x0, pwm->mmio_base + EP93XX_PWMx_ENABLE); - clk_disable(pwm->clk); - sysfs_remove_group(&pdev->dev.kobj, &ep93xx_pwm_sysfs_files); - ep93xx_pwm_release_gpio(pdev); - - return 0; -} - -static struct platform_driver ep93xx_pwm_driver = { - .driver = { - .name = "ep93xx-pwm", - .owner = THIS_MODULE, - }, - .probe = ep93xx_pwm_probe, - .remove = ep93xx_pwm_remove, -}; -module_platform_driver(ep93xx_pwm_driver); - -MODULE_AUTHOR("Matthieu Crapet , " - "H Hartley Sweeten "); -MODULE_DESCRIPTION("EP93xx PWM driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:ep93xx-pwm"); diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 75840b5..eece329 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -62,6 +62,15 @@ config PWM_BFIN To compile this driver as a module, choose M here: the module will be called pwm-bfin. +config PWM_EP93XX + tristate "Cirrus Logic EP93xx PWM support" + depends on ARCH_EP93XX + help + Generic PWM framework driver for Cirrus Logic EP93xx. + + To compile this driver as a module, choose M here: the module + will be called pwm-ep93xx. + config PWM_IMX tristate "i.MX PWM support" depends on ARCH_MXC diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 77a8c18..8b754e4 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_PWM_SYSFS) += sysfs.o obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o +obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c new file mode 100644 index 0000000..33aa446 --- /dev/null +++ b/drivers/pwm/pwm-ep93xx.c @@ -0,0 +1,230 @@ +/* + * PWM framework driver for Cirrus Logic EP93xx + * + * Copyright (c) 2009 Matthieu Crapet + * Copyright (c) 2009, 2013 H Hartley Sweeten + * + * EP9301/02 have only one channel: + * platform device ep93xx-pwm.1 - PWMOUT1 (EGPIO14) + * + * EP9307 has only one channel: + * platform device ep93xx-pwm.0 - PWMOUT + * + * EP9312/15 have two channels: + * platform device ep93xx-pwm.0 - PWMOUT + * platform device ep93xx-pwm.1 - PWMOUT1 (EGPIO14) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include /* for ep93xx_pwm_{acquire,release}_gpio() */ + +#define EP93XX_PWMx_TERM_COUNT 0x00 +#define EP93XX_PWMx_DUTY_CYCLE 0x04 +#define EP93XX_PWMx_ENABLE 0x08 +#define EP93XX_PWMx_INVERT 0x0c + +struct ep93xx_pwm { + void __iomem *base; + struct clk *clk; + struct pwm_chip chip; +}; + +static inline struct ep93xx_pwm *to_ep93xx_pwm(struct pwm_chip *chip) +{ + return container_of(chip, struct ep93xx_pwm, chip); +} + +static int ep93xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct platform_device *pdev = to_platform_device(chip->dev); + + return ep93xx_pwm_acquire_gpio(pdev); +} + +static void ep93xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct platform_device *pdev = to_platform_device(chip->dev); + + ep93xx_pwm_release_gpio(pdev); +} + +static int ep93xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip); + void __iomem *base = ep93xx_pwm->base; + unsigned long long c; + unsigned long period_cycles; + unsigned long duty_cycles; + unsigned long term; + int ret = 0; + + /* + * The clock needs to be enabled to access the PWM registers. + * Configuration can be changed at any time. + */ + if (!test_bit(PWMF_ENABLED, &pwm->flags)) { + ret = clk_enable(ep93xx_pwm->clk); + if (ret) + return ret; + } + + c = clk_get_rate(ep93xx_pwm->clk); + c *= period_ns; + do_div(c, 1000000000); + period_cycles = c; + + c = period_cycles; + c *= duty_ns; + do_div(c, period_ns); + duty_cycles = c; + + if (period_cycles < 0x10000 && duty_cycles < 0x10000) { + term = readw(base + EP93XX_PWMx_TERM_COUNT); + + /* Order is important if PWM is running */ + if (period_cycles > term) { + writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT); + writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE); + } else { + writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE); + writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT); + } + } else { + ret = -EINVAL; + } + + if (!test_bit(PWMF_ENABLED, &pwm->flags)) + clk_disable(ep93xx_pwm->clk); + + return ret; +} + +static int ep93xx_pwm_polarity(struct pwm_chip *chip, struct pwm_device *pwm, + enum pwm_polarity polarity) +{ + struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip); + int ret; + + /* + * The clock needs to be enabled to access the PWM registers. + * Polarity can only be changed when the PWM is disabled. + */ + ret = clk_enable(ep93xx_pwm->clk); + if (ret) + return ret; + + if (polarity == PWM_POLARITY_INVERSED) + writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_INVERT); + else + writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_INVERT); + + clk_disable(ep93xx_pwm->clk); + + return 0; +} + +static int ep93xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip); + int ret; + + ret = clk_enable(ep93xx_pwm->clk); + if (ret) + return ret; + + writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_ENABLE); + + return 0; +} + +static void ep93xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip); + + writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_ENABLE); + clk_disable(ep93xx_pwm->clk); +} + +static const struct pwm_ops ep93xx_pwm_ops = { + .request = ep93xx_pwm_request, + .free = ep93xx_pwm_free, + .config = ep93xx_pwm_config, + .set_polarity = ep93xx_pwm_polarity, + .enable = ep93xx_pwm_enable, + .disable = ep93xx_pwm_disable, + .owner = THIS_MODULE, +}; + +static int ep93xx_pwm_probe(struct platform_device *pdev) +{ + struct ep93xx_pwm *ep93xx_pwm; + struct resource *res; + int ret; + + ep93xx_pwm = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_pwm), GFP_KERNEL); + if (!ep93xx_pwm) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ep93xx_pwm->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ep93xx_pwm->base)) + return PTR_ERR(ep93xx_pwm->base); + + ep93xx_pwm->clk = devm_clk_get(&pdev->dev, "pwm_clk"); + if (IS_ERR(ep93xx_pwm->clk)) + return PTR_ERR(ep93xx_pwm->clk); + + ep93xx_pwm->chip.dev = &pdev->dev; + ep93xx_pwm->chip.ops = &ep93xx_pwm_ops; + ep93xx_pwm->chip.base = -1; + ep93xx_pwm->chip.npwm = 1; + + ret = pwmchip_add(&ep93xx_pwm->chip); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, ep93xx_pwm); + return 0; +} + +static int ep93xx_pwm_remove(struct platform_device *pdev) +{ + struct ep93xx_pwm *ep93xx_pwm = platform_get_drvdata(pdev); + + return pwmchip_remove(&ep93xx_pwm->chip); +} + +static struct platform_driver ep93xx_pwm_driver = { + .driver = { + .name = "ep93xx-pwm", + }, + .probe = ep93xx_pwm_probe, + .remove = ep93xx_pwm_remove, +}; +module_platform_driver(ep93xx_pwm_driver); + +MODULE_DESCRIPTION("Cirrus Logic EP93xx PWM driver"); +MODULE_AUTHOR("Matthieu Crapet , " + "H Hartley Sweeten "); +MODULE_ALIAS("platform:ep93xx-pwm"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From e4bfeda96872bfe6015cd360008b77cd3b981b2b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 18 Oct 2013 10:46:24 +0200 Subject: pwm-backlight: Fix brightness adjustment Split adjustment of the brightness (by changing the PWM duty cycle) from the power on sequence. This fixes an issue where the brightness can no longer be updated once the backlight has been enabled. Reported-by: Marc Dietrich Signed-off-by: Thierry Reding diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 32e96e3..f77a7b0 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -45,21 +45,11 @@ struct pwm_bl_data { static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness) { - unsigned int lth = pb->lth_brightness; int duty_cycle, err; if (pb->enabled) return; - if (pb->levels) - duty_cycle = pb->levels[brightness]; - else - duty_cycle = brightness; - - duty_cycle = (duty_cycle * (pb->period - lth) / pb->scale) + lth; - - pwm_config(pb->pwm, duty_cycle, pb->period); - err = regulator_enable(pb->power_supply); if (err < 0) dev_err(pb->dev, "failed to enable power supply\n"); @@ -94,10 +84,24 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb) pb->enabled = false; } +static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness) +{ + unsigned int lth = pb->lth_brightness; + int duty_cycle; + + if (pb->levels) + duty_cycle = pb->levels[brightness]; + else + duty_cycle = brightness; + + return (duty_cycle * (pb->period - lth) / pb->scale) + lth; +} + static int pwm_backlight_update_status(struct backlight_device *bl) { struct pwm_bl_data *pb = bl_get_data(bl); int brightness = bl->props.brightness; + int duty_cycle; if (bl->props.power != FB_BLANK_UNBLANK || bl->props.fb_blank != FB_BLANK_UNBLANK || @@ -107,9 +111,11 @@ static int pwm_backlight_update_status(struct backlight_device *bl) if (pb->notify) brightness = pb->notify(pb->dev, brightness); - if (brightness > 0) + if (brightness > 0) { + duty_cycle = compute_duty_cycle(pb, brightness); + pwm_config(pb->pwm, duty_cycle, pb->period); pwm_backlight_power_on(pb, brightness); - else + } else pwm_backlight_power_off(pb); if (pb->notify_after) -- cgit v0.10.2 From 1dea1fd09246ada581a99d0669108eea94b7bfee Mon Sep 17 00:00:00 2001 From: Huayi Li Date: Wed, 9 Oct 2013 10:33:02 +0800 Subject: pwm_backlight: avoid short blank screen while doing hibernation Use SIMPLE_DEV_PM_OPS macro will initialize the member "freeze" and "thaw" of pwm_backlight_pm_ops as below, .freeze = suspend_fn, .thaw = resume_fn, then during the process of making hibernation snapshot, screen will be blank at the moment of freezing, and then light at the moment of thawing. this is not the right user experience for suspending to disk. so this patch drops freeze and thaw callback, make the LCD is always lighting before the final shutdown. Signed-off-by: Huayi Li Signed-off-by: Barry Song Signed-off-by: Thierry Reding diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index f77a7b0..29953349 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -387,8 +387,14 @@ static int pwm_backlight_resume(struct device *dev) } #endif -static SIMPLE_DEV_PM_OPS(pwm_backlight_pm_ops, pwm_backlight_suspend, - pwm_backlight_resume); +static const struct dev_pm_ops pwm_backlight_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = pwm_backlight_suspend, + .resume = pwm_backlight_resume, + .poweroff = pwm_backlight_suspend, + .restore = pwm_backlight_resume, +#endif +}; static struct platform_driver pwm_backlight_driver = { .driver = { -- cgit v0.10.2 From 73d4e2b82b4bb1571b1a7f97012c0db8a0faef42 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 22 Oct 2013 09:37:05 +0200 Subject: pwm-backlight: Remove unused variable I forgot to remove this during earlier cleanup patches and only checked various builds for errors, not warnings. Reported-by: kbuild test robot Signed-off-by: Thierry Reding diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 29953349..368232a 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -45,7 +45,7 @@ struct pwm_bl_data { static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness) { - int duty_cycle, err; + int err; if (pb->enabled) return; -- cgit v0.10.2 From 702e304f198f631d746d2f383c54acc07d604700 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 24 Oct 2013 14:13:47 +0530 Subject: Documentation/pwm: Fix trivial typos Fixes some trivial typos to improve readability. Signed-off-by: Sachin Kamat Signed-off-by: Thierry Reding diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt index 1039b68..93cb979 100644 --- a/Documentation/pwm.txt +++ b/Documentation/pwm.txt @@ -39,7 +39,7 @@ New users should use the pwm_get() function and pass to it the consumer device or a consumer name. pwm_put() is used to free the PWM device. Managed variants of these functions, devm_pwm_get() and devm_pwm_put(), also exist. -After being requested a PWM has to be configured using: +After being requested, a PWM has to be configured using: int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns); @@ -94,7 +94,7 @@ for new drivers to use the generic PWM framework. A new PWM controller/chip can be added using pwmchip_add() and removed again with pwmchip_remove(). pwmchip_add() takes a filled in struct pwm_chip as argument which provides a description of the PWM chip, the -number of PWM devices provider by the chip and the chip-specific +number of PWM devices provided by the chip and the chip-specific implementation of the supported PWM operations to the framework. Locking -- cgit v0.10.2 From 006e854f15560e934b4464f957691d47d03ac6a2 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 1 Nov 2013 11:15:05 +0100 Subject: MAINTAINERS: Move PWM subsystem tree to kernel.org The PWM subsystem tree is now located on kernel.org. This will hopefully make it more reliably accessible. Signed-off-by: Thierry Reding diff --git a/MAINTAINERS b/MAINTAINERS index e61c2e8..57b0a9f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6684,8 +6684,7 @@ PWM SUBSYSTEM M: Thierry Reding L: linux-pwm@vger.kernel.org S: Maintained -W: http://gitorious.org/linux-pwm -T: git git://gitorious.org/linux-pwm/linux-pwm.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm.git F: Documentation/pwm.txt F: Documentation/devicetree/bindings/pwm/ F: include/linux/pwm.h -- cgit v0.10.2 From b577cdcf174b0e88091cb7c9926c44cda87d3d0d Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 29 Oct 2013 10:27:43 +0530 Subject: pwm: samsung: Fix kernel warning while unexporting a channel PWM channel data was set to NULL before freeing it. This caused the following kernel warning while unexporting the channel. Set the channel data to NULL after freeing it. [ 70.495000] WARNING: CPU: 0 PID: 1 at drivers/base/devres.c:805 pwm_put+0x48/0x80() [ 70.505000] Modules linked in: [ 70.505000] CPU: 0 PID: 1 Comm: sh Not tainted 3.12.0-rc6-next-20131024-00012-gd4aec04-dirty #58 [ 70.515000] [] (unwind_backtrace+0x0/0xf4) from [] (show_stack+0x10/0x14) [ 70.525000] [] (show_stack+0x10/0x14) from [] (dump_stack+0x7c/0xb0) [ 70.530000] [] (dump_stack+0x7c/0xb0) from [] (warn_slowpath_common+0x6c/0x88) [ 70.540000] [] (warn_slowpath_common+0x6c/0x88) from [] (warn_slowpath_null+0x1c/0x24) [ 70.550000] [] (warn_slowpath_null+0x1c/0x24) from [] (pwm_put+0x48/0x80) [ 70.560000] [] (pwm_put+0x48/0x80) from [] (pwm_unexport_store+0x94/0xac) [ 70.565000] [] (pwm_unexport_store+0x94/0xac) from [] (sysfs_write_file+0x148/0x1d8) [ 70.575000] [] (sysfs_write_file+0x148/0x1d8) from [] (vfs_write+0xb4/0x1a0) [ 70.585000] [] (vfs_write+0xb4/0x1a0) from [] (SyS_write+0x3c/0x78) [ 70.595000] [] (SyS_write+0x3c/0x78) from [] (ret_fast_syscall+0x0/0x30) Signed-off-by: Sachin Kamat Reviewed-by: Jingoo Han Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index 57eb8cb..b59639e 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -225,8 +225,8 @@ static int pwm_samsung_request(struct pwm_chip *chip, struct pwm_device *pwm) static void pwm_samsung_free(struct pwm_chip *chip, struct pwm_device *pwm) { - pwm_set_chip_data(pwm, NULL); devm_kfree(chip->dev, pwm_get_chip_data(pwm)); + pwm_set_chip_data(pwm, NULL); } static int pwm_samsung_enable(struct pwm_chip *chip, struct pwm_device *pwm) -- cgit v0.10.2 From 1b3f25ce991d528bd0d825b3f14a45904037a382 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 30 Oct 2013 10:09:41 +0530 Subject: Documentation/pwm: Update supported SoC name for pwm-samsung Updated supported SoC name for pwm-samsung. Signed-off-by: Sachin Kamat Reviewed-by: Tomasz Figa Signed-off-by: Thierry Reding diff --git a/Documentation/devicetree/bindings/pwm/pwm-samsung.txt b/Documentation/devicetree/bindings/pwm/pwm-samsung.txt index d61fccd..5538de9 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-samsung.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-samsung.txt @@ -15,7 +15,7 @@ Required properties: samsung,s5pc100-pwm - for 32-bit timers present on S5PC100, S5PV210, Exynos4210 rev0 SoCs samsung,exynos4210-pwm - for 32-bit timers present on Exynos4210, - Exynos4x12 and Exynos5250 SoCs + Exynos4x12, Exynos5250 and Exynos5420 SoCs - reg: base address and size of register area - interrupts: list of timer interrupts (one interrupt per timer, starting at timer 0) -- cgit v0.10.2