1 | /* |
2 | * linux/drivers/video/backlight/pwm_bl.c |
3 | * |
4 | * simple PWM based backlight control, board code has to setup |
5 | * 1) pin configuration so PWM waveforms can output |
6 | * 2) platform_data being correctly configured |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. |
11 | */ |
12 | |
13 | #include <linux/delay.h> |
14 | #include <linux/gpio/consumer.h> |
15 | #include <linux/gpio.h> |
16 | #include <linux/module.h> |
17 | #include <linux/kernel.h> |
18 | #include <linux/init.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/fb.h> |
21 | #include <linux/backlight.h> |
22 | #include <linux/err.h> |
23 | #include <linux/pwm.h> |
24 | #include <linux/pwm_backlight.h> |
25 | #include <linux/regulator/consumer.h> |
26 | #include <linux/slab.h> |
27 | |
28 | struct pwm_bl_data { |
29 | struct pwm_device *pwm; |
30 | struct device *dev; |
31 | unsigned int lth_brightness; |
32 | unsigned int *levels; |
33 | bool enabled; |
34 | struct regulator *power_supply; |
35 | struct gpio_desc *enable_gpio; |
36 | unsigned int scale; |
37 | bool legacy; |
38 | unsigned int post_pwm_on_delay; |
39 | unsigned int pwm_off_delay; |
40 | int (*notify)(struct device *, |
41 | int brightness); |
42 | void (*notify_after)(struct device *, |
43 | int brightness); |
44 | int (*check_fb)(struct device *, struct fb_info *); |
45 | void (*exit)(struct device *); |
46 | }; |
47 | |
48 | static void pwm_backlight_power_on(struct pwm_bl_data *pb) |
49 | { |
50 | struct pwm_state state; |
51 | int err; |
52 | |
53 | pwm_get_state(pb->pwm, &state); |
54 | if (pb->enabled) |
55 | return; |
56 | |
57 | err = regulator_enable(pb->power_supply); |
58 | if (err < 0) |
59 | dev_err(pb->dev, "failed to enable power supply\n" ); |
60 | |
61 | state.enabled = true; |
62 | pwm_apply_state(pb->pwm, &state); |
63 | |
64 | if (pb->post_pwm_on_delay) |
65 | msleep(pb->post_pwm_on_delay); |
66 | |
67 | if (pb->enable_gpio) |
68 | gpiod_set_value_cansleep(pb->enable_gpio, 1); |
69 | |
70 | pb->enabled = true; |
71 | } |
72 | |
73 | static void pwm_backlight_power_off(struct pwm_bl_data *pb) |
74 | { |
75 | struct pwm_state state; |
76 | |
77 | pwm_get_state(pb->pwm, &state); |
78 | if (!pb->enabled) |
79 | return; |
80 | |
81 | if (pb->enable_gpio) |
82 | gpiod_set_value_cansleep(pb->enable_gpio, 0); |
83 | |
84 | if (pb->pwm_off_delay) |
85 | msleep(pb->pwm_off_delay); |
86 | |
87 | state.enabled = false; |
88 | state.duty_cycle = 0; |
89 | pwm_apply_state(pb->pwm, &state); |
90 | |
91 | regulator_disable(pb->power_supply); |
92 | pb->enabled = false; |
93 | } |
94 | |
95 | static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness) |
96 | { |
97 | unsigned int lth = pb->lth_brightness; |
98 | struct pwm_state state; |
99 | u64 duty_cycle; |
100 | |
101 | pwm_get_state(pb->pwm, &state); |
102 | |
103 | if (pb->levels) |
104 | duty_cycle = pb->levels[brightness]; |
105 | else |
106 | duty_cycle = brightness; |
107 | |
108 | duty_cycle *= state.period - lth; |
109 | do_div(duty_cycle, pb->scale); |
110 | |
111 | return duty_cycle + lth; |
112 | } |
113 | |
114 | static int pwm_backlight_update_status(struct backlight_device *bl) |
115 | { |
116 | struct pwm_bl_data *pb = bl_get_data(bl); |
117 | int brightness = bl->props.brightness; |
118 | struct pwm_state state; |
119 | |
120 | if (bl->props.power != FB_BLANK_UNBLANK || |
121 | bl->props.fb_blank != FB_BLANK_UNBLANK || |
122 | bl->props.state & BL_CORE_FBBLANK) |
123 | brightness = 0; |
124 | |
125 | if (pb->notify) |
126 | brightness = pb->notify(pb->dev, brightness); |
127 | |
128 | if (brightness > 0) { |
129 | pwm_get_state(pb->pwm, &state); |
130 | state.duty_cycle = compute_duty_cycle(pb, brightness); |
131 | pwm_apply_state(pb->pwm, &state); |
132 | pwm_backlight_power_on(pb); |
133 | } else |
134 | pwm_backlight_power_off(pb); |
135 | |
136 | if (pb->notify_after) |
137 | pb->notify_after(pb->dev, brightness); |
138 | |
139 | return 0; |
140 | } |
141 | |
142 | static int pwm_backlight_check_fb(struct backlight_device *bl, |
143 | struct fb_info *info) |
144 | { |
145 | struct pwm_bl_data *pb = bl_get_data(bl); |
146 | |
147 | return !pb->check_fb || pb->check_fb(pb->dev, info); |
148 | } |
149 | |
150 | static const struct backlight_ops pwm_backlight_ops = { |
151 | .update_status = pwm_backlight_update_status, |
152 | .check_fb = pwm_backlight_check_fb, |
153 | }; |
154 | |
155 | #ifdef CONFIG_OF |
156 | #define PWM_LUMINANCE_SCALE 10000 /* luminance scale */ |
157 | |
158 | /* An integer based power function */ |
159 | static u64 int_pow(u64 base, int exp) |
160 | { |
161 | u64 result = 1; |
162 | |
163 | while (exp) { |
164 | if (exp & 1) |
165 | result *= base; |
166 | exp >>= 1; |
167 | base *= base; |
168 | } |
169 | |
170 | return result; |
171 | } |
172 | |
173 | /* |
174 | * CIE lightness to PWM conversion. |
175 | * |
176 | * The CIE 1931 lightness formula is what actually describes how we perceive |
177 | * light: |
178 | * Y = (L* / 902.3) if L* ≤ 0.08856 |
179 | * Y = ((L* + 16) / 116)^3 if L* > 0.08856 |
180 | * |
181 | * Where Y is the luminance, the amount of light coming out of the screen, and |
182 | * is a number between 0.0 and 1.0; and L* is the lightness, how bright a human |
183 | * perceives the screen to be, and is a number between 0 and 100. |
184 | * |
185 | * The following function does the fixed point maths needed to implement the |
186 | * above formula. |
187 | */ |
188 | static u64 cie1931(unsigned int lightness, unsigned int scale) |
189 | { |
190 | u64 retval; |
191 | |
192 | lightness *= 100; |
193 | if (lightness <= (8 * scale)) { |
194 | retval = DIV_ROUND_CLOSEST_ULL(lightness * 10, 9023); |
195 | } else { |
196 | retval = int_pow((lightness + (16 * scale)) / 116, 3); |
197 | retval = DIV_ROUND_CLOSEST_ULL(retval, (scale * scale)); |
198 | } |
199 | |
200 | return retval; |
201 | } |
202 | |
203 | /* |
204 | * Create a default correction table for PWM values to create linear brightness |
205 | * for LED based backlights using the CIE1931 algorithm. |
206 | */ |
207 | static |
208 | int pwm_backlight_brightness_default(struct device *dev, |
209 | struct platform_pwm_backlight_data *data, |
210 | unsigned int period) |
211 | { |
212 | unsigned int counter = 0; |
213 | unsigned int i, n; |
214 | u64 retval; |
215 | |
216 | /* |
217 | * Count the number of bits needed to represent the period number. The |
218 | * number of bits is used to calculate the number of levels used for the |
219 | * brightness-levels table, the purpose of this calculation is have a |
220 | * pre-computed table with enough levels to get linear brightness |
221 | * perception. The period is divided by the number of bits so for a |
222 | * 8-bit PWM we have 255 / 8 = 32 brightness levels or for a 16-bit PWM |
223 | * we have 65535 / 16 = 4096 brightness levels. |
224 | * |
225 | * Note that this method is based on empirical testing on different |
226 | * devices with PWM of 8 and 16 bits of resolution. |
227 | */ |
228 | n = period; |
229 | while (n) { |
230 | counter += n % 2; |
231 | n >>= 1; |
232 | } |
233 | |
234 | data->max_brightness = DIV_ROUND_UP(period, counter); |
235 | data->levels = devm_kcalloc(dev, data->max_brightness, |
236 | sizeof(*data->levels), GFP_KERNEL); |
237 | if (!data->levels) |
238 | return -ENOMEM; |
239 | |
240 | /* Fill the table using the cie1931 algorithm */ |
241 | for (i = 0; i < data->max_brightness; i++) { |
242 | retval = cie1931((i * PWM_LUMINANCE_SCALE) / |
243 | data->max_brightness, PWM_LUMINANCE_SCALE) * |
244 | period; |
245 | retval = DIV_ROUND_CLOSEST_ULL(retval, PWM_LUMINANCE_SCALE); |
246 | if (retval > UINT_MAX) |
247 | return -EINVAL; |
248 | data->levels[i] = (unsigned int)retval; |
249 | } |
250 | |
251 | data->dft_brightness = data->max_brightness / 2; |
252 | data->max_brightness--; |
253 | |
254 | return 0; |
255 | } |
256 | |
257 | static int pwm_backlight_parse_dt(struct device *dev, |
258 | struct platform_pwm_backlight_data *data) |
259 | { |
260 | struct device_node *node = dev->of_node; |
261 | unsigned int num_levels = 0; |
262 | unsigned int levels_count; |
263 | unsigned int num_steps = 0; |
264 | struct property *prop; |
265 | unsigned int *table; |
266 | int length; |
267 | u32 value; |
268 | int ret; |
269 | |
270 | if (!node) |
271 | return -ENODEV; |
272 | |
273 | memset(data, 0, sizeof(*data)); |
274 | |
275 | /* |
276 | * These values are optional and set as 0 by default, the out values |
277 | * are modified only if a valid u32 value can be decoded. |
278 | */ |
279 | of_property_read_u32(node, "post-pwm-on-delay-ms" , |
280 | &data->post_pwm_on_delay); |
281 | of_property_read_u32(node, "pwm-off-delay-ms" , &data->pwm_off_delay); |
282 | |
283 | data->enable_gpio = -EINVAL; |
284 | |
285 | /* |
286 | * Determine the number of brightness levels, if this property is not |
287 | * set a default table of brightness levels will be used. |
288 | */ |
289 | prop = of_find_property(node, "brightness-levels" , &length); |
290 | if (!prop) |
291 | return 0; |
292 | |
293 | data->max_brightness = length / sizeof(u32); |
294 | |
295 | /* read brightness levels from DT property */ |
296 | if (data->max_brightness > 0) { |
297 | size_t size = sizeof(*data->levels) * data->max_brightness; |
298 | unsigned int i, j, n = 0; |
299 | |
300 | data->levels = devm_kzalloc(dev, size, GFP_KERNEL); |
301 | if (!data->levels) |
302 | return -ENOMEM; |
303 | |
304 | ret = of_property_read_u32_array(node, "brightness-levels" , |
305 | data->levels, |
306 | data->max_brightness); |
307 | if (ret < 0) |
308 | return ret; |
309 | |
310 | ret = of_property_read_u32(node, "default-brightness-level" , |
311 | &value); |
312 | if (ret < 0) |
313 | return ret; |
314 | |
315 | data->dft_brightness = value; |
316 | |
317 | /* |
318 | * This property is optional, if is set enables linear |
319 | * interpolation between each of the values of brightness levels |
320 | * and creates a new pre-computed table. |
321 | */ |
322 | of_property_read_u32(node, "num-interpolated-steps" , |
323 | &num_steps); |
324 | |
325 | /* |
326 | * Make sure that there is at least two entries in the |
327 | * brightness-levels table, otherwise we can't interpolate |
328 | * between two points. |
329 | */ |
330 | if (num_steps) { |
331 | if (data->max_brightness < 2) { |
332 | dev_err(dev, "can't interpolate\n" ); |
333 | return -EINVAL; |
334 | } |
335 | |
336 | /* |
337 | * Recalculate the number of brightness levels, now |
338 | * taking in consideration the number of interpolated |
339 | * steps between two levels. |
340 | */ |
341 | for (i = 0; i < data->max_brightness - 1; i++) { |
342 | if ((data->levels[i + 1] - data->levels[i]) / |
343 | num_steps) |
344 | num_levels += num_steps; |
345 | else |
346 | num_levels++; |
347 | } |
348 | num_levels++; |
349 | dev_dbg(dev, "new number of brightness levels: %d\n" , |
350 | num_levels); |
351 | |
352 | /* |
353 | * Create a new table of brightness levels with all the |
354 | * interpolated steps. |
355 | */ |
356 | size = sizeof(*table) * num_levels; |
357 | table = devm_kzalloc(dev, size, GFP_KERNEL); |
358 | if (!table) |
359 | return -ENOMEM; |
360 | |
361 | /* Fill the interpolated table. */ |
362 | levels_count = 0; |
363 | for (i = 0; i < data->max_brightness - 1; i++) { |
364 | value = data->levels[i]; |
365 | n = (data->levels[i + 1] - value) / num_steps; |
366 | if (n > 0) { |
367 | for (j = 0; j < num_steps; j++) { |
368 | table[levels_count] = value; |
369 | value += n; |
370 | levels_count++; |
371 | } |
372 | } else { |
373 | table[levels_count] = data->levels[i]; |
374 | levels_count++; |
375 | } |
376 | } |
377 | table[levels_count] = data->levels[i]; |
378 | |
379 | /* |
380 | * As we use interpolation lets remove current |
381 | * brightness levels table and replace for the |
382 | * new interpolated table. |
383 | */ |
384 | devm_kfree(dev, data->levels); |
385 | data->levels = table; |
386 | |
387 | /* |
388 | * Reassign max_brightness value to the new total number |
389 | * of brightness levels. |
390 | */ |
391 | data->max_brightness = num_levels; |
392 | } |
393 | |
394 | data->max_brightness--; |
395 | } |
396 | |
397 | return 0; |
398 | } |
399 | |
400 | static const struct of_device_id pwm_backlight_of_match[] = { |
401 | { .compatible = "pwm-backlight" }, |
402 | { } |
403 | }; |
404 | |
405 | MODULE_DEVICE_TABLE(of, pwm_backlight_of_match); |
406 | #else |
407 | static int pwm_backlight_parse_dt(struct device *dev, |
408 | struct platform_pwm_backlight_data *data) |
409 | { |
410 | return -ENODEV; |
411 | } |
412 | |
413 | static |
414 | int pwm_backlight_brightness_default(struct device *dev, |
415 | struct platform_pwm_backlight_data *data, |
416 | unsigned int period) |
417 | { |
418 | return -ENODEV; |
419 | } |
420 | #endif |
421 | |
422 | static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb) |
423 | { |
424 | struct device_node *node = pb->dev->of_node; |
425 | |
426 | /* Not booted with device tree or no phandle link to the node */ |
427 | if (!node || !node->phandle) |
428 | return FB_BLANK_UNBLANK; |
429 | |
430 | /* |
431 | * If the driver is probed from the device tree and there is a |
432 | * phandle link pointing to the backlight node, it is safe to |
433 | * assume that another driver will enable the backlight at the |
434 | * appropriate time. Therefore, if it is disabled, keep it so. |
435 | */ |
436 | |
437 | /* if the enable GPIO is disabled, do not enable the backlight */ |
438 | if (pb->enable_gpio && gpiod_get_value_cansleep(pb->enable_gpio) == 0) |
439 | return FB_BLANK_POWERDOWN; |
440 | |
441 | /* The regulator is disabled, do not enable the backlight */ |
442 | if (!regulator_is_enabled(pb->power_supply)) |
443 | return FB_BLANK_POWERDOWN; |
444 | |
445 | /* The PWM is disabled, keep it like this */ |
446 | if (!pwm_is_enabled(pb->pwm)) |
447 | return FB_BLANK_POWERDOWN; |
448 | |
449 | return FB_BLANK_UNBLANK; |
450 | } |
451 | |
452 | static int pwm_backlight_probe(struct platform_device *pdev) |
453 | { |
454 | struct platform_pwm_backlight_data *data = dev_get_platdata(&pdev->dev); |
455 | struct platform_pwm_backlight_data defdata; |
456 | struct backlight_properties props; |
457 | struct backlight_device *bl; |
458 | struct device_node *node = pdev->dev.of_node; |
459 | struct pwm_bl_data *pb; |
460 | struct pwm_state state; |
461 | unsigned int i; |
462 | int ret; |
463 | |
464 | if (!data) { |
465 | ret = pwm_backlight_parse_dt(&pdev->dev, &defdata); |
466 | if (ret < 0) { |
467 | dev_err(&pdev->dev, "failed to find platform data\n" ); |
468 | return ret; |
469 | } |
470 | |
471 | data = &defdata; |
472 | } |
473 | |
474 | if (data->init) { |
475 | ret = data->init(&pdev->dev); |
476 | if (ret < 0) |
477 | return ret; |
478 | } |
479 | |
480 | pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL); |
481 | if (!pb) { |
482 | ret = -ENOMEM; |
483 | goto err_alloc; |
484 | } |
485 | |
486 | pb->notify = data->notify; |
487 | pb->notify_after = data->notify_after; |
488 | pb->check_fb = data->check_fb; |
489 | pb->exit = data->exit; |
490 | pb->dev = &pdev->dev; |
491 | pb->enabled = false; |
492 | pb->post_pwm_on_delay = data->post_pwm_on_delay; |
493 | pb->pwm_off_delay = data->pwm_off_delay; |
494 | |
495 | pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable" , |
496 | GPIOD_ASIS); |
497 | if (IS_ERR(pb->enable_gpio)) { |
498 | ret = PTR_ERR(pb->enable_gpio); |
499 | goto err_alloc; |
500 | } |
501 | |
502 | /* |
503 | * Compatibility fallback for drivers still using the integer GPIO |
504 | * platform data. Must go away soon. |
505 | */ |
506 | if (!pb->enable_gpio && gpio_is_valid(data->enable_gpio)) { |
507 | ret = devm_gpio_request_one(&pdev->dev, data->enable_gpio, |
508 | GPIOF_OUT_INIT_HIGH, "enable" ); |
509 | if (ret < 0) { |
510 | dev_err(&pdev->dev, "failed to request GPIO#%d: %d\n" , |
511 | data->enable_gpio, ret); |
512 | goto err_alloc; |
513 | } |
514 | |
515 | pb->enable_gpio = gpio_to_desc(data->enable_gpio); |
516 | } |
517 | |
518 | /* |
519 | * If the GPIO is not known to be already configured as output, that |
520 | * is, if gpiod_get_direction returns either 1 or -EINVAL, change the |
521 | * direction to output and set the GPIO as active. |
522 | * Do not force the GPIO to active when it was already output as it |
523 | * could cause backlight flickering or we would enable the backlight too |
524 | * early. Leave the decision of the initial backlight state for later. |
525 | */ |
526 | if (pb->enable_gpio && |
527 | gpiod_get_direction(pb->enable_gpio) != 0) |
528 | gpiod_direction_output(pb->enable_gpio, 1); |
529 | |
530 | pb->power_supply = devm_regulator_get(&pdev->dev, "power" ); |
531 | if (IS_ERR(pb->power_supply)) { |
532 | ret = PTR_ERR(pb->power_supply); |
533 | goto err_alloc; |
534 | } |
535 | |
536 | pb->pwm = devm_pwm_get(&pdev->dev, NULL); |
537 | if (IS_ERR(pb->pwm) && PTR_ERR(pb->pwm) != -EPROBE_DEFER && !node) { |
538 | dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n" ); |
539 | pb->legacy = true; |
540 | pb->pwm = pwm_request(data->pwm_id, "pwm-backlight" ); |
541 | } |
542 | |
543 | if (IS_ERR(pb->pwm)) { |
544 | ret = PTR_ERR(pb->pwm); |
545 | if (ret != -EPROBE_DEFER) |
546 | dev_err(&pdev->dev, "unable to request PWM\n" ); |
547 | goto err_alloc; |
548 | } |
549 | |
550 | dev_dbg(&pdev->dev, "got pwm for backlight\n" ); |
551 | |
552 | /* Sync up PWM state. */ |
553 | pwm_init_state(pb->pwm, &state); |
554 | |
555 | /* |
556 | * The DT case will set the pwm_period_ns field to 0 and store the |
557 | * period, parsed from the DT, in the PWM device. For the non-DT case, |
558 | * set the period from platform data if it has not already been set |
559 | * via the PWM lookup table. |
560 | */ |
561 | if (!state.period && (data->pwm_period_ns > 0)) |
562 | state.period = data->pwm_period_ns; |
563 | |
564 | ret = pwm_apply_state(pb->pwm, &state); |
565 | if (ret) { |
566 | dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n" , |
567 | ret); |
568 | goto err_alloc; |
569 | } |
570 | |
571 | if (data->levels) { |
572 | /* |
573 | * For the DT case, only when brightness levels is defined |
574 | * data->levels is filled. For the non-DT case, data->levels |
575 | * can come from platform data, however is not usual. |
576 | */ |
577 | for (i = 0; i <= data->max_brightness; i++) { |
578 | if (data->levels[i] > pb->scale) |
579 | pb->scale = data->levels[i]; |
580 | |
581 | pb->levels = data->levels; |
582 | } |
583 | } else if (!data->max_brightness) { |
584 | /* |
585 | * If no brightness levels are provided and max_brightness is |
586 | * not set, use the default brightness table. For the DT case, |
587 | * max_brightness is set to 0 when brightness levels is not |
588 | * specified. For the non-DT case, max_brightness is usually |
589 | * set to some value. |
590 | */ |
591 | |
592 | /* Get the PWM period (in nanoseconds) */ |
593 | pwm_get_state(pb->pwm, &state); |
594 | |
595 | ret = pwm_backlight_brightness_default(&pdev->dev, data, |
596 | state.period); |
597 | if (ret < 0) { |
598 | dev_err(&pdev->dev, |
599 | "failed to setup default brightness table\n" ); |
600 | goto err_alloc; |
601 | } |
602 | |
603 | for (i = 0; i <= data->max_brightness; i++) { |
604 | if (data->levels[i] > pb->scale) |
605 | pb->scale = data->levels[i]; |
606 | |
607 | pb->levels = data->levels; |
608 | } |
609 | } else { |
610 | /* |
611 | * That only happens for the non-DT case, where platform data |
612 | * sets the max_brightness value. |
613 | */ |
614 | pb->scale = data->max_brightness; |
615 | } |
616 | |
617 | pb->lth_brightness = data->lth_brightness * (state.period / pb->scale); |
618 | |
619 | memset(&props, 0, sizeof(struct backlight_properties)); |
620 | props.type = BACKLIGHT_RAW; |
621 | props.max_brightness = data->max_brightness; |
622 | bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb, |
623 | &pwm_backlight_ops, &props); |
624 | if (IS_ERR(bl)) { |
625 | dev_err(&pdev->dev, "failed to register backlight\n" ); |
626 | ret = PTR_ERR(bl); |
627 | if (pb->legacy) |
628 | pwm_free(pb->pwm); |
629 | goto err_alloc; |
630 | } |
631 | |
632 | if (data->dft_brightness > data->max_brightness) { |
633 | dev_warn(&pdev->dev, |
634 | "invalid default brightness level: %u, using %u\n" , |
635 | data->dft_brightness, data->max_brightness); |
636 | data->dft_brightness = data->max_brightness; |
637 | } |
638 | |
639 | bl->props.brightness = data->dft_brightness; |
640 | bl->props.power = pwm_backlight_initial_power_state(pb); |
641 | backlight_update_status(bl); |
642 | |
643 | platform_set_drvdata(pdev, bl); |
644 | return 0; |
645 | |
646 | err_alloc: |
647 | if (data->exit) |
648 | data->exit(&pdev->dev); |
649 | return ret; |
650 | } |
651 | |
652 | static int pwm_backlight_remove(struct platform_device *pdev) |
653 | { |
654 | struct backlight_device *bl = platform_get_drvdata(pdev); |
655 | struct pwm_bl_data *pb = bl_get_data(bl); |
656 | |
657 | backlight_device_unregister(bl); |
658 | pwm_backlight_power_off(pb); |
659 | |
660 | if (pb->exit) |
661 | pb->exit(&pdev->dev); |
662 | if (pb->legacy) |
663 | pwm_free(pb->pwm); |
664 | |
665 | return 0; |
666 | } |
667 | |
668 | static void pwm_backlight_shutdown(struct platform_device *pdev) |
669 | { |
670 | struct backlight_device *bl = platform_get_drvdata(pdev); |
671 | struct pwm_bl_data *pb = bl_get_data(bl); |
672 | |
673 | pwm_backlight_power_off(pb); |
674 | } |
675 | |
676 | #ifdef CONFIG_PM_SLEEP |
677 | static int pwm_backlight_suspend(struct device *dev) |
678 | { |
679 | struct backlight_device *bl = dev_get_drvdata(dev); |
680 | struct pwm_bl_data *pb = bl_get_data(bl); |
681 | |
682 | if (pb->notify) |
683 | pb->notify(pb->dev, 0); |
684 | |
685 | pwm_backlight_power_off(pb); |
686 | |
687 | if (pb->notify_after) |
688 | pb->notify_after(pb->dev, 0); |
689 | |
690 | return 0; |
691 | } |
692 | |
693 | static int pwm_backlight_resume(struct device *dev) |
694 | { |
695 | struct backlight_device *bl = dev_get_drvdata(dev); |
696 | |
697 | backlight_update_status(bl); |
698 | |
699 | return 0; |
700 | } |
701 | #endif |
702 | |
703 | static const struct dev_pm_ops pwm_backlight_pm_ops = { |
704 | #ifdef CONFIG_PM_SLEEP |
705 | .suspend = pwm_backlight_suspend, |
706 | .resume = pwm_backlight_resume, |
707 | .poweroff = pwm_backlight_suspend, |
708 | .restore = pwm_backlight_resume, |
709 | #endif |
710 | }; |
711 | |
712 | static struct platform_driver pwm_backlight_driver = { |
713 | .driver = { |
714 | .name = "pwm-backlight" , |
715 | .pm = &pwm_backlight_pm_ops, |
716 | .of_match_table = of_match_ptr(pwm_backlight_of_match), |
717 | }, |
718 | .probe = pwm_backlight_probe, |
719 | .remove = pwm_backlight_remove, |
720 | .shutdown = pwm_backlight_shutdown, |
721 | }; |
722 | |
723 | module_platform_driver(pwm_backlight_driver); |
724 | |
725 | MODULE_DESCRIPTION("PWM based Backlight Driver" ); |
726 | MODULE_LICENSE("GPL" ); |
727 | MODULE_ALIAS("platform:pwm-backlight" ); |
728 | |