xref: /OK3568_Linux_fs/kernel/drivers/video/backlight/vgg2432a4.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /* drivers/video/backlight/vgg2432a4.c
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * VGG2432A4 (ILI9320) LCD controller driver.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright 2007 Simtec Electronics
7*4882a593Smuzhiyun  *	http://armlinux.simtec.co.uk/
8*4882a593Smuzhiyun  *	Ben Dooks <ben@simtec.co.uk>
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/lcd.h>
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <linux/spi/spi.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <video/ili9320.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include "ili9320.h"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /* Device initialisation sequences */
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun static const struct ili9320_reg vgg_init1[] = {
27*4882a593Smuzhiyun 	{
28*4882a593Smuzhiyun 		.address = ILI9320_POWER1,
29*4882a593Smuzhiyun 		.value	 = ILI9320_POWER1_AP(0) | ILI9320_POWER1_BT(0),
30*4882a593Smuzhiyun 	}, {
31*4882a593Smuzhiyun 		.address = ILI9320_POWER2,
32*4882a593Smuzhiyun 		.value	 = (ILI9320_POWER2_VC(7) |
33*4882a593Smuzhiyun 			    ILI9320_POWER2_DC0(0) | ILI9320_POWER2_DC1(0)),
34*4882a593Smuzhiyun 	}, {
35*4882a593Smuzhiyun 		.address = ILI9320_POWER3,
36*4882a593Smuzhiyun 		.value	 = ILI9320_POWER3_VRH(0),
37*4882a593Smuzhiyun 	}, {
38*4882a593Smuzhiyun 		.address = ILI9320_POWER4,
39*4882a593Smuzhiyun 		.value	 = ILI9320_POWER4_VREOUT(0),
40*4882a593Smuzhiyun 	},
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun static const struct ili9320_reg vgg_init2[] = {
44*4882a593Smuzhiyun 	{
45*4882a593Smuzhiyun 		.address = ILI9320_POWER1,
46*4882a593Smuzhiyun 		.value   = (ILI9320_POWER1_AP(3) | ILI9320_POWER1_APE |
47*4882a593Smuzhiyun 			    ILI9320_POWER1_BT(7) | ILI9320_POWER1_SAP),
48*4882a593Smuzhiyun 	}, {
49*4882a593Smuzhiyun 		.address = ILI9320_POWER2,
50*4882a593Smuzhiyun 		.value   = ILI9320_POWER2_VC(7) | ILI9320_POWER2_DC0(3),
51*4882a593Smuzhiyun 	}
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun static const struct ili9320_reg vgg_gamma[] = {
55*4882a593Smuzhiyun 	{
56*4882a593Smuzhiyun 		.address = ILI9320_GAMMA1,
57*4882a593Smuzhiyun 		.value	 = 0x0000,
58*4882a593Smuzhiyun 	}, {
59*4882a593Smuzhiyun 		.address = ILI9320_GAMMA2,
60*4882a593Smuzhiyun 		.value   = 0x0505,
61*4882a593Smuzhiyun 	}, {
62*4882a593Smuzhiyun 		.address = ILI9320_GAMMA3,
63*4882a593Smuzhiyun 		.value	 = 0x0004,
64*4882a593Smuzhiyun 	}, {
65*4882a593Smuzhiyun 		.address = ILI9320_GAMMA4,
66*4882a593Smuzhiyun 		.value	 = 0x0006,
67*4882a593Smuzhiyun 	}, {
68*4882a593Smuzhiyun 		.address = ILI9320_GAMMA5,
69*4882a593Smuzhiyun 		.value	 = 0x0707,
70*4882a593Smuzhiyun 	}, {
71*4882a593Smuzhiyun 		.address = ILI9320_GAMMA6,
72*4882a593Smuzhiyun 		.value	 = 0x0105,
73*4882a593Smuzhiyun 	}, {
74*4882a593Smuzhiyun 		.address = ILI9320_GAMMA7,
75*4882a593Smuzhiyun 		.value	 = 0x0002,
76*4882a593Smuzhiyun 	}, {
77*4882a593Smuzhiyun 		.address = ILI9320_GAMMA8,
78*4882a593Smuzhiyun 		.value	 = 0x0707,
79*4882a593Smuzhiyun 	}, {
80*4882a593Smuzhiyun 		.address = ILI9320_GAMMA9,
81*4882a593Smuzhiyun 		.value	 = 0x0704,
82*4882a593Smuzhiyun 	}, {
83*4882a593Smuzhiyun 		.address = ILI9320_GAMMA10,
84*4882a593Smuzhiyun 		.value	 = 0x807,
85*4882a593Smuzhiyun 	}
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun static const struct ili9320_reg vgg_init0[] = {
90*4882a593Smuzhiyun 	[0]	= {
91*4882a593Smuzhiyun 		/* set direction and scan mode gate */
92*4882a593Smuzhiyun 		.address = ILI9320_DRIVER,
93*4882a593Smuzhiyun 		.value	 = ILI9320_DRIVER_SS,
94*4882a593Smuzhiyun 	}, {
95*4882a593Smuzhiyun 		.address = ILI9320_DRIVEWAVE,
96*4882a593Smuzhiyun 		.value	 = (ILI9320_DRIVEWAVE_MUSTSET |
97*4882a593Smuzhiyun 			    ILI9320_DRIVEWAVE_EOR | ILI9320_DRIVEWAVE_BC),
98*4882a593Smuzhiyun 	}, {
99*4882a593Smuzhiyun 		.address = ILI9320_ENTRYMODE,
100*4882a593Smuzhiyun 		.value	 = ILI9320_ENTRYMODE_ID(3) | ILI9320_ENTRYMODE_BGR,
101*4882a593Smuzhiyun 	}, {
102*4882a593Smuzhiyun 		.address = ILI9320_RESIZING,
103*4882a593Smuzhiyun 		.value	 = 0x0,
104*4882a593Smuzhiyun 	},
105*4882a593Smuzhiyun };
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 
vgg2432a4_lcd_init(struct ili9320 * lcd,struct ili9320_platdata * cfg)108*4882a593Smuzhiyun static int vgg2432a4_lcd_init(struct ili9320 *lcd,
109*4882a593Smuzhiyun 			      struct ili9320_platdata *cfg)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	unsigned int addr;
112*4882a593Smuzhiyun 	int ret;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	/* Set VCore before anything else (VGG243237-6UFLWA) */
115*4882a593Smuzhiyun 	ret = ili9320_write(lcd, 0x00e5, 0x8000);
116*4882a593Smuzhiyun 	if (ret)
117*4882a593Smuzhiyun 		goto err_initial;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	/* Start the oscillator up before we can do anything else. */
120*4882a593Smuzhiyun 	ret = ili9320_write(lcd, ILI9320_OSCILATION, ILI9320_OSCILATION_OSC);
121*4882a593Smuzhiyun 	if (ret)
122*4882a593Smuzhiyun 		goto err_initial;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	/* must wait at-lesat 10ms after starting */
125*4882a593Smuzhiyun 	mdelay(15);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	ret = ili9320_write_regs(lcd, vgg_init0, ARRAY_SIZE(vgg_init0));
128*4882a593Smuzhiyun 	if (ret != 0)
129*4882a593Smuzhiyun 		goto err_initial;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_DISPLAY2, cfg->display2);
132*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_DISPLAY3, cfg->display3);
133*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_DISPLAY4, cfg->display4);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_RGB_IF1, cfg->rgb_if1);
136*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_FRAMEMAKER, 0x0);
137*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_RGB_IF2, cfg->rgb_if2);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	ret = ili9320_write_regs(lcd, vgg_init1, ARRAY_SIZE(vgg_init1));
140*4882a593Smuzhiyun 	if (ret != 0)
141*4882a593Smuzhiyun 		goto err_vgg;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	mdelay(300);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	ret = ili9320_write_regs(lcd, vgg_init2, ARRAY_SIZE(vgg_init2));
146*4882a593Smuzhiyun 	if (ret != 0)
147*4882a593Smuzhiyun 		goto err_vgg2;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	mdelay(100);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_POWER3, 0x13c);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	mdelay(100);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_POWER4, 0x1c00);
156*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_POWER7, 0x000e);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	mdelay(100);
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_GRAM_HORIZ_ADDR, 0x00);
161*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_GRAM_VERT_ADD, 0x00);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	ret = ili9320_write_regs(lcd, vgg_gamma, ARRAY_SIZE(vgg_gamma));
164*4882a593Smuzhiyun 	if (ret != 0)
165*4882a593Smuzhiyun 		goto err_vgg3;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_HORIZ_START, 0x0);
168*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_HORIZ_END, cfg->hsize - 1);
169*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_VERT_START, 0x0);
170*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_VERT_END, cfg->vsize - 1);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_DRIVER2,
173*4882a593Smuzhiyun 		      ILI9320_DRIVER2_NL(((cfg->vsize - 240) / 8) + 0x1D));
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_BASE_IMAGE, 0x1);
176*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_VERT_SCROLL, 0x00);
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	for (addr = ILI9320_PARTIAL1_POSITION; addr <= ILI9320_PARTIAL2_END;
179*4882a593Smuzhiyun 	     addr++) {
180*4882a593Smuzhiyun 		ili9320_write(lcd, addr, 0x0);
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_INTERFACE1, 0x10);
184*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_INTERFACE2, cfg->interface2);
185*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_INTERFACE3, cfg->interface3);
186*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_INTERFACE4, cfg->interface4);
187*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_INTERFACE5, cfg->interface5);
188*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_INTERFACE6, cfg->interface6);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	lcd->display1 = (ILI9320_DISPLAY1_D(3) | ILI9320_DISPLAY1_DTE |
191*4882a593Smuzhiyun 			 ILI9320_DISPLAY1_GON | ILI9320_DISPLAY1_BASEE |
192*4882a593Smuzhiyun 			 0x40);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	ili9320_write(lcd, ILI9320_DISPLAY1, lcd->display1);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	return 0;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun  err_vgg3:
199*4882a593Smuzhiyun  err_vgg2:
200*4882a593Smuzhiyun  err_vgg:
201*4882a593Smuzhiyun  err_initial:
202*4882a593Smuzhiyun 	return ret;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
vgg2432a4_suspend(struct device * dev)206*4882a593Smuzhiyun static int vgg2432a4_suspend(struct device *dev)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	return ili9320_suspend(dev_get_drvdata(dev));
209*4882a593Smuzhiyun }
vgg2432a4_resume(struct device * dev)210*4882a593Smuzhiyun static int vgg2432a4_resume(struct device *dev)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	return ili9320_resume(dev_get_drvdata(dev));
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun #endif
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun static struct ili9320_client vgg2432a4_client = {
217*4882a593Smuzhiyun 	.name	= "VGG2432A4",
218*4882a593Smuzhiyun 	.init	= vgg2432a4_lcd_init,
219*4882a593Smuzhiyun };
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun /* Device probe */
222*4882a593Smuzhiyun 
vgg2432a4_probe(struct spi_device * spi)223*4882a593Smuzhiyun static int vgg2432a4_probe(struct spi_device *spi)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	int ret;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	ret = ili9320_probe_spi(spi, &vgg2432a4_client);
228*4882a593Smuzhiyun 	if (ret != 0) {
229*4882a593Smuzhiyun 		dev_err(&spi->dev, "failed to initialise ili9320\n");
230*4882a593Smuzhiyun 		return ret;
231*4882a593Smuzhiyun 	}
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	return 0;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun 
vgg2432a4_remove(struct spi_device * spi)236*4882a593Smuzhiyun static int vgg2432a4_remove(struct spi_device *spi)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun 	return ili9320_remove(spi_get_drvdata(spi));
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun 
vgg2432a4_shutdown(struct spi_device * spi)241*4882a593Smuzhiyun static void vgg2432a4_shutdown(struct spi_device *spi)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 	ili9320_shutdown(spi_get_drvdata(spi));
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(vgg2432a4_pm_ops, vgg2432a4_suspend, vgg2432a4_resume);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun static struct spi_driver vgg2432a4_driver = {
249*4882a593Smuzhiyun 	.driver = {
250*4882a593Smuzhiyun 		.name		= "VGG2432A4",
251*4882a593Smuzhiyun 		.pm		= &vgg2432a4_pm_ops,
252*4882a593Smuzhiyun 	},
253*4882a593Smuzhiyun 	.probe		= vgg2432a4_probe,
254*4882a593Smuzhiyun 	.remove		= vgg2432a4_remove,
255*4882a593Smuzhiyun 	.shutdown	= vgg2432a4_shutdown,
256*4882a593Smuzhiyun };
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun module_spi_driver(vgg2432a4_driver);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
261*4882a593Smuzhiyun MODULE_DESCRIPTION("VGG2432A4 LCD Driver");
262*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
263*4882a593Smuzhiyun MODULE_ALIAS("spi:VGG2432A4");
264