blob: ccaac708a953fa262a52db68fb3a9fb5035c7b59 [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018 MediaTek Inc.
4 *
5 */
6
7#include <linux/ctype.h>
8#include <linux/err.h>
9#include <linux/leds.h>
10#include <linux/leds_pwm.h>
11#include <linux/module.h>
12#include <linux/of_platform.h>
13#include <linux/platform_device.h>
14#include <linux/pwm.h>
15#include <linux/sched.h>
16#include <linux/sched/clock.h>
17#include <linux/slab.h>
18#include <linux/string.h>
19#include <linux/workqueue.h>
20
21
22/****************************************************************************
23 * variables
24 ***************************************************************************/
25
26struct mtk_leds_info;
27struct led_desp *leds_desp;
28
29static int led_pwm_level_set(struct led_classdev *led_cdev,
30 enum led_brightness brightness);
31
32struct led_pwm_info {
33 struct pwm_device *pwm;
34 struct led_pwm config;
35 unsigned long long duty;
36};
37
38struct led_debug_info {
39 unsigned long long current_t;
40 unsigned long long last_t;
41 char buffer[4096];
42 int count;
43};
44
45struct led_limit_info {
46
47 unsigned int limit_l;
48 u8 flag;
49 unsigned int current_l;
50 unsigned int last_l;
51};
52
53struct led_desp {
54 int index;
55 char name[16];
56};
57
58struct mtk_led_data {
59 struct led_desp desp;
60 struct led_classdev cdev;
61 struct led_pwm_info info;
62 int level;
63 int delay_on;
64 int delay_off;
65 int led_bits;
66 int trans_bits;
67 struct device_node *np;
68 struct mtk_leds_info *parent;
69 struct led_debug_info debug;
70 struct led_limit_info limit;
71 struct work_struct work;
72};
73
74struct mtk_leds_info {
75 struct device *dev;
76 struct mutex lock;
77 int nums;
78 struct mtk_led_data leds[0];
79 struct wakeup_source leds_suspend_lock;
80};
81
82static DEFINE_MUTEX(leds_mutex);
83
84
85/****************************************************************************
86 * DEBUG MACROS
87 ***************************************************************************/
88
89#define LEDS_DRV_TAG "[LED_DRV]"
90#define LEDS_DRV_INFO(format, args...) \
91 pr_info("%s:%s() line-%d: " format, \
92 LEDS_DRV_TAG, __func__, __LINE__, ## args)
93
94static void led_debug_log(struct mtk_led_data *s_led,
95 int level, int mappingLevel)
96{
97 unsigned long cur_time_mod = 0;
98 unsigned long long cur_time_display = 0;
99
100 s_led->debug.current_t = sched_clock();
101 cur_time_display = s_led->debug.current_t;
102 cur_time_mod = do_div(cur_time_display, 1000000000);
103
104 sprintf(s_led->debug.buffer + strlen(s_led->debug.buffer),
105 "T:%lld.%ld,L:%d map:%d ",
106 cur_time_display, cur_time_mod/1000000,
107 level, mappingLevel);
108
109 s_led->debug.count++;
110
111 if (level == 0 || s_led->debug.count >= 5 ||
112 (s_led->debug.current_t - s_led->debug.last_t) > 1000000000) {
113 LEDS_DRV_INFO("%s", s_led->debug.buffer);
114 s_led->debug.count = 0;
115 s_led->debug.buffer[strlen("[Light] Set directly ") +
116 strlen(s_led->cdev.name)] = '\0';
117 }
118
119 s_led->debug.last_t = sched_clock();
120}
121
122
123/****************************************************************************
124 * add API for temperature control
125 ***************************************************************************/
126
127struct led_desp *getLedDesp(char *name)
128{
129 while (leds_desp++) {
130 if (strcmp(name, leds_desp->name) == 0)
131 return leds_desp;
132 }
133 return NULL;
134}
135EXPORT_SYMBOL(getLedDesp);
136
137int setMaxBrightness(struct led_desp *desp, int percent, int enable)
138{
139 struct mtk_led_data *led_dat;
140 int limit_l, max_l;
141
142 if (!desp) {
143 LEDS_DRV_INFO("can not find leds by led_desp %s",
144 desp->name);
145 return -1;
146 }
147 led_dat = container_of(desp, struct mtk_led_data, desp);
148
149 if (!led_dat) {
150 LEDS_DRV_INFO("not support led %s CONTROL_BL_TEMPERATURE!",
151 desp->name);
152 return -1;
153 }
154 max_l = led_dat->cdev.max_brightness;
155 limit_l = (percent * max_l) / 100;
156 LEDS_DRV_INFO("name: %s, limit_l : %d, enable: %d",
157 desp->name, limit_l, enable);
158 if (enable) {
159 led_dat->limit.flag = 1;
160 led_dat->limit.limit_l = limit_l;
161 if (led_dat->limit.current_l != 0) {
162 if (led_dat->limit.limit_l < led_dat->limit.last_l) {
163 LEDS_DRV_INFO
164 ("set value control start! limit=%d\n",
165 led_dat->limit.limit_l);
166 led_dat->level = led_dat->limit.limit_l;
167 led_pwm_level_set(&led_dat->cdev,
168 led_dat->limit.limit_l);
169 } else {
170 led_pwm_level_set(&led_dat->cdev,
171 led_dat->limit.last_l);
172 }
173 }
174 } else {
175 led_dat->limit.flag = 0;
176 led_dat->limit.limit_l = (1 << led_dat->led_bits) - 1;
177
178 if (led_dat->limit.current_l != 0) {
179 LEDS_DRV_INFO("control temperature close:limit=%d\n",
180 led_dat->limit.limit_l);
181 led_pwm_level_set(&led_dat->cdev,
182 led_dat->limit.last_l);
183 }
184 }
185
186 return 0;
187
188}
189EXPORT_SYMBOL(setMaxBrightness);
190
191/****************************************************************************
192 * driver functions
193 ***************************************************************************/
194static void __led_pwm_set(struct led_pwm_info *led_info)
195{
196 int new_duty = led_info->duty;
197
198 pwm_config(led_info->pwm, new_duty, led_info->config.pwm_period_ns);
199 if (new_duty == 0)
200 pwm_disable(led_info->pwm);
201 else
202 pwm_enable(led_info->pwm);
203}
204
205static int led_pwm_set(struct mtk_led_data *led_dat,
206 unsigned int brightness)
207{
208 unsigned int max;
209 unsigned long long duty;
210
211 led_dat->level = brightness;
212 max = led_dat->cdev.max_brightness;
213 duty = led_dat->info.config.pwm_period_ns;
214 duty *= brightness;
215 LEDS_DRV_INFO("brightness=%d, max_brightness=%d, duty=%lld",
216 brightness, max, duty);
217 do_div(duty, max);
218
219 if (led_dat->info.config.active_low)
220 duty = led_dat->info.config.pwm_period_ns - duty;
221
222 led_dat->info.duty = duty;
223
224 __led_pwm_set(&led_dat->info);
225
226 return 0;
227}
228
229
230void mtk_led_work(struct work_struct *work)
231{
232 struct mtk_led_data *led_data =
233 container_of(work, struct mtk_led_data, work);
234
235 mutex_lock(&leds_mutex);
236 led_pwm_set(led_data, led_data->level);
237 mutex_unlock(&leds_mutex);
238}
239
240static int led_level_set(struct mtk_led_data *s_led,
241 enum led_brightness brightness)
242{
243
244 unsigned int mappingLevel = (
245 (((1 << s_led->trans_bits) - 1) * brightness
246 + (((1 << s_led->led_bits) - 1) / 2))
247 / ((1 << s_led->led_bits) - 1));
248
249 schedule_work(&s_led->work);
250 s_led->level = brightness;
251 led_debug_log(s_led, brightness, mappingLevel);
252 led_pwm_set(s_led, brightness);
253 return 0;
254}
255
256static int led_pwm_disable(struct led_pwm_info *led_info)
257{
258
259 pwm_config(led_info->pwm, 0, led_info->config.pwm_period_ns);
260 pwm_disable(led_info->pwm);
261
262 return 0;
263}
264
265static int led_pwm_level_set(struct led_classdev *led_cdev,
266 enum led_brightness brightness)
267{
268 struct mtk_led_data *led_dat =
269 container_of(led_cdev, struct mtk_led_data, cdev);
270
271 if (strcmp(led_dat->info.config.name, "lcd-backlight")) {
272 led_dat->limit.current_l = brightness;
273 if (led_dat->limit.flag) {
274 if (led_dat->limit.limit_l < led_dat->limit.current_l)
275 brightness = led_dat->limit.limit_l;
276 } else
277 led_dat->limit.last_l = brightness;
278 }
279 if (led_dat->level != brightness)
280 return led_level_set(led_dat, brightness);
281 return 0;
282}
283
284static void led_data_init(struct mtk_led_data *s_led)
285{
286 if (!strcmp(s_led->info.config.name, "lcd-backlight")) {
287 s_led->limit.last_l = 0;
288 s_led->limit.limit_l = 255;
289 s_led->limit.flag = 0;
290 s_led->limit.current_l = 0;
291 }
292 INIT_WORK(&s_led->work, mtk_led_work);
293 sprintf(s_led->debug.buffer + strlen(s_led->debug.buffer),
294 "[Light] Set %s directly ", s_led->info.config.name);
295
296}
297
298static int led_pwm_config_add(struct device *dev,
299 struct mtk_led_data *s_led)
300{
301 struct pwm_args pargs;
302 int ret = 0;
303
304 s_led->cdev.name = s_led->info.config.name;
305 s_led->cdev.default_trigger = s_led->info.config.default_trigger;
306 s_led->cdev.brightness = s_led->level;
307 s_led->cdev.max_brightness = s_led->info.config.max_brightness;
308 s_led->cdev.flags = LED_CORE_SUSPENDRESUME;
309 s_led->cdev.brightness_set_blocking = led_pwm_level_set;
310 ret = devm_led_classdev_register(dev, &(s_led->cdev));
311 LEDS_DRV_INFO("%s devm_led_classdev_register ok! ", s_led->cdev.name);
312
313 if (s_led->np != NULL)
314 s_led->info.pwm = devm_of_pwm_get(dev, s_led->np,
315 s_led->info.config.name);
316 else
317 s_led->info.pwm = devm_pwm_get(dev, s_led->info.config.name);
318 if (IS_ERR(s_led->info.pwm)) {
319 ret = PTR_ERR(s_led->info.pwm);
320 if (ret != -EPROBE_DEFER) {
321 dev_err(dev, "unable to request PWM for %s, err_code: %d\n",
322 s_led->info.config.name, ret);
323 goto err;
324 }
325 }
326
327 pwm_apply_args(s_led->info.pwm);
328 pwm_get_args(s_led->info.pwm, &pargs);
329
330 s_led->info.config.pwm_period_ns = pargs.period;
331 if (!s_led->info.config.pwm_period_ns && (pargs.period > 0))
332 s_led->info.config.pwm_period_ns = pargs.period;
333 LEDS_DRV_INFO("info.config.pwm_period_ns = %d!",
334 s_led->info.config.pwm_period_ns);
335
336 led_pwm_level_set(&s_led->cdev, s_led->cdev.brightness);
337 LEDS_DRV_INFO("set led pwm OK!");
338 return ret;
339
340 err:
341 dev_err(dev, "add pwm failed!\n");
342 ret = -ENOMEM;
343 return ret;
344
345}
346
347static int mtk_leds_parse_dt(struct device *dev,
348 struct mtk_leds_info *m_leds)
349{
350 struct device_node *leds_np, *child;
351 struct mtk_led_data *s_led;
352 int ret = 0, num = 0;
353 const char *state;
354
355 if (!dev->of_node) {
356 dev_err(dev, "Error load dts: node not exist!\n");
357 return ret;
358 }
359 leds_np = of_find_node_by_name(dev->of_node, "backlight");
360 if (!leds_np) {
361 dev_err(dev, "Error load dts node, node name error!\n");
362 return ret;
363 }
364
365 for_each_available_child_of_node(dev->of_node, child) {
366
367 s_led = &(m_leds->leds[num]);
368 ret = of_property_read_string(child, "label",
369 &(s_led->info.config.name));
370 if (ret) {
371 dev_err(dev, "Fail to read label property");
372 goto out_led_dt;
373 }
374 ret = of_property_read_string(child, "default-trigger",
375 &(s_led->info.config.default_trigger));
376 if (ret) {
377 dev_err(dev, "Fail to read default-trigger property");
378 goto out_led_dt;
379 }
380 ret = of_property_read_u8(child, "active-low",
381 &(s_led->info.config.active_low));
382 if (ret) {
383 dev_err(dev, "Fail to read active-low property\n");
384 goto out_led_dt;
385 }
386 ret = of_property_read_u32(child,
387 "led-bits", &(s_led->led_bits));
388 if (ret) {
389 LEDS_DRV_INFO("No led-bits, use default value 8");
390 s_led->led_bits = 8;
391 }
392 s_led->info.config.max_brightness =
393 (1 << s_led->led_bits) - 1;
394 ret = of_property_read_u8(child,
395 "limit-state", &(s_led->limit.flag));
396 if (ret) {
397 LEDS_DRV_INFO("No limit-state, use default value 0");
398 s_led->limit.flag = 0;
399 }
400 ret = of_property_read_u32(child,
401 "trans-bits", &(s_led->trans_bits));
402 if (ret) {
403 LEDS_DRV_INFO("No trans-bits, use default value 10");
404 s_led->trans_bits = 10;
405 }
406 ret = of_property_read_string(child, "default-state", &state);
407 if (!ret) {
408 if (!strcmp(state, "half"))
409 s_led->level =
410 s_led->info.config.max_brightness / 2;
411 else if (!strcmp(state, "on"))
412 s_led->level =
413 s_led->info.config.max_brightness;
414 else
415 s_led->level = 0;
416
417 } else
418 s_led->level = s_led->info.config.max_brightness;
419 LEDS_DRV_INFO("parse %d leds dt: %s, %s, %d, %d, %d\n",
420 num, s_led->info.config.name,
421 s_led->info.config.default_trigger,
422 s_led->info.config.active_low,
423 s_led->info.config.max_brightness,
424 s_led->led_bits);
425 s_led->np = child;
426 s_led->parent = m_leds;
427 s_led->desp.index = num;
428 strncpy(s_led->desp.name, s_led->info.config.name,
429 strlen(s_led->info.config.name));
430 leds_desp[num] = s_led->desp;
431 led_data_init(s_led);
432 led_pwm_config_add(dev, s_led);
433 led_pwm_level_set(&s_led->cdev, s_led->level);
434 num++;
435 }
436 m_leds->nums = num;
437 LEDS_DRV_INFO("load dts ok!");
438 return ret;
439out_led_dt:
440 dev_err(dev, "Error load dts node!\n");
441 of_node_put(child);
442 return ret;
443}
444
445
446/****************************************************************************
447 * driver functions
448 ***************************************************************************/
449
450static int mtk_leds_probe(struct platform_device *pdev)
451{
452
453 struct device *dev = &pdev->dev;
454 struct mtk_leds_info *m_leds;
455 int ret, nums;
456
457 LEDS_DRV_INFO("probe begain +++");
458
459 nums = of_get_child_count(dev->of_node);
460 LEDS_DRV_INFO("Load dts node nums: %d", nums);
461 m_leds = devm_kzalloc(dev, (sizeof(struct mtk_leds_info) +
462 (sizeof(struct mtk_led_data) * (nums))), GFP_KERNEL);
463 if (!m_leds)
464 goto err;
465 leds_desp = devm_kzalloc(dev,
466 (sizeof(struct led_desp) * (nums)), GFP_KERNEL);
467 if (!leds_desp)
468 goto err;
469
470 platform_set_drvdata(pdev, m_leds);
471 m_leds->dev = dev;
472 mutex_init(&m_leds->lock);
473 ret = mtk_leds_parse_dt(&(pdev->dev), m_leds);
474 if (ret) {
475 dev_err(&pdev->dev, "Failed to parse devicetree!\n");
476 goto err;
477 }
478
479 LEDS_DRV_INFO("probe end ---");
480 return 0;
481 err:
482 dev_err(&pdev->dev, "Failed to probe!\n");
483 ret = -ENOMEM;
484 return ret;
485}
486
487static int mtk_leds_remove(struct platform_device *pdev)
488{
489 int i;
490 struct mtk_leds_info *m_leds = dev_get_platdata(&pdev->dev);
491
492 if (m_leds)
493 return 0;
494 for (i = 0; i < m_leds->nums; i++) {
495 if (!m_leds->leds[i].parent)
496 continue;
497 led_classdev_unregister(&m_leds->leds[i].cdev);
498 cancel_work_sync(&m_leds->leds[i].work);
499 m_leds->leds[i].parent = NULL;
500 }
501 kfree(m_leds);
502 m_leds = NULL;
503
504 return 0;
505}
506
507static void mtk_leds_shutdown(struct platform_device *pdev)
508{
509 int i;
510 struct mtk_leds_info *m_leds = dev_get_platdata(&pdev->dev);
511
512 LEDS_DRV_INFO("Turn off backlight\n");
513
514 for (i = 0; m_leds && i < m_leds->nums; i++) {
515 if (!&(m_leds->leds[i]))
516 continue;
517 led_pwm_disable(&(m_leds->leds[i].info));
518 }
519
520}
521
522static const struct of_device_id of_mtk_pwm_leds_match[] = {
523 { .compatible = "mediatek,pwm-leds", },
524 {},
525};
526MODULE_DEVICE_TABLE(of, of_mtk_pwm_leds_match);
527
528static struct platform_driver mtk_pwm_leds_driver = {
529 .driver = {
530 .name = "mtk-pwm-leds",
531 .owner = THIS_MODULE,
532 .of_match_table = of_mtk_pwm_leds_match,
533 },
534 .probe = mtk_leds_probe,
535 .remove = mtk_leds_remove,
536 .shutdown = mtk_leds_shutdown,
537
538};
539
540static int __init mtk_leds_init(void)
541{
542 int ret;
543
544 LEDS_DRV_INFO("Leds init\n");
545 ret = platform_driver_register(&mtk_pwm_leds_driver);
546
547 if (ret) {
548 LEDS_DRV_INFO("driver register error: %d\n", ret);
549 return ret;
550 }
551
552 return ret;
553}
554
555static void __exit mtk_leds_exit(void)
556{
557 platform_driver_unregister(&mtk_pwm_leds_driver);
558}
559
560/* delay leds init, for (1)display has delayed to use clock upstream.
561 * (2)to fix repeat switch battary and power supply caused BL KE issue,
562 * battary calling bl .shutdown whitch need to call disp_pwm and display
563 * function and they not yet probe.
564 */
565late_initcall(mtk_leds_init);
566module_exit(mtk_leds_exit);
567
568MODULE_AUTHOR("Mediatek Corporation");
569MODULE_DESCRIPTION("MTK Disp PWM Backlight Driver");
570MODULE_LICENSE("GPL");
571
572