Merge tag 'dm-pull-8jan20' of git://git.denx.de/u-boot-dm
[oweals/u-boot.git] / drivers / video / lg4573.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * LCD: LG4573, TFT 4.3", 480x800, RGB24
4  * LCD initialization via SPI
5  *
6  */
7 #include <common.h>
8 #include <backlight.h>
9 #include <display.h>
10 #include <dm.h>
11 #include <dm/read.h>
12 #include <dm/uclass-internal.h>
13 #include <errno.h>
14 #include <spi.h>
15 #include <asm/gpio.h>
16
17 #define PWR_ON_DELAY_MSECS  120
18
19 static int lb043wv_spi_write_u16(struct spi_slave *slave, u16 val)
20 {
21         unsigned short buf16 = htons(val);
22         int ret = 0;
23
24         ret = spi_xfer(slave, 16, &buf16, NULL,
25                        SPI_XFER_BEGIN | SPI_XFER_END);
26         if (ret)
27                 debug("%s: Failed to send: %d\n", __func__, ret);
28
29         return ret;
30 }
31
32 static void lb043wv_spi_write_u16_array(struct spi_slave *slave, u16 *buff,
33                                         int size)
34 {
35         int i;
36
37         for (i = 0; i < size; i++)
38                 lb043wv_spi_write_u16(slave, buff[i]);
39 }
40
41 static void lb043wv_display_mode_settings(struct spi_slave *slave)
42 {
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");
79         lb043wv_spi_write_u16_array(slave, display_mode_settings,
80                                     ARRAY_SIZE(display_mode_settings));
81 }
82
83 static void lb043wv_power_settings(struct spi_slave *slave)
84 {
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");
110         lb043wv_spi_write_u16_array(slave, power_settings,
111                                     ARRAY_SIZE(power_settings));
112 }
113
114 static void lb043wv_gamma_settings(struct spi_slave *slave)
115 {
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");
180         lb043wv_spi_write_u16_array(slave, gamma_settings,
181                                     ARRAY_SIZE(gamma_settings));
182 }
183
184 static void lb043wv_display_on(struct spi_slave *slave)
185 {
186         static u16 sleep_out = 0x7011;
187         static u16 display_on = 0x7029;
188
189         lb043wv_spi_write_u16(slave, sleep_out);
190         mdelay(PWR_ON_DELAY_MSECS);
191         lb043wv_spi_write_u16(slave, display_on);
192 }
193
194 static int lg4573_spi_startup(struct spi_slave *slave)
195 {
196         int ret;
197
198         ret = spi_claim_bus(slave);
199         if (ret)
200                 return ret;
201
202         lb043wv_display_mode_settings(slave);
203         lb043wv_power_settings(slave);
204         lb043wv_gamma_settings(slave);
205         lb043wv_display_on(slave);
206
207         spi_release_bus(slave);
208         return 0;
209 }
210
211 static int do_lgset(cmd_tbl_t *cmdtp, int flag, int argc,
212                        char * const argv[])
213 {
214         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
231         return 0;
232 }
233
234 U_BOOT_CMD(
235         lgset,  2,      1,      do_lgset,
236         "set lgdisplay",
237         ""
238 );
239
240 static int lg4573_bind(struct udevice *dev)
241 {
242         return 0;
243 }
244
245 static int lg4573_probe(struct udevice *dev)
246 {
247         return 0;
248 }
249
250 static const struct udevice_id lg4573_ids[] = {
251         { .compatible = "lg,lg4573" },
252         { }
253 };
254
255 struct 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
263 static 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
273 static 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
289 static const struct dm_display_ops lg4573_lcd_ops = {
290         .read_timing = lg4573_lcd_read_timing,
291         .enable = lg4573_lcd_enable,
292 };
293
294 static 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
319 U_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 };