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