1 /*
2 * Copyright (C) 2019 Allwinnertech Co.Ltd
3 * Authors: zhengwanyu
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 */
11 #include <drm/drm_print.h>
12 #include "disp_sys_intf.h"
13 #include "sunxi_common.h"
14 #include "sunxi_backlight.h"
15
16 static unsigned int sunxi_backlight_cnt;
17 static struct sunxi_lcd_backlight *sunxi_backlight[BL_NUM_MAX];
18
19 static struct sunxi_lcd_backlight *
sunxi_backlight_get_backlight(unsigned int lcd_id)20 sunxi_backlight_get_backlight(unsigned int lcd_id)
21 {
22 if (lcd_id < BL_NUM_MAX)
23 return sunxi_backlight[lcd_id];
24 return NULL;
25 }
26
sunxi_backlight_info(char * buf)27 ssize_t sunxi_backlight_info(char *buf)
28 {
29 ssize_t n = 0;
30 unsigned int i, j;
31 struct sunxi_lcd_backlight *bl;
32
33 n += sprintf(buf+n, "backlight count:%u\n\n", sunxi_backlight_cnt);
34 for (i = 0; i < BL_NUM_MAX; i++) {
35 bl = sunxi_backlight_get_backlight(i);
36 n += sprintf(buf + n, "is LCD:%u backlight\n", i);
37 n += sprintf(buf + n, "bl_en info:\n");
38 n += sprintf(buf + n, "use_bl_en:%u\n", bl->use_bl_en);
39 n += sprintf(buf + n, "gpio setting, name:%s gpio:%d\n",
40 bl->bl_en_gpio.name, bl->bl_en_gpio.gpio);
41 n += sprintf(buf + n, "bl_gpio_hdl:%d\n", bl->bl_gpio_hdl);
42 n += sprintf(buf + n, "bl_en_power:%s\n", bl->bl_en_power);
43 n += sprintf(buf + n, "bl_en_count:%u\n\n", bl->bl_en_count);
44
45 n += sprintf(buf + n, "use_pwm:%u\n", bl->use_pwm);
46 n += sprintf(buf + n, "bright:%llu\n", bl->bright);
47 n += sprintf(buf + n, "pwm_info:chn%u pol:%u period_ns:%u"
48 " duty_ns:%u en:%u\n", bl->pwm_info.channel,
49 bl->pwm_info.polarity, bl->pwm_info.period_ns,
50 bl->pwm_info.duty_ns, bl->pwm_info.enabled);
51 n += sprintf(buf + n, "diming:%u\n", bl->dimming);
52 n += sprintf(buf + n, "bright_curve_tbl:\n");
53 for (j = 0; j < 256; j++) {
54 if ((j != 0) && !(j % 10))
55 n += sprintf(buf + n, "\n");
56 n += sprintf(buf + n, "%02x ", bl->bright_curve_tbl[j]);
57 }
58 n += sprintf(buf + n, "\n");
59 }
60
61 return n;
62 }
63
64 /*To check if there is a backlight that contain a same pwm*/
sunxi_backlight_get_same_pwm(unsigned int lcd_id,unsigned int pwm_ch)65 struct pwm_info *sunxi_backlight_get_same_pwm(unsigned int lcd_id,
66 unsigned int pwm_ch)
67 {
68 int i;
69 struct sunxi_lcd_backlight *bl;
70
71 if (lcd_id >= BL_NUM_MAX)
72 return NULL;
73
74 for (i = 0; i < lcd_id; i++) {
75 bl = sunxi_backlight_get_backlight(i);
76 if (bl->pwm_info.channel == pwm_ch)
77 return &bl->pwm_info;
78 }
79
80 return NULL;
81 }
82
sunxi_backlight_set_bright(unsigned int lcd_id,unsigned int bright)83 static int sunxi_backlight_set_bright(unsigned int lcd_id,
84 unsigned int bright)
85 {
86 int ret = 0;
87 unsigned int bl_value, brightness;
88 struct sunxi_lcd_backlight *bl = NULL;
89
90 bl = sunxi_backlight_get_backlight(lcd_id);
91 if (!bl) {
92 DRM_ERROR("Null bl pointer!\n");
93 return -1;
94 }
95
96 brightness = (bright > 255) ? 255 : bright;
97
98 /*######################################*/
99 /******need to implement SMBL here*******/
100 /*######################################*/
101
102 #if IS_ENABLED(CONFIG_AW_PWM) || IS_ENABLED(CONFIG_PWM_SUNXI_NEW) || IS_ENABLED(CONFIG_PWM_SUNXI_GROUP)
103 if (bl->pwm_info.pwm_dev) {
104 if (brightness != 0)
105 brightness += 1;
106 brightness = (brightness > 255) ? 255 : brightness;
107 bl_value = bl->bright_curve_tbl[brightness];
108
109
110 bl->dimming = bl->dimming ? bl->dimming : 256;
111
112 bl->pwm_info.duty_ns = (bl_value * bl->dimming
113 * bl->pwm_info.period_ns / 256 + 128) / 256;
114 ret = pwm_config(bl->pwm_info.pwm_dev, bl->pwm_info.duty_ns,
115 bl->pwm_info.period_ns);
116 if (ret < 0) {
117 DRM_ERROR("[SUNXI_BL]%s pwm_config failed\n", __func__);
118 return -1;
119 }
120 }
121 #endif
122
123 /*######################################*/
124 /******need to implement panel set bright here*******/
125 /*######################################*/
126 bl->bright = brightness;
127
128 return 0;
129 }
130
sunxi_backlight_get_bright(unsigned int lcd_id)131 unsigned int sunxi_backlight_get_bright(unsigned int lcd_id)
132 {
133 struct sunxi_lcd_backlight *bl = sunxi_backlight_get_backlight(lcd_id);
134
135 if (bl)
136 return bl->bright;
137 else
138 return 0;
139 }
140
141 /**
142 * @name :sunxi_backlight_set_backlight_device
143 * @brief :set backligt_device pointer, memer of sunxi_lcd_backlight
144 * @param[IN] :lcd_id: sunxi lcd index
145 * @param[IN] :p_bl_dev:pointer to set
146 * @return :0 if success, -1 else
147 */
sunxi_backlight_set_backlight_device(unsigned int lcd_id,struct backlight_device * p_bl_dev)148 int sunxi_backlight_set_backlight_device(unsigned int lcd_id,
149 struct backlight_device *p_bl_dev)
150 {
151 int ret = 0;
152 struct sunxi_lcd_backlight *bl = sunxi_backlight_get_backlight(lcd_id);
153
154 if (p_bl_dev && bl)
155 bl->bl_dev = p_bl_dev;
156 else
157 ret = -1;
158
159 return ret;
160 }
161
162 /**
163 * @name :sunxi_backlight_get_backlight_device
164 * @brief :get pointer of backlight_device of specified lcd_id
165 * @param[IN] :lcd_id: sunxi lcd index
166 * @return :pointer of backlight_device, NULL if fail to get one
167 */
168 struct backlight_device *
sunxi_backlight_get_backlight_device(unsigned int lcd_id)169 sunxi_backlight_get_backlight_device(unsigned int lcd_id)
170 {
171 struct sunxi_lcd_backlight *bl = sunxi_backlight_get_backlight(lcd_id);
172
173 if (bl)
174 return bl->bl_dev;
175 return NULL;
176 }
177
sunxi_backlight_set_bright_dimming(unsigned int lcd_id,unsigned int dimming)178 unsigned int sunxi_backlight_set_bright_dimming(unsigned int lcd_id,
179 unsigned int dimming)
180 {
181 struct sunxi_lcd_backlight *bl = NULL;
182
183 bl = sunxi_backlight_get_backlight(lcd_id);
184 if (!bl) {
185 DRM_ERROR("Null bl pointer!\n");
186 return -1;
187 }
188
189 bl->dimming = dimming > 256 ? 256 : dimming;
190 if (sunxi_backlight_set_bright(lcd_id, bl->bright) < 0) {
191 DRM_ERROR("sunxi_backling_set_bright failed\n");
192 return -1;
193 }
194
195 return 0;
196 }
197
198
sunxi_backlight_pwm_enable(unsigned int lcd_id)199 int sunxi_backlight_pwm_enable(unsigned int lcd_id)
200 {
201 #if IS_ENABLED(CONFIG_AW_PWM) || IS_ENABLED(CONFIG_PWM_SUNXI_NEW) || IS_ENABLED(CONFIG_PWM_SUNXI_GROUP)
202 int ret = 0;
203 struct sunxi_lcd_backlight *bl = sunxi_backlight_get_backlight(lcd_id);
204 struct pwm_device *pwm_dev = bl->pwm_info.pwm_dev;
205 struct pwm_state state;
206
207 if (!bl->use_pwm || !bl->pwm_info.pwm_dev) {
208 DRM_INFO("Warn: NOT use PWM\n");
209 return 0;
210 }
211
212 memset(&state, 0, sizeof(struct pwm_state));
213 pwm_get_state(pwm_dev, &state);
214 state.polarity = bl->pwm_info.polarity;
215 state.period = bl->pwm_info.period_ns;
216 state.duty_cycle = bl->pwm_info.duty_ns;
217 ret = pwm_apply_state(pwm_dev, &state);
218 if (ret) {
219 DRM_ERROR("[sunxi_bl lcd:%d] pwm_apply_state failed, ret = %d\n", lcd_id, ret);
220 return -1;
221 }
222
223 sunxi_backlight_set_bright(lcd_id, bl->bright);
224
225 ret = pwm_enable(bl->pwm_info.pwm_dev);
226 if (ret < 0) {
227 DRM_ERROR("pwm_enable failed\n");
228 return -1;
229 }
230 #endif
231
232 return 0;
233 }
234
sunxi_backlight_pwm_disable(unsigned int lcd_id)235 int sunxi_backlight_pwm_disable(unsigned int lcd_id)
236 {
237 #if IS_ENABLED(CONFIG_AW_PWM) || IS_ENABLED(CONFIG_PWM_SUNXI_NEW) || IS_ENABLED(CONFIG_PWM_SUNXI_GROUP)
238 struct sunxi_lcd_backlight *bl = sunxi_backlight_get_backlight(lcd_id);
239 struct pwm_device *pwm_dev = bl->pwm_info.pwm_dev;
240 struct pwm_state state;
241
242 if (bl->use_pwm) {
243 if (pwm_dev) {
244 pwm_disable(pwm_dev);
245
246 /*following is for reset pwm state purpose*/
247 pwm_config(pwm_dev, pwm_dev->state.duty_cycle - 1,
248 pwm_dev->state.period);
249 memset(&state, 0, sizeof(struct pwm_state));
250 pwm_get_state(pwm_dev, &state);
251 state.polarity = bl->pwm_info.polarity;
252 pwm_apply_state(pwm_dev, &state);
253 } else {
254 DRM_ERROR("%s NULL pwm_dev hdl\n", __func__);
255 return -1;
256 }
257 }
258 #endif
259
260 return 0;
261 }
262
sunxi_backlight_bl_en_enable(struct sunxi_lcd_backlight * bl)263 static int sunxi_backlight_bl_en_enable(struct sunxi_lcd_backlight *bl)
264 {
265
266 if (!bl->use_bl_en) {
267 DRM_INFO("[sunxi_bl lcd:%d] Warn: NOT use bl_en function\n", bl->lcd_id);
268 return 0;
269 }
270
271 if (!strcmp(bl->bl_en_power, "")
272 || !strcmp(bl->bl_en_power, "none")) {
273 DRM_INFO("[sunxi_bl lcd:%d]Warn: do NOT have bl_en_power\n", bl->lcd_id);
274 //return 0;
275 } else if (sunxi_drm_sys_power_enable(bl->dev, bl->bl_en_power) < 0) {
276 DRM_ERROR("%s sunxi_drm_sys_power_enable failed\n",
277 __func__);
278 return -1;
279 }
280
281 bl->bl_gpio_hdl = sunxi_drm_sys_gpio_request(&bl->bl_en_gpio);
282 if (bl->bl_gpio_hdl < 0) {
283 DRM_ERROR("%s sunxi_drm_sys_gpio_request failed\n",
284 __func__);
285 return -1;
286 }
287
288
289 return 0;
290 }
291
sunxi_backlight_bl_en_disable(struct sunxi_lcd_backlight * bl)292 static int sunxi_backlight_bl_en_disable(struct sunxi_lcd_backlight *bl)
293 {
294 if (!bl->use_bl_en) {
295 DRM_INFO("[sunxi_bl lcd:%d]Warn: NOT use bl_en function\n", bl->lcd_id);
296 return 0;
297 }
298
299 sunxi_drm_sys_gpio_release(bl->bl_gpio_hdl);
300
301 if (!strcmp(bl->bl_en_power, "")
302 || !strcmp(bl->bl_en_power, "none")) {
303 DRM_INFO("[sunxi_bl lcd:%d]Warn: do NOT have bl_en_power\n", bl->lcd_id);
304 return 0;
305 }
306
307 if (sunxi_drm_sys_power_disable(bl->dev, bl->bl_en_power) < 0) {
308 DRM_ERROR("%s sunxi_drm_sys_power_enable failed\n",
309 __func__);
310 return -1;
311 }
312
313 return 0;
314 }
315
316 /*
317 * NOTE: This function not only enable bl_en, but also include PWM
318 * enable backlight--->set bright
319 */
sunxi_backlight_enable(unsigned int lcd_id)320 int sunxi_backlight_enable(unsigned int lcd_id)
321 {
322 struct sunxi_lcd_backlight *bl = NULL;
323 int ret = -1;
324
325 bl = sunxi_backlight_get_backlight(lcd_id);
326 if (!bl) {
327 DRM_ERROR("[sunxi_bl lcd:%d] Null bl pointer!\n", lcd_id);
328 goto OUT;
329 }
330
331 /*if bl_en has been enable, increase that count*/
332 if (bl->bl_en_count) {
333 bl->bl_en_count++;
334 DRM_INFO("[sunxi_bl lcd:%d]Warn:bl_en has been enabled, count:%d\n",
335 lcd_id, bl->bl_en_count - 1);
336 return 0;
337 }
338
339 ret = sunxi_backlight_pwm_enable(lcd_id);
340 if (ret) {
341 DRM_ERROR("[sunxi_bl lcd:%d] PWM enable fail!\n", lcd_id);
342 //goto OUT;
343 }
344 ret = sunxi_backlight_bl_en_enable(bl);
345 if (ret) {
346 DRM_ERROR("[sunxi_bl lcd:%d] sunxi_backlight_bl_en_enabl failed\n",
347 lcd_id);
348 goto OUT;
349 }
350
351 bl->bl_en_count++;
352
353 OUT:
354 return ret;
355 }
356
sunxi_backlight_disable(unsigned int lcd_id)357 int sunxi_backlight_disable(unsigned int lcd_id)
358 {
359 struct sunxi_lcd_backlight *bl = NULL;
360 int ret = -1;
361
362 bl = sunxi_backlight_get_backlight(lcd_id);
363 if (!bl) {
364 DRM_ERROR("[sunxi_bl lcd:%d] Null bl pointer!\n", lcd_id);
365 goto OUT;
366 }
367
368 if (!bl->bl_en_count) {
369 DRM_INFO("[lcd:%d sunxi_bl]Warn:bl_en has NOT been enabled\n", lcd_id);
370 return 0;
371 }
372
373 bl->bl_en_count--;
374 if (bl->bl_en_count) {
375 DRM_INFO("[lcd:%d sunxi_bl]Warn:There is another panel use bl_en, "
376 " we should NOT close bl_en. count:%d\n",
377 lcd_id, bl->bl_en_count);
378 return 0;
379 }
380
381 ret = sunxi_backlight_pwm_disable(lcd_id);
382 if (ret) {
383 DRM_ERROR("[lcd:%d sunxi_bl] PWM disable fail!\n", lcd_id);
384 goto OUT;
385 }
386
387 ret = sunxi_backlight_bl_en_disable(bl);
388 if (ret) {
389 DRM_ERROR("[lcd:%d sunxi_bl] sunxi_backlight_bl_en_enabl failed\n",
390 lcd_id);
391 goto OUT;
392 }
393
394 OUT:
395 return ret;
396 }
397
398 /* get a backlight and init it
399 * return: id of backlight
400 */
sunxi_backlight_init(int lcd_id,struct backlight_config * config,unsigned int * bl_curve_tbl)401 int sunxi_backlight_init(int lcd_id, struct backlight_config *config,
402 unsigned int *bl_curve_tbl)
403 {
404 struct sunxi_lcd_backlight *bl;
405 struct pwm_info *pwm_info;
406 struct pwm_info *pwm_tmp = NULL;
407 struct pwm_config *pwm = &config->pwm;
408 unsigned long long period_ns, duty_ns;
409
410 if (!bl_curve_tbl || !config) {
411 DRM_ERROR("bl_curve_tbl or config NULL hdl\n");
412 return -1;
413 }
414
415 if (lcd_id >= BL_NUM_MAX) {
416 DRM_ERROR("can NOT get a free/idle backlight\n");
417 return -1;
418 }
419
420 sunxi_backlight_cnt++;
421 bl = kzalloc(sizeof(struct sunxi_lcd_backlight),
422 GFP_KERNEL);
423 if (!bl) {
424 DRM_INFO("[SUNXI-BL] kzalloc for lcd:%d backlinght failed\n",
425 lcd_id);
426 return -1;
427 }
428
429 sunxi_backlight[lcd_id] = bl;
430 bl->lcd_id = lcd_id;
431
432 mutex_init(&bl->backlight_lock);
433 /*acquire bl_en info*/
434 bl->use_bl_en = config->use_bl_en;
435 memcpy(&bl->bl_en_gpio, &config->bl_en_gpio,
436 sizeof(struct disp_gpio_info));
437 memcpy(bl->bl_en_power, config->bl_en_power, 32);
438
439 /*acquire pwm related info*/
440 pwm_info = &bl->pwm_info;
441
442 memcpy(bl->bright_curve_tbl, bl_curve_tbl, 256 * sizeof(unsigned int));
443
444 bl->bright = config->bright;
445 bl->use_pwm = config->use_pwm;
446
447 if (bl->use_pwm) {
448 pwm_tmp = sunxi_backlight_get_same_pwm(lcd_id, pwm->lcd_pwm_ch);
449 if (pwm_tmp) {
450 memcpy(pwm_info, pwm_tmp, sizeof(struct pwm_info));
451 DRM_INFO("[sunxi_bl lcd:%d] Get same pwm, ch:%u\n",
452 lcd_id, pwm->lcd_pwm_ch);
453 goto out;
454 }
455
456 pwm_info->channel = pwm->lcd_pwm_ch;
457 pwm_info->polarity = pwm->lcd_pwm_pol;
458 if (pwm->lcd_pwm_freq != 0) {
459 period_ns = 1000 * 1000 * 1000 / pwm->lcd_pwm_freq;
460 } else {
461 DRM_INFO("[sunxi_bl lcd:%d] lcd_pwm_freq is ZERO\n",
462 lcd_id);
463 /* default 1khz */
464 period_ns = 1000 * 1000 * 1000 / 1000;
465 }
466
467 duty_ns = (bl->bright * period_ns) / 256;
468 pwm_info->duty_ns = duty_ns;
469 pwm_info->period_ns = period_ns;
470
471 #if IS_ENABLED(CONFIG_AW_PWM) || IS_ENABLED(CONFIG_PWM_SUNXI_NEW) || IS_ENABLED(CONFIG_PWM_SUNXI_GROUP)
472 pwm_info->pwm_dev = pwm_request(pwm_info->channel, "lcd");
473 if ((!pwm_info->pwm_dev) || IS_ERR(pwm_info->pwm_dev)) {
474 DRM_ERROR("get pwm device failed\n");
475 return -1;
476 }
477 #endif
478 }
479
480 out:
481 return 0;
482 }
483
sunxi_backlight_remove(int lcd_id)484 void sunxi_backlight_remove(int lcd_id)
485 {
486 struct sunxi_lcd_backlight *bl = sunxi_backlight_get_backlight(lcd_id);
487 struct pwm_info *pwm_info = &bl->pwm_info;
488
489 #if IS_ENABLED(CONFIG_AW_PWM) || IS_ENABLED(CONFIG_PWM_SUNXI_NEW) || IS_ENABLED(CONFIG_PWM_SUNXI_GROUP)
490 if (bl->use_pwm)
491 pwm_free(pwm_info->pwm_dev);
492 #endif
493
494 kfree(bl);
495 sunxi_backlight[lcd_id] = NULL;
496 }
497
sunxi_backlight_drv_init(void)498 int sunxi_backlight_drv_init(void)
499 {
500 sunxi_backlight_cnt = 0;
501 memset(sunxi_backlight, 0,
502 sizeof(struct sunxi_lcd_backlight *) * BL_NUM_MAX);
503 return 0;
504 }
505
sunxi_backlight_drv_exit(void)506 int sunxi_backlight_drv_exit(void)
507 {
508 int i = 0;
509
510 for (i = 0; i < BL_NUM_MAX; i++) {
511 if (sunxi_backlight[i]) {
512 kfree(sunxi_backlight[i]);
513 sunxi_backlight[i] = NULL;
514 }
515 }
516
517 return 0;
518 }
519
520 /**
521 * @name :sunxi_backlight_get_bl_en_count
522 * @brief :get backlight enable count
523 * @param[IN] :lcd_id: sunxi lcd index
524 * @return :backlight enable count, -1 if fail
525 */
sunxi_backlight_get_bl_en_count(unsigned int lcd_id)526 int sunxi_backlight_get_bl_en_count(unsigned int lcd_id)
527 {
528 struct sunxi_lcd_backlight *bl = NULL;
529
530 bl = sunxi_backlight_get_backlight(lcd_id);
531 if (!bl) {
532 DRM_ERROR("Null bl pointer!\n");
533 return -1;
534 }
535
536 return (int)bl->bl_en_count;
537 }
538
539 #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
540 /* set backlight brightness to level in range [0..max], scaling wrt hw min */
sunxi_panel_set_backlight(struct sunxi_lcd_backlight * bl,u32 user_level,u32 user_max)541 static void sunxi_panel_set_backlight(struct sunxi_lcd_backlight *bl,
542 u32 user_level, u32 user_max)
543 {
544 if (!bl)
545 return;
546
547 mutex_lock(&bl->backlight_lock);
548 sunxi_backlight_set_bright(bl->lcd_id, user_level);
549 mutex_unlock(&bl->backlight_lock);
550 }
551
sunxi_backlight_device_update_status(struct backlight_device * bd)552 static int sunxi_backlight_device_update_status(struct backlight_device *bd)
553 {
554 struct sunxi_lcd_backlight *bl = bl_get_data(bd);
555 u32 enable = 0;
556
557 DRM_DEBUG_KMS("updating sunxi_backlight, brightness=%d/%d\n",
558 bd->props.brightness, bd->props.max_brightness);
559
560 enable = bl->bl_en_count;
561 if (bd->props.power != FB_BLANK_POWERDOWN) {
562 if (!enable)
563 sunxi_backlight_enable(bl->lcd_id);
564 sunxi_panel_set_backlight(bl, bd->props.brightness,
565 bd->props.max_brightness);
566 } else {
567 sunxi_panel_set_backlight(bl, 0,
568 bd->props.max_brightness);
569 if (enable)
570 sunxi_backlight_disable(bl->lcd_id);
571 }
572
573 return 0;
574 }
575
sunxi_backlight_device_get_brightness(struct backlight_device * bd)576 static int sunxi_backlight_device_get_brightness(struct backlight_device *bd)
577 {
578 struct sunxi_lcd_backlight *bl = bl_get_data(bd);
579 int ret = -1;
580
581 mutex_lock(&bl->backlight_lock);
582 ret = bl->bright;
583 mutex_unlock(&bl->backlight_lock);
584
585 return ret;
586 }
587
588 static const struct backlight_ops sunxi_backlight_device_ops = {
589 .update_status = sunxi_backlight_device_update_status,
590 .get_brightness = sunxi_backlight_device_get_brightness,
591 };
592
593 /**
594 * @name :sunxi_backlight_device_register
595 * @brief :register sysfs backlight (Linux backlight system)
596 * @param[IN] :connector:pointer of drm_connector
597 * @param[IN] :lcd_id: index of sunxi_lcd whose backlight's going to be registered
598 * @return :0 if success, -1 else
599 */
sunxi_backlight_device_register(struct device * device,unsigned int lcd_id)600 int sunxi_backlight_device_register(struct device *device,
601 unsigned int lcd_id)
602 {
603 struct backlight_properties props;
604 int ret = 0;
605 char sunxi_bl_name[40] = {0};
606 struct backlight_device *p_bl_dev = NULL;
607 struct sunxi_lcd_backlight *bl = NULL;
608
609 if (!device) {
610 ret = -1;
611 DRM_ERROR("Null device pointer!\n");
612 goto OUT;
613 }
614
615 memset(&props, 0, sizeof(props));
616 props.type = BACKLIGHT_RAW;
617
618 bl = sunxi_backlight_get_backlight(lcd_id);
619
620 if (!bl) {
621 ret = 0;
622 DRM_INFO("[WARN]LCD:%d has NOT backlight\n", lcd_id);
623 goto OUT;
624 }
625
626 if (!bl->use_pwm) {
627 DRM_DEBUG_DRIVER("lcd:%d has NO pwm, need NOT "
628 "to register a linux backlight\n", lcd_id);
629 ret = 0;
630 goto OUT;
631 }
632
633 /*
634 * Note: Everything should work even if the backlight device max
635 * presented to the userspace is arbitrarily chosen.
636 */
637 props.max_brightness = 255;
638 props.brightness = bl->bright;
639
640 props.power = FB_BLANK_UNBLANK;
641
642 snprintf(sunxi_bl_name, 40, "lcd%d_backlight", lcd_id);
643 p_bl_dev =
644 backlight_device_register(sunxi_bl_name,
645 device, bl,
646 &sunxi_backlight_device_ops, &props);
647
648 if (IS_ERR(p_bl_dev)) {
649 DRM_ERROR("Failed to register backlight: %ld\n",
650 PTR_ERR(p_bl_dev));
651 p_bl_dev = NULL;
652 return -ENODEV;
653 }
654
655 bl->dev = device;
656 bl->bl_dev = p_bl_dev;
657
658 DRM_DEBUG_KMS("lcd:%d backlight sysfs interface registered\n",
659 lcd_id);
660
661 OUT:
662 return ret;
663 }
664
665 /**
666 * @name :sunxi_backlight_device_unregister
667 * @brief :Unregister backlight device of lcd: lcd_id
668 * @param[IN] :lcd_id: index of sunxi_lcd
669 * @return :NONE
670 */
sunxi_backlight_device_unregister(unsigned int lcd_id)671 void sunxi_backlight_device_unregister(unsigned int lcd_id)
672 {
673 struct backlight_device *p_bl_dev = NULL;
674 struct sunxi_lcd_backlight *bl = sunxi_backlight_get_backlight(lcd_id);
675
676 p_bl_dev = bl->bl_dev;
677 if (p_bl_dev) {
678 backlight_device_unregister(p_bl_dev);
679 bl->bl_dev = NULL;
680 } else
681 DRM_WARN("[sunxi_bl lcd:%d] Can not find corresponding backlight device\n", lcd_id);
682 }
683 #else
sunxi_backlight_device_unregister(unsigned int lcd_id)684 void sunxi_backlight_device_unregister(unsigned int lcd_id)
685 {
686 DRM_WARN("You must select CONFIG_BACKLIGHT_CLASS_DEVICE in menuconfig\n");
687 }
688
sunxi_backlight_device_register(unsigned int lcd_id)689 int sunxi_backlight_device_register(unsigned int lcd_id)
690 {
691 DRM_WARN("You must select CONFIG_BACKLIGHT_CLASS_DEVICE in menuconfig\n");
692 return 0;
693 }
694 #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
695