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