kernel: port brightness settings from rel-st8-l
[linux-3.10.git] / drivers / video / backlight / pwm_bl.c
1 /*
2  * linux/drivers/video/backlight/pwm_bl.c
3  *
4  * Copyright (c) 2013-2015, NVIDIA CORPORATION, All rights reserved.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * simple PWM based backlight control, board code has to setup
16  * 1) pin configuration so PWM waveforms can output
17  * 2) platform_data being correctly configured
18  *
19  * This program is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License version 2 as
21  * published by the Free Software Foundation.
22  */
23
24 #include <linux/module.h>
25 #include <linux/kernel.h>
26 #include <linux/init.h>
27 #include <linux/platform_device.h>
28 #include <linux/fb.h>
29 #include <linux/backlight.h>
30 #include <linux/err.h>
31 #include <linux/gpio.h>
32 #include <linux/of_gpio.h>
33 #include <linux/pwm.h>
34 #include <linux/pwm_backlight.h>
35 #include <linux/slab.h>
36 #include "../../../arch/arm/mach-tegra/board.h"
37
38 static int pwm_backlight_set(struct backlight_device *bl, int brightness)
39 {
40         struct pwm_bl_data *pb = bl_get_data(bl);
41         int max = bl->props.max_brightness;
42
43         if (bl->props.power != FB_BLANK_UNBLANK ||
44             bl->props.fb_blank != FB_BLANK_UNBLANK ||
45             bl->props.state & BL_CORE_FBBLANK)
46                 brightness = 0;
47
48         if (pb->notify)
49                 brightness = pb->notify(pb->dev, brightness);
50
51         if (brightness == 0) {
52                 pwm_config(pb->pwm, 0, pb->period);
53                 pwm_disable(pb->pwm);
54         } else {
55                 int duty_cycle;
56
57                 if (pb->levels) {
58                         duty_cycle = pb->levels[brightness];
59                         max = pb->levels[max];
60                 } else {
61                         duty_cycle = brightness;
62                 }
63
64                 duty_cycle = pb->lth_brightness +
65                      (duty_cycle * (pb->period - pb->lth_brightness) / max);
66                 pwm_config(pb->pwm, duty_cycle, pb->period);
67                 pwm_enable(pb->pwm);
68         }
69
70         if (pb->notify_after)
71                 pb->notify_after(pb->dev, brightness);
72
73         return 0;
74 }
75
76 static int pwm_backlight_update_status(struct backlight_device *bl)
77 {
78         int brightness = bl->props.brightness;
79         return pwm_backlight_set(bl, brightness);
80 }
81
82 static int pwm_backlight_get_brightness(struct backlight_device *bl)
83 {
84         return bl->props.brightness;
85 }
86
87 static int pwm_backlight_check_fb(struct backlight_device *bl,
88                                   struct fb_info *info)
89 {
90         struct pwm_bl_data *pb = bl_get_data(bl);
91
92         return !pb->check_fb || pb->check_fb(pb->dev, info);
93 }
94
95 static const struct backlight_ops pwm_backlight_ops = {
96         .update_status  = pwm_backlight_update_status,
97         .get_brightness = pwm_backlight_get_brightness,
98         .check_fb       = pwm_backlight_check_fb,
99 };
100
101 #ifdef CONFIG_OF
102 static int pwm_backlight_parse_dt(struct device *dev,
103                                   struct platform_pwm_backlight_data *data,
104                                   const char *blnode_compatible,
105                                   struct device_node **target_bl_node)
106 {
107         struct device_node *node = dev->of_node;
108         struct device_node *bl_node = NULL;
109         struct device_node *compat_node = NULL;
110         struct property *prop;
111         const __be32 *p;
112         u32 u;
113         int length;
114         u32 value;
115         int ret = 0;
116         int n_bl_nonlinear = 0;
117         int n_bl_measured = 0;
118
119         if (!node)
120                 return -ENODEV;
121
122         /* If there's compat_node which is contained in
123          * backlight parent node, that means, there are
124          * multi pwm-bl device nodes and right one is
125          * chosen, with blnode_compatible */
126         if (blnode_compatible)
127                 compat_node = of_find_compatible_node(node, NULL,
128                         blnode_compatible);
129
130         if (!blnode_compatible || !compat_node)
131                 bl_node = node;
132         else
133                 bl_node = compat_node;
134
135         *target_bl_node = bl_node;
136
137         /* determine the number of brightness levels */
138         prop = of_find_property(bl_node, "brightness-levels", &length);
139         if (!prop) {
140                 /* if brightness levels array is not defined,
141                  * parse max brightness and default brightness,
142                  * directly.
143                  */
144                 ret = of_property_read_u32(bl_node, "max-brightness",
145                                            &value);
146                 if (ret < 0) {
147                         pr_info("fail to parse max-brightness\n");
148                         goto fail_parse_dt;
149                 }
150
151                 data->max_brightness = value;
152
153 #ifdef CONFIG_ANDROID
154                 if (get_androidboot_mode_charger())
155                         ret = of_property_read_u32(bl_node,
156                                                    "default-charge-brightness",
157                                                    &value);
158                 else
159 #endif
160                 ret = of_property_read_u32(bl_node, "default-brightness",
161                                            &value);
162                 if (ret < 0) {
163                         pr_info("fail to parse default-brightness\n");
164                         goto fail_parse_dt;
165                 }
166
167                 data->dft_brightness = value;
168         } else {
169                 size_t size = 0;
170                 int item_counts;
171                 item_counts = length / sizeof(u32);
172                 if (item_counts > 0)
173                         size = sizeof(*data->levels) * item_counts;
174
175                 data->levels = devm_kzalloc(dev, size, GFP_KERNEL);
176                 if (!data->levels)
177                         ret = -ENOMEM;
178                         goto fail_parse_dt;
179
180                 ret = of_property_read_u32_array(bl_node,
181                                                  "brightness-levels",
182                                                  data->levels,
183                                                  item_counts);
184                 if (ret < 0) {
185                         pr_info("fail to parse brightness-levels\n");
186                         goto fail_parse_dt;
187                 }
188
189                 /*
190                  * default-brightness-level: the default brightness level
191                  * (index into the array defined by the "brightness-levels"
192                  * property)
193                  */
194                 ret = of_property_read_u32(bl_node,
195                                            "default-brightness-level",
196                                            &value);
197                 if (ret < 0) {
198                         pr_info("fail to parse default-brightness-level\n");
199                         goto fail_parse_dt;
200                 }
201
202                 if (value >= item_counts) {
203                         dev_warn(dev, "invalid default brightness level: %u, use %u\n",
204                                 value, item_counts - 1);
205                         value = item_counts - 1;
206                 }
207
208                 data->dft_brightness = data->levels[value];
209                 data->max_brightness = data->levels[item_counts - 1];
210         }
211
212         value = 0;
213         ret = of_property_read_u32(bl_node, "lth-brightness",
214                 &value);
215         data->lth_brightness = (unsigned int)value;
216
217         data->pwm_gpio = of_get_named_gpio(bl_node, "pwm-gpio", 0);
218
219         of_property_for_each_u32(bl_node, "bl-nonlinear", prop, p, u)
220                 n_bl_nonlinear++;
221         if (n_bl_nonlinear > 0) {
222                 data->bl_nonlinear = devm_kzalloc(dev,
223                         sizeof(*data->bl_nonlinear) * n_bl_nonlinear,
224                         GFP_KERNEL);
225                 if (!data->bl_nonlinear) {
226                         pr_err("bl_nonlinear memory allocation failed\n");
227                         ret = -ENOMEM;
228                         goto fail_parse_dt;
229                 }
230                 n_bl_nonlinear = 0;
231                 of_property_for_each_u32(bl_node,
232                         "bl-nonlinear", prop, p, u)
233                         data->bl_nonlinear[n_bl_nonlinear++] = u;
234         }
235
236         of_property_for_each_u32(bl_node, "bl-measured", prop, p, u)
237                 n_bl_measured++;
238         if (n_bl_measured > 0) {
239                 data->bl_measured = devm_kzalloc(dev,
240                         sizeof(*data->bl_measured) * n_bl_measured, GFP_KERNEL);
241                 if (!data->bl_measured) {
242                         pr_err("bl_measured memory allocation failed\n");
243                         ret = -ENOMEM;
244                         goto fail_parse_dt;
245                 }
246                 n_bl_measured = 0;
247                 of_property_for_each_u32(bl_node,
248                         "bl-measured", prop, p, u)
249                         data->bl_measured[n_bl_measured++] = u;
250         }
251         of_node_put(compat_node);
252         return 0;
253
254 fail_parse_dt:
255         of_node_put(compat_node);
256         return ret;
257 }
258
259 static struct of_device_id pwm_backlight_of_match[] = {
260         { .compatible = "pwm-backlight" },
261         { }
262 };
263
264 MODULE_DEVICE_TABLE(of, pwm_backlight_of_match);
265 #else
266 static int pwm_backlight_parse_dt(struct device *dev,
267                                   struct platform_pwm_backlight_data *data,
268                                   const char *blnode_compatible,
269                                   struct device_node **target_bl_node)
270 {
271         return -ENODEV;
272 }
273 #endif
274
275 static int pwm_backlight_probe(struct platform_device *pdev)
276 {
277         struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
278         struct device_node *np = pdev->dev.of_node;
279         struct platform_pwm_backlight_data defdata;
280         struct backlight_properties props;
281         struct backlight_device *bl;
282         struct pwm_bl_data *pb;
283         struct device_node *target_bl_node = NULL;
284         unsigned int max;
285         int ret;
286         const char *blnode_compatible = NULL;
287
288         if (!np && !pdev->dev.platform_data) {
289                 dev_err(&pdev->dev, "no platform data for pwm_bl\n");
290                 return -ENOENT;
291         }
292
293         if (np) {
294                 struct pwm_bl_data_dt_ops *pops;
295                 pops = (struct pwm_bl_data_dt_ops *)platform_get_drvdata(pdev);
296                 memset(&defdata, 0, sizeof(defdata));
297                 if (pops) {
298                         defdata.init = pops->init;
299                         defdata.notify = pops->notify;
300                         defdata.notify_after = pops->notify_after;
301                         defdata.check_fb = pops->check_fb;
302                         defdata.exit = pops->exit;
303                         blnode_compatible = pops->blnode_compatible;
304                 }
305                 ret = pwm_backlight_parse_dt(&pdev->dev, &defdata,
306                         blnode_compatible, &target_bl_node);
307                 if (ret < 0) {
308                         dev_err(&pdev->dev, "fail to find platform data\n");
309                         return ret;
310                 }
311                 data = &defdata;
312
313                 /* initialize dev drv data */
314                 platform_set_drvdata(pdev, NULL);
315         }
316
317         if (data->init) {
318                 ret = data->init(&pdev->dev);
319                 if (ret < 0)
320                         return ret;
321         }
322
323         pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
324         if (!pb) {
325                 dev_err(&pdev->dev, "no memory for state\n");
326                 ret = -ENOMEM;
327                 goto err_alloc;
328         }
329
330         if (data->levels) {
331                 max = data->levels[data->max_brightness];
332                 pb->levels = data->levels;
333         } else
334                 max = data->max_brightness;
335
336         pb->notify = data->notify;
337         pb->notify_after = data->notify_after;
338         pb->bl_nonlinear = data->bl_nonlinear;
339         pb->bl_measured = data->bl_measured;
340         pb->check_fb = data->check_fb;
341         pb->exit = data->exit;
342         pb->dev = &pdev->dev;
343         pb->pwm_gpio = data->pwm_gpio;
344         /*
345          * For DT case, devm_pwm_get will finally call of_pwm_get.
346          * It is not necessary to parse data->pwm_id value from separate
347          * device tree property since in of_pwm_get, we will use 1st argument
348          * of pwms property for pwm_id, global PWM device index.
349          */
350
351         pb->pwm = devm_pwm_get(&pdev->dev, NULL);
352         if (IS_ERR(pb->pwm)) {
353                 dev_info(&pdev->dev,
354                         "PWM request fail by devm_pwm_get, trying of_pwm_get\n");
355                 pb->pwm = of_pwm_get(target_bl_node, NULL);
356                 if (IS_ERR(pb->pwm)) {
357                         dev_info(&pdev->dev, "Trying PWM req with legacy API\n");
358                         pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
359                         if (IS_ERR(pb->pwm)) {
360                                 dev_err(&pdev->dev,
361                                         "unable to request legacy PWM\n");
362                                 ret = PTR_ERR(pb->pwm);
363                                 goto err_alloc;
364                         }
365                 }
366         }
367
368         dev_dbg(&pdev->dev, "got pwm for backlight\n");
369
370         /*
371          * The DT case will not set pwm_period_ns. Instead, it stores the
372          * period, parsed from the DT, in the PWM device. In other words,
373          * the 2nd argument of pwms property indicates pwm_period in
374          * nonoseconds. For the non-DT case, set the period from
375          * platform data.
376          */
377         if (data->pwm_period_ns > 0)
378                 pwm_set_period(pb->pwm, data->pwm_period_ns);
379
380         pb->period = pwm_get_period(pb->pwm);
381         pb->lth_brightness = data->lth_brightness * (pb->period / max);
382
383         memset(&props, 0, sizeof(struct backlight_properties));
384         props.type = BACKLIGHT_RAW;
385         props.max_brightness = data->max_brightness;
386
387         if (gpio_is_valid(pb->pwm_gpio)) {
388                 ret = gpio_request(pb->pwm_gpio, "disp_bl");
389                 if (ret)
390                         dev_err(&pdev->dev, "backlight gpio request failed\n");
391         }
392
393         bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,
394                                        &pwm_backlight_ops, &props);
395         if (IS_ERR(bl)) {
396                 dev_err(&pdev->dev, "failed to register backlight\n");
397                 ret = PTR_ERR(bl);
398                 goto err_alloc;
399         }
400
401         if (data->dft_brightness > data->max_brightness) {
402                 dev_warn(&pdev->dev,
403                          "invalid dft brightness: %u, using max one %u\n",
404                          data->dft_brightness, data->max_brightness);
405                 data->dft_brightness = data->max_brightness;
406         }
407
408         platform_set_drvdata(pdev, bl);
409         bl->props.brightness = data->dft_brightness;
410         backlight_update_status(bl);
411
412         if (gpio_is_valid(pb->pwm_gpio))
413                 gpio_free(pb->pwm_gpio);
414
415         return 0;
416
417 err_alloc:
418         if (data->exit)
419                 data->exit(&pdev->dev);
420         return ret;
421 }
422
423 static int pwm_backlight_remove(struct platform_device *pdev)
424 {
425         struct backlight_device *bl = platform_get_drvdata(pdev);
426         struct pwm_bl_data *pb = bl_get_data(bl);
427
428         backlight_device_unregister(bl);
429         pwm_config(pb->pwm, 0, pb->period);
430         pwm_disable(pb->pwm);
431         if (pb->exit)
432                 pb->exit(&pdev->dev);
433         return 0;
434 }
435
436 #ifdef CONFIG_PM_SLEEP
437 static int pwm_backlight_suspend(struct device *dev)
438 {
439         struct backlight_device *bl = dev_get_drvdata(dev);
440
441         return pwm_backlight_set(bl, 0);
442 }
443
444 static int pwm_backlight_resume(struct device *dev)
445 {
446         struct backlight_device *bl = dev_get_drvdata(dev);
447
448         backlight_update_status(bl);
449         return 0;
450 }
451
452 static SIMPLE_DEV_PM_OPS(pwm_backlight_pm_ops, pwm_backlight_suspend,
453                          pwm_backlight_resume);
454
455 #endif
456
457 static struct platform_driver pwm_backlight_driver = {
458         .driver         = {
459                 .name           = "pwm-backlight",
460                 .owner          = THIS_MODULE,
461 #ifdef CONFIG_PM_SLEEP
462                 .pm             = &pwm_backlight_pm_ops,
463 #endif
464                 .of_match_table = of_match_ptr(pwm_backlight_of_match),
465         },
466         .probe          = pwm_backlight_probe,
467         .remove         = pwm_backlight_remove,
468 };
469
470 module_platform_driver(pwm_backlight_driver);
471
472 MODULE_DESCRIPTION("PWM based Backlight Driver");
473 MODULE_LICENSE("GPL");
474 MODULE_ALIAS("platform:pwm-backlight");
475