xref: /openbmc/u-boot/drivers/video/scf0403_lcd.c (revision 8a23fc9c)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * scf0403.c -- support for DataImage SCF0403 LCD
4  *
5  * Copyright (c) 2013 Adapted from Linux driver:
6  * Copyright (c) 2012 Anders Electronics plc. All Rights Reserved.
7  * Copyright (c) 2012 CompuLab, Ltd
8  *           Dmitry Lifshitz <lifshitz@compulab.co.il>
9  *           Ilya Ledvich <ilya@compulab.co.il>
10  * Inspired by Alberto Panizzo <maramaopercheseimorto@gmail.com> &
11  *	Marek Vasut work in l4f00242t03.c
12  *
13  * U-Boot port: Nikita Kiryanov <nikita@compulab.co.il>
14  */
15 
16 #include <common.h>
17 #include <asm/gpio.h>
18 #include <spi.h>
19 
20 struct scf0403_cmd {
21 	u16 cmd;
22 	u16 *params;
23 	int count;
24 };
25 
26 struct scf0403_initseq_entry {
27 	struct scf0403_cmd cmd;
28 	int delay_ms;
29 };
30 
31 struct scf0403_priv {
32 	struct spi_slave *spi;
33 	unsigned int reset_gpio;
34 	u32 rddid;
35 	struct scf0403_initseq_entry *init_seq;
36 	int seq_size;
37 };
38 
39 struct scf0403_priv priv;
40 
41 #define SCF0403852GGU04_ID 0x000080
42 
43 /* SCF0403526GGU20 model commands parameters */
44 static u16 extcmd_params_sn20[]		= {0xff, 0x98, 0x06};
45 static u16 spiinttype_params_sn20[]	= {0x60};
46 static u16 bc_params_sn20[]		= {
47 		0x01, 0x10, 0x61, 0x74, 0x01, 0x01, 0x1B,
48 		0x12, 0x71, 0x00, 0x00, 0x00, 0x01, 0x01,
49 		0x05, 0x00, 0xFF, 0xF2, 0x01, 0x00, 0x40,
50 };
51 static u16 bd_params_sn20[] = {0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67};
52 static u16 be_params_sn20[] = {
53 		0x01, 0x22, 0x22, 0xBA, 0xDC, 0x26, 0x28, 0x22,	0x22,
54 };
55 static u16 vcom_params_sn20[]		= {0x74};
56 static u16 vmesur_params_sn20[]		= {0x7F, 0x0F, 0x00};
57 static u16 powerctl_params_sn20[]	= {0x03, 0x0b, 0x00};
58 static u16 lvglvolt_params_sn20[]	= {0x08};
59 static u16 engsetting_params_sn20[]	= {0x00, 0x00, 0x00, 0x00, 0x00, 0x20};
60 static u16 dispfunc_params_sn20[]	= {0xa0};
61 static u16 dvddvolt_params_sn20[]	= {0x74};
62 static u16 dispinv_params_sn20[]	= {0x00, 0x00, 0x00};
63 static u16 panelres_params_sn20[]	= {0x82};
64 static u16 framerate_params_sn20[]	= {0x00, 0x13, 0x13};
65 static u16 timing_params_sn20[]		= {0x80, 0x05, 0x40, 0x28};
66 static u16 powerctl2_params_sn20[]	= {0x17, 0x75, 0x79, 0x20};
67 static u16 memaccess_params_sn20[]	= {0x00};
68 static u16 pixfmt_params_sn20[]		= {0x66};
69 static u16 pgamma_params_sn20[]		= {
70 		0x00, 0x03, 0x0b, 0x0c, 0x0e, 0x08, 0xc5, 0x04,
71 		0x08, 0x0c, 0x13, 0x11, 0x11, 0x14, 0x0c, 0x10,
72 };
73 static u16 ngamma_params_sn20[] = {
74 		0x00, 0x0d, 0x11, 0x0c, 0x0c, 0x04, 0x76, 0x03,
75 		0x08, 0x0b, 0x16, 0x10, 0x0d, 0x16, 0x0a, 0x00,
76 };
77 static u16 tearing_params_sn20[] = {0x00};
78 
79 /* SCF0403852GGU04 model commands parameters */
80 static u16 memaccess_params_sn04[]	= {0x08};
81 static u16 pixfmt_params_sn04[]		= {0x66};
82 static u16 modectl_params_sn04[]	= {0x01};
83 static u16 dispfunc_params_sn04[]	= {0x22, 0xe2, 0xFF, 0x04};
84 static u16 vcom_params_sn04[]		= {0x00, 0x6A};
85 static u16 pgamma_params_sn04[]		= {
86 		0x00, 0x07, 0x0d, 0x10, 0x13, 0x19, 0x0f, 0x0c,
87 		0x05, 0x08, 0x06, 0x13,	0x0f, 0x30, 0x20, 0x1f,
88 };
89 static u16 ngamma_params_sn04[]		= {
90 		0x1F, 0x20, 0x30, 0x0F, 0x13, 0x06, 0x08, 0x05,
91 		0x0C, 0x0F, 0x19, 0x13, 0x10, 0x0D, 0x07, 0x00,
92 };
93 static u16 dispinv_params_sn04[]	= {0x02};
94 
95 /* Common commands */
96 static struct scf0403_cmd scf0403_cmd_slpout	= {0x11, NULL, 0};
97 static struct scf0403_cmd scf0403_cmd_dison	= {0x29, NULL, 0};
98 
99 /* SCF0403852GGU04 init sequence */
100 static struct scf0403_initseq_entry scf0403_initseq_sn04[] = {
101 	{{0x36, memaccess_params_sn04,	ARRAY_SIZE(memaccess_params_sn04)}, 0},
102 	{{0x3A, pixfmt_params_sn04,	ARRAY_SIZE(pixfmt_params_sn04)}, 0},
103 	{{0xB6, dispfunc_params_sn04,	ARRAY_SIZE(dispfunc_params_sn04)}, 0},
104 	{{0xC5, vcom_params_sn04,	ARRAY_SIZE(vcom_params_sn04)}, 0},
105 	{{0xE0, pgamma_params_sn04,	ARRAY_SIZE(pgamma_params_sn04)}, 0},
106 	{{0xE1, ngamma_params_sn04,	ARRAY_SIZE(ngamma_params_sn04)}, 20},
107 	{{0xB0, modectl_params_sn04,	ARRAY_SIZE(modectl_params_sn04)}, 0},
108 	{{0xB4, dispinv_params_sn04,	ARRAY_SIZE(dispinv_params_sn04)}, 100},
109 };
110 
111 /* SCF0403526GGU20 init sequence */
112 static struct scf0403_initseq_entry scf0403_initseq_sn20[] = {
113 	{{0xff, extcmd_params_sn20,	ARRAY_SIZE(extcmd_params_sn20)}, 0},
114 	{{0xba, spiinttype_params_sn20,	ARRAY_SIZE(spiinttype_params_sn20)}, 0},
115 	{{0xbc, bc_params_sn20,		ARRAY_SIZE(bc_params_sn20)}, 0},
116 	{{0xbd, bd_params_sn20,		ARRAY_SIZE(bd_params_sn20)}, 0},
117 	{{0xbe, be_params_sn20,		ARRAY_SIZE(be_params_sn20)}, 0},
118 	{{0xc7, vcom_params_sn20,	ARRAY_SIZE(vcom_params_sn20)}, 0},
119 	{{0xed, vmesur_params_sn20,	ARRAY_SIZE(vmesur_params_sn20)}, 0},
120 	{{0xc0, powerctl_params_sn20,	ARRAY_SIZE(powerctl_params_sn20)}, 0},
121 	{{0xfc, lvglvolt_params_sn20,	ARRAY_SIZE(lvglvolt_params_sn20)}, 0},
122 	{{0xb6, dispfunc_params_sn20,	ARRAY_SIZE(dispfunc_params_sn20)}, 0},
123 	{{0xdf, engsetting_params_sn20,	ARRAY_SIZE(engsetting_params_sn20)}, 0},
124 	{{0xf3, dvddvolt_params_sn20,	ARRAY_SIZE(dvddvolt_params_sn20)}, 0},
125 	{{0xb4, dispinv_params_sn20,	ARRAY_SIZE(dispinv_params_sn20)}, 0},
126 	{{0xf7, panelres_params_sn20,	ARRAY_SIZE(panelres_params_sn20)}, 0},
127 	{{0xb1, framerate_params_sn20,	ARRAY_SIZE(framerate_params_sn20)}, 0},
128 	{{0xf2, timing_params_sn20,	ARRAY_SIZE(timing_params_sn20)}, 0},
129 	{{0xc1, powerctl2_params_sn20,	ARRAY_SIZE(powerctl2_params_sn20)}, 0},
130 	{{0x36, memaccess_params_sn20,	ARRAY_SIZE(memaccess_params_sn20)}, 0},
131 	{{0x3a, pixfmt_params_sn20,	ARRAY_SIZE(pixfmt_params_sn20)}, 0},
132 	{{0xe0, pgamma_params_sn20,	ARRAY_SIZE(pgamma_params_sn20)}, 0},
133 	{{0xe1, ngamma_params_sn20,	ARRAY_SIZE(ngamma_params_sn20)}, 0},
134 	{{0x35, tearing_params_sn20,	ARRAY_SIZE(tearing_params_sn20)}, 0},
135 };
136 
137 static void scf0403_gpio_reset(unsigned int gpio)
138 {
139 	if (!gpio_is_valid(gpio))
140 		return;
141 
142 	gpio_set_value(gpio, 1);
143 	mdelay(100);
144 	gpio_set_value(gpio, 0);
145 	mdelay(40);
146 	gpio_set_value(gpio, 1);
147 	mdelay(100);
148 }
149 
150 static int scf0403_spi_read_rddid(struct spi_slave *spi, u32 *rddid)
151 {
152 	int error = 0;
153 	u8 ids_buf = 0x00;
154 	u16 dummy_buf = 0x00;
155 	u16 cmd = 0x04;
156 
157 	error = spi_set_wordlen(spi, 9);
158 	if (error)
159 		return error;
160 
161 	/* Here 9 bits required to transmit a command */
162 	error = spi_xfer(spi, 9, &cmd, NULL, SPI_XFER_ONCE);
163 	if (error)
164 		return error;
165 
166 	/*
167 	 * Here 8 + 1 bits required to arrange extra clock cycle
168 	 * before the first data bit.
169 	 * According to the datasheet - first parameter is the dummy data.
170 	 */
171 	error = spi_xfer(spi, 9, NULL, &dummy_buf, SPI_XFER_ONCE);
172 	if (error)
173 		return error;
174 
175 	error = spi_set_wordlen(spi, 8);
176 	if (error)
177 		return error;
178 
179 	/* Read rest of the data */
180 	error = spi_xfer(spi, 8, NULL, &ids_buf, SPI_XFER_ONCE);
181 	if (error)
182 		return error;
183 
184 	*rddid = ids_buf;
185 
186 	return 0;
187 }
188 
189 static int scf0403_spi_transfer(struct spi_slave *spi, struct scf0403_cmd *cmd)
190 {
191 	int i, error;
192 	u32 command = cmd->cmd;
193 	u32 msg;
194 
195 	error = spi_set_wordlen(spi, 9);
196 	if (error)
197 		return error;
198 
199 	error = spi_xfer(spi, 9, &command, NULL, SPI_XFER_ONCE);
200 	if (error)
201 		return error;
202 
203 	for (i = 0; i < cmd->count; i++) {
204 		msg = (cmd->params[i] | 0x100);
205 		error = spi_xfer(spi, 9, &msg, NULL, SPI_XFER_ONCE);
206 		if (error)
207 			return error;
208 	}
209 
210 	return 0;
211 }
212 
213 static void scf0403_lcd_init(struct scf0403_priv *priv)
214 {
215 	int i;
216 
217 	/* reset LCD */
218 	scf0403_gpio_reset(priv->reset_gpio);
219 
220 	for (i = 0; i < priv->seq_size; i++) {
221 		if (scf0403_spi_transfer(priv->spi, &priv->init_seq[i].cmd) < 0)
222 			puts("SPI transfer failed\n");
223 
224 		mdelay(priv->init_seq[i].delay_ms);
225 	}
226 }
227 
228 static int scf0403_request_reset_gpio(unsigned gpio)
229 {
230 	int err = gpio_request(gpio, "lcd reset");
231 
232 	if (err)
233 		return err;
234 
235 	err = gpio_direction_output(gpio, 0);
236 	if (err)
237 		gpio_free(gpio);
238 
239 	return err;
240 }
241 
242 int scf0403_init(int reset_gpio)
243 {
244 	int error;
245 
246 	if (gpio_is_valid(reset_gpio)) {
247 		error = scf0403_request_reset_gpio(reset_gpio);
248 		if (error) {
249 			printf("Failed requesting reset GPIO%d: %d\n",
250 			       reset_gpio, error);
251 			return error;
252 		}
253 	}
254 
255 	priv.reset_gpio = reset_gpio;
256 	priv.spi = spi_setup_slave(3, 0, 1000000, SPI_MODE_0);
257 	error = spi_claim_bus(priv.spi);
258 	if (error)
259 		goto bus_claim_fail;
260 
261 	/* reset LCD */
262 	scf0403_gpio_reset(reset_gpio);
263 
264 	error = scf0403_spi_read_rddid(priv.spi, &priv.rddid);
265 	if (error) {
266 		puts("IDs read failed\n");
267 		goto readid_fail;
268 	}
269 
270 	if (priv.rddid == SCF0403852GGU04_ID) {
271 		priv.init_seq = scf0403_initseq_sn04;
272 		priv.seq_size = ARRAY_SIZE(scf0403_initseq_sn04);
273 	} else {
274 		priv.init_seq = scf0403_initseq_sn20;
275 		priv.seq_size = ARRAY_SIZE(scf0403_initseq_sn20);
276 	}
277 
278 	scf0403_lcd_init(&priv);
279 
280 	/* Start operation */
281 	scf0403_spi_transfer(priv.spi, &scf0403_cmd_dison);
282 	mdelay(100);
283 	scf0403_spi_transfer(priv.spi, &scf0403_cmd_slpout);
284 	spi_release_bus(priv.spi);
285 
286 	return 0;
287 
288 readid_fail:
289 	spi_release_bus(priv.spi);
290 bus_claim_fail:
291 	if (gpio_is_valid(priv.reset_gpio))
292 		gpio_free(priv.reset_gpio);
293 
294 	return error;
295 }
296