• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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