xref: /OK3568_Linux_fs/kernel/arch/sh/boards/mach-kfr2r09/lcd_wqvga.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * KFR2R09 LCD panel support
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2009 Magnus Damm
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Register settings based on the out-of-tree t33fb.c driver
8*4882a593Smuzhiyun  * Copyright (C) 2008 Lineo Solutions, Inc.
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/err.h>
13*4882a593Smuzhiyun #include <linux/fb.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include <linux/gpio.h>
18*4882a593Smuzhiyun #include <video/sh_mobile_lcdc.h>
19*4882a593Smuzhiyun #include <mach/kfr2r09.h>
20*4882a593Smuzhiyun #include <cpu/sh7724.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /* The on-board LCD module is a Hitachi TX07D34VM0AAA. This module is made
23*4882a593Smuzhiyun  * up of a 240x400 LCD hooked up to a R61517 driver IC. The driver IC is
24*4882a593Smuzhiyun  * communicating with the main port of the LCDC using an 18-bit SYS interface.
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  * The device code for this LCD module is 0x01221517.
27*4882a593Smuzhiyun  */
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun static const unsigned char data_frame_if[] = {
30*4882a593Smuzhiyun 	0x02, /* WEMODE: 1=cont, 0=one-shot */
31*4882a593Smuzhiyun 	0x00, 0x00,
32*4882a593Smuzhiyun 	0x00, /* EPF, DFM */
33*4882a593Smuzhiyun 	0x02, /* RIM[1] : 1 (18bpp) */
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun static const unsigned char data_panel[] = {
37*4882a593Smuzhiyun 	0x0b,
38*4882a593Smuzhiyun 	0x63, /* 400 lines */
39*4882a593Smuzhiyun 	0x04, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00,
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun static const unsigned char data_timing[] = {
43*4882a593Smuzhiyun 	0x00, 0x00, 0x13, 0x08, 0x08,
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static const unsigned char data_timing_src[] = {
47*4882a593Smuzhiyun 	0x11, 0x01, 0x00, 0x01,
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun static const unsigned char data_gamma[] = {
51*4882a593Smuzhiyun 	0x01, 0x02, 0x08, 0x23,	0x03, 0x0c, 0x00, 0x06,	0x00, 0x00,
52*4882a593Smuzhiyun 	0x01, 0x00, 0x0c, 0x23, 0x03, 0x08, 0x02, 0x06, 0x00, 0x00,
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun static const unsigned char data_power[] = {
56*4882a593Smuzhiyun 	0x07, 0xc5, 0xdc, 0x02,	0x33, 0x0a,
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun 
read_reg(void * sohandle,struct sh_mobile_lcdc_sys_bus_ops * so)59*4882a593Smuzhiyun static unsigned long read_reg(void *sohandle,
60*4882a593Smuzhiyun 			      struct sh_mobile_lcdc_sys_bus_ops *so)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	return so->read_data(sohandle);
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
write_reg(void * sohandle,struct sh_mobile_lcdc_sys_bus_ops * so,int i,unsigned long v)65*4882a593Smuzhiyun static void write_reg(void *sohandle,
66*4882a593Smuzhiyun 		      struct sh_mobile_lcdc_sys_bus_ops *so,
67*4882a593Smuzhiyun 		      int i, unsigned long v)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	if (i)
70*4882a593Smuzhiyun 		so->write_data(sohandle, v); /* PTH4/LCDRS High [param, 17:0] */
71*4882a593Smuzhiyun 	else
72*4882a593Smuzhiyun 		so->write_index(sohandle, v); /* PTH4/LCDRS Low [cmd, 7:0] */
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
write_data(void * sohandle,struct sh_mobile_lcdc_sys_bus_ops * so,unsigned char const * data,int no_data)75*4882a593Smuzhiyun static void write_data(void *sohandle,
76*4882a593Smuzhiyun 		       struct sh_mobile_lcdc_sys_bus_ops *so,
77*4882a593Smuzhiyun 		       unsigned char const *data, int no_data)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	int i;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	for (i = 0; i < no_data; i++)
82*4882a593Smuzhiyun 		write_reg(sohandle, so, 1, data[i]);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
read_device_code(void * sohandle,struct sh_mobile_lcdc_sys_bus_ops * so)85*4882a593Smuzhiyun static unsigned long read_device_code(void *sohandle,
86*4882a593Smuzhiyun 				      struct sh_mobile_lcdc_sys_bus_ops *so)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	unsigned long device_code;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	/* access protect OFF */
91*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xb0);
92*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	/* deep standby OFF */
95*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xb1);
96*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	/* device code command */
99*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xbf);
100*4882a593Smuzhiyun 	mdelay(50);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	/* dummy read */
103*4882a593Smuzhiyun 	read_reg(sohandle, so);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	/* read device code */
106*4882a593Smuzhiyun 	device_code = ((read_reg(sohandle, so) & 0xff) << 24);
107*4882a593Smuzhiyun 	device_code |= ((read_reg(sohandle, so) & 0xff) << 16);
108*4882a593Smuzhiyun 	device_code |= ((read_reg(sohandle, so) & 0xff) << 8);
109*4882a593Smuzhiyun 	device_code |= (read_reg(sohandle, so) & 0xff);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	return device_code;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
write_memory_start(void * sohandle,struct sh_mobile_lcdc_sys_bus_ops * so)114*4882a593Smuzhiyun static void write_memory_start(void *sohandle,
115*4882a593Smuzhiyun 			       struct sh_mobile_lcdc_sys_bus_ops *so)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0x2c);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
clear_memory(void * sohandle,struct sh_mobile_lcdc_sys_bus_ops * so)120*4882a593Smuzhiyun static void clear_memory(void *sohandle,
121*4882a593Smuzhiyun 			 struct sh_mobile_lcdc_sys_bus_ops *so)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	int i;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	/* write start */
126*4882a593Smuzhiyun 	write_memory_start(sohandle, so);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	/* paint it black */
129*4882a593Smuzhiyun 	for (i = 0; i < (240 * 400); i++)
130*4882a593Smuzhiyun 		write_reg(sohandle, so, 1, 0x00);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
display_on(void * sohandle,struct sh_mobile_lcdc_sys_bus_ops * so)133*4882a593Smuzhiyun static void display_on(void *sohandle,
134*4882a593Smuzhiyun 		       struct sh_mobile_lcdc_sys_bus_ops *so)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	/* access protect off */
137*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xb0);
138*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	/* exit deep standby mode */
141*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xb1);
142*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	/* frame memory I/F */
145*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xb3);
146*4882a593Smuzhiyun 	write_data(sohandle, so, data_frame_if, ARRAY_SIZE(data_frame_if));
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	/* display mode and frame memory write mode */
149*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xb4);
150*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00); /* DBI, internal clock */
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	/* panel */
153*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xc0);
154*4882a593Smuzhiyun 	write_data(sohandle, so, data_panel, ARRAY_SIZE(data_panel));
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	/* timing (normal) */
157*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xc1);
158*4882a593Smuzhiyun 	write_data(sohandle, so, data_timing, ARRAY_SIZE(data_timing));
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/* timing (partial) */
161*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xc2);
162*4882a593Smuzhiyun 	write_data(sohandle, so, data_timing, ARRAY_SIZE(data_timing));
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	/* timing (idle) */
165*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xc3);
166*4882a593Smuzhiyun 	write_data(sohandle, so, data_timing, ARRAY_SIZE(data_timing));
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	/* timing (source/VCOM/gate driving) */
169*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xc4);
170*4882a593Smuzhiyun 	write_data(sohandle, so, data_timing_src, ARRAY_SIZE(data_timing_src));
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	/* gamma (red) */
173*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xc8);
174*4882a593Smuzhiyun 	write_data(sohandle, so, data_gamma, ARRAY_SIZE(data_gamma));
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	/* gamma (green) */
177*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xc9);
178*4882a593Smuzhiyun 	write_data(sohandle, so, data_gamma, ARRAY_SIZE(data_gamma));
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	/* gamma (blue) */
181*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xca);
182*4882a593Smuzhiyun 	write_data(sohandle, so, data_gamma, ARRAY_SIZE(data_gamma));
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	/* power (common) */
185*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xd0);
186*4882a593Smuzhiyun 	write_data(sohandle, so, data_power, ARRAY_SIZE(data_power));
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	/* VCOM */
189*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xd1);
190*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
191*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x0f);
192*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x02);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	/* power (normal) */
195*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xd2);
196*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x63);
197*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x24);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	/* power (partial) */
200*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xd3);
201*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x63);
202*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x24);
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	/* power (idle) */
205*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xd4);
206*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x63);
207*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x24);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0xd8);
210*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x77);
211*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x77);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	/* TE signal */
214*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0x35);
215*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	/* TE signal line */
218*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0x44);
219*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
220*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	/* column address */
223*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0x2a);
224*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
225*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
226*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
227*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0xef);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	/* page address */
230*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0x2b);
231*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
232*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x00);
233*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x01);
234*4882a593Smuzhiyun 	write_reg(sohandle, so, 1, 0x8f);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	/* exit sleep mode */
237*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0x11);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	mdelay(120);
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	/* clear vram */
242*4882a593Smuzhiyun 	clear_memory(sohandle, so);
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	/* display ON */
245*4882a593Smuzhiyun 	write_reg(sohandle, so, 0, 0x29);
246*4882a593Smuzhiyun 	mdelay(1);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	write_memory_start(sohandle, so);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
kfr2r09_lcd_setup(void * sohandle,struct sh_mobile_lcdc_sys_bus_ops * so)251*4882a593Smuzhiyun int kfr2r09_lcd_setup(void *sohandle, struct sh_mobile_lcdc_sys_bus_ops *so)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	/* power on */
254*4882a593Smuzhiyun 	gpio_set_value(GPIO_PTF4, 0);  /* PROTECT/ -> L */
255*4882a593Smuzhiyun 	gpio_set_value(GPIO_PTE4, 0);  /* LCD_RST/ -> L */
256*4882a593Smuzhiyun 	gpio_set_value(GPIO_PTF4, 1);  /* PROTECT/ -> H */
257*4882a593Smuzhiyun 	udelay(1100);
258*4882a593Smuzhiyun 	gpio_set_value(GPIO_PTE4, 1);  /* LCD_RST/ -> H */
259*4882a593Smuzhiyun 	udelay(10);
260*4882a593Smuzhiyun 	gpio_set_value(GPIO_PTF4, 0);  /* PROTECT/ -> L */
261*4882a593Smuzhiyun 	mdelay(20);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	if (read_device_code(sohandle, so) != 0x01221517)
264*4882a593Smuzhiyun 		return -ENODEV;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	pr_info("KFR2R09 WQVGA LCD Module detected.\n");
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	display_on(sohandle, so);
269*4882a593Smuzhiyun 	return 0;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
kfr2r09_lcd_start(void * sohandle,struct sh_mobile_lcdc_sys_bus_ops * so)272*4882a593Smuzhiyun void kfr2r09_lcd_start(void *sohandle, struct sh_mobile_lcdc_sys_bus_ops *so)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	write_memory_start(sohandle, so);
275*4882a593Smuzhiyun }
276