tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / video / sprdfb / lcd / lcd_jd9161_mipi.c
1 /* drivers/video/sc8825/lcd_jd9161_mipi.c\r
2  *\r
3  * Support for jd9161 mipi LCD device\r
4  *\r
5  * Copyright (C) 2010 Spreadtrum\r
6  *\r
7  * This software is licensed under the terms of the GNU General Public\r
8  * License version 2, as published by the Free Software Foundation, and\r
9  * may be copied, distributed, and modified under those terms.\r
10  *\r
11  * This program is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  */\r
16 \r
17 #include <linux/kernel.h>\r
18 #include <linux/bug.h>\r
19 #include <linux/delay.h>\r
20 #include "../sprdfb_panel.h"\r
21 \r
22 #define  LCD_DEBUG\r
23 #ifdef LCD_DEBUG\r
24 #define LCD_PRINT printk\r
25 #else\r
26 #define LCD_PRINT(...)\r
27 #endif\r
28 \r
29 #define MAX_DATA   48\r
30 \r
31 typedef struct LCM_Init_Code_tag {\r
32         unsigned int tag;\r
33         unsigned char data[MAX_DATA];\r
34 }LCM_Init_Code;\r
35 \r
36 typedef struct LCM_force_cmd_code_tag{\r
37         unsigned int datatype;\r
38         LCM_Init_Code real_cmd_code;\r
39 }LCM_Force_Cmd_Code;\r
40 \r
41 #define LCM_TAG_SHIFT 24\r
42 #define LCM_TAG_MASK  ((1 << 24) -1)\r
43 #define LCM_SEND(len) ((1 << LCM_TAG_SHIFT)| len)\r
44 #define LCM_SLEEP(ms) ((2 << LCM_TAG_SHIFT)| ms)\r
45 //#define ARRAY_SIZE(array) ( sizeof(array) / sizeof(array[0]))\r
46 \r
47 #define LCM_TAG_SEND  (1<< 0)\r
48 #define LCM_TAG_SLEEP (1 << 1)\r
49 \r
50 static LCM_Init_Code init_data[] = {\r
51         {LCM_SEND(6), {4,0,0xBF,0x91,0x61,0xF2}},\r
52         {LCM_SLEEP(1)},\r
53         {LCM_SEND(5), {3,0,0xB3,0x00,0x7F}},//VCOM\r
54         {LCM_SLEEP(1)},\r
55         {LCM_SEND(5), {3,0,0xB4,0x00,0x7F}},//VCOM_R\r
56         {LCM_SLEEP(1)},\r
57         {LCM_SEND(9), {7,0,0xB8,0x00,0xB6,0x01,0x00,0xB6,0x01}},//VGMP, VGSP, VGMN  \r
58         {LCM_SLEEP(1)},         \r
59         {LCM_SEND(6), {4,0,0xBA,0x34,0x23,0x00}},//GIP output volta\r
60         {LCM_SLEEP(1)},\r
61         {LCM_SEND(2), {0xC3,0x02}},//column\r
62         {LCM_SLEEP(1)},\r
63         {LCM_SEND(5), {3,0,0xC4,0x00,0x64}},//TCON\r
64         {LCM_SLEEP(1)},\r
65         {LCM_SEND(12), {10,0,0xC7,0x00,0x01,0x32,0x05,0x65,0x2C,0x13,0xA5,0xA5}},//POWER CTRL\r
66         {LCM_SLEEP(1)},\r
67         //Gamma\r
68         {LCM_SEND(41), {39,0,0xC8,0x74,0x70,0x2C,0x3A,0x1C,0x11,0x17,0x06,0x24,0x29,\r
69                         0x2F,0x55,0x4B,0x5D,0x58,0x61,0x5D,0x57,0x50,\r
70                                   0x74,0x70,0x2C,0x3A,0x1C,0x11,0x17,0x06,0x24,0x29,\r
71                         0x2F,0x55,0x4B,0x5D,0x58,0x61,0x5D,0x57,0x50}},\r
72         {LCM_SLEEP(1)},\r
73         {LCM_SEND(19), {17,0,0xD4,0x1F,0x1E,0x1F,0x00,0x10,0x1F,0x1F,0x04,0x08,0x06,\r
74                         0x0A,0x1F,0x1F,0x1F,0x1F,0x1F}},                                //SET GIP_L\r
75         {LCM_SLEEP(1)},\r
76         {LCM_SEND(19), {17,0,0xD5,0x1F,0x1E,0x1F,0x01,0x11,0x1F,0x1F,0x05,0x09,0x07,\r
77                         0x0B,0x1F,0x1F,0x1F,0x1F,0x1F}},                                //SET GIP_R\r
78         {LCM_SLEEP(1)},\r
79         {LCM_SEND(19), {17,0,0xD6,0x1F,0x1F,0x1E,0x11,0x01,0x1F,0x1F,0x0B,0x07,0x09,\r
80                         0x05,0x1F,0x1F,0x1F,0x1F,0x1F}},                                //SET GIP_GS_L\r
81         {LCM_SLEEP(1)},\r
82         {LCM_SEND(19), {17,0,0xD7,0x1F,0x1F,0x1E,0x10,0x00,0x1F,0x1F,0x0A,0x06,0x08,\r
83                         0x04,0x1F,0x1F,0x1F,0x1F,0x1F}},                                //SET GIP_GS_R\r
84         {LCM_SLEEP(1)},\r
85         {LCM_SEND(23), {21,0,0xD8,0x20,0x02,0x0A,0x10,0x05,0x30,0x01,0x02,0x30,0x01,0x02,0x06,0x70,\r
86                         0x53,0x2C,0x73,0x09,0x06,0x70,0x08}},           //SET GIP1\r
87         {LCM_SLEEP(1)},\r
88         {LCM_SEND(22), {20,0,0xD9,0x00,0x0A,0x0A,0x88,0x00,0x00,0x06,0x7B,0x00,0x00,\r
89                         0x00,0x3B,0x2F,0x1F,0x00,0x00,0x00,0x03,0x7B}},                 //SET GIP2\r
90         {LCM_SLEEP(1)},\r
91         {LCM_SEND(1), {0x11}},//SLP OUT\r
92         {LCM_SLEEP(120)},\r
93         {LCM_SEND(1), {0x29}},//DISP ON\r
94         {LCM_SLEEP(50)},\r
95 \r
96  };\r
97 \r
98 static LCM_Init_Code disp_on =  {LCM_SEND(1), {0x29}};\r
99 \r
100 static LCM_Init_Code sleep_in[] =  {\r
101     {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x00}},\r
102     {LCM_SLEEP(1)},\r
103 \r
104     {LCM_SEND(1), {0x28}},\r
105     {LCM_SLEEP(120)},\r
106     {LCM_SEND(1), {0x10}},\r
107     {LCM_SLEEP(10)},\r
108     {LCM_SEND(8), {6, 0,0xFF,0xFF,0x98,0x06,0x04,0x01}},\r
109     {LCM_SLEEP(1)},\r
110 \r
111     {LCM_SEND(2), {0x58,0x91}},\r
112 };\r
113 \r
114 static LCM_Init_Code sleep_out[] =  {\r
115     {LCM_SEND(1), {0x11}},\r
116     {LCM_SLEEP(120)},\r
117     {LCM_SEND(1), {0x29}},\r
118     {LCM_SLEEP(20)},\r
119 };\r
120 \r
121 static LCM_Force_Cmd_Code rd_prep_code[]={\r
122         {0x39, {LCM_SEND(6), {4,0,0xBF,0x91,0x61,0xF2}}},\r
123         {0x37, {LCM_SEND(2), {0x3, 0}}},\r
124 };\r
125 \r
126 static LCM_Force_Cmd_Code rd_prep_code_1[]={\r
127         {0x37, {LCM_SEND(2), {0x1, 0}}},\r
128 };\r
129 static int32_t jd9161_mipi_init(struct panel_spec *self)\r
130 {\r
131         int32_t i;\r
132         LCM_Init_Code *init = init_data;\r
133         unsigned int tag;\r
134 \r
135         mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;\r
136         mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;\r
137         mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;\r
138 \r
139         printk( "kernel  jd9161_mipi_init\n");\r
140 \r
141         msleep(2);\r
142         mipi_set_cmd_mode();\r
143         mipi_eotp_set(1,0);\r
144 \r
145         for(i = 0; i < ARRAY_SIZE(init_data); i++){\r
146                 tag = (init->tag >>24);\r
147                 if(tag & LCM_TAG_SEND){\r
148                         mipi_gen_write(init->data, (init->tag & LCM_TAG_MASK));\r
149                         udelay(20);\r
150                 }else if(tag & LCM_TAG_SLEEP){\r
151                         //udelay((init->tag & LCM_TAG_MASK) * 1000);\r
152                                 msleep(init->tag & LCM_TAG_MASK);\r
153                 }\r
154                 init++;\r
155         }\r
156         mipi_eotp_set(1,1);\r
157 \r
158         return 0;\r
159 }\r
160 \r
161 static uint32_t jd9161_readid(struct panel_spec *self)\r
162 {\r
163         /*Jessica TODO: need read id*/\r
164         int32_t i = 0;\r
165         uint32_t j =0;\r
166         LCM_Force_Cmd_Code * rd_prepare = rd_prep_code;\r
167         uint8_t read_data[3] = {0};\r
168         int32_t read_rtn = 0;\r
169         unsigned int tag = 0;\r
170         mipi_set_cmd_mode_t mipi_set_cmd_mode = self->info.mipi->ops->mipi_set_cmd_mode;\r
171         mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;\r
172         mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;\r
173         mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;\r
174 \r
175         printk("kernel lcd_jd9161_mipi read id!\n");\r
176 #if 1\r
177         mipi_set_cmd_mode();\r
178         mipi_eotp_set(1,0);\r
179 \r
180         for(j = 0; j < 4; j++){\r
181                 rd_prepare = rd_prep_code;\r
182                 for(i = 0; i < ARRAY_SIZE(rd_prep_code); i++){\r
183                         tag = (rd_prepare->real_cmd_code.tag >> 24);\r
184                         if(tag & LCM_TAG_SEND){\r
185                                 mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));\r
186                                 udelay(20);\r
187                         }else if(tag & LCM_TAG_SLEEP){\r
188                                 msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));\r
189                         }\r
190                         rd_prepare++;\r
191                 }\r
192                 read_rtn = mipi_force_read(0x04, 3,(uint8_t *)read_data);\r
193                 printk("lcd_jd9161_mipi read id 0x04 value is 0x%x, 0x%x, 0x%x!\n", read_data[0], read_data[1], read_data[2]);\r
194 \r
195                 if((0x91 == read_data[0])){\r
196                         printk("lcd_jd9161_mipi read id success!\n");\r
197                         mipi_eotp_set(1,1);\r
198                         return 0x916100;\r
199                 }\r
200         }\r
201         mipi_eotp_set(1,1);\r
202         #endif\r
203         return 0x916100;\r
204 }\r
205 \r
206 static int32_t jd9161_enter_sleep(struct panel_spec *self, uint8_t is_sleep)\r
207 {\r
208         int32_t i;\r
209         LCM_Init_Code *sleep_in_out = NULL;\r
210         unsigned int tag;\r
211         int32_t size = 0;\r
212 \r
213         mipi_gen_write_t mipi_gen_write = self->info.mipi->ops->mipi_gen_write;\r
214         mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;\r
215 \r
216         printk("jd9161_enter_sleep, is_sleep = %d\n", is_sleep);\r
217 \r
218         if(is_sleep){\r
219                 sleep_in_out = sleep_in;\r
220                 size = ARRAY_SIZE(sleep_in);\r
221         }else{\r
222                 sleep_in_out = sleep_out;\r
223                 size = ARRAY_SIZE(sleep_out);\r
224         }\r
225         mipi_eotp_set(1,0);\r
226 \r
227         for(i = 0; i <size ; i++){\r
228                 tag = (sleep_in_out->tag >>24);\r
229                 if(tag & LCM_TAG_SEND){\r
230                         mipi_gen_write(sleep_in_out->data, (sleep_in_out->tag & LCM_TAG_MASK));\r
231                         udelay(20);\r
232                 }else if(tag & LCM_TAG_SLEEP){\r
233                         //udelay((sleep_in_out->tag & LCM_TAG_MASK) * 1000);\r
234                         msleep((sleep_in_out->tag & LCM_TAG_MASK));\r
235                 }\r
236                 sleep_in_out++;\r
237         }\r
238         return 0;\r
239 }\r
240 \r
241 static uint32_t jd9161_readpowermode(struct panel_spec *self)\r
242 {\r
243         int32_t i = 0;\r
244         uint32_t j =0;\r
245         LCM_Force_Cmd_Code * rd_prepare = rd_prep_code_1;\r
246         uint8_t read_data[1] = {0};\r
247         int32_t read_rtn = 0;\r
248         unsigned int tag = 0;\r
249         uint32_t reg_val_1 = 0;\r
250         uint32_t reg_val_2 = 0;\r
251 \r
252         mipi_force_write_t mipi_force_write = self->info.mipi->ops->mipi_force_write;\r
253         mipi_force_read_t mipi_force_read = self->info.mipi->ops->mipi_force_read;\r
254         mipi_eotp_set_t mipi_eotp_set = self->info.mipi->ops->mipi_eotp_set;\r
255 \r
256         pr_debug("lcd_jd9161_mipi read power mode!\n");\r
257         mipi_eotp_set(0,1);\r
258 \r
259         for(j = 0; j < 4; j++){\r
260                 rd_prepare = rd_prep_code_1;\r
261                 for(i = 0; i < ARRAY_SIZE(rd_prep_code_1); i++){\r
262                         tag = (rd_prepare->real_cmd_code.tag >> 24);\r
263                         if(tag & LCM_TAG_SEND){\r
264                                 mipi_force_write(rd_prepare->datatype, rd_prepare->real_cmd_code.data, (rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));\r
265                                 udelay(20);\r
266                         }else if(tag & LCM_TAG_SLEEP){\r
267                                 msleep((rd_prepare->real_cmd_code.tag & LCM_TAG_MASK));\r
268                         }\r
269                         rd_prepare++;\r
270                 }\r
271 \r
272                 read_rtn = mipi_force_read(0x0A, 1,(uint8_t *)read_data);\r
273                 //printk("lcd_jd9161 mipi read power mode 0x0A value is 0x%x! , read result(%d)\n", read_data[0], read_rtn);\r
274 \r
275                 if((0x9c == read_data[0])  && (0 == read_rtn)){\r
276                         pr_debug("lcd_jd9161_mipi read power mode success!\n");\r
277                         mipi_eotp_set(1,1);\r
278                         return 0x9c;\r
279                 }\r
280         }\r
281 \r
282         mipi_eotp_set(1,1);\r
283         return 0x0;\r
284 }\r
285 \r
286 \r
287 static uint32_t jd9161_check_esd(struct panel_spec *self)\r
288 {\r
289         uint32_t power_mode;\r
290 \r
291         pr_debug("jd9161_check_esd!\n");\r
292         mipi_set_lp_mode_t mipi_set_data_lp_mode = self->info.mipi->ops->mipi_set_data_lp_mode;\r
293         mipi_set_hs_mode_t mipi_set_data_hs_mode = self->info.mipi->ops->mipi_set_data_hs_mode;\r
294 \r
295         mipi_set_lp_mode_t mipi_set_lp_mode = self->info.mipi->ops->mipi_set_lp_mode;\r
296         mipi_set_hs_mode_t mipi_set_hs_mode = self->info.mipi->ops->mipi_set_hs_mode;\r
297         uint16_t work_mode = self->info.mipi->work_mode;\r
298 \r
299         if(SPRDFB_MIPI_MODE_CMD==work_mode){\r
300                 mipi_set_lp_mode();\r
301         }else{\r
302                 mipi_set_data_lp_mode();\r
303         }\r
304         power_mode = jd9161_readpowermode(self);\r
305         //power_mode = 0x0;\r
306         if(SPRDFB_MIPI_MODE_CMD==work_mode){\r
307                 mipi_set_hs_mode();\r
308         }else{\r
309                 mipi_set_data_hs_mode();\r
310         }\r
311         if(power_mode == 0x9c){\r
312                 pr_debug("jd9161_check_esd OK!\n");\r
313                 return 1;\r
314         }else{\r
315                 printk("jd9161_check_esd fail!(0x%x)\n", power_mode);\r
316                 return 0;\r
317         }\r
318 }\r
319 \r
320 \r
321 static struct panel_operations lcd_jd9161_mipi_operations = {\r
322         .panel_init = jd9161_mipi_init,\r
323         .panel_readid = jd9161_readid,\r
324         .panel_enter_sleep = jd9161_enter_sleep,\r
325         .panel_esd_check = jd9161_check_esd,\r
326 };\r
327
328 static struct timing_rgb lcd_jd9161_mipi_timing = {\r
329         .hfp = 20,  /* unit: pixel */// 100\r
330         .hbp = 20,//80\r
331         .hsync = 20,//6\r
332         .vfp = 6, /*unit: line*/\r
333         .vbp = 6,\r
334         .vsync =6, //6,\r
335 };\r
336 \r
337 static struct info_mipi lcd_jd9161_mipi_info = {\r
338         .work_mode  = SPRDFB_MIPI_MODE_VIDEO,\r
339         .video_bus_width = 24, /*18,16*/\r
340         .lan_number = 2,\r
341         .phy_feq = 450*1000, //500->10MHz,400->8M in lp mode\r
342         .h_sync_pol = SPRDFB_POLARITY_POS,\r
343         .v_sync_pol = SPRDFB_POLARITY_POS,\r
344         .de_pol = SPRDFB_POLARITY_POS,\r
345         .te_pol = SPRDFB_POLARITY_POS,\r
346         .color_mode_pol = SPRDFB_POLARITY_NEG,\r
347         .shut_down_pol = SPRDFB_POLARITY_NEG,\r
348         .timing = &lcd_jd9161_mipi_timing,\r
349         .ops = NULL,\r
350 };\r
351 \r
352 struct panel_spec lcd_jd9161_mipi_spec = {\r
353         //.cap = PANEL_CAP_NOT_TEAR_SYNC,\r
354         .width = 480,\r
355         .height = 800,\r
356         .fps = 60,\r
357         .type = LCD_MODE_DSI,\r
358         .direction = LCD_DIRECT_NORMAL,\r
359         .is_clean_lcd = true,\r
360         .reset_timing = {5, 15, 120},\r
361         .info = {\r
362                 .mipi = &lcd_jd9161_mipi_info\r
363         },\r
364         .ops = &lcd_jd9161_mipi_operations,\r
365 };\r
366 \r
367 struct panel_cfg lcd_jd9161_mipi = {\r
368         /* this panel can only be main lcd */\r
369         .dev_id = SPRDFB_MAINLCD_ID,\r
370         .lcd_id = 0x916100,\r
371         .lcd_name = "lcd_jd9161_mipi",\r
372         .panel = &lcd_jd9161_mipi_spec,\r
373 };\r
374 \r
375 static int __init lcd_jd9161_mipi_init(void)\r
376 {\r
377         return sprdfb_panel_register(&lcd_jd9161_mipi);\r
378 }\r
379 \r
380 subsys_initcall(lcd_jd9161_mipi_init);\r