1
2
3
4
5
6
7#include <common.h>
8#include <backlight.h>
9#include <command.h>
10#include <display.h>
11#include <dm.h>
12#include <log.h>
13#include <dm/read.h>
14#include <dm/uclass-internal.h>
15#include <errno.h>
16#include <spi.h>
17#include <asm/gpio.h>
18#include <linux/delay.h>
19
20#define PWR_ON_DELAY_MSECS 120
21
22static int lb043wv_spi_write_u16(struct spi_slave *slave, u16 val)
23{
24 unsigned short buf16 = htons(val);
25 int ret = 0;
26
27 ret = spi_xfer(slave, 16, &buf16, NULL,
28 SPI_XFER_BEGIN | SPI_XFER_END);
29 if (ret)
30 debug("%s: Failed to send: %d\n", __func__, ret);
31
32 return ret;
33}
34
35static void lb043wv_spi_write_u16_array(struct spi_slave *slave, u16 *buff,
36 int size)
37{
38 int i;
39
40 for (i = 0; i < size; i++)
41 lb043wv_spi_write_u16(slave, buff[i]);
42}
43
44static void lb043wv_display_mode_settings(struct spi_slave *slave)
45{
46 static u16 display_mode_settings[] = {
47 0x703A,
48 0x7270,
49 0x70B1,
50 0x7208,
51 0x723B,
52 0x720F,
53 0x70B2,
54 0x7200,
55 0x72C8,
56 0x70B3,
57 0x7200,
58 0x70B4,
59 0x7200,
60 0x70B5,
61 0x7242,
62 0x7210,
63 0x7210,
64 0x7200,
65 0x7220,
66 0x70B6,
67 0x720B,
68 0x720F,
69 0x723C,
70 0x7213,
71 0x7213,
72 0x72E8,
73 0x70B7,
74 0x7246,
75 0x7206,
76 0x720C,
77 0x7200,
78 0x7200,
79 };
80
81 debug("transfer display mode settings\n");
82 lb043wv_spi_write_u16_array(slave, display_mode_settings,
83 ARRAY_SIZE(display_mode_settings));
84}
85
86static void lb043wv_power_settings(struct spi_slave *slave)
87{
88 static u16 power_settings[] = {
89 0x70C0,
90 0x7201,
91 0x7211,
92 0x70C3,
93 0x7207,
94 0x7203,
95 0x7204,
96 0x7204,
97 0x7204,
98 0x70C4,
99 0x7212,
100 0x7224,
101 0x7218,
102 0x7218,
103 0x7202,
104 0x7249,
105 0x70C5,
106 0x726F,
107 0x70C6,
108 0x7241,
109 0x7263,
110 };
111
112 debug("transfer power settings\n");
113 lb043wv_spi_write_u16_array(slave, power_settings,
114 ARRAY_SIZE(power_settings));
115}
116
117static void lb043wv_gamma_settings(struct spi_slave *slave)
118{
119 static u16 gamma_settings[] = {
120 0x70D0,
121 0x7203,
122 0x7207,
123 0x7273,
124 0x7235,
125 0x7200,
126 0x7201,
127 0x7220,
128 0x7200,
129 0x7203,
130 0x70D1,
131 0x7203,
132 0x7207,
133 0x7273,
134 0x7235,
135 0x7200,
136 0x7201,
137 0x7220,
138 0x7200,
139 0x7203,
140 0x70D2,
141 0x7203,
142 0x7207,
143 0x7273,
144 0x7235,
145 0x7200,
146 0x7201,
147 0x7220,
148 0x7200,
149 0x7203,
150 0x70D3,
151 0x7203,
152 0x7207,
153 0x7273,
154 0x7235,
155 0x7200,
156 0x7201,
157 0x7220,
158 0x7200,
159 0x7203,
160 0x70D4,
161 0x7203,
162 0x7207,
163 0x7273,
164 0x7235,
165 0x7200,
166 0x7201,
167 0x7220,
168 0x7200,
169 0x7203,
170 0x70D5,
171 0x7203,
172 0x7207,
173 0x7273,
174 0x7235,
175 0x7200,
176 0x7201,
177 0x7220,
178 0x7200,
179 0x7203,
180 };
181
182 debug("transfer gamma settings\n");
183 lb043wv_spi_write_u16_array(slave, gamma_settings,
184 ARRAY_SIZE(gamma_settings));
185}
186
187static void lb043wv_display_on(struct spi_slave *slave)
188{
189 static u16 sleep_out = 0x7011;
190 static u16 display_on = 0x7029;
191
192 lb043wv_spi_write_u16(slave, sleep_out);
193 mdelay(PWR_ON_DELAY_MSECS);
194 lb043wv_spi_write_u16(slave, display_on);
195}
196
197static int lg4573_spi_startup(struct spi_slave *slave)
198{
199 int ret;
200
201 ret = spi_claim_bus(slave);
202 if (ret)
203 return ret;
204
205 lb043wv_display_mode_settings(slave);
206 lb043wv_power_settings(slave);
207 lb043wv_gamma_settings(slave);
208 lb043wv_display_on(slave);
209
210 spi_release_bus(slave);
211 return 0;
212}
213
214static int do_lgset(struct cmd_tbl *cmdtp, int flag, int argc,
215 char *const argv[])
216{
217 struct spi_slave *slave;
218 struct udevice *dev;
219 int ret;
220
221 ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
222 DM_DRIVER_GET(lg4573_lcd), &dev);
223 if (ret) {
224 printf("%s: Could not get lg4573 device\n", __func__);
225 return ret;
226 }
227 slave = dev_get_parent_priv(dev);
228 if (!slave) {
229 printf("%s: No slave data\n", __func__);
230 return -ENODEV;
231 }
232 lg4573_spi_startup(slave);
233
234 return 0;
235}
236
237U_BOOT_CMD(
238 lgset, 2, 1, do_lgset,
239 "set lgdisplay",
240 ""
241);
242
243static int lg4573_bind(struct udevice *dev)
244{
245 return 0;
246}
247
248static int lg4573_probe(struct udevice *dev)
249{
250 return 0;
251}
252
253static const struct udevice_id lg4573_ids[] = {
254 { .compatible = "lg,lg4573" },
255 { }
256};
257
258struct lg4573_lcd_priv {
259 struct display_timing timing;
260 struct udevice *backlight;
261 struct gpio_desc enable;
262 int panel_bpp;
263 u32 power_on_delay;
264};
265
266static int lg4573_lcd_read_timing(struct udevice *dev,
267 struct display_timing *timing)
268{
269 struct lg4573_lcd_priv *priv = dev_get_priv(dev);
270
271 memcpy(timing, &priv->timing, sizeof(struct display_timing));
272
273 return 0;
274}
275
276static int lg4573_lcd_enable(struct udevice *dev, int bpp,
277 const struct display_timing *edid)
278{
279 struct spi_slave *slave = dev_get_parent_priv(dev);
280 struct lg4573_lcd_priv *priv = dev_get_priv(dev);
281 int ret = 0;
282
283 dm_gpio_set_value(&priv->enable, 1);
284 ret = backlight_enable(priv->backlight);
285
286 mdelay(priv->power_on_delay);
287 lg4573_spi_startup(slave);
288
289 return ret;
290};
291
292static const struct dm_display_ops lg4573_lcd_ops = {
293 .read_timing = lg4573_lcd_read_timing,
294 .enable = lg4573_lcd_enable,
295};
296
297static int lg4573_of_to_plat(struct udevice *dev)
298{
299 struct lg4573_lcd_priv *priv = dev_get_priv(dev);
300 int ret;
301
302 ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
303 "backlight", &priv->backlight);
304 if (ret) {
305 debug("%s: Cannot get backlight: ret=%d\n", __func__, ret);
306 return log_ret(ret);
307 }
308 ret = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable,
309 GPIOD_IS_OUT);
310 if (ret) {
311 debug("%s: Warning: cannot get enable GPIO: ret=%d\n",
312 __func__, ret);
313 if (ret != -ENOENT)
314 return log_ret(ret);
315 }
316
317 priv->power_on_delay = dev_read_u32_default(dev, "power-on-delay", 10);
318
319 return 0;
320}
321
322U_BOOT_DRIVER(lg4573_lcd) = {
323 .name = "lg4573",
324 .id = UCLASS_DISPLAY,
325 .ops = &lg4573_lcd_ops,
326 .of_to_plat = lg4573_of_to_plat,
327 .of_match = lg4573_ids,
328 .bind = lg4573_bind,
329 .probe = lg4573_probe,
330 .priv_auto = sizeof(struct lg4573_lcd_priv),
331};
332