1 /* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 #include <linux/memory.h>
21 #include <linux/kernel.h>
22 #include <linux/sched.h>
23 #include <linux/time.h>
24 #include <linux/init.h>
25 #include <linux/interrupt.h>
26 #include "linux/proc_fs.h"
28 #include <linux/delay.h>
30 #include <mach/hardware.h>
33 #include <asm/system.h>
34 #include <asm/mach-types.h>
36 /* The following are for MSM5100 on Gator
40 #endif /* FEATURE_PM1000 */
41 /* The following are for MSM6050 on Bambi
43 #ifdef FEATURE_PMIC_LCDKBD_LED_DRIVER
45 #endif /* FEATURE_PMIC_LCDKBD_LED_DRIVER */
47 #ifdef DISP_DEVICE_18BPP
48 #undef DISP_DEVICE_18BPP
49 #define DISP_DEVICE_16BPP
52 #define QCIF_WIDTH 176
53 #define QCIF_HEIGHT 220
55 static void *DISP_CMD_PORT
;
56 static void *DISP_DATA_PORT
;
58 #define DISP_CMD_DISON 0xaf
59 #define DISP_CMD_DISOFF 0xae
60 #define DISP_CMD_DISNOR 0xa6
61 #define DISP_CMD_DISINV 0xa7
62 #define DISP_CMD_DISCTL 0xca
63 #define DISP_CMD_GCP64 0xcb
64 #define DISP_CMD_GCP16 0xcc
65 #define DISP_CMD_GSSET 0xcd
66 #define DISP_GS_2 0x02
67 #define DISP_GS_16 0x01
68 #define DISP_GS_64 0x00
69 #define DISP_CMD_SLPIN 0x95
70 #define DISP_CMD_SLPOUT 0x94
71 #define DISP_CMD_SD_PSET 0x75
72 #define DISP_CMD_MD_PSET 0x76
73 #define DISP_CMD_SD_CSET 0x15
74 #define DISP_CMD_MD_CSET 0x16
75 #define DISP_CMD_DATCTL 0xbc
76 #define DISP_DATCTL_666 0x08
77 #define DISP_DATCTL_565 0x28
78 #define DISP_DATCTL_444 0x38
79 #define DISP_CMD_RAMWR 0x5c
80 #define DISP_CMD_RAMRD 0x5d
81 #define DISP_CMD_PTLIN 0xa8
82 #define DISP_CMD_PTLOUT 0xa9
83 #define DISP_CMD_ASCSET 0xaa
84 #define DISP_CMD_SCSTART 0xab
85 #define DISP_CMD_VOLCTL 0xc6
86 #define DISP_VOLCTL_TONE 0x80
87 #define DISP_CMD_NOp 0x25
88 #define DISP_CMD_OSSEL 0xd0
89 #define DISP_CMD_3500KSET 0xd1
90 #define DISP_CMD_3500KEND 0xd2
91 #define DISP_CMD_14MSET 0xd3
92 #define DISP_CMD_14MEND 0xd4
94 #define DISP_CMD_OUT(cmd) outpw(DISP_CMD_PORT, cmd);
96 #define DISP_DATA_OUT(data) outpw(DISP_DATA_PORT, data);
98 #define DISP_DATA_IN() inpw(DISP_DATA_PORT);
100 /* Epson device column number starts at 2
102 #define DISP_SET_RECT(ulhc_row, lrhc_row, ulhc_col, lrhc_col) \
103 DISP_CMD_OUT(DISP_CMD_SD_PSET) \
104 DISP_DATA_OUT((ulhc_row) & 0xFF) \
105 DISP_DATA_OUT((ulhc_row) >> 8) \
106 DISP_DATA_OUT((lrhc_row) & 0xFF) \
107 DISP_DATA_OUT((lrhc_row) >> 8) \
108 DISP_CMD_OUT(DISP_CMD_SD_CSET) \
109 DISP_DATA_OUT(((ulhc_col)+2) & 0xFF) \
110 DISP_DATA_OUT(((ulhc_col)+2) >> 8) \
111 DISP_DATA_OUT(((lrhc_col)+2) & 0xFF) \
112 DISP_DATA_OUT(((lrhc_col)+2) >> 8)
114 #define DISP_MIN_CONTRAST 0
115 #define DISP_MAX_CONTRAST 127
116 #define DISP_DEFAULT_CONTRAST 80
118 #define DISP_MIN_BACKLIGHT 0
119 #define DISP_MAX_BACKLIGHT 15
120 #define DISP_DEFAULT_BACKLIGHT 2
122 #define WAIT_SEC(sec) mdelay((sec)/1000)
124 static word disp_area_start_row
;
125 static word disp_area_end_row
;
126 static byte disp_contrast
= DISP_DEFAULT_CONTRAST
;
127 static boolean disp_powered_up
;
128 static boolean disp_initialized
= FALSE
;
129 /* For some reason the contrast set at init time is not good. Need to do
132 static boolean display_on
= FALSE
;
133 static void epsonQcif_disp_init(struct platform_device
*pdev
);
134 static void epsonQcif_disp_set_contrast(word contrast
);
135 static void epsonQcif_disp_set_display_area(word start_row
, word end_row
);
136 static int epsonQcif_disp_off(struct platform_device
*pdev
);
137 static int epsonQcif_disp_on(struct platform_device
*pdev
);
138 static void epsonQcif_disp_set_rect(int x
, int y
, int xres
, int yres
);
140 volatile word databack
;
141 static void epsonQcif_disp_init(struct platform_device
*pdev
)
143 struct msm_fb_data_type
*mfd
;
147 if (disp_initialized
)
150 mfd
= platform_get_drvdata(pdev
);
152 DISP_CMD_PORT
= mfd
->cmd_port
;
153 DISP_DATA_PORT
= mfd
->data_port
;
156 DISP_CMD_OUT(DISP_CMD_SLPIN
);
159 DISP_CMD_OUT(DISP_CMD_DISOFF
);
162 DISP_CMD_OUT(DISP_CMD_DISNOR
);
165 DISP_CMD_OUT(DISP_CMD_DATCTL
);
166 DISP_DATA_OUT(DISP_DATCTL_565
);
168 /* Set display timing */
169 DISP_CMD_OUT(DISP_CMD_DISCTL
);
170 DISP_DATA_OUT(0x1c); /* p1 */
171 DISP_DATA_OUT(0x02); /* p1 */
172 DISP_DATA_OUT(0x82); /* p2 */
173 DISP_DATA_OUT(0x00); /* p3 */
174 DISP_DATA_OUT(0x00); /* p4 */
175 DISP_DATA_OUT(0xe0); /* p5 */
176 DISP_DATA_OUT(0x00); /* p5 */
177 DISP_DATA_OUT(0xdc); /* p6 */
178 DISP_DATA_OUT(0x00); /* p6 */
179 DISP_DATA_OUT(0x02); /* p7 */
180 DISP_DATA_OUT(0x00); /* p8 */
182 /* Set 64 gray scale level */
183 DISP_CMD_OUT(DISP_CMD_GCP64
);
184 DISP_DATA_OUT(0x08); /* p01 */
186 DISP_DATA_OUT(0x2a); /* p02 */
188 DISP_DATA_OUT(0x4e); /* p03 */
190 DISP_DATA_OUT(0x6b); /* p04 */
192 DISP_DATA_OUT(0x88); /* p05 */
194 DISP_DATA_OUT(0xa3); /* p06 */
196 DISP_DATA_OUT(0xba); /* p07 */
198 DISP_DATA_OUT(0xd1); /* p08 */
200 DISP_DATA_OUT(0xe5); /* p09 */
202 DISP_DATA_OUT(0xf3); /* p10 */
204 DISP_DATA_OUT(0x03); /* p11 */
206 DISP_DATA_OUT(0x13); /* p12 */
208 DISP_DATA_OUT(0x22); /* p13 */
210 DISP_DATA_OUT(0x2f); /* p14 */
212 DISP_DATA_OUT(0x3b); /* p15 */
214 DISP_DATA_OUT(0x46); /* p16 */
216 DISP_DATA_OUT(0x51); /* p17 */
218 DISP_DATA_OUT(0x5b); /* p18 */
220 DISP_DATA_OUT(0x64); /* p19 */
222 DISP_DATA_OUT(0x6c); /* p20 */
224 DISP_DATA_OUT(0x74); /* p21 */
226 DISP_DATA_OUT(0x7c); /* p22 */
228 DISP_DATA_OUT(0x83); /* p23 */
230 DISP_DATA_OUT(0x8a); /* p24 */
232 DISP_DATA_OUT(0x91); /* p25 */
234 DISP_DATA_OUT(0x98); /* p26 */
236 DISP_DATA_OUT(0x9f); /* p27 */
238 DISP_DATA_OUT(0xa6); /* p28 */
240 DISP_DATA_OUT(0xac); /* p29 */
242 DISP_DATA_OUT(0xb2); /* p30 */
244 DISP_DATA_OUT(0xb7); /* p31 */
246 DISP_DATA_OUT(0xbc); /* p32 */
248 DISP_DATA_OUT(0xc1); /* p33 */
250 DISP_DATA_OUT(0xc6); /* p34 */
252 DISP_DATA_OUT(0xcb); /* p35 */
254 DISP_DATA_OUT(0xd0); /* p36 */
256 DISP_DATA_OUT(0xd4); /* p37 */
258 DISP_DATA_OUT(0xd8); /* p38 */
260 DISP_DATA_OUT(0xdc); /* p39 */
262 DISP_DATA_OUT(0xe0); /* p40 */
264 DISP_DATA_OUT(0xe4); /* p41 */
266 DISP_DATA_OUT(0xe8); /* p42 */
268 DISP_DATA_OUT(0xec); /* p43 */
270 DISP_DATA_OUT(0xf0); /* p44 */
272 DISP_DATA_OUT(0xf4); /* p45 */
274 DISP_DATA_OUT(0xf8); /* p46 */
276 DISP_DATA_OUT(0xfb); /* p47 */
278 DISP_DATA_OUT(0xfe); /* p48 */
280 DISP_DATA_OUT(0x01); /* p49 */
282 DISP_DATA_OUT(0x03); /* p50 */
284 DISP_DATA_OUT(0x05); /* p51 */
286 DISP_DATA_OUT(0x07); /* p52 */
288 DISP_DATA_OUT(0x09); /* p53 */
290 DISP_DATA_OUT(0x0b); /* p54 */
292 DISP_DATA_OUT(0x0d); /* p55 */
294 DISP_DATA_OUT(0x0f); /* p56 */
296 DISP_DATA_OUT(0x11); /* p57 */
298 DISP_DATA_OUT(0x13); /* p58 */
300 DISP_DATA_OUT(0x15); /* p59 */
302 DISP_DATA_OUT(0x17); /* p60 */
304 DISP_DATA_OUT(0x19); /* p61 */
306 DISP_DATA_OUT(0x1b); /* p62 */
308 DISP_DATA_OUT(0x1c); /* p63 */
311 /* Set 16 gray scale level */
312 DISP_CMD_OUT(DISP_CMD_GCP16
);
313 DISP_DATA_OUT(0x1a); /* p01 */
314 DISP_DATA_OUT(0x32); /* p02 */
315 DISP_DATA_OUT(0x42); /* p03 */
316 DISP_DATA_OUT(0x4c); /* p04 */
317 DISP_DATA_OUT(0x58); /* p05 */
318 DISP_DATA_OUT(0x5f); /* p06 */
319 DISP_DATA_OUT(0x66); /* p07 */
320 DISP_DATA_OUT(0x6b); /* p08 */
321 DISP_DATA_OUT(0x70); /* p09 */
322 DISP_DATA_OUT(0x74); /* p10 */
323 DISP_DATA_OUT(0x78); /* p11 */
324 DISP_DATA_OUT(0x7b); /* p12 */
325 DISP_DATA_OUT(0x7e); /* p13 */
326 DISP_DATA_OUT(0x80); /* p14 */
327 DISP_DATA_OUT(0x82); /* p15 */
330 DISP_CMD_OUT(DISP_CMD_MD_CSET
);
337 DISP_CMD_OUT(DISP_CMD_MD_PSET
);
344 DISP_CMD_OUT(DISP_CMD_SD_CSET
);
347 DISP_DATA_OUT((QCIF_WIDTH
+ 1) & 0xFF);
348 DISP_DATA_OUT((QCIF_WIDTH
+ 1) >> 8);
351 DISP_CMD_OUT(DISP_CMD_SD_PSET
);
354 DISP_DATA_OUT((QCIF_HEIGHT
- 1) & 0xFF);
355 DISP_DATA_OUT((QCIF_HEIGHT
- 1) >> 8);
357 /* Set 64 gray scales */
358 DISP_CMD_OUT(DISP_CMD_GSSET
);
359 DISP_DATA_OUT(DISP_GS_64
);
361 DISP_CMD_OUT(DISP_CMD_OSSEL
);
365 DISP_CMD_OUT(DISP_CMD_SLPOUT
);
369 /* Initialize power IC */
370 DISP_CMD_OUT(DISP_CMD_VOLCTL
);
371 DISP_DATA_OUT(DISP_VOLCTL_TONE
);
375 /* Set electronic volume, d'xx */
376 DISP_CMD_OUT(DISP_CMD_VOLCTL
);
377 DISP_DATA_OUT(DISP_DEFAULT_CONTRAST
); /* value from 0 to 127 */
379 /* Initialize display data */
380 DISP_SET_RECT(0, (QCIF_HEIGHT
- 1), 0, (QCIF_WIDTH
- 1));
381 DISP_CMD_OUT(DISP_CMD_RAMWR
);
382 for (i
= 0; i
< QCIF_HEIGHT
* QCIF_WIDTH
; i
++)
383 DISP_DATA_OUT(0xffff);
385 DISP_CMD_OUT(DISP_CMD_RAMRD
);
386 databack
= DISP_DATA_IN();
387 databack
= DISP_DATA_IN();
388 databack
= DISP_DATA_IN();
389 databack
= DISP_DATA_IN();
393 DISP_CMD_OUT(DISP_CMD_DISON
);
395 disp_area_start_row
= 0;
396 disp_area_end_row
= QCIF_HEIGHT
- 1;
397 disp_powered_up
= TRUE
;
398 disp_initialized
= TRUE
;
399 epsonQcif_disp_set_display_area(0, QCIF_HEIGHT
- 1);
403 static void epsonQcif_disp_set_rect(int x
, int y
, int xres
, int yres
)
405 if (!disp_initialized
)
408 DISP_SET_RECT(y
, y
+ yres
- 1, x
, x
+ xres
- 1);
409 DISP_CMD_OUT(DISP_CMD_RAMWR
);
412 static void epsonQcif_disp_set_display_area(word start_row
, word end_row
)
414 if (!disp_initialized
)
417 if ((start_row
== disp_area_start_row
)
418 && (end_row
== disp_area_end_row
))
420 disp_area_start_row
= start_row
;
421 disp_area_end_row
= end_row
;
425 if (end_row
>= QCIF_HEIGHT
)
426 end_row
= QCIF_HEIGHT
- 1;
427 if (start_row
> end_row
)
430 /* When display is not the full screen, gray scale is set to
431 ** 2; otherwise it is set to 64.
433 if ((start_row
== 0) && (end_row
== (QCIF_HEIGHT
- 1))) {
434 /* The whole screen */
435 DISP_CMD_OUT(DISP_CMD_PTLOUT
);
437 DISP_CMD_OUT(DISP_CMD_DISOFF
);
439 DISP_CMD_OUT(DISP_CMD_GSSET
);
440 DISP_DATA_OUT(DISP_GS_64
);
442 DISP_CMD_OUT(DISP_CMD_DISON
);
445 DISP_CMD_OUT(DISP_CMD_PTLIN
);
446 DISP_DATA_OUT(start_row
);
447 DISP_DATA_OUT(start_row
>> 8);
448 DISP_DATA_OUT(end_row
);
449 DISP_DATA_OUT(end_row
>> 8);
450 DISP_CMD_OUT(DISP_CMD_GSSET
);
451 DISP_DATA_OUT(DISP_GS_2
);
455 static int epsonQcif_disp_off(struct platform_device
*pdev
)
457 if (!disp_initialized
)
458 epsonQcif_disp_init(pdev
);
461 DISP_CMD_OUT(DISP_CMD_DISOFF
);
462 DISP_CMD_OUT(DISP_CMD_SLPIN
);
469 static int epsonQcif_disp_on(struct platform_device
*pdev
)
471 if (!disp_initialized
)
472 epsonQcif_disp_init(pdev
);
475 DISP_CMD_OUT(DISP_CMD_SLPOUT
);
477 DISP_CMD_OUT(DISP_CMD_DISON
);
478 epsonQcif_disp_set_contrast(disp_contrast
);
485 static void epsonQcif_disp_set_contrast(word contrast
)
487 if (!disp_initialized
)
490 /* Initialize power IC, d'24 */
491 DISP_CMD_OUT(DISP_CMD_VOLCTL
);
492 DISP_DATA_OUT(DISP_VOLCTL_TONE
);
496 /* Set electronic volume, d'xx */
497 DISP_CMD_OUT(DISP_CMD_VOLCTL
);
500 DISP_DATA_OUT(contrast
); /* value from 0 to 127 */
501 disp_contrast
= (byte
) contrast
;
502 } /* End disp_set_contrast */
504 static void epsonQcif_disp_clear_screen_area(
505 word start_row
, word end_row
, word start_column
, word end_column
) {
508 /* Clear the display screen */
509 DISP_SET_RECT(start_row
, end_row
, start_column
, end_column
);
510 DISP_CMD_OUT(DISP_CMD_RAMWR
);
511 i
= (end_row
- start_row
+ 1) * (end_column
- start_column
+ 1);
513 DISP_DATA_OUT(0xffff);
516 static int __init
epsonQcif_probe(struct platform_device
*pdev
)
518 msm_fb_add_device(pdev
);
523 static struct platform_driver this_driver
= {
524 .probe
= epsonQcif_probe
,
526 .name
= "ebi2_epson_qcif",
530 static struct msm_fb_panel_data epsonQcif_panel_data
= {
531 .on
= epsonQcif_disp_on
,
532 .off
= epsonQcif_disp_off
,
533 .set_rect
= epsonQcif_disp_set_rect
,
536 static struct platform_device this_device
= {
537 .name
= "ebi2_epson_qcif",
540 .platform_data
= &epsonQcif_panel_data
,
544 static int __init
epsonQcif_init(void)
547 struct msm_panel_info
*pinfo
;
549 ret
= platform_driver_register(&this_driver
);
551 pinfo
= &epsonQcif_panel_data
.panel_info
;
552 pinfo
->xres
= QCIF_WIDTH
;
553 pinfo
->yres
= QCIF_HEIGHT
;
554 pinfo
->type
= EBI2_PANEL
;
555 pinfo
->pdest
= DISPLAY_2
;
556 pinfo
->wait_cycle
= 0x808000;
559 pinfo
->lcd
.vsync_enable
= FALSE
;
561 ret
= platform_device_register(&this_device
);
563 platform_driver_unregister(&this_driver
);
569 module_init(epsonQcif_init
);