1 /* drivers/video/backlight/ktd3102_bl.c
3 * Copyright (C) 2015 Samsung Electronics Co, Ltd.
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.
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.
15 #include <linux/module.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>
25 #include <linux/of_gpio.h>
26 #include <linux/platform_data/gen-panel-bl.h>
28 #define KTD3102_BL_NAME ("kinetic,backlight-ktd3102")
29 #define IS_HBM(level) (level >= 6)
30 static int temp[MAX_BRT_VALUE_IDX][2] = {
39 static DEFINE_SPINLOCK(bl_ctrl_lock);
41 struct ktd3102_backlight_info {
42 struct gen_panel_backlight_info ginfo;
47 int ktd3102_get_tune_level(struct ktd3102_backlight_info *bl_info,
50 struct gen_panel_backlight_info *ginfo = &bl_info->ginfo;
51 struct brt_value *range = ginfo->range;
52 int tune_level = 0, idx;
54 if (unlikely(!range)) {
55 pr_err("%s: brightness range not exist!\n", __func__);
59 if (brightness > range[BRT_VALUE_MAX].brightness ||
61 pr_err("%s: out of range (%d)\n", __func__, brightness);
65 if (IS_HBM(ginfo->auto_brightness) &&
66 brightness == range[BRT_VALUE_MAX].brightness)
67 return ginfo->outdoor_value.tune_level;
69 for (idx = 0; idx < MAX_BRT_VALUE_IDX; idx++)
70 if (brightness <= range[idx].brightness)
73 if (idx == MAX_BRT_VALUE_IDX) {
74 pr_err("%s: out of brt_value table (%d)\n",
75 __func__, brightness);
79 if (idx <= BRT_VALUE_MIN)
80 tune_level = range[idx].tune_level;
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);
90 void ktd3102_set_bl_level(struct ktd3102_backlight_info *bl_info, int level)
92 struct gen_panel_backlight_info *ginfo = &bl_info->ginfo;
94 int i, bl_ctrl = bl_info->pin_ctrl;
95 int bl_pwm = bl_info->pin_pwm;
98 pr_debug("%s, level(%d)\n", __func__, level);
102 gpio_set_value(bl_ctrl, 0);
103 gpio_set_value(bl_pwm, 0);
108 if (ginfo->prev_tune_level == 0) {
110 gpio_set_value(bl_pwm, 1);
111 gpio_set_value(bl_ctrl, 1);
115 pulse = ginfo->prev_tune_level - level;
118 pr_info("%s: pre lev=%d, cur lev=%d, pulse=%d\n",
119 __func__, ginfo->prev_tune_level, level, pulse);
121 spin_lock_irqsave(&bl_ctrl_lock, flags);
122 for(i = 0; i < pulse; i++) {
124 gpio_set_value(bl_ctrl, 0);
126 gpio_set_value(bl_ctrl, 1);
128 spin_unlock_irqrestore(&bl_ctrl_lock, flags);
133 static int ktd3102_backlight_set_brightness(
134 struct ktd3102_backlight_info *bl_info, int brightness)
136 struct gen_panel_backlight_info *ginfo = &bl_info->ginfo;
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);
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;
152 mutex_unlock(&ginfo->ops_lock);
157 static int ktd3102_backlight_update_status(struct backlight_device *bd)
159 struct ktd3102_backlight_info *bl_info =
160 (struct ktd3102_backlight_info *)bl_get_data(bd);
161 int brightness = bd->props.brightness;
163 if (unlikely(!bl_info)) {
164 pr_err("%s, no platform data\n", __func__);
168 if (bd->props.power != FB_BLANK_UNBLANK ||
169 bd->props.fb_blank != FB_BLANK_UNBLANK ||
170 !bl_info->ginfo.enable)
173 ktd3102_backlight_set_brightness(bl_info, brightness);
179 static int ktd3102_backlight_get_brightness(struct backlight_device *bd)
181 return bd->props.brightness;
184 static struct backlight_ops ktd3102_backlight_ops = {
185 .update_status = ktd3102_backlight_update_status,
186 .get_brightness = ktd3102_backlight_get_brightness,
189 static ssize_t auto_brightness_show(struct device *dev,
190 struct device_attribute *attr, char *buf)
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);
196 return sprintf(buf, "auto_brightness : %d\n", bl_info->ginfo.auto_brightness);
199 static ssize_t auto_brightness_store(struct device *dev,
200 struct device_attribute *attr, const char *buf, size_t count)
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;
209 rc = kstrtoul(buf, 0, &value);
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;
219 mutex_unlock(&ginfo->ops_lock);
220 backlight_update_status(bd);
224 static DEVICE_ATTR(auto_brightness, 0644,
225 auto_brightness_show, auto_brightness_store);
227 static int ktd3102_parse_dt_gpio(struct device_node *np, const char *prop)
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",
238 pr_info("%s, get gpio(%d)\n", __func__, gpio);
243 static void ktd3102_backlight_dump(struct ktd3102_backlight_info *info)
245 struct gen_panel_backlight_info *ginfo = &info->ginfo;
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);
266 static int ktd3102_backlight_probe(struct platform_device *pdev)
268 struct backlight_device *bd;
269 struct backlight_properties props;
270 struct ktd3102_backlight_info *bl_info;
271 struct gen_panel_backlight_info *ginfo;
273 bool outdoor_mode_en;
275 bl_info = devm_kzalloc(&pdev->dev, sizeof(*bl_info), GFP_KERNEL);
276 if (unlikely(!bl_info))
278 ginfo = &bl_info->ginfo;
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;
285 ret = of_property_read_string(np, "backlight-name",
288 bl_info->pin_ctrl = ktd3102_parse_dt_gpio(np, "bl-ctrl");
290 if (bl_info->pin_ctrl < 0) {
291 pr_err("%s, failed to parse dt\n", __func__);
294 /* PWM pin isn't mandatory */
295 bl_info->pin_pwm = ktd3102_parse_dt_gpio(np, "bl-pwm");
297 pr_info("%s: ctrl=%d, pwm=%d\n",
298 __func__, bl_info->pin_ctrl, bl_info->pin_pwm);
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);
308 ginfo->outdoor_value.brightness = arr[0];
309 ginfo->outdoor_value.tune_level = arr[1];
311 ginfo->outdoor_value.brightness = temp[BRT_VALUE_HBM][0];
312 ginfo->outdoor_value.tune_level = temp[BRT_VALUE_HBM][1];
316 ret = of_property_read_u32_array(brt_node,
317 "backlight-brt-range",
318 arr, MAX_BRT_VALUE_IDX * 2);
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];
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];
332 if (unlikely(pdev->dev.platform_data == NULL)) {
333 dev_err(&pdev->dev, "no platform data!\n");
337 /* TODO: fill bl_info data */
339 ktd3102_backlight_dump(bl_info);
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;
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;
353 mutex_init(&ginfo->ops_lock);
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);
365 bd = backlight_device_register(KTD3102_BL_NAME, &pdev->dev, bl_info,
366 &ktd3102_backlight_ops, &props);
368 dev_err(&pdev->dev, "failed to register backlight\n");
370 goto err_bl_gpio_request;
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);
380 ginfo->enable = true;
382 pm_runtime_enable(&pdev->dev);
383 platform_set_drvdata(pdev, bd);
384 pm_runtime_get_sync(&pdev->dev);
389 devm_kfree(&pdev->dev, bl_info);
394 static int ktd3102_backlight_remove(struct platform_device *pdev)
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);
401 pr_err("%s, no platform data\n", __func__);
405 ktd3102_backlight_set_brightness(bl_info, 0);
406 pm_runtime_disable(&pdev->dev);
407 backlight_device_unregister(bd);
412 static void ktd3102_backlight_shutdown(struct platform_device *pdev)
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);
419 pr_err("%s, no platform data\n", __func__);
422 ktd3102_backlight_set_brightness(bl_info, 0);
423 pm_runtime_disable(&pdev->dev);
426 static const struct of_device_id backlight_of_match[] = {
427 { .compatible = KTD3102_BL_NAME },
431 #if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
432 static int ktd3102_backlight_runtime_suspend(struct device *dev)
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);
439 pr_err("%s, no platform data\n", __func__);
443 bl_info->ginfo.enable = false;
444 backlight_update_status(bd);
446 dev_info(dev, "ktd3102_backlight suspended\n");
450 static int ktd3102_backlight_runtime_resume(struct device *dev)
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);
457 pr_err("%s, no platform data\n", __func__);
461 bl_info->ginfo.enable = true;
462 backlight_update_status(bd);
464 dev_info(dev, "ktd3102_backlight resumed.\n");
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)
474 static struct platform_driver ktd3102_backlight_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,
482 .of_match_table = backlight_of_match,
485 .probe = ktd3102_backlight_probe,
486 .remove = ktd3102_backlight_remove,
487 .shutdown = ktd3102_backlight_shutdown,
490 static int __init ktd3102_backlight_init(void)
492 return platform_driver_register(&ktd3102_backlight_driver);
494 module_init(ktd3102_backlight_init);
496 static void __exit ktd3102_backlight_exit(void)
498 platform_driver_unregister(&ktd3102_backlight_driver);
500 module_exit(ktd3102_backlight_exit);
502 MODULE_DESCRIPTION("ktd3102 based Backlight Driver");
503 MODULE_LICENSE("GPL");