tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / video / backlight / ktd3102_bl.c
1 /* drivers/video/backlight/ktd3102_bl.c
2  *
3  * Copyright (C) 2015 Samsung Electronics Co, Ltd.
4  *
5  * This software is licensed under the terms of the GNU General Public
6  * License version 2, as published by the Free Software Foundation, and
7  * may be copied, distributed, and modified under those terms.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 #include <linux/module.h>
16 #include <linux/fb.h>
17 #include <linux/gpio.h>
18 #include <linux/delay.h>
19 #include <linux/backlight.h>
20 #include <linux/spinlock.h>
21 #include <linux/mutex.h>
22 #include <linux/pm_runtime.h>
23 #include <linux/platform_device.h>
24 #include <linux/of.h>
25 #include <linux/of_gpio.h>
26 #include <linux/platform_data/gen-panel-bl.h>
27
28 #define KTD3102_BL_NAME         ("kinetic,backlight-ktd3102")
29 #define IS_HBM(level)   (level >= 6)
30 static int temp[MAX_BRT_VALUE_IDX][2] = {
31         {0, 5},
32         {10, 6},
33         {60, 16},
34         {100, 29},
35         {255, 29},
36         {0, 0}
37 };
38
39 static DEFINE_SPINLOCK(bl_ctrl_lock);
40
41 struct ktd3102_backlight_info {
42         struct gen_panel_backlight_info ginfo;
43         int pin_ctrl;
44         int pin_pwm;
45 };
46
47 int ktd3102_get_tune_level(struct ktd3102_backlight_info *bl_info,
48                 int brightness)
49 {
50         struct gen_panel_backlight_info *ginfo = &bl_info->ginfo;
51         struct brt_value *range = ginfo->range;
52         int tune_level = 0, idx;
53
54         if (unlikely(!range)) {
55                 pr_err("%s: brightness range not exist!\n", __func__);
56                 return -EINVAL;
57         }
58
59         if (brightness > range[BRT_VALUE_MAX].brightness ||
60                         brightness < 0) {
61                 pr_err("%s: out of range (%d)\n", __func__, brightness);
62                 return -EINVAL;
63         }
64
65         if (IS_HBM(ginfo->auto_brightness) &&
66                         brightness == range[BRT_VALUE_MAX].brightness)
67                 return ginfo->outdoor_value.tune_level;
68
69         for (idx = 0; idx < MAX_BRT_VALUE_IDX; idx++)
70                 if (brightness <= range[idx].brightness)
71                         break;
72
73         if (idx == MAX_BRT_VALUE_IDX) {
74                 pr_err("%s: out of brt_value table (%d)\n",
75                                 __func__, brightness);
76                 return -EINVAL;
77         }
78
79         if (idx <= BRT_VALUE_MIN)
80                 tune_level = range[idx].tune_level;
81         else
82                 tune_level = range[idx].tune_level -
83                         (range[idx].brightness - brightness) *
84                         (range[idx].tune_level - range[idx - 1].tune_level) /
85                         (range[idx].brightness - range[idx - 1].brightness);
86
87         return tune_level;
88 }
89
90 void ktd3102_set_bl_level(struct ktd3102_backlight_info *bl_info, int level)
91 {
92         struct gen_panel_backlight_info *ginfo = &bl_info->ginfo;
93         unsigned long flags;
94         int i, bl_ctrl = bl_info->pin_ctrl;
95         int bl_pwm = bl_info->pin_pwm;
96         int pulse;
97
98         pr_debug("%s, level(%d)\n", __func__, level);
99
100         if (level == 0) {
101                 /* power off */
102                 gpio_set_value(bl_ctrl, 0);
103                 gpio_set_value(bl_pwm, 0);
104                 mdelay(3);
105                 return;
106         }
107
108         if (ginfo->prev_tune_level == 0) {
109                 /* power on */
110                 gpio_set_value(bl_pwm, 1);
111                 gpio_set_value(bl_ctrl, 1);
112                 udelay(100);
113         }
114
115         pulse = ginfo->prev_tune_level - level;
116         if (pulse < 0)
117                 pulse += 32;
118         pr_info("%s: pre lev=%d, cur lev=%d, pulse=%d\n",
119                         __func__, ginfo->prev_tune_level, level, pulse);
120
121         spin_lock_irqsave(&bl_ctrl_lock, flags);
122         for(i = 0; i < pulse; i++) {
123                 udelay(2);
124                 gpio_set_value(bl_ctrl, 0);
125                 udelay(2);
126                 gpio_set_value(bl_ctrl, 1);
127         }
128         spin_unlock_irqrestore(&bl_ctrl_lock, flags);
129
130         return;
131 }
132
133 static int ktd3102_backlight_set_brightness(
134                 struct ktd3102_backlight_info *bl_info, int brightness)
135 {
136         struct gen_panel_backlight_info *ginfo = &bl_info->ginfo;
137         int tune_level;
138
139         tune_level = ktd3102_get_tune_level(bl_info, brightness);
140         if (unlikely(tune_level < 0)) {
141                 pr_err("%s, failed to find tune_level. (%d) tune_level(%d)\n",
142                                 __func__, brightness, tune_level);
143                 return -EINVAL;
144         }
145         pr_info("[BACKLIGHT] %s: brightness(%d), tune_level(%d)\n",
146                         __func__, brightness, tune_level);
147         mutex_lock(&ginfo->ops_lock);
148         if (ginfo->prev_tune_level != tune_level) {
149                 ktd3102_set_bl_level(bl_info, tune_level);
150                 ginfo->prev_tune_level = tune_level;
151         }
152         mutex_unlock(&ginfo->ops_lock);
153
154         return tune_level;
155 }
156
157 static int ktd3102_backlight_update_status(struct backlight_device *bd)
158 {
159         struct ktd3102_backlight_info *bl_info =
160                 (struct ktd3102_backlight_info *)bl_get_data(bd);
161         int brightness = bd->props.brightness;
162
163         if (unlikely(!bl_info)) {
164                 pr_err("%s, no platform data\n", __func__);
165                 return 0;
166         }
167
168         if (bd->props.power != FB_BLANK_UNBLANK ||
169                         bd->props.fb_blank != FB_BLANK_UNBLANK ||
170                         !bl_info->ginfo.enable)
171                 brightness = 0;
172
173         ktd3102_backlight_set_brightness(bl_info, brightness);
174
175         return 0;
176
177 }
178
179 static int ktd3102_backlight_get_brightness(struct backlight_device *bd)
180 {
181         return bd->props.brightness;
182 }
183
184 static struct backlight_ops ktd3102_backlight_ops = {
185         .update_status  = ktd3102_backlight_update_status,
186         .get_brightness = ktd3102_backlight_get_brightness,
187 };
188
189 static ssize_t auto_brightness_show(struct device *dev,
190                 struct device_attribute *attr, char *buf)
191 {
192         struct backlight_device *bd = to_backlight_device(dev);
193         struct ktd3102_backlight_info *bl_info =
194                 (struct ktd3102_backlight_info *)bl_get_data(bd);
195
196         return sprintf(buf, "auto_brightness : %d\n", bl_info->ginfo.auto_brightness);
197 }
198
199 static ssize_t auto_brightness_store(struct device *dev,
200                 struct device_attribute *attr, const char *buf, size_t count)
201 {
202         int rc;
203         struct backlight_device *bd = to_backlight_device(dev);
204         struct ktd3102_backlight_info *bl_info =
205                 (struct ktd3102_backlight_info *)bl_get_data(bd);
206         struct gen_panel_backlight_info *ginfo = &bl_info->ginfo;
207         unsigned long value;
208
209         rc = kstrtoul(buf, 0, &value);
210         if (rc)
211                 return rc;
212
213         mutex_lock(&ginfo->ops_lock);
214         if (ginfo->auto_brightness != (unsigned int)value) {
215                 pr_info("%s, auto_brightness : %u\n",
216                                 __func__, (unsigned int)value);
217                 ginfo->auto_brightness = (unsigned int)value;
218         }
219         mutex_unlock(&ginfo->ops_lock);
220         backlight_update_status(bd);
221
222         return count;
223 }
224 static DEVICE_ATTR(auto_brightness, 0644,
225                 auto_brightness_show, auto_brightness_store);
226
227 static int ktd3102_parse_dt_gpio(struct device_node *np, const char *prop)
228 {
229         int gpio;
230
231         gpio = of_get_named_gpio(np, prop, 0);
232         if (unlikely(gpio < 0)) {
233                 pr_err("%s: of_get_named_gpio failed: %d\n",
234                                 __func__, gpio);
235                 return -EINVAL;
236         }
237
238         pr_info("%s, get gpio(%d)\n", __func__, gpio);
239
240         return gpio;
241 }
242
243 static void ktd3102_backlight_dump(struct ktd3102_backlight_info *info)
244 {
245         struct gen_panel_backlight_info *ginfo = &info->ginfo;
246
247         pr_info("KTD3102 backlight device : %s\n", ginfo->name);
248         pr_info("pin num: ctrl=%d, pwm=%d\n", info->pin_ctrl, info->pin_pwm);
249         pr_info("[BRT_VALUE_OFF] brightness(%d), tune_level(%d)\n",
250                         ginfo->range[BRT_VALUE_OFF].brightness,
251                         ginfo->range[BRT_VALUE_OFF].tune_level);
252         pr_info("[BRT_VALUE_MIN] brightness(%d), tune_level(%d)\n",
253                         ginfo->range[BRT_VALUE_MIN].brightness,
254                         ginfo->range[BRT_VALUE_MIN].tune_level);
255         pr_info("[BRT_VALUE_DIM] brightness(%d), tune_level(%d)\n",
256                         ginfo->range[BRT_VALUE_DIM].brightness,
257                         ginfo->range[BRT_VALUE_DIM].tune_level);
258         pr_info("[BRT_VALUE_DEF] brightness(%d), tune_level(%d)\n",
259                         ginfo->range[BRT_VALUE_DEF].brightness,
260                         ginfo->range[BRT_VALUE_DEF].tune_level);
261         pr_info("[BRT_VALUE_MAX] brightness(%d), tune_level(%d)\n",
262                         ginfo->range[BRT_VALUE_MAX].brightness,
263                         ginfo->range[BRT_VALUE_MAX].tune_level);
264 }
265
266 static int ktd3102_backlight_probe(struct platform_device *pdev)
267 {
268         struct backlight_device *bd;
269         struct backlight_properties props;
270         struct ktd3102_backlight_info *bl_info;
271         struct gen_panel_backlight_info *ginfo;
272         int ret;
273         bool outdoor_mode_en;
274
275         bl_info = devm_kzalloc(&pdev->dev, sizeof(*bl_info), GFP_KERNEL);
276         if (unlikely(!bl_info))
277                 return -ENOMEM;
278         ginfo = &bl_info->ginfo;
279
280         if (IS_ENABLED(CONFIG_OF)) {
281                 struct device_node *np = pdev->dev.of_node;
282                 struct device_node *brt_node;
283                 int arr[MAX_BRT_VALUE_IDX * 2], i;
284
285                 ret = of_property_read_string(np, "backlight-name",
286                                 &ginfo->name);
287
288                 bl_info->pin_ctrl = ktd3102_parse_dt_gpio(np, "bl-ctrl");
289                 
290                 if (bl_info->pin_ctrl < 0) {
291                         pr_err("%s, failed to parse dt\n", __func__);
292                         return -EINVAL;
293                 }
294                 /* PWM pin isn't mandatory */
295                 bl_info->pin_pwm = ktd3102_parse_dt_gpio(np, "bl-pwm");
296                         
297                 pr_info("%s: ctrl=%d, pwm=%d\n",
298                                 __func__, bl_info->pin_ctrl, bl_info->pin_pwm);
299
300                 /* get default brightness table */
301                 brt_node = of_get_next_child(np, NULL);
302                 outdoor_mode_en = of_property_read_bool(brt_node,
303                                 "gen-panel-outdoor-mode-en");
304                 if (outdoor_mode_en) {
305                         ret = of_property_read_u32_array(brt_node,
306                                         "backlight-brt-outdoor", arr, 2);
307                         if (ret == 0) {
308                                 ginfo->outdoor_value.brightness = arr[0];
309                                 ginfo->outdoor_value.tune_level = arr[1];
310                         } else {
311                                 ginfo->outdoor_value.brightness = temp[BRT_VALUE_HBM][0];
312                                 ginfo->outdoor_value.tune_level = temp[BRT_VALUE_HBM][1];
313                         }
314                 }
315
316                 ret = of_property_read_u32_array(brt_node,
317                                 "backlight-brt-range",
318                                 arr, MAX_BRT_VALUE_IDX * 2);
319                 if (ret < 0) {
320                         for (i = 0; i < MAX_BRT_VALUE_IDX; i++) {
321                                 ginfo->range[i].brightness = temp[i][0];
322                                 ginfo->range[i].tune_level = temp[i][1];
323                         }
324                 } else {
325                         for (i = 0; i < MAX_BRT_VALUE_IDX; i++) {
326                                 ginfo->range[i].brightness = arr[i * 2];
327                                 ginfo->range[i].tune_level = arr[i * 2 + 1];
328                         }
329                 }
330         } else {
331                 int i;
332                 if (unlikely(pdev->dev.platform_data == NULL)) {
333                         dev_err(&pdev->dev, "no platform data!\n");
334                         return -EINVAL;
335                 }
336
337                 /* TODO: fill bl_info data */
338         }
339         ktd3102_backlight_dump(bl_info);
340
341         ret = gpio_request(bl_info->pin_ctrl, "BL_CTRL");
342         if (unlikely(ret < 0)) {
343                 pr_err("%s, request gpio(%d) failed\n", __func__, bl_info->pin_ctrl);
344                 goto err_bl_gpio_request;
345         }
346
347         ret = gpio_request(bl_info->pin_pwm, "BL_PWM");
348         if (unlikely(ret < 0)) {
349                 pr_err("%s, request gpio(%d) failed\n", __func__, bl_info->pin_pwm);
350                 goto err_bl_gpio_request;
351         }
352
353         mutex_init(&ginfo->ops_lock);
354
355         /* register backlight device */
356         memset(&props, 0, sizeof(struct backlight_properties));
357         props.type = BACKLIGHT_PLATFORM;
358         props.max_brightness = ginfo->range[BRT_VALUE_MAX].brightness;
359         props.brightness = ginfo->range[BRT_VALUE_DEF].brightness;
360         ginfo->current_brightness = ginfo->range[BRT_VALUE_DEF].brightness;
361         ginfo->prev_tune_level = ginfo->range[BRT_VALUE_DEF].tune_level;
362         pr_info("%s: cur brt=%d, prev tune lev=%d\n", __func__,
363                         ginfo->current_brightness, ginfo->prev_tune_level);
364
365         bd = backlight_device_register(KTD3102_BL_NAME, &pdev->dev, bl_info,
366                         &ktd3102_backlight_ops, &props);
367         if (IS_ERR(bd)) {
368                 dev_err(&pdev->dev, "failed to register backlight\n");
369                 ret = PTR_ERR(bd);
370                 goto err_bl_gpio_request;
371         }
372
373         if (outdoor_mode_en) {
374                 ret = device_create_file(&bd->dev, &dev_attr_auto_brightness);
375                 if (unlikely(ret < 0)) {
376                         pr_err("Failed to create device file(%s)!\n",
377                                         dev_attr_auto_brightness.attr.name);
378                 }
379         }
380         ginfo->enable = true;
381
382         pm_runtime_enable(&pdev->dev);
383         platform_set_drvdata(pdev, bd);
384         pm_runtime_get_sync(&pdev->dev);
385
386         return 0;
387
388 err_bl_gpio_request:
389         devm_kfree(&pdev->dev, bl_info);
390
391         return ret;
392 }
393
394 static int ktd3102_backlight_remove(struct platform_device *pdev)
395 {
396         struct backlight_device *bd = platform_get_drvdata(pdev);
397         struct ktd3102_backlight_info *bl_info =
398                 (struct ktd3102_backlight_info *)bl_get_data(bd);
399
400         if (!bl_info) {
401                 pr_err("%s, no platform data\n", __func__);
402                 return 0;
403         }
404
405         ktd3102_backlight_set_brightness(bl_info, 0);
406         pm_runtime_disable(&pdev->dev);
407         backlight_device_unregister(bd);
408
409         return 0;
410 }
411
412 static void ktd3102_backlight_shutdown(struct platform_device *pdev)
413 {
414         struct backlight_device *bd = platform_get_drvdata(pdev);
415         struct ktd3102_backlight_info *bl_info =
416                 (struct ktd3102_backlight_info *)bl_get_data(bd);
417
418         if (!bl_info) {
419                 pr_err("%s, no platform data\n", __func__);
420                 return;
421         }
422         ktd3102_backlight_set_brightness(bl_info, 0);
423         pm_runtime_disable(&pdev->dev);
424 }
425
426 static const struct of_device_id backlight_of_match[] = {
427         { .compatible = KTD3102_BL_NAME },
428         { }
429 };
430
431 #if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
432 static int ktd3102_backlight_runtime_suspend(struct device *dev)
433 {
434         struct backlight_device *bd = dev_get_drvdata(dev);
435         struct ktd3102_backlight_info *bl_info =
436                 (struct ktd3102_backlight_info *)bl_get_data(bd);
437
438         if (!bl_info) {
439                 pr_err("%s, no platform data\n", __func__);
440                 return -EINVAL;
441         }
442
443         bl_info->ginfo.enable = false;
444         backlight_update_status(bd);
445
446         dev_info(dev, "ktd3102_backlight suspended\n");
447         return 0;
448 }
449
450 static int ktd3102_backlight_runtime_resume(struct device *dev)
451 {
452         struct backlight_device *bd = dev_get_drvdata(dev);
453         struct ktd3102_backlight_info *bl_info =
454                 (struct ktd3102_backlight_info *)bl_get_data(bd);
455
456         if (!bl_info) {
457                 pr_err("%s, no platform data\n", __func__);
458                 return -EINVAL;
459         }
460
461         bl_info->ginfo.enable = true;
462         backlight_update_status(bd);
463
464         dev_info(dev, "ktd3102_backlight resumed.\n");
465         return 0;
466 }
467
468 const struct dev_pm_ops ktd3102_backlight_pm_ops = {
469         SET_RUNTIME_PM_OPS(ktd3102_backlight_runtime_suspend,
470                         ktd3102_backlight_runtime_resume, NULL)
471 };
472 #endif
473
474 static struct platform_driver ktd3102_backlight_driver = {
475         .driver         = {
476                 .name   = KTD3102_BL_NAME,
477                 .owner  = THIS_MODULE,
478 #if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
479                 .pm     = &ktd3102_backlight_pm_ops,
480 #endif
481 #ifdef CONFIG_OF
482                 .of_match_table = backlight_of_match,
483 #endif
484         },
485         .probe          = ktd3102_backlight_probe,
486         .remove         = ktd3102_backlight_remove,
487         .shutdown      = ktd3102_backlight_shutdown,
488 };
489
490 static int __init ktd3102_backlight_init(void)
491 {
492         return platform_driver_register(&ktd3102_backlight_driver);
493 }
494 module_init(ktd3102_backlight_init);
495
496 static void __exit ktd3102_backlight_exit(void)
497 {
498         platform_driver_unregister(&ktd3102_backlight_driver);
499 }
500 module_exit(ktd3102_backlight_exit);
501
502 MODULE_DESCRIPTION("ktd3102 based Backlight Driver");
503 MODULE_LICENSE("GPL");