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);