diff options
-rw-r--r-- | Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt | 5 | ||||
-rw-r--r-- | drivers/video/backlight/pwm_bl.c | 57 |
2 files changed, 55 insertions, 7 deletions
diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt index 1e4fc727f3b1..72810cc2dbc1 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: | |||
14 | Optional properties: | 14 | Optional properties: |
15 | - pwm-names: a list of names for the PWM devices specified in the | 15 | - pwm-names: a list of names for the PWM devices specified in the |
16 | "pwms" property (see PWM binding[0]) | 16 | "pwms" property (see PWM binding[0]) |
17 | - enable-gpios: contains a single GPIO specifier for the GPIO which enables | ||
18 | and disables the backlight (see GPIO binding[1]) | ||
17 | 19 | ||
18 | [0]: Documentation/devicetree/bindings/pwm/pwm.txt | 20 | [0]: Documentation/devicetree/bindings/pwm/pwm.txt |
21 | [1]: Documentation/devicetree/bindings/gpio/gpio.txt | ||
19 | 22 | ||
20 | Example: | 23 | Example: |
21 | 24 | ||
@@ -25,4 +28,6 @@ Example: | |||
25 | 28 | ||
26 | brightness-levels = <0 4 8 16 32 64 128 255>; | 29 | brightness-levels = <0 4 8 16 32 64 128 255>; |
27 | default-brightness-level = <6>; | 30 | default-brightness-level = <6>; |
31 | |||
32 | enable-gpios = <&gpio 58 0>; | ||
28 | }; | 33 | }; |
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 4053efbe5edb..cdef4a346555 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c | |||
@@ -10,6 +10,8 @@ | |||
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/gpio.h> | ||
14 | #include <linux/of_gpio.h> | ||
13 | #include <linux/module.h> | 15 | #include <linux/module.h> |
14 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
15 | #include <linux/init.h> | 17 | #include <linux/init.h> |
@@ -28,6 +30,8 @@ struct pwm_bl_data { | |||
28 | unsigned int lth_brightness; | 30 | unsigned int lth_brightness; |
29 | unsigned int *levels; | 31 | unsigned int *levels; |
30 | bool enabled; | 32 | bool enabled; |
33 | int enable_gpio; | ||
34 | unsigned long enable_gpio_flags; | ||
31 | int (*notify)(struct device *, | 35 | int (*notify)(struct device *, |
32 | int brightness); | 36 | int brightness); |
33 | void (*notify_after)(struct device *, | 37 | void (*notify_after)(struct device *, |
@@ -55,6 +59,14 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness, | |||
55 | pb->lth_brightness; | 59 | pb->lth_brightness; |
56 | 60 | ||
57 | pwm_config(pb->pwm, duty_cycle, pb->period); | 61 | pwm_config(pb->pwm, duty_cycle, pb->period); |
62 | |||
63 | if (gpio_is_valid(pb->enable_gpio)) { | ||
64 | if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW) | ||
65 | gpio_set_value(pb->enable_gpio, 0); | ||
66 | else | ||
67 | gpio_set_value(pb->enable_gpio, 1); | ||
68 | } | ||
69 | |||
58 | pwm_enable(pb->pwm); | 70 | pwm_enable(pb->pwm); |
59 | pb->enabled = true; | 71 | pb->enabled = true; |
60 | } | 72 | } |
@@ -67,6 +79,13 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb) | |||
67 | pwm_config(pb->pwm, 0, pb->period); | 79 | pwm_config(pb->pwm, 0, pb->period); |
68 | pwm_disable(pb->pwm); | 80 | pwm_disable(pb->pwm); |
69 | 81 | ||
82 | if (gpio_is_valid(pb->enable_gpio)) { | ||
83 | if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW) | ||
84 | gpio_set_value(pb->enable_gpio, 1); | ||
85 | else | ||
86 | gpio_set_value(pb->enable_gpio, 0); | ||
87 | } | ||
88 | |||
70 | pb->enabled = false; | 89 | pb->enabled = false; |
71 | } | 90 | } |
72 | 91 | ||
@@ -119,6 +138,7 @@ static int pwm_backlight_parse_dt(struct device *dev, | |||
119 | struct platform_pwm_backlight_data *data) | 138 | struct platform_pwm_backlight_data *data) |
120 | { | 139 | { |
121 | struct device_node *node = dev->of_node; | 140 | struct device_node *node = dev->of_node; |
141 | enum of_gpio_flags flags; | ||
122 | struct property *prop; | 142 | struct property *prop; |
123 | int length; | 143 | int length; |
124 | u32 value; | 144 | u32 value; |
@@ -159,11 +179,13 @@ static int pwm_backlight_parse_dt(struct device *dev, | |||
159 | data->max_brightness--; | 179 | data->max_brightness--; |
160 | } | 180 | } |
161 | 181 | ||
162 | /* | 182 | data->enable_gpio = of_get_named_gpio_flags(node, "enable-gpios", 0, |
163 | * TODO: Most users of this driver use a number of GPIOs to control | 183 | &flags); |
164 | * backlight power. Support for specifying these needs to be | 184 | if (data->enable_gpio == -EPROBE_DEFER) |
165 | * added. | 185 | return -EPROBE_DEFER; |
166 | */ | 186 | |
187 | if (gpio_is_valid(data->enable_gpio) && (flags & OF_GPIO_ACTIVE_LOW)) | ||
188 | data->enable_gpio_flags |= PWM_BACKLIGHT_GPIO_ACTIVE_LOW; | ||
167 | 189 | ||
168 | return 0; | 190 | return 0; |
169 | } | 191 | } |
@@ -221,6 +243,8 @@ static int pwm_backlight_probe(struct platform_device *pdev) | |||
221 | } else | 243 | } else |
222 | max = data->max_brightness; | 244 | max = data->max_brightness; |
223 | 245 | ||
246 | pb->enable_gpio = data->enable_gpio; | ||
247 | pb->enable_gpio_flags = data->enable_gpio_flags; | ||
224 | pb->notify = data->notify; | 248 | pb->notify = data->notify; |
225 | pb->notify_after = data->notify_after; | 249 | pb->notify_after = data->notify_after; |
226 | pb->check_fb = data->check_fb; | 250 | pb->check_fb = data->check_fb; |
@@ -228,6 +252,22 @@ static int pwm_backlight_probe(struct platform_device *pdev) | |||
228 | pb->dev = &pdev->dev; | 252 | pb->dev = &pdev->dev; |
229 | pb->enabled = false; | 253 | pb->enabled = false; |
230 | 254 | ||
255 | if (gpio_is_valid(pb->enable_gpio)) { | ||
256 | unsigned long flags; | ||
257 | |||
258 | if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW) | ||
259 | flags = GPIOF_OUT_INIT_HIGH; | ||
260 | else | ||
261 | flags = GPIOF_OUT_INIT_LOW; | ||
262 | |||
263 | ret = gpio_request_one(pb->enable_gpio, flags, "enable"); | ||
264 | if (ret < 0) { | ||
265 | dev_err(&pdev->dev, "failed to request GPIO#%d: %d\n", | ||
266 | pb->enable_gpio, ret); | ||
267 | goto err_alloc; | ||
268 | } | ||
269 | } | ||
270 | |||
231 | pb->pwm = devm_pwm_get(&pdev->dev, NULL); | 271 | pb->pwm = devm_pwm_get(&pdev->dev, NULL); |
232 | if (IS_ERR(pb->pwm)) { | 272 | if (IS_ERR(pb->pwm)) { |
233 | dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n"); | 273 | 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) | |||
236 | if (IS_ERR(pb->pwm)) { | 276 | if (IS_ERR(pb->pwm)) { |
237 | dev_err(&pdev->dev, "unable to request legacy PWM\n"); | 277 | dev_err(&pdev->dev, "unable to request legacy PWM\n"); |
238 | ret = PTR_ERR(pb->pwm); | 278 | ret = PTR_ERR(pb->pwm); |
239 | goto err_alloc; | 279 | goto err_gpio; |
240 | } | 280 | } |
241 | } | 281 | } |
242 | 282 | ||
@@ -261,7 +301,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) | |||
261 | if (IS_ERR(bl)) { | 301 | if (IS_ERR(bl)) { |
262 | dev_err(&pdev->dev, "failed to register backlight\n"); | 302 | dev_err(&pdev->dev, "failed to register backlight\n"); |
263 | ret = PTR_ERR(bl); | 303 | ret = PTR_ERR(bl); |
264 | goto err_alloc; | 304 | goto err_gpio; |
265 | } | 305 | } |
266 | 306 | ||
267 | if (data->dft_brightness > data->max_brightness) { | 307 | if (data->dft_brightness > data->max_brightness) { |
@@ -277,6 +317,9 @@ static int pwm_backlight_probe(struct platform_device *pdev) | |||
277 | platform_set_drvdata(pdev, bl); | 317 | platform_set_drvdata(pdev, bl); |
278 | return 0; | 318 | return 0; |
279 | 319 | ||
320 | err_gpio: | ||
321 | if (gpio_is_valid(pb->enable_gpio)) | ||
322 | gpio_free(pb->enable_gpio); | ||
280 | err_alloc: | 323 | err_alloc: |
281 | if (data->exit) | 324 | if (data->exit) |
282 | data->exit(&pdev->dev); | 325 | data->exit(&pdev->dev); |