video: Add simple driver for ST-Ericsson MCDE with pre-configured display
[platform/kernel/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 #include <linux/delay.h>
19
20 #define PWR_ON_DELAY_MSECS  120
21
22 static 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
35 static 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
44 static 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
86 static 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
117 static 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
187 static 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
197 static 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
214 static 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
237 U_BOOT_CMD(
238         lgset,  2,      1,      do_lgset,
239         "set lgdisplay",
240         ""
241 );
242
243 static int lg4573_bind(struct udevice *dev)
244 {
245         return 0;
246 }
247
248 static int lg4573_probe(struct udevice *dev)
249 {
250         return 0;
251 }
252
253 static const struct udevice_id lg4573_ids[] = {
254         { .compatible = "lg,lg4573" },
255         { }
256 };
257
258 struct 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
266 static 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
276 static 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
292 static const struct dm_display_ops lg4573_lcd_ops = {
293         .read_timing = lg4573_lcd_read_timing,
294         .enable = lg4573_lcd_enable,
295 };
296
297 static 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
322 U_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 };