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
12 #include <linux/dma-mapping.h>
13 #include <linux/clk.h>
14 #include <drm/drm_print.h>
15
16 #include "sunxi_common.h"
17 #include "sunxi_tcon.h"
18 #include "sunxi_lcd.h"
19
20 #if defined(CONFIG_AW_DRM_BACKLIGHT)
21 #include "sunxi_backlight.h"
22 #endif
23
24 #define LCD_PIN_STATE_ACTIVE "active"
25 #define LCD_PIN_STATE_SLEEP "sleep"
26
27 static struct sunxi_lcd_drv *lcd_drv;
28 static struct device *g_lcd_dev; /* fix me */
29
sunxi_lcd_get_count(void)30 unsigned char sunxi_lcd_get_count(void)
31 {
32 return lcd_drv->lcd_cnt;
33 }
34
35 struct sunxi_dispdev_name sunxi_lcd_connector_type_name[] = {
36 {LCD_IF_HV, "RGB"},
37 {LCD_IF_CPU, "CPU"},
38 {LCD_IF_LVDS, "LVDS"},
39 {LCD_IF_DSI, "DSI"},
40 {LCD_IF_EDP, "EDP"},
41 {LCD_IF_EXT_DSI, "EXT_DSI"},
42 {LCD_IF_VDPO, "VDPO"},
43 };
44
45 /*RGB*/
46 struct sunxi_dispdev_name sunxi_hv_if_name[] = {
47 {PARALLEL_RGB, "PARALLEL_RGB"},
48 {SERIAL_RGB, "SERIAL_RGB"},
49 {DUMMY_RGB, "DUMMY_RGB"},
50 {RGB_DUMMY, "RGB_DUMMY"},
51 {SERIAL_YUV, "SERIAL_YUV"},
52 };
53
54 /*CPU*/
55 struct sunxi_dispdev_name sunxi_cpu_if_name[] = {
56 {RGB666_18_1, "RGB666_18_1"},
57 {RGB565_16_1, "RGB565_16_1"},
58 {RGB666_18_3, "RGB666_18_3"},
59 {RGB565_16_2, "RGB565_16_2"},
60 {RGB666_9_1, "RGB666_9_1"},
61 {RGB666_8_3, "RGB666_8_3"},
62 {RGB565_8_2, "RGB565_8_2"},
63 };
64
65 struct sunxi_dispdev_name sunxi_lvds_if_name[] = {
66 {SINGLE_LINK, "SINGLE_LINK"},
67 {DUAL_LINK, "DUAL_LINK"},
68 };
69
70 struct sunxi_dispdev_name sunxi_dsi_if_name[] = {
71 {VIDEO_MODE, "VIDEO_MODE"},
72 {COMMAND_MODE, "COMMAND_MODE"},
73 {VIDEO_BURST_MODE, "VIDEO_BURST_MODE"},
74 };
75
76 struct __lcd_panel *sunxi_panel[] = {
77 #ifdef CONFIG_EINK_PANEL_USED
78 &default_eink,
79 #endif
80 #ifdef CONFIG_LCD_SUPPORT_DEFAULT
81 &default_panel,
82 #endif
83 #ifdef CONFIG_LCD_SUPPORT_LT070ME05000
84 <070me05000_panel,
85 #endif
86 #ifdef CONFIG_LCD_SUPPORT_WTQ05027D01
87 &wtq05027d01_panel,
88 #endif
89 #ifdef CONFIG_LCD_SUPPORT_T27P06
90 &t27p06_panel,
91 #endif
92 #ifdef CONFIG_LCD_SUPPORT_DX0960BE40A1
93 &dx0960be40a1_panel,
94 #endif
95 #ifdef CONFIG_LCD_SUPPORT_TFT720X1280
96 &tft720x1280_panel,
97 #endif
98 #ifdef CONFIG_LCD_SUPPORT_S6D7AA0X01
99 &S6D7AA0X01_panel,
100 #endif
101 #ifdef CONFIG_LCD_SUPPORT_GG1P4062UTSW
102 &gg1p4062utsw_panel,
103 #endif
104 #ifdef CONFIG_LCD_SUPPORT_LS029B3SX02
105 &ls029b3sx02_panel,
106 #endif
107 #ifdef CONFIG_LCD_SUPPORT_HE0801A068
108 &he0801a068_panel,
109 #endif
110 #ifdef CONFIG_LCD_SUPPORT_INET_DSI_PANEL
111 &inet_dsi_panel,
112 #endif
113 #ifdef CONFIG_LCD_SUPPORT_LQ101R1SX03
114 &lq101r1sx03_panel,
115 #endif
116 /* add new panel below */
117 #ifdef CONFIG_LCD_SUPPORT_WILLIAMLCD
118 &WilliamLcd_panel,
119 #endif
120
121 #ifdef CONFIG_LCD_SUPPORT_KD101N51
122 &kd101n51_panel,
123 #endif
124
125 #ifdef CONFIG_LCD_SUPPORT_BP101WX1
126 &bp101wx1_panel,
127 #endif
128 };
129
sunxi_lcd_get_connector_type_name(int type)130 static char *sunxi_lcd_get_connector_type_name(int type)
131 {
132 int i, cnt;
133
134 cnt = sizeof(sunxi_lcd_connector_type_name)
135 / sizeof(struct sunxi_dispdev_name);
136
137 for (i = 0; i < cnt; i++)
138 if (sunxi_lcd_connector_type_name[i].device == type)
139 return sunxi_lcd_connector_type_name[i].name;
140
141 return NULL;
142 }
143
144 /*RGB*/
sunxi_lcd_get_hv_if_name(int type)145 static char *sunxi_lcd_get_hv_if_name(int type)
146 {
147 int i, cnt;
148
149 cnt = sizeof(sunxi_hv_if_name)
150 / sizeof(struct sunxi_dispdev_name);
151
152 for (i = 0; i < cnt; i++)
153 if (sunxi_hv_if_name[i].device == type)
154 return sunxi_hv_if_name[i].name;
155
156 return NULL;
157 }
158
sunxi_lcd_get_cpu_if_name(int type)159 static char *sunxi_lcd_get_cpu_if_name(int type)
160 {
161 int i, cnt;
162
163 cnt = sizeof(sunxi_cpu_if_name)
164 / sizeof(struct sunxi_dispdev_name);
165
166 for (i = 0; i < cnt; i++)
167 if (sunxi_cpu_if_name[i].device == type)
168 return sunxi_cpu_if_name[i].name;
169
170 return NULL;
171 }
172
sunxi_lcd_get_lvds_if_name(int type)173 static char *sunxi_lcd_get_lvds_if_name(int type)
174 {
175 int i, cnt;
176
177 cnt = sizeof(sunxi_lvds_if_name)
178 / sizeof(struct sunxi_dispdev_name);
179
180 for (i = 0; i < cnt; i++)
181 if (sunxi_lvds_if_name[i].device == type)
182 return sunxi_lvds_if_name[i].name;
183
184 return NULL;
185 }
186
sunxi_lcd_get_dsi_if_name(int type)187 static char *sunxi_lcd_get_dsi_if_name(int type)
188 {
189 int i, cnt;
190
191 cnt = sizeof(sunxi_dsi_if_name)
192 / sizeof(struct sunxi_dispdev_name);
193
194 for (i = 0; i < cnt; i++)
195 if (sunxi_dsi_if_name[i].device == type)
196 return sunxi_dsi_if_name[i].name;
197
198 return NULL;
199 }
200
sunxi_lcd_get_panel(char * name)201 static struct __lcd_panel *sunxi_lcd_get_panel(char *name)
202 {
203 int i;
204
205 for (i = 0; i < ARRAY_SIZE(sunxi_panel); i++)
206 if (sunxi_panel[i] && (!strcmp(name, sunxi_panel[i]->name)))
207 return sunxi_panel[i];
208
209 return NULL;
210 }
211
212 /**
213 * @name :sunxi_dsi_io_cfg
214 * @brief :open dsi io
215 * @param[IN] :type_id:dsi index
216 * @param[OUT] :enable:1->en, 0->disable
217 * @return :always 0
218 */
sunxi_dsi_io_cfg(int lcd_id,unsigned int enable)219 static int sunxi_dsi_io_cfg(int lcd_id, unsigned int enable)
220 {
221 int type_id = -1;
222 struct disp_panel_para *panel = NULL;
223
224 type_id = sunxi_lcd_get_type_id(lcd_id);
225 panel = sunxi_lcd_get_panel_para(lcd_id);
226
227 if (!panel || type_id < 0) {
228 DRM_ERROR("NULL pointer!\n");
229 return -1;
230 }
231
232 if (enable == 1) {
233 #if defined(SUPPORT_DSI)
234 dsi_io_open(type_id, panel);
235 if (panel->lcd_tcon_mode == DISP_TCON_DUAL_DSI &&
236 type_id + 1 < DEVICE_DSI_NUM)
237 dsi_io_open(type_id + 1, panel);
238 #endif
239 } else {
240 #if defined(SUPPORT_DSI)
241 dsi_io_close(type_id);
242 if (panel->lcd_tcon_mode == DISP_TCON_DUAL_DSI &&
243 type_id + 1 < DEVICE_DSI_NUM)
244 dsi_io_close(type_id + 1);
245 #endif
246 }
247 return 0;
248 }
249
250 /**
251 * @name :sunxi_lcd_get_lcd
252 * @brief :get lcd structure of specified lcd id
253 * @param[IN] :lcd_id: id of lcd
254 * @return :a pointer of sunxi_lcd or NULL if fail to get one
255 */
sunxi_lcd_get_lcd(unsigned int lcd_id)256 struct sunxi_lcd *sunxi_lcd_get_lcd(unsigned int lcd_id)
257 {
258 struct sunxi_lcd *lcd = NULL;
259
260 if (lcd_id < LCD_NUM_MAX)
261 lcd = &lcd_drv->hwlcd[lcd_id];
262
263 return lcd;
264 }
265
sunxi_lcd_get_hw_funcs(int lcd_id)266 struct sunxi_lcd_funcs *sunxi_lcd_get_hw_funcs(int lcd_id)
267 {
268 struct sunxi_lcd *lcd;
269
270 lcd = sunxi_lcd_get_lcd(lcd_id);
271
272 return lcd->funcs;
273 }
274
275
276 /***********###############pinctrl and pin power################*********/
277 /* pin power
278 * pin set state: Active or Sleep
279 * explain: pin_cfg belongs to pinctrl that configured int DTS.
280 * pin_power: means that power conresponse to the pinctrl configured int DTS.
281 */
sunxi_lcd_pin_cfg(unsigned int lcd_id,unsigned char enable)282 int sunxi_lcd_pin_cfg(unsigned int lcd_id, unsigned char enable)
283 {
284 int i, ret = 0;
285 struct disp_lcd_cfg *cfg;
286 struct sunxi_lcd *lcd;
287 char dev_name[25];
288
289 lcd = sunxi_lcd_get_lcd(lcd_id);
290 if (!lcd) {
291 DRM_ERROR("Null lcd pointer!\n");
292 return -1;
293 }
294 cfg = &lcd->lcd_cfg;
295
296 /*set pin power enable*/
297 if (enable) {
298 for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
299 if (cfg->lcd_power_used[i]) {
300 ret = sunxi_drm_sys_power_enable(g_lcd_dev,
301 cfg->lcd_pin_power[i]);
302 if (ret) {
303 DRM_ERROR("sunxi_lcd_pin_cfg"
304 " sunxi_drm_sys_power_enable failed");
305 }
306 }
307 }
308 }
309
310 sprintf(dev_name, "lcd%d", lcd_id);
311 ret = sunxi_drm_sys_pin_set_state(dev_name, enable ?
312 LCD_PIN_STATE_ACTIVE : LCD_PIN_STATE_SLEEP);
313 if (ret) {
314 DRM_ERROR("sunxi_drm_sys_pin_set_state failed\n");
315 return ret;
316 }
317
318 if (lcd->type == LCD_IF_DSI)
319 sunxi_dsi_io_cfg(lcd_id, enable);
320
321
322 /*set pin power disable*/
323 if (!enable) {
324 for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
325 if (cfg->lcd_power_used[i]) {
326 ret = sunxi_drm_sys_power_disable(g_lcd_dev,
327 cfg->lcd_pin_power[i]);
328 if (ret) {
329 DRM_ERROR("sunxi_lcd_pin_cfg"
330 " sunxi_drm_sys_power_disable failed");
331 return -1;
332 }
333 }
334 }
335 }
336
337 return 0;
338 }
339
340
341 /***********#########################lcd power#####################***********/
sunxi_lcd_all_power_enable(unsigned int lcd_id)342 int sunxi_lcd_all_power_enable(unsigned int lcd_id)
343 {
344 int i, ret;
345 struct sunxi_lcd *lcd;
346 char *power;
347
348 lcd = sunxi_lcd_get_lcd(lcd_id);
349 if (!lcd) {
350 DRM_ERROR("Null lcd pointer!\n");
351 return -1;
352 }
353
354 power = lcd->lcd_cfg.lcd_bl_en_power;
355 if (strcmp(power, "")) {
356 ret = sunxi_drm_sys_power_enable(g_lcd_dev, power);
357 if (ret) {
358 DRM_ERROR("disp_lcd_power_enable:%s failed\n", power);
359 return ret;
360 }
361 }
362
363 for (i = 0; i < LCD_POWER_NUM; i++) {
364 if (!lcd->lcd_cfg.lcd_power_used[i])
365 continue;
366 power = lcd->lcd_cfg.lcd_power[i];
367 ret = sunxi_drm_sys_power_enable(g_lcd_dev, power);
368 if (ret) {
369 DRM_ERROR("disp_lcd_power_enable:%s failed\n", power);
370 return ret;
371 }
372 }
373
374 for (i = 0; i < LCD_POWER_NUM; i++) {
375 if (!lcd->lcd_cfg.lcd_fix_power_used[i])
376 continue;
377 power = lcd->lcd_cfg.lcd_fix_power[i];
378 ret = sunxi_drm_sys_power_enable(g_lcd_dev, power);
379 if (ret) {
380 DRM_ERROR("disp_lcd_power_enable:%s failed\n", power);
381 return ret;
382 }
383 }
384
385 for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
386 if (!lcd->lcd_cfg.lcd_power_used[i])
387 continue;
388 power = lcd->lcd_cfg.lcd_gpio_power[i];
389 ret = sunxi_drm_sys_power_enable(g_lcd_dev, power);
390 if (ret) {
391 DRM_ERROR("disp_lcd_power_enable:%s failed\n", power);
392 return ret;
393 }
394 }
395
396 for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
397 if (!lcd->lcd_cfg.lcd_power_used[i])
398 continue;
399 power = lcd->lcd_cfg.lcd_pin_power[i];
400 ret = sunxi_drm_sys_power_enable(g_lcd_dev, power);
401 if (ret) {
402 DRM_ERROR("disp_lcd_power_enable:%s failed\n", power);
403 return ret;
404 }
405 }
406
407 return 0;
408 }
409
410 /*
411 * The power effect on the whole lcd
412 */
sunxi_lcd_power_enable(unsigned int lcd_id,u32 power_id)413 int sunxi_lcd_power_enable(unsigned int lcd_id, u32 power_id)
414 {
415 int ret = 0;
416 struct sunxi_lcd *lcd;
417
418 lcd = sunxi_lcd_get_lcd(lcd_id);
419 if (!lcd) {
420 DRM_ERROR("Null lcd pointer!\n");
421 return -1;
422 }
423
424 if (lcd->lcd_cfg.lcd_power_used[power_id]) {
425 /* regulator type */
426 ret = sunxi_drm_sys_power_enable(g_lcd_dev, lcd->lcd_cfg.lcd_power[power_id]);
427 if (ret) {
428 DRM_ERROR("disp_lcd_power_enable"
429 " sunxi_drm_sys_power_disable failed");
430 return -1;
431 }
432 }
433
434 return 0;
435 }
436
sunxi_lcd_power_disable(unsigned int lcd_id,u32 power_id)437 int sunxi_lcd_power_disable(unsigned int lcd_id, u32 power_id)
438 {
439 int ret = 0;
440 struct sunxi_lcd *lcd;
441
442 lcd = sunxi_lcd_get_lcd(lcd_id);
443 if (!lcd) {
444 DRM_ERROR("Null lcd pointer!\n");
445 return -1;
446 }
447 if (lcd->lcd_cfg.lcd_power_used[power_id]) {
448 /* regulator type */
449 ret = sunxi_drm_sys_power_disable(g_lcd_dev, lcd->lcd_cfg.lcd_power[power_id]);
450 if (ret) {
451 DRM_ERROR("disp_lcd_power_enable"
452 " sunxi_drm_sys_power_disable failed");
453 return -1;
454 }
455 }
456
457
458 return 0;
459 }
460
461 /***********#########################lcd power#####################***********/
462
sunxi_lcd_fix_power_enable(struct sunxi_lcd * lcd)463 int sunxi_lcd_fix_power_enable(struct sunxi_lcd *lcd)
464 {
465 int ret = 0, i;
466
467 for (i = 0; i < LCD_POWER_NUM; i++) {
468 if (lcd->lcd_cfg.lcd_fix_power_used[i]) {
469 /* regulator type */
470 ret = sunxi_drm_sys_power_enable(g_lcd_dev, lcd->lcd_cfg.lcd_fix_power[i]);
471 if (ret) {
472 DRM_ERROR("disp_lcd_power_enable"
473 " sunxi_drm_sys_power_disable failed");
474 return -1;
475 }
476 }
477 }
478
479 return 0;
480 }
481
sunxi_lcd_fix_power_disable(struct sunxi_lcd * lcd)482 int sunxi_lcd_fix_power_disable(struct sunxi_lcd *lcd)
483 {
484 int ret = 0, i;
485
486 for (i = 0; i < LCD_POWER_NUM; i++) {
487 if (lcd->lcd_cfg.lcd_fix_power_used[i]) {
488 /* regulator type */
489 ret = sunxi_drm_sys_power_disable(g_lcd_dev, lcd->lcd_cfg.lcd_fix_power[i]);
490 if (ret) {
491 DRM_ERROR("disp_lcd_power_enable"
492 " sunxi_drm_sys_power_disable failed");
493 return -1;
494 }
495 }
496 }
497
498
499 return 0;
500 }
501
502
503 /***********##############lcd_gpio and lcd_gpio_power################*********/
504 /*
505 *lcd_gpio: the general gpio that used in whole lcd
506 *lcd_gpio_power: the coresponsible power of lcd_gpio
507 */
sunxi_lcd_gpio_power_enable(struct sunxi_lcd * lcd,u32 power_id)508 static int sunxi_lcd_gpio_power_enable(struct sunxi_lcd *lcd, u32 power_id)
509 {
510 int ret = 0;
511
512 if (lcd->lcd_cfg.lcd_power_used[power_id]) {
513 /* regulator type */
514 ret = sunxi_drm_sys_power_enable(g_lcd_dev, lcd->lcd_cfg.lcd_gpio_power[power_id]);
515 if (ret) {
516 DRM_ERROR("disp_lcd_power_enable"
517 " sunxi_drm_sys_power_disable failed");
518 return -1;
519 }
520 }
521
522 return 0;
523 }
524
sunxi_lcd_gpio_power_disable(struct sunxi_lcd * lcd,u32 power_id)525 static int sunxi_lcd_gpio_power_disable(struct sunxi_lcd *lcd, u32 power_id)
526 {
527 int ret = 0;
528
529 if (lcd->lcd_cfg.lcd_power_used[power_id]) {
530 /* regulator type */
531 ret = sunxi_drm_sys_power_disable(g_lcd_dev, lcd->lcd_cfg.lcd_gpio_power[power_id]);
532 if (ret) {
533 DRM_ERROR("disp_lcd_power_enable"
534 " sunxi_drm_sys_power_disable failed");
535 return -1;
536 }
537 }
538
539
540 return 0;
541 }
542
543 /* enable lcd_gpio power and set it as sys_config set
544 * lcd_gpio: the gpio effect on whole lcd, has no speciffic function, like bl_en
545 * gpio
546 */
sunxi_lcd_gpio_init(struct sunxi_lcd * lcd)547 int sunxi_lcd_gpio_init(struct sunxi_lcd *lcd)
548 {
549 int i;
550 struct disp_lcd_cfg *lcd_cfg = &lcd->lcd_cfg;
551
552 for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
553 if (sunxi_lcd_gpio_power_enable(lcd, i) < 0) {
554 DRM_ERROR("sunxi_lcd_power_enable failed\n");
555 }
556 }
557
558 for (i = 0; i < LCD_GPIO_NUM; i++) {
559 lcd_cfg->gpio_hdl[i] = 0;
560 if (lcd_cfg->lcd_gpio_used[i]) {
561 lcd_cfg->gpio_hdl[i]
562 = sunxi_drm_sys_gpio_request((struct disp_gpio_info *)&lcd_cfg->lcd_gpio[i]);
563 if (lcd_cfg->gpio_hdl[i] < 0) {
564 DRM_ERROR("%s"
565 " sunxi_drm_sys_gpio_request failed", __func__);
566 }
567 }
568 }
569
570 return 0;
571 }
572
sunxi_lcd_gpio_exit(struct sunxi_lcd * lcd)573 int sunxi_lcd_gpio_exit(struct sunxi_lcd *lcd)
574 {
575 int i;
576 struct disp_gpio_info gpio_info;
577 struct disp_lcd_cfg *lcd_cfg = &lcd->lcd_cfg;
578
579 for (i = 0; i < LCD_GPIO_NUM; i++) {
580 if (lcd_cfg->gpio_hdl[i]) {
581 sunxi_drm_sys_gpio_release(lcd_cfg->gpio_hdl[i]);
582
583 memcpy(&gpio_info, &(lcd_cfg->lcd_gpio[i]),
584 sizeof(struct disp_gpio_info));
585
586 lcd_cfg->gpio_hdl[i] = sunxi_drm_sys_gpio_request(&gpio_info);
587 if (lcd_cfg->gpio_hdl[i] < 0) {
588 DRM_ERROR("sunxi_drm_sys_gpio_request failed\n");
589 }
590 sunxi_drm_sys_gpio_release(lcd_cfg->gpio_hdl[i]);
591 lcd_cfg->gpio_hdl[i] = 0;
592 }
593 }
594
595 /* io-pad */
596 for (i = LCD_GPIO_REGU_NUM - 1; i >= 0; i--) {
597 if (sunxi_lcd_gpio_power_disable(lcd, i) < 0) {
598 DRM_ERROR("sunxi_lcd_power_disable failed\n");
599 }
600 }
601
602 return 0;
603 }
604
605 /* direction: input(0), output(1) */
sunxi_lcd_gpio_set_direction(struct sunxi_lcd * lcd,unsigned int io_index,unsigned int direction)606 int sunxi_lcd_gpio_set_direction(struct sunxi_lcd *lcd, unsigned int io_index,
607 unsigned int direction)
608 {
609 char gpio_name[20];
610
611 sprintf(gpio_name, "lcd_gpio_%d", io_index);
612 return sunxi_drm_sys_gpio_set_direction(lcd->lcd_cfg.gpio_hdl[io_index],
613 direction, gpio_name);
614 }
615
sunxi_lcd_gpio_set_value(unsigned int lcd_id,unsigned int io_index,unsigned int data)616 int sunxi_lcd_gpio_set_value(unsigned int lcd_id, unsigned int io_index,
617 unsigned int data)
618 {
619 char gpio_name[20];
620 struct sunxi_lcd *lcd;
621
622 lcd = sunxi_lcd_get_lcd(lcd_id);
623 if (!lcd) {
624 DRM_ERROR("Null lcd pointer!\n");
625 return -1;
626 }
627
628 if (io_index >= LCD_GPIO_NUM) {
629 DRM_ERROR("gpio num out of range\n");
630 return -1;
631 }
632
633 sprintf(gpio_name, "lcd_gpio_%d", io_index);
634
635 return sunxi_drm_sys_gpio_set_value(lcd->lcd_cfg.lcd_gpio[io_index].gpio/*lcd->lcd_cfg.gpio_hdl[io_index]*/,
636 data, gpio_name);
637 }
638
sunxi_lcd_get_tcon_id(unsigned int lcd_id)639 unsigned int sunxi_lcd_get_tcon_id(unsigned int lcd_id)
640 {
641 int tcon_id = sunxi_tcon_lcd_get_tcon_id(lcd_id);
642
643 if (tcon_id < 0) {
644 DRM_ERROR("\n");
645 return -1;
646 }
647
648 return tcon_id;
649 }
650
sunxi_lcd_get_type_id(unsigned int lcd_id)651 unsigned int sunxi_lcd_get_type_id(unsigned int lcd_id)
652 {
653 struct sunxi_lcd *lcd;
654
655 lcd = sunxi_lcd_get_lcd(lcd_id);
656 if (!lcd) {
657 DRM_ERROR("Null lcd pointer!\n");
658 return 0;
659 }
660
661 return lcd->type_id;
662 }
663
sunxi_lcd_get_type(unsigned int lcd_id)664 unsigned int sunxi_lcd_get_type(unsigned int lcd_id)
665 {
666 struct sunxi_lcd *lcd;
667
668 lcd = sunxi_lcd_get_lcd(lcd_id);
669 if (!lcd) {
670 DRM_ERROR("Null lcd pointer!\n");
671 return 0;
672 }
673
674 return lcd->type;
675 }
676
sunxi_lcd_get_panel_para(unsigned int lcd_id)677 struct disp_panel_para *sunxi_lcd_get_panel_para(unsigned int lcd_id)
678 {
679 struct sunxi_lcd *lcd;
680
681 lcd = sunxi_lcd_get_lcd(lcd_id);
682 if (!lcd) {
683 DRM_ERROR("Null lcd pointer!\n");
684 return 0;
685 }
686
687 return &lcd->panel_para;
688 }
689
sunxi_lcd_get_panel_ext_para(unsigned int lcd_id)690 struct panel_extend_para *sunxi_lcd_get_panel_ext_para(unsigned int lcd_id)
691 {
692 struct sunxi_lcd *lcd;
693
694 lcd = sunxi_lcd_get_lcd(lcd_id);
695 if (!lcd) {
696 DRM_ERROR("Null lcd pointer!\n");
697 return NULL;
698 }
699
700 return &lcd->extend_para;
701 }
702
sunxi_lcd_get_panel_func(unsigned int lcd_id)703 struct disp_lcd_panel_fun *sunxi_lcd_get_panel_func(unsigned int lcd_id)
704 {
705 struct sunxi_lcd *lcd;
706
707 lcd = sunxi_lcd_get_lcd(lcd_id);
708 if (!lcd) {
709 DRM_ERROR("Null lcd pointer!\n");
710 return NULL;
711 }
712 if (!lcd->panel) {
713 DRM_ERROR("lcd%d has NO panel\n", lcd_id);
714 return NULL;
715 }
716
717 return &lcd->panel->func;
718 }
719
720 /*
721 *@return: MHz
722 */
sunxi_lcd_get_dclk(unsigned int lcd_id)723 unsigned int sunxi_lcd_get_dclk(unsigned int lcd_id)
724 {
725 struct disp_panel_para *para = sunxi_lcd_get_panel_para(lcd_id);
726
727 return para->lcd_dclk_freq;
728 }
729
sunxi_lcd_get_lcd_if(unsigned int lcd_id)730 unsigned int sunxi_lcd_get_lcd_if(unsigned int lcd_id)
731 {
732 struct disp_panel_para *para = sunxi_lcd_get_panel_para(lcd_id);
733
734 return para->lcd_if;
735 }
736
sunxi_lcd_get_usec_per_line(unsigned int lcd_id)737 unsigned int sunxi_lcd_get_usec_per_line(unsigned int lcd_id)
738 {
739 unsigned int usec_per_line;
740 struct disp_panel_para *para = sunxi_lcd_get_panel_para(lcd_id);
741
742 usec_per_line = para->lcd_ht / para->lcd_dclk_freq;
743
744 return usec_per_line;
745 }
746
747 /**
748 * @name :sunxi_lcd_clk_config
749 * @brief :set lcd clk rate
750 * @param[IN] :lcd_id:lcd index
751 * @return :0 if success, -1 else
752 * @TODO :set dual dsi clk
753 */
sunxi_lcd_clk_config(unsigned int lcd_id)754 static int sunxi_lcd_clk_config(unsigned int lcd_id)
755 {
756 int ret = -1;
757 struct lcd_clk_info clk_info;
758 struct disp_panel_para *p_panel = NULL;
759 unsigned long dclk_rate = 33000000;
760 unsigned long pll_rate = 297000000, lcd_rate = 33000000;
761 unsigned long dsi_rate = 0;
762 unsigned long dsi_rate_set = 0, pll_rate_set = 0;
763 struct sunxi_lcd *lcd = NULL;
764 struct clk *parent_clk = NULL;
765
766 p_panel = sunxi_lcd_get_panel_para(lcd_id);
767
768 lcd = sunxi_lcd_get_lcd(lcd_id);
769
770 if (!lcd || !p_panel) {
771 DRM_ERROR("Null lcd or panel pointer!\n");
772 return -1;
773 }
774
775 /* no need to set clk rate */
776 if (p_panel->lcd_if != LCD_IF_DSI)
777 return 0;
778
779
780 memset(&clk_info, 0, sizeof(struct lcd_clk_info));
781 ret = sunxi_tcon_get_clk_info(lcd_id, &clk_info);
782 if (ret) {
783 DRM_WARN("Get clk_info fail!\n");
784 return ret;
785 }
786 dclk_rate = ((unsigned long long)sunxi_lcd_get_dclk(lcd_id)) * 1000000;
787
788 lcd_rate = dclk_rate * clk_info.dsi_div;
789 pll_rate = lcd_rate * clk_info.lcd_div;
790 dsi_rate = pll_rate / clk_info.dsi_div;
791 pll_rate_set = pll_rate;
792 parent_clk = clk_get_parent(lcd->mclk);
793 if (parent_clk)
794 pll_rate_set = clk_get_rate(parent_clk);
795
796 if (p_panel->lcd_if == LCD_IF_DSI) {
797 if (p_panel->lcd_dsi_if == LCD_DSI_IF_COMMAND_MODE)
798 dsi_rate_set = pll_rate_set;
799 else
800 dsi_rate_set = pll_rate_set / clk_info.dsi_div;
801
802 dsi_rate_set =
803 (clk_info.dsi_rate == 0) ? dsi_rate_set : clk_info.dsi_rate;
804 clk_set_rate(lcd->mclk, dsi_rate_set);
805 dsi_rate_set = clk_get_rate(lcd->mclk);
806 if (dsi_rate_set != dsi_rate)
807 DRM_WARN("Dsi rate to be set:%lu, real clk rate:%lu\n", dsi_rate,
808 dsi_rate_set);
809 }
810
811 return ret;
812 }
813
sunxi_lcd_is_use_irq(unsigned int lcd_id)814 bool sunxi_lcd_is_use_irq(unsigned int lcd_id)
815 {
816 struct sunxi_lcd *lcd;
817
818 lcd = sunxi_lcd_get_lcd(lcd_id);
819 if (!lcd) {
820 DRM_ERROR("Null lcd pointer!\n");
821 return false;
822 }
823
824 return lcd->irq_used;
825 }
826
sunxi_lcd_get_irq_no(unsigned int lcd_id)827 unsigned int sunxi_lcd_get_irq_no(unsigned int lcd_id)
828 {
829 struct sunxi_lcd *lcd;
830
831 lcd = sunxi_lcd_get_lcd(lcd_id);
832 if (!lcd) {
833 DRM_ERROR("Null lcd pointer!\n");
834 return 0;
835 }
836
837 return lcd->irq_no;
838 }
839
sunxi_lcd_prepare(unsigned int lcd_id)840 static int sunxi_lcd_prepare(unsigned int lcd_id)
841 {
842 int ret = 0;
843 struct sunxi_lcd *lcd;
844
845 lcd = sunxi_lcd_get_lcd(lcd_id);
846 if (!lcd) {
847 DRM_ERROR("Null lcd pointer!\n");
848 return -1;
849 }
850
851 if (lcd_drv->res.rst_bus_lvds) {
852 ret = reset_control_deassert(lcd_drv->res.rst_bus_lvds);
853 if (ret) {
854 DRM_ERROR("reset_control_deassert for rst_bus_lvds failed!\n");
855 return -1;
856 }
857 }
858
859 sunxi_lcd_clk_config(lcd_id);
860 if (lcd->mclk) {
861 ret = clk_prepare_enable(lcd->mclk);
862 if (ret) {
863 DRM_ERROR("clk_prepare_enable failed\n");
864 return -1;
865 }
866 }
867
868 if (lcd->mclk_bus) {
869 ret = clk_prepare_enable(lcd->mclk_bus);
870 if (ret) {
871 DRM_ERROR("clk_prepare_enable failed\n");
872 return -1;
873 }
874 }
875
876 ret = sunxi_lcd_fix_power_enable(lcd);
877 if (ret) {
878 DRM_ERROR("sunxi_lcd_fix_power_enable failed\n");
879 return -1;
880 }
881
882 ret = sunxi_lcd_gpio_init(lcd);
883 if (ret) {
884 DRM_ERROR("sunxi_lcd_gpio_init failed\n");
885 return -1;
886 }
887
888 return 0;
889 }
890
sunxi_lcd_sw_prepare(unsigned int lcd_id)891 static int sunxi_lcd_sw_prepare(unsigned int lcd_id)
892 {
893 int ret = 0;
894 struct sunxi_lcd *lcd;
895
896 lcd = sunxi_lcd_get_lcd(lcd_id);
897 if (!lcd) {
898 DRM_ERROR("Null lcd pointer!\n");
899 return -1;
900 }
901
902 if (lcd->mclk) {
903 ret = clk_prepare_enable(lcd->mclk);
904 if (ret) {
905 DRM_ERROR("clk_prepare_enable failed\n");
906 return -1;
907 }
908 }
909
910 ret = sunxi_lcd_fix_power_enable(lcd);
911 if (ret) {
912 DRM_ERROR("sunxi_lcd_fix_power_enable failed\n");
913 return -1;
914 }
915
916 ret = sunxi_lcd_gpio_init(lcd);
917 if (ret) {
918 DRM_ERROR("sunxi_lcd_gpio_init failed\n");
919 return -1;
920 }
921
922 return 0;
923 }
924
925
sunxi_lcd_unprepare(unsigned int lcd_id)926 static void sunxi_lcd_unprepare(unsigned int lcd_id)
927 {
928 int ret = 0;
929 struct sunxi_lcd *lcd;
930
931 lcd = sunxi_lcd_get_lcd(lcd_id);
932 if (!lcd) {
933 DRM_ERROR("Null lcd pointer!\n");
934 return;
935 }
936
937 ret = sunxi_lcd_gpio_exit(lcd);
938 if (ret) {
939 DRM_ERROR("sunxi_lcd_gpio_exit failed\n");
940 return;
941 }
942
943 ret = sunxi_lcd_fix_power_disable(lcd);
944 if (ret) {
945 DRM_ERROR("sunxi_lcd_fix_power_disable failed\n");
946 return;
947 }
948
949 if (lcd->mclk)
950 clk_disable_unprepare(lcd->mclk);
951
952 }
953
sunxi_lcd_sw_enable(unsigned int lcd_id)954 int sunxi_lcd_sw_enable(unsigned int lcd_id)
955 {
956 struct disp_lcd_panel_fun *panel_func = NULL;
957
958 panel_func = sunxi_lcd_get_panel_func(lcd_id);
959
960 sunxi_lcd_sw_prepare(lcd_id);
961
962 if (!panel_func->cfg_open_flow) {
963 DRM_ERROR("cfg_sw_open_flow hdl is NULL\n");
964 return -1;
965 }
966 panel_func->cfg_open_flow(lcd_id);
967
968 return 0;
969 }
970
sunxi_lcd_dsi_enable(unsigned int lcd_id)971 static int sunxi_lcd_dsi_enable(unsigned int lcd_id)
972 {
973 int ret;
974 struct disp_panel_para *panel_para;
975 struct disp_lcd_panel_fun *panel_func = NULL;
976 struct sunxi_lcd *lcd = sunxi_lcd_get_lcd(lcd_id);
977
978 ret = sunxi_lcd_prepare(lcd_id);
979 if (ret < 0) {
980 DRM_ERROR("sunxi_lcd:%d prepare fialed\n", lcd_id);
981 return -1;
982 }
983
984 panel_para = sunxi_lcd_get_panel_para(lcd_id);
985 panel_func = sunxi_lcd_get_panel_func(lcd_id);
986 if (!panel_para) {
987 DRM_ERROR("lcd_id:%d panel_para is NULL\n", lcd_id);
988 return -1;
989 }
990 #if defined(SUPPORT_DSI)
991 if (dsi_cfg(lcd->type_id, panel_para) != 0) {
992 DRM_ERROR("dsi_cfg failed\n");
993 return -1;
994 }
995 #endif
996 if (!panel_func) {
997 DRM_ERROR("GET panal_func Failed!\n");
998 return -1;
999 }
1000
1001 if (!panel_func->cfg_open_flow) {
1002 DRM_ERROR("cfg_open_flow hdl is NULL\n");
1003 return -1;
1004 }
1005 panel_func->cfg_open_flow(lcd_id);
1006
1007 return 0;
1008 }
1009
sunxi_lcd_dsi_disable(unsigned int lcd_id)1010 static void sunxi_lcd_dsi_disable(unsigned int lcd_id)
1011 {
1012 struct disp_lcd_panel_fun *panel_func = NULL;
1013
1014 panel_func = sunxi_lcd_get_panel_func(lcd_id);
1015 if (!panel_func) {
1016 DRM_ERROR("GET panal_func Failed!\n");
1017 return;
1018 }
1019
1020 if (!panel_func->cfg_close_flow) {
1021 DRM_ERROR("cfg_open_close hdl is NULL\n");
1022 return;
1023 }
1024 panel_func->cfg_close_flow(lcd_id);
1025 #if defined(SUPPORT_DSI)
1026 if (dsi_exit(lcd_id) != 0) {
1027 DRM_ERROR("dsi_exit failed\n");
1028 return;
1029 }
1030 #endif
1031 sunxi_lcd_unprepare(lcd_id);
1032
1033 }
1034
sunxi_lcd_hv_enable(unsigned int lcd_id)1035 static int sunxi_lcd_hv_enable(unsigned int lcd_id)
1036 {
1037 int ret;
1038 struct disp_lcd_panel_fun *panel_func = NULL;
1039
1040 /*set lcd output*/
1041 ret = sunxi_lcd_prepare(lcd_id);
1042 if (ret < 0) {
1043 DRM_ERROR("sunxi_lcd:%d prepare fialed\n", lcd_id);
1044 return -1;
1045 }
1046
1047 panel_func = sunxi_lcd_get_panel_func(lcd_id);
1048 if (!panel_func) {
1049 DRM_ERROR("GET panal_func Failed!\n");
1050 return -1;
1051 }
1052
1053 if (!panel_func->cfg_open_flow) {
1054 DRM_ERROR("cfg_open_flow hdl is NULL\n");
1055 return -1;
1056 }
1057
1058 panel_func->cfg_open_flow(lcd_id);
1059
1060 return 0;
1061
1062 }
1063
sunxi_lcd_hv_disable(unsigned int lcd_id)1064 static void sunxi_lcd_hv_disable(unsigned int lcd_id)
1065 {
1066 struct disp_lcd_panel_fun *panel_func = NULL;
1067
1068 panel_func = sunxi_lcd_get_panel_func(lcd_id);
1069 if (!panel_func) {
1070 DRM_ERROR("GET panal_func Failed!\n");
1071 return;
1072 }
1073
1074 if (!panel_func->cfg_close_flow) {
1075 DRM_ERROR("cfg_open_close hdl is NULL\n");
1076 return;
1077 }
1078 panel_func->cfg_close_flow(lcd_id);
1079
1080 sunxi_lcd_unprepare(lcd_id);
1081 }
1082
sunxi_lcd_lvds_enable(unsigned int lcd_id)1083 static int sunxi_lcd_lvds_enable(unsigned int lcd_id)
1084 {
1085 int ret;
1086 struct disp_lcd_panel_fun *panel_func = NULL;
1087
1088 /*set lcd output*/
1089 ret = sunxi_lcd_prepare(lcd_id);
1090 if (ret < 0) {
1091 DRM_ERROR("sunxi_lcd:%d prepare fialed\n", lcd_id);
1092 return -1;
1093 }
1094
1095 panel_func = sunxi_lcd_get_panel_func(lcd_id);
1096 if (!panel_func) {
1097 DRM_ERROR("GET panal_func Failed!\n");
1098 return -1;
1099 }
1100
1101 if (!panel_func->cfg_open_flow) {
1102 DRM_ERROR("cfg_open_flow hdl is NULL\n");
1103 return -1;
1104 }
1105
1106 panel_func->cfg_open_flow(lcd_id);
1107
1108 return 0;
1109
1110 }
1111
sunxi_lcd_lvds_disable(unsigned int lcd_id)1112 static void sunxi_lcd_lvds_disable(unsigned int lcd_id)
1113 {
1114 struct disp_lcd_panel_fun *panel_func = NULL;
1115
1116 panel_func = sunxi_lcd_get_panel_func(lcd_id);
1117 if (!panel_func) {
1118 DRM_ERROR("GET panal_func Failed!\n");
1119 return;
1120 }
1121
1122 if (!panel_func->cfg_close_flow) {
1123 DRM_ERROR("cfg_open_close hdl is NULL\n");
1124 return;
1125 }
1126 panel_func->cfg_close_flow(lcd_id);
1127
1128 sunxi_lcd_unprepare(lcd_id);
1129 }
1130
backlight_info_show(struct device * dev,struct device_attribute * attr,char * buf)1131 static ssize_t backlight_info_show(struct device *dev,
1132 struct device_attribute *attr, char *buf)
1133 {
1134 #if defined(CONFIG_AW_DRM_BACKLIGHT)
1135 return sunxi_backlight_info(buf);
1136 #else
1137 DRM_WARN("You must select CONFIG_AW_DRM_BACKLIGHT in menuconfig!\n");
1138 return 0;
1139 #endif
1140 }
1141
backlight_info_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1142 static ssize_t backlight_info_store(struct device *dev,
1143 struct device_attribute *attr,
1144 const char *buf, size_t count)
1145 {
1146 return count;
1147 }
1148
1149 static DEVICE_ATTR(backlight_info, 0660, backlight_info_show,
1150 backlight_info_store);
1151
sunxi_lcd_cfg_dump(char * buf,struct disp_lcd_cfg * cfg)1152 static ssize_t sunxi_lcd_cfg_dump(char *buf, struct disp_lcd_cfg *cfg)
1153 {
1154 ssize_t n = 0;
1155 unsigned int i;
1156
1157 if (cfg->lcd_bl_en_used) {
1158 n += sprintf(buf + n, "lcd_bl_en gpio_name:%s gpio:%d\n",
1159 cfg->lcd_bl_en.name, cfg->lcd_bl_en.gpio);
1160 n += sprintf(buf + n, "lcd_bl_en_power:%s\n",
1161 cfg->lcd_bl_en_power);
1162 }
1163
1164 for (i = 0; i < LCD_POWER_NUM; i++) {
1165 if (cfg->lcd_power_used[i])
1166 n += sprintf(buf + n, "lcd_power%d:%s\n",
1167 i, cfg->lcd_power[i]);
1168 }
1169
1170 for (i = 0; i < LCD_POWER_NUM; i++) {
1171 if (cfg->lcd_fix_power_used[i])
1172 n += sprintf(buf + n, "lcd_fix_power%d:%s\n",
1173 i, cfg->lcd_fix_power[i]);
1174 }
1175
1176 for (i = 0; i < LCD_GPIO_NUM; i++) {
1177 if (cfg->lcd_gpio_used[i])
1178 n += sprintf(buf + n, "lcd_gpio%d name:%s gpio:%d\n",
1179 i, cfg->lcd_gpio[i].name,
1180 cfg->lcd_gpio[i].gpio);
1181 }
1182
1183 for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
1184 if (cfg->lcd_power_used[i])
1185 n += sprintf(buf + n, "lcd_gpio_power%d:%s\n",
1186 i, cfg->lcd_gpio_power[i]);
1187 }
1188
1189 for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
1190 if (cfg->lcd_power_used[i])
1191 n += sprintf(buf + n, "lcd_pin_power%d:%s\n",
1192 i, cfg->lcd_pin_power[i]);
1193 }
1194
1195 n += sprintf(buf + n, "backlight_bright:%u\n", cfg->backlight_bright);
1196 n += sprintf(buf + n, "backlight_dimming:%u\n", cfg->backlight_dimming);
1197 n += sprintf(buf + n, "lcd_bright:%u\n", cfg->lcd_bright);
1198 n += sprintf(buf + n, "lcd_contrast:%u\n", cfg->lcd_contrast);
1199 n += sprintf(buf + n, "lcd_saturation:%u\n", cfg->lcd_saturation);
1200 n += sprintf(buf + n, "lcd_hue:%u\n", cfg->lcd_hue);
1201
1202 return n;
1203 }
1204
sunxi_lcd_exten_para_dump(char * buf,struct panel_extend_para * para)1205 static ssize_t sunxi_lcd_exten_para_dump(char *buf,
1206 struct panel_extend_para *para)
1207 {
1208 ssize_t n = 0;
1209
1210 n += sprintf(buf + n, "lcd_gamma_en:%u\n", para->lcd_gamma_en);
1211 n += sprintf(buf + n, "lcd_cmap_en:%u\n", para->lcd_cmap_en);
1212
1213 return n;
1214 }
1215
sunxi_lcd_panel_para_dump(char * buf,struct disp_panel_para * para)1216 static ssize_t sunxi_lcd_panel_para_dump(char *buf, struct disp_panel_para *para)
1217 {
1218 ssize_t n = 0;
1219
1220 n += sprintf(buf + n, "lcd_if:%s\n",
1221 sunxi_lcd_get_connector_type_name(para->lcd_if));
1222 n += sprintf(buf + n, "lcd_width:%u\n", para->lcd_width);
1223 n += sprintf(buf + n, "lcd_height:%u\n", para->lcd_height);
1224 n += sprintf(buf + n, "lcd_dclk_freq:%u\n", para->lcd_dclk_freq);
1225 n += sprintf(buf + n, "lcd_frm:%u\n", para->lcd_frm);
1226 n += sprintf(buf + n, "lcd_rb_swap:%u\n", para->lcd_rb_swap);
1227 n += sprintf(buf + n, "lcd_gamma_en:%u\n", para->lcd_gamma_en);
1228 n += sprintf(buf + n, "lcd_cmap_en:%u\n", para->lcd_cmap_en);
1229 n += sprintf(buf + n, "lcd_xtal_freq:%u\n", para->lcd_xtal_freq);
1230 n += sprintf(buf + n, "lcd_size:%s\n", para->lcd_size);
1231 n += sprintf(buf + n, "lcd_model_name:%s\n", para->lcd_model_name);
1232 if (para->lcd_pwm_used) {
1233 n += sprintf(buf + n, "lcd_pwm_ch:%u\n", para->lcd_pwm_ch);
1234 n += sprintf(buf + n, "lcd_pwm_freq:%u\n", para->lcd_pwm_freq);
1235 n += sprintf(buf + n, "lcd_pwm_pol:%u\n", para->lcd_pwm_pol);
1236 } else {
1237 n += sprintf(buf + n, "%s\n", "NOT use PWM");
1238 }
1239
1240 if (para->lcd_if == LCD_IF_LVDS) {
1241 n += sprintf(buf + n, "lcd_lvds_if:%s\n",
1242 sunxi_lcd_get_lvds_if_name(para->lcd_hv_if));
1243 n += sprintf(buf + n, "lcd_lvds_mode:%u\n",
1244 para->lcd_lvds_mode);
1245 n += sprintf(buf + n, "lcd_lvds_colordepth:%u\n",
1246 para->lcd_lvds_colordepth);
1247 n += sprintf(buf + n, "lcd_lvds_io_polarity:%u\n",
1248 para->lcd_lvds_io_polarity);
1249 n += sprintf(buf + n, "lcd_lvds_clk_polarity:%u\n",
1250 para->lcd_lvds_clk_polarity);
1251 } else if (para->lcd_if == LCD_IF_HV) { /*RGB*/
1252 n += sprintf(buf + n, "lcd_hv_if:%s\n",
1253 sunxi_lcd_get_hv_if_name(para->lcd_hv_if));
1254 n += sprintf(buf + n, "lcd_hv_clk_phase:%u\n",
1255 para->lcd_hv_clk_phase);
1256 n += sprintf(buf + n, "lcd_hv_sync_polarity:%u\n",
1257 para->lcd_hv_sync_polarity);
1258 n += sprintf(buf + n, "lcd_hv_srgb_seq:%u\n",
1259 para->lcd_hv_srgb_seq);
1260 n += sprintf(buf + n, "lcd_hv_syuv_seq:%u\n",
1261 para->lcd_hv_syuv_seq);
1262 n += sprintf(buf + n, "lcd_hv_syuv_fdly:%u\n",
1263 para->lcd_hv_syuv_fdly);
1264 } else if (para->lcd_if == LCD_IF_CPU) {
1265 n += sprintf(buf + n, "lcd_cpu_if:%s\n",
1266 sunxi_lcd_get_cpu_if_name(para->lcd_cpu_if));
1267 n += sprintf(buf + n, "lcd_cpu_te:%u\n", para->lcd_cpu_te);
1268 } else if (para->lcd_if == LCD_IF_DSI) {
1269 n += sprintf(buf + n, "lcd_dsi_if:%s\n",
1270 sunxi_lcd_get_dsi_if_name(para->lcd_dsi_if));
1271 n += sprintf(buf + n, "lcd_dsi_lane:%u\n", para->lcd_dsi_lane);
1272 n += sprintf(buf + n, "lcd_dsi_format:%u\n",
1273 para->lcd_dsi_format);
1274 n += sprintf(buf + n, "lcd_dsi_eotp:%u\n", para->lcd_dsi_eotp);
1275 n += sprintf(buf + n, "lcd_dsi_te:%u\n", para->lcd_dsi_te);
1276 } else if (para->lcd_if == LCD_IF_EDP) {
1277 }
1278
1279 return n;
1280 }
1281
lcd_info_show(struct device * dev,struct device_attribute * attr,char * buf)1282 static ssize_t lcd_info_show(struct device *dev,
1283 struct device_attribute *attr, char *buf)
1284 {
1285 ssize_t n = 0;
1286 unsigned int i;
1287 struct sunxi_lcd *lcd;
1288
1289 n += sprintf(buf + n, "%s\n", "sunxi LCD info:");
1290 n += sprintf(buf + n, "lcd count:%u\n", lcd_drv->lcd_cnt);
1291 if (lcd_drv->lvds_cnt)
1292 n += sprintf(buf + n, "lvds count:%u\n", lcd_drv->lvds_cnt);
1293 if (lcd_drv->rgb_cnt)
1294 n += sprintf(buf + n, "rgb count:%u\n", lcd_drv->rgb_cnt);
1295 if (lcd_drv->dsi_cnt)
1296 n += sprintf(buf + n, "dsi count:%u\n", lcd_drv->dsi_cnt);
1297 if (lcd_drv->edp_cnt)
1298 n += sprintf(buf + n, "edp count:%u\n", lcd_drv->edp_cnt);
1299 n += sprintf(buf + n, "\n");
1300
1301 for (i = 0; i < lcd_drv->lcd_cnt; i++) {
1302 lcd = sunxi_lcd_get_lcd(i);
1303 if (!lcd) {
1304 DRM_ERROR("Null lcd pointer!\n");
1305 return 0;
1306 }
1307 n += sprintf(buf + n, "id:%d\n", lcd->id);
1308 if (!lcd->is_used) {
1309 n += sprintf(buf + n, "%s\n\n", "NOT used");
1310 continue;
1311 }
1312
1313 n += sprintf(buf + n, "type:%s%d\n",
1314 sunxi_lcd_get_connector_type_name(lcd->type),
1315 lcd->type_id);
1316
1317 if (!lcd->reg_base)
1318 n += sprintf(buf + n, "%s\n", "Do NOT have reg_base"
1319 ", rely on TCON");
1320 else
1321 n += sprintf(buf + n, "reg_base:%lu\n", lcd->reg_base);
1322
1323 if (lcd->mclk) {
1324 n += sprintf(buf + n, "clk_name:%s clk_rate: %lu"
1325 " enable count:%d\n",
1326 __clk_get_name(lcd->mclk),
1327 clk_get_rate(lcd->mclk),
1328 __clk_get_enable_count(lcd->mclk));
1329 } else {
1330 n += sprintf(buf + n, "%s\n", "ERROR: NOT have CLK");
1331 }
1332
1333 if (lcd->irq_used)
1334 n += sprintf(buf + n, "irq_no:%u\n", lcd->irq_no);
1335 else
1336 n += sprintf(buf + n, "%s\n", "NOT use irq and "
1337 "do NOT have irq_no ");
1338
1339 if (lcd->use_bl)
1340 n += sprintf(buf + n, "Use Backlight\n");
1341 else
1342 n += sprintf(buf + n, "NOT use Backlight\n");
1343
1344 n += sunxi_lcd_cfg_dump(buf + n, &lcd->lcd_cfg);
1345 n += sunxi_lcd_exten_para_dump(buf + n, &lcd->extend_para);
1346 n += sunxi_lcd_panel_para_dump(buf + n, &lcd->panel_para);
1347
1348 n += sprintf(buf + n, "\n");
1349 }
1350
1351
1352
1353 return n;
1354 }
1355
lcd_info_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1356 static ssize_t lcd_info_store(struct device *dev,
1357 struct device_attribute *attr,
1358 const char *buf, size_t count)
1359 {
1360 return count;
1361 }
1362
1363 static DEVICE_ATTR(lcd_info, 0660, lcd_info_show, lcd_info_store);
1364
lcd_reg_show(struct device * dev,struct device_attribute * attr,char * buf)1365 static ssize_t lcd_reg_show(struct device *dev,
1366 struct device_attribute *attr, char *buf)
1367 {
1368 return 0;
1369 }
1370
lcd_reg_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1371 static ssize_t lcd_reg_store(struct device *dev,
1372 struct device_attribute *attr,
1373 const char *buf, size_t count)
1374 {
1375 return count;
1376 }
1377
1378 static DEVICE_ATTR(reg, 0660, lcd_reg_show, lcd_reg_store);
1379
1380
1381 static struct attribute *lcd_attributes[] = {
1382 &dev_attr_lcd_info.attr,
1383 &dev_attr_reg.attr,
1384 &dev_attr_backlight_info.attr,
1385 NULL
1386 };
1387
1388 static struct attribute_group lcd_attribute_group = {
1389 .name = "attr",
1390 .attrs = lcd_attributes,
1391 };
1392
sunxi_lcd_dts_parse_lcd_core(struct platform_device * pdev,struct sunxi_lcd_resource * res)1393 static int sunxi_lcd_dts_parse_lcd_core(struct platform_device *pdev,
1394 struct sunxi_lcd_resource *res)
1395 {
1396 unsigned int count = 0, i;
1397 struct device_node *node = pdev->dev.of_node;
1398
1399 /*for (i = 0; i < DEVICE_DSI_NUM; i++) {
1400 res->reg_base[SUNXI_DSI0 + i]
1401 = (uintptr_t __force)of_iomap(node, i);
1402 if (!res->reg_base[SUNXI_DSI0 + i]) {
1403 DRM_ERROR("unable to map dsi-%d registers\n",
1404 i);
1405 return -EINVAL;
1406 }
1407 }
1408
1409 count = 0;*/
1410 #ifdef SUPPORT_LVDS
1411 #ifndef CONFIG_ARCH_SUN50IW9
1412 res->mclk[SUNXI_LVDS0] = of_clk_get(node, count);
1413 if (IS_ERR(res->mclk[SUNXI_LVDS0])) {
1414 DRM_ERROR("fail to get clk for lvds\n");
1415 return -EINVAL;
1416 }
1417 count++;
1418 #endif
1419 res->rst_bus_lvds = devm_reset_control_get_shared(&pdev->dev, "rst_bus_lvds");
1420 if (IS_ERR(res->rst_bus_lvds)) {
1421 DRM_ERROR("fail to get reset clk for rst_bus_lvds\n");
1422 return -EINVAL;
1423 }
1424 #endif
1425 #if 0
1426 for (i = 0; i < DRM_DSI_NUM; i++) {
1427 res->mclk[SUNXI_DSI0 + i] = of_clk_get(node, count);
1428 if (IS_ERR(res->mclk[SUNXI_DSI0 + i])) {
1429 DRM_ERROR("fail to get clk for dsi\n");
1430 return -EINVAL;
1431 }
1432 count++;
1433 }
1434
1435 count = 0;
1436 for (i = 0; i < DRM_DSI_NUM; i++) {
1437 res->irq_no[SUNXI_DSI0 + i] = irq_of_parse_and_map(node, count);
1438 if (!res->irq_no[SUNXI_DSI0 + i]) {
1439 DRM_ERROR("[SUNXI-TCON]get irq no of DSI%d failed\n", i);
1440 return -EINVAL;
1441 }
1442 count++;
1443 }
1444 #endif
1445 return 0;
1446 }
1447
sunxi_lcd_init_al(struct sunxi_lcd_resource * res)1448 static int sunxi_lcd_init_al(struct sunxi_lcd_resource *res)
1449 {
1450 #if 0 // defined(SUPPORT_DSI)
1451 int i;
1452 for (i = 0; i < DRM_DSI_NUM; ++i)
1453 dsi_set_reg_base(i, res->reg_base[SUNXI_DSI0 + i]);
1454 #endif
1455 return 0;
1456 }
1457
1458 /* parse lcd gpio info
1459 * lcd_bl_en: backlight enable gpio
1460 * lcd_gpio_xxx: lcd general gpio
1461 * lcd_gpio_sda/scl
1462 */
sunxi_lcd_dts_parse_gpio_info(struct platform_device * pdev,struct disp_lcd_cfg * lcd_cfg)1463 static int sunxi_lcd_dts_parse_gpio_info(struct platform_device *pdev,
1464 struct disp_lcd_cfg *lcd_cfg)
1465 {
1466 struct disp_gpio_info *gpio_info;
1467 char sub_name[25];
1468 int ret, i;
1469 struct device_node *node = pdev->dev.of_node;
1470
1471 /* lcd_bl_en gpio
1472 * gpio for enable LCD backlight
1473 * NOTE: it is NOT PWM
1474 */
1475 lcd_cfg->lcd_bl_en_used = 0;
1476 gpio_info = (struct disp_gpio_info *)&(lcd_cfg->lcd_bl_en);
1477 ret = sunxi_drm_get_sys_item_gpio(node, "lcd_bl_en", gpio_info);
1478 if (ret == 0) {
1479 lcd_cfg->lcd_bl_en_used = 1;
1480 DRM_INFO("[SUNXI-LCD]get gpio:lcd_bl_en: ");
1481 DRM_INFO("[SUNXI-LCD]name:%s gpio:%d\n",
1482 gpio_info->name, gpio_info->gpio);
1483 }
1484
1485 /* lcd_gpio_0/1/2
1486 * LCD common gpio, such as LCD-RST/ so on
1487 */
1488 for (i = 0; i < LCD_GPIO_NUM; i++) {
1489 sprintf(sub_name, "lcd_gpio_%d", i);
1490 gpio_info = (struct disp_gpio_info *)&(lcd_cfg->lcd_gpio[i]);
1491 ret = sunxi_drm_get_sys_item_gpio(node, sub_name, gpio_info);
1492 if (ret == 0) {
1493 lcd_cfg->lcd_gpio_used[i] = 1;
1494 DRM_INFO("[SUNXI-LCD]get gpio:%s: ", sub_name);
1495 DRM_INFO("[SUNXI-LCD]name:%s gpio:%d\n",
1496 gpio_info->name, gpio_info->gpio);
1497 }
1498 }
1499
1500 /* lcd_gpio_scl,lcd_gpio_sda */
1501 gpio_info = (struct disp_gpio_info *)&(lcd_cfg->lcd_gpio[LCD_GPIO_SCL]);
1502 ret = sunxi_drm_get_sys_item_gpio(node, "lcd_gpio_scl", gpio_info);
1503 if (ret == 0) {
1504 lcd_cfg->lcd_gpio_used[LCD_GPIO_SCL] = 1;
1505 DRM_INFO("[SUNXI-LCD]get lcd_gpio_scl: ");
1506 DRM_INFO("[SUNXI-LCD]name:%s gpio:%d\n",
1507 gpio_info->name, gpio_info->gpio);
1508 }
1509
1510 gpio_info = (struct disp_gpio_info *)&(lcd_cfg->lcd_gpio[LCD_GPIO_SDA]);
1511 ret = sunxi_drm_get_sys_item_gpio(node, "lcd_gpio_sda", gpio_info);
1512 if (ret == 0) {
1513 lcd_cfg->lcd_gpio_used[LCD_GPIO_SDA] = 1;
1514 DRM_INFO("[SUNXI-LCD]get lcd_gpio_sda: ");
1515 DRM_INFO("[SUNXI-LCD]name:%s gpio:%d\n",
1516 gpio_info->name, gpio_info->gpio);
1517 }
1518
1519 return 0;
1520 }
1521
1522 /* parse LCD power info
1523 * lcd_bl_en_power
1524 * lcd_fix_power
1525 * lcd_power/lcd_power0/1/2
1526 * lcd_gpio_power
1527 * lcd_pin_power
1528 */
sunxi_lcd_dts_parse_power_info(struct platform_device * pdev,struct disp_lcd_cfg * lcd_cfg)1529 static int sunxi_lcd_dts_parse_power_info(struct platform_device *pdev,
1530 struct disp_lcd_cfg *lcd_cfg)
1531 {
1532 char sub_name[25];
1533 struct device_node *node = pdev->dev.of_node;
1534 int ret, i;
1535 g_lcd_dev = &pdev->dev;
1536 /* lcd_bl_en_power */
1537 sprintf(sub_name, "lcd_bl_en_power");
1538 ret = sunxi_drm_get_sys_item_char(node, sub_name,
1539 lcd_cfg->lcd_bl_en_power);
1540 if (ret == 0)
1541 DRM_INFO("[SUNXI-LCD]get %s(%s)\n", sub_name,
1542 lcd_cfg->lcd_bl_en_power);
1543
1544 /* lcd fix power
1545 * lcd connector type specific power
1546 * often used for vcc-dsi/vcc-lvds
1547 */
1548 for (i = 0; i < LCD_POWER_NUM; i++) {
1549 if (i == 0)
1550 sprintf(sub_name, "lcd_fix_power");
1551 else
1552 sprintf(sub_name, "lcd_fix_power%d", i);
1553
1554 lcd_cfg->lcd_fix_power_used[i] = 0;
1555 ret = sunxi_drm_get_sys_item_char(node, sub_name,
1556 lcd_cfg->lcd_fix_power[i]);
1557 if (ret == 0) {
1558 lcd_cfg->lcd_fix_power_used[i] = 1;
1559 DRM_INFO("[SUNXI-LCD]get %s(%s)\n", sub_name,
1560 lcd_cfg->lcd_fix_power[i]);
1561 }
1562 }
1563
1564 /* lcd_power lcd common power
1565 * such as: vcc-lcd
1566 */
1567 for (i = 0; i < LCD_POWER_NUM; i++) {
1568 if (i == 0)
1569 sprintf(sub_name, "lcd_power");
1570 else
1571 sprintf(sub_name, "lcd_power%d", i);
1572
1573 lcd_cfg->lcd_power_used[i] = 0;
1574 ret = sunxi_drm_get_sys_item_char(node, sub_name,
1575 lcd_cfg->lcd_power[i]);
1576 if (ret == 0) {
1577 lcd_cfg->lcd_power_used[i] = 1;
1578 DRM_INFO("[SUNXI-LCD]get %s(%s)\n", sub_name,
1579 lcd_cfg->lcd_power[i]);
1580 }
1581 }
1582
1583 for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
1584 sprintf(sub_name, "lcd_gpio_power%d", i);
1585 ret = sunxi_drm_get_sys_item_char(node, sub_name,
1586 lcd_cfg->lcd_gpio_power[i]);
1587 if (ret == 0) {
1588 lcd_cfg->lcd_power_used[i] = 1;
1589 DRM_INFO("[SUNXI-LCD]get %s(%s)\n", sub_name,
1590 lcd_cfg->lcd_gpio_power[i]);
1591 }
1592 }
1593
1594 /* lcd power for pin, such as: vcc-pd */
1595 for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
1596 if (0 == i)
1597 sprintf(sub_name, "lcd_pin_power");
1598 else
1599 sprintf(sub_name, "lcd_pin_power%d", i);
1600
1601 ret = sunxi_drm_get_sys_item_char(node, sub_name,
1602 lcd_cfg->lcd_pin_power[i]);
1603 if (ret == 0) {
1604 lcd_cfg->lcd_power_used[i] = 1;
1605 DRM_INFO("[SUNXI-LCD]get %s(%s)\n", sub_name,
1606 lcd_cfg->lcd_pin_power[i]);
1607 }
1608 }
1609
1610 return 0;
1611 }
1612
1613 /* lcd backlight
1614 * NOTE: is often PWM, different from backlight enable(lcd_bl_en)
1615 */
sunxi_lcd_dts_parse_backlight_info(struct platform_device * pdev,struct disp_lcd_cfg * lcd_cfg)1616 static int sunxi_lcd_dts_parse_backlight_info(struct platform_device *pdev,
1617 struct disp_lcd_cfg *lcd_cfg)
1618 {
1619 struct device_node *node = pdev->dev.of_node;
1620 int ret, i, value = 1;
1621 char sub_name[25];
1622
1623 /* backlight adjust */
1624 for (i = 0; i < 101; i++) {
1625 sprintf(sub_name, "lcd_bl_%d_percent", i);
1626 lcd_cfg->backlight_curve_adjust[i] = 0;
1627
1628 if (i == 100) {
1629 lcd_cfg->backlight_curve_adjust[i] = 255;
1630 }
1631
1632 ret = of_property_read_u32(node, sub_name, &value);
1633 if (ret == 0) {
1634 value = (value > 100) ? 100:value;
1635 value = value * 255 / 100;
1636 lcd_cfg->backlight_curve_adjust[i] = value;
1637 }
1638 }
1639
1640 sprintf(sub_name, "lcd_backlight");
1641 ret = of_property_read_u32(node, sub_name, &value);
1642 if (ret == 0) {
1643 value = (value > 256) ? 256:value;
1644 lcd_cfg->backlight_bright = value;
1645 } else {
1646 lcd_cfg->backlight_bright = 197;
1647 }
1648 lcd_cfg->lcd_bright = lcd_cfg->backlight_bright;
1649
1650 return 0;
1651 }
1652
sunxi_lcd_dts_parse_pannel_timing(struct platform_device * pdev,struct disp_panel_para * info)1653 static int sunxi_lcd_dts_parse_pannel_timing(struct platform_device *pdev,
1654 struct disp_panel_para *info)
1655 {
1656 struct device_node *node = pdev->dev.of_node;
1657 int ret, value = 1;
1658
1659 /* display mode */
1660 ret = of_property_read_u32(node, "lcd_x", &value);
1661 if (ret != 0) {
1662 DRM_ERROR("parse lcd_x failed\n");
1663 return -1;
1664 }
1665 info->lcd_x = value;
1666
1667 ret = of_property_read_u32(node, "lcd_y", &value);
1668 if (ret != 0) {
1669 DRM_ERROR("parse lcd_y failed\n");
1670 return -1;
1671 }
1672 info->lcd_y = value;
1673
1674 ret = of_property_read_u32(node, "lcd_hbp", &value);
1675 if (ret == 0)
1676 info->lcd_hbp = value;
1677
1678 ret = of_property_read_u32(node, "lcd_ht", &value);
1679 if (ret == 0)
1680 info->lcd_ht = value;
1681
1682 ret = of_property_read_u32(node, "lcd_vbp", &value);
1683 if (ret == 0)
1684 info->lcd_vbp = value;
1685
1686 ret = of_property_read_u32(node, "lcd_vt", &value);
1687 if (ret == 0)
1688 info->lcd_vt = value;
1689
1690 ret = of_property_read_u32(node, "lcd_vspw", &value);
1691 if (ret == 0)
1692 info->lcd_vspw = value;
1693
1694 ret = of_property_read_u32(node, "lcd_hspw", &value);
1695 if (ret == 0)
1696 info->lcd_hspw = value;
1697
1698 return 0;
1699 }
1700
sunxi_lcd_dts_parse_pwm(struct platform_device * pdev,struct disp_panel_para * info)1701 static int sunxi_lcd_dts_parse_pwm(struct platform_device *pdev,
1702 struct disp_panel_para *info)
1703 {
1704 struct device_node *node = pdev->dev.of_node;
1705 int ret, value = 1;
1706
1707 ret = of_property_read_u32(node, "lcd_pwm_ch", &value);
1708 if (ret != 0) {
1709 DRM_ERROR("parse lcd_pwm_ch failed\n");
1710 return -1;
1711 }
1712 info->lcd_pwm_ch = value;
1713
1714 ret = of_property_read_u32(node, "lcd_pwm_freq", &value);
1715 if (ret != 0) {
1716 DRM_ERROR("parse lcd_pwm_freq failed\n");
1717 return -1;
1718 }
1719 info->lcd_pwm_freq = value;
1720
1721 ret = of_property_read_u32(node, "lcd_pwm_pol", &value);
1722 if (ret != 0) {
1723 DRM_ERROR("parse lcd_pwm_pol failed\n");
1724 return -1;
1725 }
1726 info->lcd_pwm_pol = value;
1727
1728
1729 return 0;
1730 }
1731
1732 /* RGB */
sunxi_lcd_dts_parse_hv(struct platform_device * pdev,struct disp_panel_para * info)1733 static int sunxi_lcd_dts_parse_hv(struct platform_device *pdev,
1734 struct disp_panel_para *info)
1735 {
1736 struct device_node *node = pdev->dev.of_node;
1737 int ret, value = 1;
1738
1739 ret = of_property_read_u32(node, "lcd_hv_if", &value);
1740 if (ret != 0) {
1741 DRM_ERROR("parse lcd_hv_if failed\n");
1742 return -1;
1743 }
1744 info->lcd_hv_if = value;
1745
1746 ret = of_property_read_u32(node, "lcd_hv_clk_phase", &value);
1747 if (ret != 0) {
1748 DRM_ERROR("parse lcd_hv_clk_phase failed\n");
1749 return -1;
1750 }
1751 info->lcd_hv_clk_phase = value;
1752
1753 ret = of_property_read_u32(node, "lcd_hv_sync_polarity", &value);
1754 if (ret != 0) {
1755 DRM_ERROR("parse lcd_hv_sync_polarity failed\n");
1756 return -1;
1757 }
1758 info->lcd_hv_sync_polarity = value;
1759
1760 ret = of_property_read_u32(node, "lcd_hv_srgb_seq", &value);
1761 if (ret != 0) {
1762 DRM_ERROR("parse lcd_hv_srgb_seq failed\n");
1763 return -1;
1764 }
1765 info->lcd_hv_srgb_seq = value;
1766
1767 ret = of_property_read_u32(node, "lcd_hv_syuv_seq", &value);
1768 if (ret != 0) {
1769 DRM_ERROR("parse lcd_hv_syuv_seq failed\n");
1770 return -1;
1771 }
1772 info->lcd_hv_syuv_seq = value;
1773
1774 ret = of_property_read_u32(node, "lcd_hv_syuv_fdly", &value);
1775 if (ret != 0) {
1776 DRM_ERROR("parse lcd_hv_syuv_fdly failed\n");
1777 return -1;
1778 }
1779 info->lcd_hv_syuv_fdly = value;
1780
1781 return 0;
1782 }
1783
sunxi_lcd_dts_parse_lvds(struct platform_device * pdev,struct disp_panel_para * info)1784 static int sunxi_lcd_dts_parse_lvds(struct platform_device *pdev,
1785 struct disp_panel_para *info)
1786 {
1787 struct device_node *node = pdev->dev.of_node;
1788 int ret, value = 1;
1789
1790 ret = of_property_read_u32(node, "lcd_lvds_if", &value);
1791 if (ret != 0) {
1792 DRM_ERROR("parse lcd_lvds_if failed\n");
1793 return -1;
1794 }
1795 info->lcd_lvds_if = value;
1796
1797 ret = of_property_read_u32(node, "lcd_lvds_mode", &value);
1798 if (ret != 0) {
1799 DRM_ERROR("parse lcd_lvds_mode failed\n");
1800 return -1;
1801 }
1802 info->lcd_lvds_mode = value;
1803
1804 ret = of_property_read_u32(node, "lcd_lvds_colordepth",
1805 &value);
1806 if (ret != 0) {
1807 DRM_ERROR("parse lcd_lvds_colordepth failed\n");
1808 return -1;
1809 }
1810 info->lcd_lvds_colordepth = value;
1811
1812 ret = of_property_read_u32(node, "lcd_lvds_io_polarity",
1813 &value);
1814 if (ret == 0)
1815 info->lcd_lvds_io_polarity = value;
1816
1817 ret = of_property_read_u32(node, "lcd_lvds_clk_polarity",
1818 &value);
1819 if (ret == 0)
1820 info->lcd_lvds_clk_polarity = value;
1821
1822 return 0;
1823 }
1824
sunxi_lcd_dts_parse_cpu(struct platform_device * pdev,struct disp_panel_para * info)1825 static int sunxi_lcd_dts_parse_cpu(struct platform_device *pdev,
1826 struct disp_panel_para *info)
1827 {
1828 struct device_node *node = pdev->dev.of_node;
1829 int ret, value = 1;
1830
1831 ret = of_property_read_u32(node, "lcd_cpu_if", &value);
1832 if (ret != 0) {
1833 DRM_ERROR("parse lcd_cpu_if failed\n");
1834 return -1;
1835 }
1836 info->lcd_cpu_if = value;
1837
1838 ret = of_property_read_u32(node, "lcd_cpu_te", &value);
1839 if (ret != 0) {
1840 DRM_ERROR("parse lcd_cpu_te failed\n");
1841 return -1;
1842 }
1843 info->lcd_cpu_te = value;
1844
1845 return 0;
1846 }
1847
sunxi_lcd_dts_parse_dsi(struct platform_device * pdev,struct disp_panel_para * info)1848 static int sunxi_lcd_dts_parse_dsi(struct platform_device *pdev,
1849 struct disp_panel_para *info)
1850 {
1851 struct device_node *node = pdev->dev.of_node;
1852 int ret, value = 1;
1853
1854 ret = of_property_read_u32(node, "lcd_dsi_if", &value);
1855 if (ret != 0) {
1856 DRM_ERROR("parse lcd_dsi_if failed\n");
1857 return -1;
1858 }
1859 info->lcd_dsi_if = value;
1860
1861 ret = of_property_read_u32(node, "lcd_dsi_lane", &value);
1862 if (ret != 0) {
1863 DRM_ERROR("parse lcd_dsi_lane failed\n");
1864 return -1;
1865 }
1866 info->lcd_dsi_lane = value;
1867
1868 ret = of_property_read_u32(node, "lcd_dsi_format",
1869 &value);
1870 if (ret != 0) {
1871 DRM_ERROR("parse lcd_dsi_format failed\n");
1872 return -1;
1873 }
1874 info->lcd_dsi_format = value;
1875
1876 ret = of_property_read_u32(node, "lcd_dsi_eotp", &value);
1877 if (ret != 0) {
1878 DRM_ERROR("parse lcd_dsi_eotp failed\n");
1879 return -1;
1880 }
1881 info->lcd_dsi_eotp = value;
1882
1883 ret = of_property_read_u32(node, "lcd_dsi_te", &value);
1884 if (ret != 0) {
1885 DRM_ERROR("parse lcd_dsi_te failed\n");
1886 return -1;
1887 }
1888 info->lcd_dsi_te = value;
1889
1890 return 0;
1891 }
1892
sunxi_lcd_dts_parse_edp(struct platform_device * pdev,struct disp_panel_para * info)1893 static int sunxi_lcd_dts_parse_edp(struct platform_device *pdev,
1894 struct disp_panel_para *info)
1895 {
1896 struct device_node *node = pdev->dev.of_node;
1897 int ret, value = 1;
1898
1899 ret = of_property_read_u32(node, "lcd_edp_rate", &value);
1900 if (ret != 0) {
1901 DRM_ERROR("parse lcd_edp_rate failed\n");
1902 return -1;
1903 }
1904 // info->lcd_edp_rate = value
1905
1906 ret = of_property_read_u32(node, "lcd_edp_lane", &value);
1907 if (ret != 0) {
1908 DRM_ERROR("parse lcd_edp_lane failed\n");
1909 return -1;
1910 }
1911 // info->lcd_edp_lane = value
1912
1913 ret = of_property_read_u32(node, "lcd_edp_colordepth", &value);
1914 if (ret != 0) {
1915 DRM_ERROR("parse lcd_edp_colordepth failed\n");
1916 return -1;
1917 }
1918 // info->lcd_edp_colordepth = value
1919
1920 ret = of_property_read_u32(node, "lcd_edp_fps", &value);
1921 if (ret != 0) {
1922 DRM_ERROR("parse lcd_edp_fps failed\n");
1923 return -1;
1924 }
1925 // info->lcd_edp_fps = value
1926
1927 return 0;
1928 }
1929
sunxi_lcd_dts_parse_panel_info(struct platform_device * pdev,struct disp_panel_para * info)1930 static int sunxi_lcd_dts_parse_panel_info(struct platform_device *pdev,
1931 struct disp_panel_para *info)
1932 {
1933 struct device_node *node = pdev->dev.of_node;
1934 int ret, value = 1;
1935
1936
1937 ret = of_property_read_u32(node, "lcd_width", &value);
1938 if (ret < 0) {
1939 DRM_ERROR("get lcd_width failed\n");
1940 return -1;
1941 }
1942 info->lcd_width = value;
1943
1944 ret = of_property_read_u32(node, "lcd_height", &value);
1945 if (ret < 0) {
1946 DRM_ERROR("get lcd_height failed\n");
1947 return -1;
1948 }
1949 info->lcd_height = value;
1950
1951 ret = of_property_read_u32(node, "lcd_dclk_freq", &value);
1952 if (ret < 0) {
1953 DRM_ERROR("get lcd_dclk_freq failed\n");
1954 return -1;
1955 }
1956 info->lcd_dclk_freq = value;
1957
1958 ret = sunxi_lcd_dts_parse_pannel_timing(pdev, info);
1959 if (ret < 0) {
1960 DRM_ERROR("sunxi_lcd_dts_parse_pannel_timing failed\n");
1961 return -1;
1962 }
1963
1964
1965 ret = of_property_read_u32(node, "lcd_pwm_used", &value);
1966 if (ret == 0) {
1967 info->lcd_pwm_used = value;
1968 if (sunxi_lcd_dts_parse_pwm(pdev, info)) {
1969 DRM_ERROR("sunxi_lcd_dts_parse_pwm failed\n");
1970 return -1;
1971 }
1972 } else {
1973 DRM_INFO("[SUNXI-LCD]NOT use PWM\n");
1974 }
1975
1976 ret = of_property_read_u32(node, "lcd_if", &value);
1977 if (ret != 0) {
1978 DRM_ERROR("parse lcd_if failed\n");
1979 return -1;
1980 }
1981 info->lcd_if = value;
1982
1983 if (info->lcd_if == LCD_IF_HV) { /* RGB */
1984 /* if (sunxi_lcd_dts_parse_hv(pdev, info)) {
1985 DRM_ERROR("sunxi_lcd_dts_parse_hv failed\n");
1986 return -1;
1987 } */
1988 } else if (info->lcd_if == LCD_IF_LVDS) {
1989 if (sunxi_lcd_dts_parse_lvds(pdev, info)) {
1990 DRM_ERROR("sunxi_lcd_dts_parse_lvds failed\n");
1991 return -1;
1992 }
1993 } else if (info->lcd_if == LCD_IF_CPU) {
1994 if (sunxi_lcd_dts_parse_cpu(pdev, info)) {
1995 DRM_ERROR("sunxi_lcd_dts_parse_lvds failed\n");
1996 return -1;
1997 }
1998 } else if (info->lcd_if == LCD_IF_DSI) {
1999 if (sunxi_lcd_dts_parse_dsi(pdev, info)) {
2000 DRM_ERROR("sunxi_lcd_dts_parse_dsi failed\n");
2001 return -1;
2002 }
2003 } else if (info->lcd_if == LCD_IF_EDP) {
2004 if (sunxi_lcd_dts_parse_edp(pdev, info)) {
2005 DRM_ERROR("sunxi_lcd_dts_parse_edp failed\n");
2006 return -1;
2007 }
2008 }
2009
2010 ret = of_property_read_u32(node, "lcd_frm", &value);
2011 if (ret == 0)
2012 info->lcd_frm = value;
2013
2014 ret = of_property_read_u32(node, "lcd_rb_swap", &value);
2015 if (ret == 0)
2016 info->lcd_rb_swap = value;
2017
2018 ret = of_property_read_u32(node, "lcd_gamma_en", &value);
2019 if (ret == 0)
2020 info->lcd_gamma_en = value;
2021
2022 ret = of_property_read_u32(node, "lcd_cmap_en", &value);
2023 if (ret == 0)
2024 info->lcd_cmap_en = value;
2025
2026 ret = of_property_read_u32(node, "lcd_xtal_freq", &value);
2027 if (ret == 0)
2028 info->lcd_xtal_freq = value;
2029
2030 ret = sunxi_drm_get_sys_item_char(node, "lcd_size",
2031 (void *)info->lcd_size);
2032 ret = sunxi_drm_get_sys_item_char(node, "lcd_model_name",
2033 (void *)info->lcd_model_name);
2034 if (ret) {
2035 ret = sunxi_drm_get_sys_item_char(node, "lcd_driver_name",
2036 (void *)info->lcd_model_name);
2037 if (ret) {
2038 DRM_ERROR("get lcd_driver_name failed\n");
2039 return -1;
2040 }
2041 DRM_INFO("[SUNXI-LCD]get lcd panel driver:%s\n",
2042 info->lcd_model_name);
2043 } else {
2044 DRM_INFO("[SUNXI-LCD]get lcd panel driver:%s\n",
2045 info->lcd_model_name);
2046 }
2047
2048 return 0;
2049 }
2050
sunxi_lcd_dts_parse(struct platform_device * pdev,struct sunxi_lcd * sunxi_lcd)2051 int sunxi_lcd_dts_parse(struct platform_device *pdev,
2052 struct sunxi_lcd *sunxi_lcd)
2053 {
2054 struct disp_lcd_cfg *lcd_cfg;
2055 struct disp_panel_para *info;
2056
2057 lcd_cfg = &sunxi_lcd->lcd_cfg;
2058 info = &sunxi_lcd->panel_para;
2059
2060 if (sunxi_lcd_dts_parse_gpio_info(pdev, lcd_cfg) < 0) {
2061 DRM_ERROR("sunxi_lcd_dts_parse_gpio_info failed\n");
2062 return -1;
2063 }
2064
2065 if (sunxi_lcd_dts_parse_power_info(pdev, lcd_cfg) < 0) {
2066 DRM_ERROR("sunxi_lcd_dts_parse_power_info failed\n");
2067 return -1;
2068 }
2069
2070 if (sunxi_lcd_dts_parse_backlight_info(pdev, lcd_cfg) < 0) {
2071 DRM_ERROR("sunxi_lcd_dts_parse_backlight_info failed\n");
2072 return -1;
2073 }
2074
2075 if (sunxi_lcd_dts_parse_panel_info(pdev, info) < 0) {
2076 DRM_ERROR("sunxi_lcd_dts_parse_panel_info failed\n");
2077 return -1;
2078 }
2079
2080 return 0;
2081 }
2082
sunxi_lcd_cal_backlight_curve(struct sunxi_lcd * lcd)2083 static int sunxi_lcd_cal_backlight_curve(struct sunxi_lcd *lcd)
2084 {
2085 unsigned int i = 0, j = 0;
2086 unsigned int items = 0;
2087 unsigned int lcd_bright_curve_tbl[101][2];
2088 struct disp_lcd_cfg *cfg = &lcd->lcd_cfg;
2089 struct panel_extend_para *extend_para = &lcd->extend_para;
2090
2091 for (i = 0; i < 101; i++) {
2092 if (cfg->backlight_curve_adjust[i] == 0) {
2093 if (i == 0) {
2094 lcd_bright_curve_tbl[items][0] = 0;
2095 lcd_bright_curve_tbl[items][1] = 0;
2096 items++;
2097 }
2098 } else {
2099 lcd_bright_curve_tbl[items][0] = 255 * i / 100;
2100 lcd_bright_curve_tbl[items][1] =
2101 cfg->backlight_curve_adjust[i];
2102 items++;
2103 }
2104 }
2105
2106 for (i = 0; i < items - 1; i++) {
2107 u32 num = lcd_bright_curve_tbl[i + 1][0]
2108 - lcd_bright_curve_tbl[i][0];
2109
2110 for (j = 0; j < num; j++) {
2111 u32 value = 0;
2112
2113 value = lcd_bright_curve_tbl[i][1]
2114 + ((lcd_bright_curve_tbl[i + 1][1]
2115 - lcd_bright_curve_tbl[i][1]) * j) / num;
2116 extend_para->lcd_bright_curve_tbl[
2117 lcd_bright_curve_tbl[i][0] + j] = value;
2118 }
2119 }
2120
2121 extend_para->lcd_bright_curve_tbl[255] =
2122 lcd_bright_curve_tbl[items - 1][1];
2123
2124 return 0;
2125 }
2126
2127 #if defined(CONFIG_AW_DRM_BACKLIGHT)
sunxi_lcd_backlight_init(struct sunxi_lcd * lcd)2128 static int sunxi_lcd_backlight_init(struct sunxi_lcd *lcd)
2129 {
2130 struct backlight_config bl_cfg;
2131 struct disp_lcd_cfg *lcd_cfg = &lcd->lcd_cfg;
2132 struct disp_panel_para *panel_para = &lcd->panel_para;
2133 struct panel_extend_para *extend_para = &lcd->extend_para;
2134 int ret = 0;
2135
2136 bl_cfg.use_bl_en = lcd_cfg->lcd_bl_en_used;
2137 memcpy(&bl_cfg.bl_en_gpio, &lcd_cfg->lcd_bl_en,
2138 sizeof(struct disp_gpio_info));
2139 memcpy(bl_cfg.bl_en_power, lcd_cfg->lcd_bl_en_power, LCD_POWER_STR_LEN);
2140
2141 if (sunxi_lcd_cal_backlight_curve(lcd) < 0) {
2142 DRM_ERROR("sunxi_lcd_cal_backlight_curve failed\n");
2143 return -1;
2144 }
2145
2146 bl_cfg.bright = lcd_cfg->backlight_bright;
2147 bl_cfg.use_pwm = panel_para->lcd_pwm_used;
2148 if (bl_cfg.use_pwm) {
2149 bl_cfg.pwm.lcd_pwm_ch = panel_para->lcd_pwm_ch;
2150 bl_cfg.pwm.lcd_pwm_pol = panel_para->lcd_pwm_pol;
2151 bl_cfg.pwm.lcd_pwm_freq = panel_para->lcd_pwm_freq;
2152 }
2153
2154 ret = sunxi_backlight_init(lcd->id, &bl_cfg,
2155 extend_para->lcd_bright_curve_tbl);
2156 if (ret < 0) {
2157 DRM_ERROR("sunxi_backlight_init failed\n");
2158 return -1;
2159 }
2160
2161 return 0;
2162 }
2163
sunxi_lcd_backlight_remove(struct sunxi_lcd * lcd)2164 static void sunxi_lcd_backlight_remove(struct sunxi_lcd *lcd)
2165 {
2166 sunxi_backlight_remove(lcd->id);
2167 }
2168 #endif
2169
2170 static struct sunxi_lcd_funcs sunxi_hv_funcs = {
2171 .get_type = sunxi_lcd_get_type,
2172 .get_panel_para = sunxi_lcd_get_panel_para,
2173 .is_use_irq = sunxi_lcd_is_use_irq,
2174 .get_irq_no = sunxi_lcd_get_irq_no,
2175
2176 .enable = sunxi_lcd_hv_enable,
2177 .sw_enable = sunxi_lcd_sw_enable,
2178 .disable = sunxi_lcd_hv_disable,
2179 };
2180
2181 static struct sunxi_lcd_funcs sunxi_lvds_funcs = {
2182 .get_type = sunxi_lcd_get_type,
2183 .get_panel_para = sunxi_lcd_get_panel_para,
2184 .is_use_irq = sunxi_lcd_is_use_irq,
2185 .get_irq_no = sunxi_lcd_get_irq_no,
2186
2187 .enable = sunxi_lcd_lvds_enable,
2188 .sw_enable = sunxi_lcd_sw_enable,
2189 .disable = sunxi_lcd_lvds_disable,
2190 };
2191
2192 static struct sunxi_lcd_funcs sunxi_dsi_funcs = {
2193 .get_type = sunxi_lcd_get_type,
2194 .get_panel_para = sunxi_lcd_get_panel_para,
2195 .is_use_irq = sunxi_lcd_is_use_irq,
2196 .get_irq_no = sunxi_lcd_get_irq_no,
2197
2198 .enable = sunxi_lcd_dsi_enable,
2199 .sw_enable = sunxi_lcd_sw_enable,
2200 .disable = sunxi_lcd_dsi_disable,
2201 };
2202
sunxi_lcd_probe(struct platform_device * pdev)2203 static int sunxi_lcd_probe(struct platform_device *pdev)
2204 {
2205 u32 lcd_used = 0, id;
2206 struct sunxi_lcd *lcd;
2207 struct sunxi_lcd_resource *res;
2208
2209 res = &lcd_drv->res;
2210
2211 DRM_INFO("pdev name:%s\n", pdev->name);
2212
2213 /* init LCD CORE */
2214 if ((!strcmp(pdev->name, "lcd-core"))
2215 || strstr(pdev->name, "lcd-core")) {
2216 DRM_INFO("[SUNXI-LCD]: find sunxi-lcd\n");
2217 if (sunxi_lcd_dts_parse_lcd_core(pdev, res) < 0) {
2218 DRM_ERROR("sunxi_lcd_dts_parse_lcd_core failed");
2219 DRM_ERROR("probe failed\n");
2220 return -EINVAL;
2221 }
2222
2223 if (sunxi_lcd_init_al(&lcd_drv->res) < 0) {
2224 DRM_ERROR("sunxi_lcd_init_al failed");
2225 DRM_ERROR("probe failed\n");
2226 return -EINVAL;
2227 }
2228
2229 #if defined(CONFIG_AW_DRM_BACKLIGHT)
2230 /* initial backlight driver */
2231 if (sunxi_backlight_drv_init() < 0) {
2232 DRM_ERROR("sunxi_backlight_drv_init failed");
2233 DRM_ERROR("probe failed\n");
2234 return -EINVAL;
2235 }
2236 #endif
2237
2238
2239 DRM_INFO("[SUNXI-LCD]lcd-core probe end\n");
2240 return 0;
2241 }
2242
2243 /* init lcd0/1/2/3 */
2244 id = lcd_drv->lcd_cnt;
2245
2246 lcd = &lcd_drv->hwlcd[id];
2247 lcd->id = id;
2248 lcd->pdev = pdev;
2249
2250 if (of_property_read_u32(pdev->dev.of_node,
2251 "lcd_used", &lcd_used)) {
2252 DRM_ERROR("DTS parse lcd_used failed\n");
2253 goto lcd_err;
2254 }
2255
2256 if (!lcd_used) {
2257 DRM_INFO("[SUNXI-LCD]Warn: lcd%d is NOT be used!\n", id);
2258 goto lcd_err;
2259 }
2260
2261 lcd->is_used = true;
2262
2263 if (sunxi_lcd_dts_parse(pdev, lcd) < 0) {
2264 DRM_ERROR("sunxi_lcd_dts_parse failed\n");
2265 goto lcd_err;
2266 }
2267 lcd->type = lcd->panel_para.lcd_if;
2268
2269 lcd->extend_para.lcd_gamma_en = lcd->panel_para.lcd_gamma_en;
2270
2271 /* LCD-CORE dispatch reg_base/irq_no/clk to sunxi_lcd */
2272 if (lcd->type == LCD_IF_DSI) { /* DSI */
2273 #ifdef SUPPORT_DSI
2274 lcd->type_id = lcd_drv->dsi_cnt;
2275 lcd_drv->dsi_cnt++;
2276 lcd->reg_base = res->reg_base[SUNXI_DSI0 + lcd->type_id];
2277
2278 lcd->mclk = res->mclk[SUNXI_DSI0 + lcd->type_id];
2279 lcd->mclk_bus = res->mclk_bus[SUNXI_DSI0 + lcd->type_id];
2280 lcd->parent_clk = clk_get_parent(lcd->mclk);
2281 #ifdef DSI_VERSION_40
2282 lcd->irq_used = true;
2283 #else
2284 lcd->irq_used = false;
2285 #endif
2286 lcd->irq_no = res->irq_no[SUNXI_DSI0 + lcd->type_id];
2287 #endif
2288 } else if (lcd->type == LCD_IF_LVDS) { /* LVDS */
2289 lcd->type_id = lcd_drv->lvds_cnt;
2290 lcd_drv->lvds_cnt++;
2291 lcd->mclk = res->mclk[SUNXI_LVDS0 + lcd->type_id];
2292 lcd->parent_clk = clk_get_parent(lcd->mclk);
2293 lcd->irq_used = false;
2294 } else if (lcd->type == LCD_IF_HV) { /* RGB */
2295 lcd->type_id = lcd_drv->rgb_cnt;
2296 lcd_drv->rgb_cnt++;
2297 lcd->mclk = res->mclk[SUNXI_RGB0 + lcd->type_id];
2298 lcd->parent_clk = clk_get_parent(lcd->mclk);
2299 lcd->irq_used = false;
2300 } else if (lcd->type == LCD_IF_CPU) { /* CPU */
2301 lcd->type_id = lcd_drv->cpu_cnt;
2302 lcd_drv->cpu_cnt++;
2303 lcd->mclk = res->mclk[SUNXI_CPU0 + lcd->type_id];
2304 lcd->parent_clk = clk_get_parent(lcd->mclk);
2305 lcd->irq_used = false;
2306 } else {
2307 DRM_ERROR("lcd type:%d haven't been Implement\n", lcd->type);
2308 goto lcd_err;
2309 }
2310
2311 /* sunxi_lcd get a backlight */
2312
2313 if (lcd->lcd_cfg.lcd_bl_en_used || lcd->panel_para.lcd_pwm_used) {
2314 lcd->use_bl = 1;
2315 #if defined(CONFIG_AW_DRM_BACKLIGHT)
2316 if (sunxi_lcd_backlight_init(lcd) < 0) {
2317 DRM_ERROR("sunxi_lcd_backlight_init failed\n");
2318 goto lcd_err;
2319 }
2320 #endif
2321 }
2322
2323 /* initial lcd panel */
2324 lcd->panel = sunxi_lcd_get_panel(lcd->panel_para.lcd_model_name);
2325 if (!lcd->panel) {
2326 DRM_ERROR("get panel failed\n");
2327 goto lcd_err;
2328 }
2329
2330 lcd->panel->func.cfg_panel_info(&lcd->extend_para);
2331
2332 if (lcd->type == LCD_IF_DSI) {
2333 lcd->funcs = &sunxi_dsi_funcs;
2334 } else if (lcd->type == LCD_IF_LVDS) {
2335 lcd->funcs = &sunxi_lvds_funcs;
2336 } else if (lcd->type == LCD_IF_HV) {
2337 lcd->funcs = &sunxi_hv_funcs;
2338 } else if (lcd->type == LCD_IF_CPU) {
2339 // lcd->funcs = &sunxi_cpu_funcs
2340 } else {
2341 DRM_ERROR("lcd type:%d haven't been Implement\n", lcd->type);
2342 goto lcd_err;
2343 }
2344
2345 /* increase lcd count */
2346 lcd_drv->lcd_cnt++;
2347
2348 DRM_INFO("[SUNXI-LCD]lcd%d probe end\n", lcd->id);
2349 return 0;
2350
2351 lcd_err:
2352 // lcd_drv->lcd_cnt++
2353 DRM_ERROR("probe failed\n");
2354 return -EINVAL;
2355 }
2356
sunxi_lcd_remove(struct platform_device * pdev)2357 static int sunxi_lcd_remove(struct platform_device *pdev)
2358 {
2359 #if defined(CONFIG_AW_DRM_BACKLIGHT)
2360 struct sunxi_lcd *lcd;
2361 int i = 0, lcd_cnt;
2362
2363 lcd_cnt = sunxi_lcd_get_count();
2364 for (i = 0; i < lcd_cnt; i++) {
2365 lcd = sunxi_lcd_get_lcd(i);
2366 sunxi_lcd_backlight_remove(lcd);
2367 }
2368
2369 sunxi_backlight_drv_exit();
2370 #endif
2371
2372 return 0;
2373 }
2374
2375
2376 static const struct of_device_id sunxi_lcd_match[] = {
2377 { .compatible = "allwinner,sunxi-lcd", },
2378 { .compatible = "allwinner,sunxi-lcd0", },
2379 { .compatible = "allwinner,sunxi-lcd1", },
2380
2381 /* generally, we at most use two lcd at the same time.
2382 * but if you want to use more, and use these config below, and
2383 * set lcd configs in sys_config.fex
2384 */
2385 /*
2386 { .compatible = "allwinner,sunxi-lcd2", },
2387 { .compatible = "allwinner,sunxi-lcd3", },
2388 */
2389 {},
2390 };
2391
2392 struct platform_driver sunxi_lcd_platform_driver = {
2393 .probe = sunxi_lcd_probe,
2394 .remove = sunxi_lcd_remove,
2395 .driver = {
2396 .name = "lcd",
2397 .owner = THIS_MODULE,
2398 .of_match_table = sunxi_lcd_match,
2399 },
2400 };
2401
sunxi_lcd_module_init(void)2402 int sunxi_lcd_module_init(void)
2403 {
2404 int ret = 0, err;
2405 struct drv_model_info *drv_model;
2406
2407 DRM_INFO("[SUNXI-LCD]sunxi_lcd_module_init\n");
2408
2409 lcd_drv = kzalloc(sizeof(struct sunxi_lcd_drv), GFP_KERNEL);
2410 if (!lcd_drv) {
2411 DRM_ERROR("can NOT allocate memory for lcd_drv\n");
2412 goto lcd_err;
2413 }
2414 drv_model = &lcd_drv->drv_model;
2415
2416 if (alloc_chrdev_region(&drv_model->devid, 0, 1, "lcd") < 0) {
2417 DRM_ERROR("alloc_chrdev_region failed\n");
2418 goto lcd_err;
2419 }
2420
2421 drv_model->cdev = cdev_alloc();
2422 if (!drv_model->cdev) {
2423 DRM_ERROR("cdev_alloc failed\n");
2424 goto lcd_err;
2425 }
2426
2427 cdev_init(drv_model->cdev, NULL);
2428 drv_model->cdev->owner = THIS_MODULE;
2429 err = cdev_add(drv_model->cdev, drv_model->devid, 1);
2430 if (err) {
2431 DRM_ERROR("cdev_add major number:%d failed\n",
2432 MAJOR(drv_model->devid));
2433 goto lcd_err;
2434 }
2435
2436 drv_model->sysclass = class_create(THIS_MODULE, "lcd");
2437 if (IS_ERR(drv_model->sysclass)) {
2438 DRM_ERROR("create class error\n");
2439 goto lcd_err;
2440 }
2441
2442 drv_model->dev = device_create(drv_model->sysclass, NULL,
2443 drv_model->devid, NULL, "lcd");
2444 if (!drv_model->dev) {
2445 DRM_ERROR("device_create failed\n");
2446 goto lcd_err;
2447 }
2448
2449 ret = platform_driver_register(&sunxi_lcd_platform_driver);
2450 if (ret) {
2451 DRM_ERROR("platform_driver_register failed\n");
2452 goto lcd_err;
2453 }
2454
2455 ret = sysfs_create_group(&drv_model->dev->kobj,
2456 &lcd_attribute_group);
2457 if (ret < 0) {
2458 DRM_ERROR("sysfs_create_file fail!\n");
2459 goto lcd_err;
2460 }
2461
2462 DRM_INFO("[SUNXI-LCD]sunxi_lcd_module_init end\n\n");
2463 return 0;
2464
2465 lcd_err:
2466 DRM_ERROR("sunxi_lcd_module_init failed\n");
2467 kfree(lcd_drv);
2468 return -EINVAL;
2469 }
2470
sunxi_lcd_module_exit(void)2471 void sunxi_lcd_module_exit(void)
2472 {
2473 struct drv_model_info *drv_model;
2474
2475 DRM_INFO("[SUNXI-LCD]sunxi_lcd_module_exit\n");
2476 platform_driver_unregister(&sunxi_lcd_platform_driver);
2477
2478 drv_model = &lcd_drv->drv_model;
2479 device_destroy(drv_model->sysclass, drv_model->devid);
2480 class_destroy(drv_model->sysclass);
2481
2482 cdev_del(drv_model->cdev);
2483 if (lcd_drv)
2484 kfree(lcd_drv);
2485 }
2486
2487