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