blob: 997e854ef8f9c3c4cbfd0b23b8c2b6d656d75bc1 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0
Heiko Schocherfc1a79d2015-04-12 10:20:19 +02002/*
3 * LCD: LG4573, TFT 4.3", 480x800, RGB24
4 * LCD initialization via SPI
5 *
Heiko Schocherfc1a79d2015-04-12 10:20:19 +02006 */
7#include <common.h>
Heiko Schocher79db1b42019-12-01 11:23:05 +01008#include <backlight.h>
9#include <display.h>
10#include <dm.h>
11#include <dm/read.h>
12#include <dm/uclass-internal.h>
Heiko Schocherfc1a79d2015-04-12 10:20:19 +020013#include <errno.h>
14#include <spi.h>
Heiko Schocher79db1b42019-12-01 11:23:05 +010015#include <asm/gpio.h>
Heiko Schocherfc1a79d2015-04-12 10:20:19 +020016
17#define PWR_ON_DELAY_MSECS 120
18
Heiko Schocher79db1b42019-12-01 11:23:05 +010019static int lb043wv_spi_write_u16(struct spi_slave *slave, u16 val)
Heiko Schocherfc1a79d2015-04-12 10:20:19 +020020{
Heiko Schocherfc1a79d2015-04-12 10:20:19 +020021 unsigned short buf16 = htons(val);
22 int ret = 0;
23
Heiko Schocher79db1b42019-12-01 11:23:05 +010024 ret = spi_xfer(slave, 16, &buf16, NULL,
25 SPI_XFER_BEGIN | SPI_XFER_END);
Heiko Schocherfc1a79d2015-04-12 10:20:19 +020026 if (ret)
27 debug("%s: Failed to send: %d\n", __func__, ret);
28
29 return ret;
30}
31
Heiko Schocher79db1b42019-12-01 11:23:05 +010032static void lb043wv_spi_write_u16_array(struct spi_slave *slave, u16 *buff,
Heiko Schocherfc1a79d2015-04-12 10:20:19 +020033 int size)
34{
35 int i;
36
37 for (i = 0; i < size; i++)
Heiko Schocher79db1b42019-12-01 11:23:05 +010038 lb043wv_spi_write_u16(slave, buff[i]);
Heiko Schocherfc1a79d2015-04-12 10:20:19 +020039}
40
Heiko Schocher79db1b42019-12-01 11:23:05 +010041static void lb043wv_display_mode_settings(struct spi_slave *slave)
Heiko Schocherfc1a79d2015-04-12 10:20:19 +020042{
43 static u16 display_mode_settings[] = {
44 0x703A,
45 0x7270,
46 0x70B1,
47 0x7208,
48 0x723B,
49 0x720F,
50 0x70B2,
51 0x7200,
52 0x72C8,
53 0x70B3,
54 0x7200,
55 0x70B4,
56 0x7200,
57 0x70B5,
58 0x7242,
59 0x7210,
60 0x7210,
61 0x7200,
62 0x7220,
63 0x70B6,
64 0x720B,
65 0x720F,
66 0x723C,
67 0x7213,
68 0x7213,
69 0x72E8,
70 0x70B7,
71 0x7246,
72 0x7206,
73 0x720C,
74 0x7200,
75 0x7200,
76 };
77
78 debug("transfer display mode settings\n");
Heiko Schocher79db1b42019-12-01 11:23:05 +010079 lb043wv_spi_write_u16_array(slave, display_mode_settings,
Heiko Schocherfc1a79d2015-04-12 10:20:19 +020080 ARRAY_SIZE(display_mode_settings));
81}
82
Heiko Schocher79db1b42019-12-01 11:23:05 +010083static void lb043wv_power_settings(struct spi_slave *slave)
Heiko Schocherfc1a79d2015-04-12 10:20:19 +020084{
85 static u16 power_settings[] = {
86 0x70C0,
87 0x7201,
88 0x7211,
89 0x70C3,
90 0x7207,
91 0x7203,
92 0x7204,
93 0x7204,
94 0x7204,
95 0x70C4,
96 0x7212,
97 0x7224,
98 0x7218,
99 0x7218,
100 0x7202,
101 0x7249,
102 0x70C5,
103 0x726F,
104 0x70C6,
105 0x7241,
106 0x7263,
107 };
108
109 debug("transfer power settings\n");
Heiko Schocher79db1b42019-12-01 11:23:05 +0100110 lb043wv_spi_write_u16_array(slave, power_settings,
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200111 ARRAY_SIZE(power_settings));
112}
113
Heiko Schocher79db1b42019-12-01 11:23:05 +0100114static void lb043wv_gamma_settings(struct spi_slave *slave)
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200115{
116 static u16 gamma_settings[] = {
117 0x70D0,
118 0x7203,
119 0x7207,
120 0x7273,
121 0x7235,
122 0x7200,
123 0x7201,
124 0x7220,
125 0x7200,
126 0x7203,
127 0x70D1,
128 0x7203,
129 0x7207,
130 0x7273,
131 0x7235,
132 0x7200,
133 0x7201,
134 0x7220,
135 0x7200,
136 0x7203,
137 0x70D2,
138 0x7203,
139 0x7207,
140 0x7273,
141 0x7235,
142 0x7200,
143 0x7201,
144 0x7220,
145 0x7200,
146 0x7203,
147 0x70D3,
148 0x7203,
149 0x7207,
150 0x7273,
151 0x7235,
152 0x7200,
153 0x7201,
154 0x7220,
155 0x7200,
156 0x7203,
157 0x70D4,
158 0x7203,
159 0x7207,
160 0x7273,
161 0x7235,
162 0x7200,
163 0x7201,
164 0x7220,
165 0x7200,
166 0x7203,
167 0x70D5,
168 0x7203,
169 0x7207,
170 0x7273,
171 0x7235,
172 0x7200,
173 0x7201,
174 0x7220,
175 0x7200,
176 0x7203,
177 };
178
179 debug("transfer gamma settings\n");
Heiko Schocher79db1b42019-12-01 11:23:05 +0100180 lb043wv_spi_write_u16_array(slave, gamma_settings,
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200181 ARRAY_SIZE(gamma_settings));
182}
183
Heiko Schocher79db1b42019-12-01 11:23:05 +0100184static void lb043wv_display_on(struct spi_slave *slave)
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200185{
186 static u16 sleep_out = 0x7011;
187 static u16 display_on = 0x7029;
188
Heiko Schocher79db1b42019-12-01 11:23:05 +0100189 lb043wv_spi_write_u16(slave, sleep_out);
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200190 mdelay(PWR_ON_DELAY_MSECS);
Heiko Schocher79db1b42019-12-01 11:23:05 +0100191 lb043wv_spi_write_u16(slave, display_on);
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200192}
193
Heiko Schocher79db1b42019-12-01 11:23:05 +0100194static int lg4573_spi_startup(struct spi_slave *slave)
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200195{
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200196 int ret;
197
Heiko Schocher79db1b42019-12-01 11:23:05 +0100198 ret = spi_claim_bus(slave);
199 if (ret)
200 return ret;
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200201
Heiko Schocher79db1b42019-12-01 11:23:05 +0100202 lb043wv_display_mode_settings(slave);
203 lb043wv_power_settings(slave);
204 lb043wv_gamma_settings(slave);
205 lb043wv_display_on(slave);
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200206
Heiko Schocher79db1b42019-12-01 11:23:05 +0100207 spi_release_bus(slave);
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200208 return 0;
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200209}
210
211static int do_lgset(cmd_tbl_t *cmdtp, int flag, int argc,
212 char * const argv[])
213{
Heiko Schocher79db1b42019-12-01 11:23:05 +0100214 struct spi_slave *slave;
215 struct udevice *dev;
216 int ret;
217
218 ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
219 DM_GET_DRIVER(lg4573_lcd), &dev);
220 if (ret) {
221 printf("%s: Could not get lg4573 device\n", __func__);
222 return ret;
223 }
224 slave = dev_get_parent_priv(dev);
225 if (!slave) {
226 printf("%s: No slave data\n", __func__);
227 return -ENODEV;
228 }
229 lg4573_spi_startup(slave);
230
Heiko Schocherfc1a79d2015-04-12 10:20:19 +0200231 return 0;
232}
233
234U_BOOT_CMD(
235 lgset, 2, 1, do_lgset,
236 "set lgdisplay",
237 ""
238);
Heiko Schocher79db1b42019-12-01 11:23:05 +0100239
240static int lg4573_bind(struct udevice *dev)
241{
242 return 0;
243}
244
245static int lg4573_probe(struct udevice *dev)
246{
247 return 0;
248}
249
250static const struct udevice_id lg4573_ids[] = {
251 { .compatible = "lg,lg4573" },
252 { }
253};
254
255struct lg4573_lcd_priv {
256 struct display_timing timing;
257 struct udevice *backlight;
258 struct gpio_desc enable;
259 int panel_bpp;
260 u32 power_on_delay;
261};
262
263static int lg4573_lcd_read_timing(struct udevice *dev,
264 struct display_timing *timing)
265{
266 struct lg4573_lcd_priv *priv = dev_get_priv(dev);
267
268 memcpy(timing, &priv->timing, sizeof(struct display_timing));
269
270 return 0;
271}
272
273static int lg4573_lcd_enable(struct udevice *dev, int bpp,
274 const struct display_timing *edid)
275{
276 struct spi_slave *slave = dev_get_parent_priv(dev);
277 struct lg4573_lcd_priv *priv = dev_get_priv(dev);
278 int ret = 0;
279
280 dm_gpio_set_value(&priv->enable, 1);
281 ret = backlight_enable(priv->backlight);
282
283 mdelay(priv->power_on_delay);
284 lg4573_spi_startup(slave);
285
286 return ret;
287};
288
289static const struct dm_display_ops lg4573_lcd_ops = {
290 .read_timing = lg4573_lcd_read_timing,
291 .enable = lg4573_lcd_enable,
292};
293
294static int lg4573_ofdata_to_platdata(struct udevice *dev)
295{
296 struct lg4573_lcd_priv *priv = dev_get_priv(dev);
297 int ret;
298
299 ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
300 "backlight", &priv->backlight);
301 if (ret) {
302 debug("%s: Cannot get backlight: ret=%d\n", __func__, ret);
303 return log_ret(ret);
304 }
305 ret = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable,
306 GPIOD_IS_OUT);
307 if (ret) {
308 debug("%s: Warning: cannot get enable GPIO: ret=%d\n",
309 __func__, ret);
310 if (ret != -ENOENT)
311 return log_ret(ret);
312 }
313
314 priv->power_on_delay = dev_read_u32_default(dev, "power-on-delay", 10);
315
316 return 0;
317}
318
319U_BOOT_DRIVER(lg4573_lcd) = {
320 .name = "lg4573",
321 .id = UCLASS_DISPLAY,
322 .ops = &lg4573_lcd_ops,
323 .ofdata_to_platdata = lg4573_ofdata_to_platdata,
324 .of_match = lg4573_ids,
325 .bind = lg4573_bind,
326 .probe = lg4573_probe,
327 .priv_auto_alloc_size = sizeof(struct lg4573_lcd_priv),
328};