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 
lb043wv_spi_write_u16(struct spi_slave * slave,u16 val)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 
lb043wv_spi_write_u16_array(struct spi_slave * slave,u16 * buff,int size)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 
lb043wv_display_mode_settings(struct spi_slave * slave)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 
lb043wv_power_settings(struct spi_slave * slave)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 
lb043wv_gamma_settings(struct spi_slave * slave)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 
lb043wv_display_on(struct spi_slave * slave)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 
lg4573_spi_startup(struct spi_slave * slave)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 
do_lgset(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])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 
lg4573_bind(struct udevice * dev)243 static int lg4573_bind(struct udevice *dev)
244 {
245 	return 0;
246 }
247 
lg4573_probe(struct udevice * dev)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 
lg4573_lcd_read_timing(struct udevice * dev,struct display_timing * timing)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 
lg4573_lcd_enable(struct udevice * dev,int bpp,const struct display_timing * edid)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 
lg4573_of_to_plat(struct udevice * dev)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 };
332