xref: /openbmc/linux/drivers/video/backlight/hx8357.c (revision 2a598d0b)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Driver for the Himax HX-8357 LCD Controller
4  *
5  * Copyright 2012 Free Electrons
6  */
7 
8 #include <linux/delay.h>
9 #include <linux/lcd.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/of_device.h>
13 #include <linux/of_gpio.h>
14 #include <linux/spi/spi.h>
15 
16 #define HX8357_NUM_IM_PINS	3
17 
18 #define HX8357_SWRESET			0x01
19 #define HX8357_GET_RED_CHANNEL		0x06
20 #define HX8357_GET_GREEN_CHANNEL	0x07
21 #define HX8357_GET_BLUE_CHANNEL		0x08
22 #define HX8357_GET_POWER_MODE		0x0a
23 #define HX8357_GET_MADCTL		0x0b
24 #define HX8357_GET_PIXEL_FORMAT		0x0c
25 #define HX8357_GET_DISPLAY_MODE		0x0d
26 #define HX8357_GET_SIGNAL_MODE		0x0e
27 #define HX8357_GET_DIAGNOSTIC_RESULT	0x0f
28 #define HX8357_ENTER_SLEEP_MODE		0x10
29 #define HX8357_EXIT_SLEEP_MODE		0x11
30 #define HX8357_ENTER_PARTIAL_MODE	0x12
31 #define HX8357_ENTER_NORMAL_MODE	0x13
32 #define HX8357_EXIT_INVERSION_MODE	0x20
33 #define HX8357_ENTER_INVERSION_MODE	0x21
34 #define HX8357_SET_DISPLAY_OFF		0x28
35 #define HX8357_SET_DISPLAY_ON		0x29
36 #define HX8357_SET_COLUMN_ADDRESS	0x2a
37 #define HX8357_SET_PAGE_ADDRESS		0x2b
38 #define HX8357_WRITE_MEMORY_START	0x2c
39 #define HX8357_READ_MEMORY_START	0x2e
40 #define HX8357_SET_PARTIAL_AREA		0x30
41 #define HX8357_SET_SCROLL_AREA		0x33
42 #define HX8357_SET_TEAR_OFF		0x34
43 #define HX8357_SET_TEAR_ON		0x35
44 #define HX8357_SET_ADDRESS_MODE		0x36
45 #define HX8357_SET_SCROLL_START		0x37
46 #define HX8357_EXIT_IDLE_MODE		0x38
47 #define HX8357_ENTER_IDLE_MODE		0x39
48 #define HX8357_SET_PIXEL_FORMAT		0x3a
49 #define HX8357_SET_PIXEL_FORMAT_DBI_3BIT	(0x1)
50 #define HX8357_SET_PIXEL_FORMAT_DBI_16BIT	(0x5)
51 #define HX8357_SET_PIXEL_FORMAT_DBI_18BIT	(0x6)
52 #define HX8357_SET_PIXEL_FORMAT_DPI_3BIT	(0x1 << 4)
53 #define HX8357_SET_PIXEL_FORMAT_DPI_16BIT	(0x5 << 4)
54 #define HX8357_SET_PIXEL_FORMAT_DPI_18BIT	(0x6 << 4)
55 #define HX8357_WRITE_MEMORY_CONTINUE	0x3c
56 #define HX8357_READ_MEMORY_CONTINUE	0x3e
57 #define HX8357_SET_TEAR_SCAN_LINES	0x44
58 #define HX8357_GET_SCAN_LINES		0x45
59 #define HX8357_READ_DDB_START		0xa1
60 #define HX8357_SET_DISPLAY_MODE		0xb4
61 #define HX8357_SET_DISPLAY_MODE_RGB_THROUGH	(0x3)
62 #define HX8357_SET_DISPLAY_MODE_RGB_INTERFACE	(1 << 4)
63 #define HX8357_SET_PANEL_DRIVING	0xc0
64 #define HX8357_SET_DISPLAY_FRAME	0xc5
65 #define HX8357_SET_RGB			0xc6
66 #define HX8357_SET_RGB_ENABLE_HIGH		(1 << 1)
67 #define HX8357_SET_GAMMA		0xc8
68 #define HX8357_SET_POWER		0xd0
69 #define HX8357_SET_VCOM			0xd1
70 #define HX8357_SET_POWER_NORMAL		0xd2
71 #define HX8357_SET_PANEL_RELATED	0xe9
72 
73 #define HX8369_SET_DISPLAY_BRIGHTNESS		0x51
74 #define HX8369_WRITE_CABC_DISPLAY_VALUE		0x53
75 #define HX8369_WRITE_CABC_BRIGHT_CTRL		0x55
76 #define HX8369_WRITE_CABC_MIN_BRIGHTNESS	0x5e
77 #define HX8369_SET_POWER			0xb1
78 #define HX8369_SET_DISPLAY_MODE			0xb2
79 #define HX8369_SET_DISPLAY_WAVEFORM_CYC		0xb4
80 #define HX8369_SET_VCOM				0xb6
81 #define HX8369_SET_EXTENSION_COMMAND		0xb9
82 #define HX8369_SET_GIP				0xd5
83 #define HX8369_SET_GAMMA_CURVE_RELATED		0xe0
84 
85 struct hx8357_data {
86 	unsigned		im_pins[HX8357_NUM_IM_PINS];
87 	unsigned		reset;
88 	struct spi_device	*spi;
89 	int			state;
90 	bool			use_im_pins;
91 };
92 
93 static u8 hx8357_seq_power[] = {
94 	HX8357_SET_POWER, 0x44, 0x41, 0x06,
95 };
96 
97 static u8 hx8357_seq_vcom[] = {
98 	HX8357_SET_VCOM, 0x40, 0x10,
99 };
100 
101 static u8 hx8357_seq_power_normal[] = {
102 	HX8357_SET_POWER_NORMAL, 0x05, 0x12,
103 };
104 
105 static u8 hx8357_seq_panel_driving[] = {
106 	HX8357_SET_PANEL_DRIVING, 0x14, 0x3b, 0x00, 0x02, 0x11,
107 };
108 
109 static u8 hx8357_seq_display_frame[] = {
110 	HX8357_SET_DISPLAY_FRAME, 0x0c,
111 };
112 
113 static u8 hx8357_seq_panel_related[] = {
114 	HX8357_SET_PANEL_RELATED, 0x01,
115 };
116 
117 static u8 hx8357_seq_undefined1[] = {
118 	0xea, 0x03, 0x00, 0x00,
119 };
120 
121 static u8 hx8357_seq_undefined2[] = {
122 	0xeb, 0x40, 0x54, 0x26, 0xdb,
123 };
124 
125 static u8 hx8357_seq_gamma[] = {
126 	HX8357_SET_GAMMA, 0x00, 0x15, 0x00, 0x22, 0x00,
127 	0x08, 0x77, 0x26, 0x77, 0x22, 0x04, 0x00,
128 };
129 
130 static u8 hx8357_seq_address_mode[] = {
131 	HX8357_SET_ADDRESS_MODE, 0xc0,
132 };
133 
134 static u8 hx8357_seq_pixel_format[] = {
135 	HX8357_SET_PIXEL_FORMAT,
136 	HX8357_SET_PIXEL_FORMAT_DPI_18BIT |
137 	HX8357_SET_PIXEL_FORMAT_DBI_18BIT,
138 };
139 
140 static u8 hx8357_seq_column_address[] = {
141 	HX8357_SET_COLUMN_ADDRESS, 0x00, 0x00, 0x01, 0x3f,
142 };
143 
144 static u8 hx8357_seq_page_address[] = {
145 	HX8357_SET_PAGE_ADDRESS, 0x00, 0x00, 0x01, 0xdf,
146 };
147 
148 static u8 hx8357_seq_rgb[] = {
149 	HX8357_SET_RGB, 0x02,
150 };
151 
152 static u8 hx8357_seq_display_mode[] = {
153 	HX8357_SET_DISPLAY_MODE,
154 	HX8357_SET_DISPLAY_MODE_RGB_THROUGH |
155 	HX8357_SET_DISPLAY_MODE_RGB_INTERFACE,
156 };
157 
158 static u8 hx8369_seq_write_CABC_min_brightness[] = {
159 	HX8369_WRITE_CABC_MIN_BRIGHTNESS, 0x00,
160 };
161 
162 static u8 hx8369_seq_write_CABC_control[] = {
163 	HX8369_WRITE_CABC_DISPLAY_VALUE, 0x24,
164 };
165 
166 static u8 hx8369_seq_set_display_brightness[] = {
167 	HX8369_SET_DISPLAY_BRIGHTNESS, 0xFF,
168 };
169 
170 static u8 hx8369_seq_write_CABC_control_setting[] = {
171 	HX8369_WRITE_CABC_BRIGHT_CTRL, 0x02,
172 };
173 
174 static u8 hx8369_seq_extension_command[] = {
175 	HX8369_SET_EXTENSION_COMMAND, 0xff, 0x83, 0x69,
176 };
177 
178 static u8 hx8369_seq_display_related[] = {
179 	HX8369_SET_DISPLAY_MODE, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00,
180 	0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00,	0x01,
181 };
182 
183 static u8 hx8369_seq_panel_waveform_cycle[] = {
184 	HX8369_SET_DISPLAY_WAVEFORM_CYC, 0x0a, 0x1d, 0x80, 0x06, 0x02,
185 };
186 
187 static u8 hx8369_seq_set_address_mode[] = {
188 	HX8357_SET_ADDRESS_MODE, 0x00,
189 };
190 
191 static u8 hx8369_seq_vcom[] = {
192 	HX8369_SET_VCOM, 0x3e, 0x3e,
193 };
194 
195 static u8 hx8369_seq_gip[] = {
196 	HX8369_SET_GIP, 0x00, 0x01, 0x03, 0x25, 0x01, 0x02, 0x28, 0x70,
197 	0x11, 0x13, 0x00, 0x00, 0x40, 0x26, 0x51, 0x37, 0x00, 0x00, 0x71,
198 	0x35, 0x60, 0x24, 0x07, 0x0f, 0x04, 0x04,
199 };
200 
201 static u8 hx8369_seq_power[] = {
202 	HX8369_SET_POWER, 0x01, 0x00, 0x34, 0x03, 0x00, 0x11, 0x11, 0x32,
203 	0x2f, 0x3f, 0x3f, 0x01, 0x3a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
204 };
205 
206 static u8 hx8369_seq_gamma_curve_related[] = {
207 	HX8369_SET_GAMMA_CURVE_RELATED, 0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d,
208 	0x2e, 0x4a, 0x08, 0x0e, 0x0f, 0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
209 	0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d, 0x2e, 0x4a, 0x08, 0x0e, 0x0f,
210 	0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
211 };
212 
213 static int hx8357_spi_write_then_read(struct lcd_device *lcdev,
214 				u8 *txbuf, u16 txlen,
215 				u8 *rxbuf, u16 rxlen)
216 {
217 	struct hx8357_data *lcd = lcd_get_data(lcdev);
218 	struct spi_message msg;
219 	struct spi_transfer xfer[2];
220 	u16 *local_txbuf = NULL;
221 	int ret = 0;
222 
223 	memset(xfer, 0, sizeof(xfer));
224 	spi_message_init(&msg);
225 
226 	if (txlen) {
227 		int i;
228 
229 		local_txbuf = kcalloc(txlen, sizeof(*local_txbuf), GFP_KERNEL);
230 
231 		if (!local_txbuf)
232 			return -ENOMEM;
233 
234 		for (i = 0; i < txlen; i++) {
235 			local_txbuf[i] = txbuf[i];
236 			if (i > 0)
237 				local_txbuf[i] |= 1 << 8;
238 		}
239 
240 		xfer[0].len = 2 * txlen;
241 		xfer[0].bits_per_word = 9;
242 		xfer[0].tx_buf = local_txbuf;
243 		spi_message_add_tail(&xfer[0], &msg);
244 	}
245 
246 	if (rxlen) {
247 		xfer[1].len = rxlen;
248 		xfer[1].bits_per_word = 8;
249 		xfer[1].rx_buf = rxbuf;
250 		spi_message_add_tail(&xfer[1], &msg);
251 	}
252 
253 	ret = spi_sync(lcd->spi, &msg);
254 	if (ret < 0)
255 		dev_err(&lcdev->dev, "Couldn't send SPI data\n");
256 
257 	if (txlen)
258 		kfree(local_txbuf);
259 
260 	return ret;
261 }
262 
263 static inline int hx8357_spi_write_array(struct lcd_device *lcdev,
264 					u8 *value, u8 len)
265 {
266 	return hx8357_spi_write_then_read(lcdev, value, len, NULL, 0);
267 }
268 
269 static inline int hx8357_spi_write_byte(struct lcd_device *lcdev,
270 					u8 value)
271 {
272 	return hx8357_spi_write_then_read(lcdev, &value, 1, NULL, 0);
273 }
274 
275 static int hx8357_enter_standby(struct lcd_device *lcdev)
276 {
277 	int ret;
278 
279 	ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_OFF);
280 	if (ret < 0)
281 		return ret;
282 
283 	usleep_range(10000, 12000);
284 
285 	ret = hx8357_spi_write_byte(lcdev, HX8357_ENTER_SLEEP_MODE);
286 	if (ret < 0)
287 		return ret;
288 
289 	/*
290 	 * The controller needs 120ms when entering in sleep mode before we can
291 	 * send the command to go off sleep mode
292 	 */
293 	msleep(120);
294 
295 	return 0;
296 }
297 
298 static int hx8357_exit_standby(struct lcd_device *lcdev)
299 {
300 	int ret;
301 
302 	ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
303 	if (ret < 0)
304 		return ret;
305 
306 	/*
307 	 * The controller needs 120ms when exiting from sleep mode before we
308 	 * can send the command to enter in sleep mode
309 	 */
310 	msleep(120);
311 
312 	ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
313 	if (ret < 0)
314 		return ret;
315 
316 	return 0;
317 }
318 
319 static void hx8357_lcd_reset(struct lcd_device *lcdev)
320 {
321 	struct hx8357_data *lcd = lcd_get_data(lcdev);
322 
323 	/* Reset the screen */
324 	gpio_set_value(lcd->reset, 1);
325 	usleep_range(10000, 12000);
326 	gpio_set_value(lcd->reset, 0);
327 	usleep_range(10000, 12000);
328 	gpio_set_value(lcd->reset, 1);
329 
330 	/* The controller needs 120ms to recover from reset */
331 	msleep(120);
332 }
333 
334 static int hx8357_lcd_init(struct lcd_device *lcdev)
335 {
336 	struct hx8357_data *lcd = lcd_get_data(lcdev);
337 	int ret;
338 
339 	/*
340 	 * Set the interface selection pins to SPI mode, with three
341 	 * wires
342 	 */
343 	if (lcd->use_im_pins) {
344 		gpio_set_value_cansleep(lcd->im_pins[0], 1);
345 		gpio_set_value_cansleep(lcd->im_pins[1], 0);
346 		gpio_set_value_cansleep(lcd->im_pins[2], 1);
347 	}
348 
349 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_power,
350 				ARRAY_SIZE(hx8357_seq_power));
351 	if (ret < 0)
352 		return ret;
353 
354 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_vcom,
355 				ARRAY_SIZE(hx8357_seq_vcom));
356 	if (ret < 0)
357 		return ret;
358 
359 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_power_normal,
360 				ARRAY_SIZE(hx8357_seq_power_normal));
361 	if (ret < 0)
362 		return ret;
363 
364 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_driving,
365 				ARRAY_SIZE(hx8357_seq_panel_driving));
366 	if (ret < 0)
367 		return ret;
368 
369 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_frame,
370 				ARRAY_SIZE(hx8357_seq_display_frame));
371 	if (ret < 0)
372 		return ret;
373 
374 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_related,
375 				ARRAY_SIZE(hx8357_seq_panel_related));
376 	if (ret < 0)
377 		return ret;
378 
379 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined1,
380 				ARRAY_SIZE(hx8357_seq_undefined1));
381 	if (ret < 0)
382 		return ret;
383 
384 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined2,
385 				ARRAY_SIZE(hx8357_seq_undefined2));
386 	if (ret < 0)
387 		return ret;
388 
389 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_gamma,
390 				ARRAY_SIZE(hx8357_seq_gamma));
391 	if (ret < 0)
392 		return ret;
393 
394 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_address_mode,
395 				ARRAY_SIZE(hx8357_seq_address_mode));
396 	if (ret < 0)
397 		return ret;
398 
399 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_pixel_format,
400 				ARRAY_SIZE(hx8357_seq_pixel_format));
401 	if (ret < 0)
402 		return ret;
403 
404 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_column_address,
405 				ARRAY_SIZE(hx8357_seq_column_address));
406 	if (ret < 0)
407 		return ret;
408 
409 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_page_address,
410 				ARRAY_SIZE(hx8357_seq_page_address));
411 	if (ret < 0)
412 		return ret;
413 
414 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_rgb,
415 				ARRAY_SIZE(hx8357_seq_rgb));
416 	if (ret < 0)
417 		return ret;
418 
419 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_mode,
420 				ARRAY_SIZE(hx8357_seq_display_mode));
421 	if (ret < 0)
422 		return ret;
423 
424 	ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
425 	if (ret < 0)
426 		return ret;
427 
428 	/*
429 	 * The controller needs 120ms to fully recover from exiting sleep mode
430 	 */
431 	msleep(120);
432 
433 	ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
434 	if (ret < 0)
435 		return ret;
436 
437 	usleep_range(5000, 7000);
438 
439 	ret = hx8357_spi_write_byte(lcdev, HX8357_WRITE_MEMORY_START);
440 	if (ret < 0)
441 		return ret;
442 
443 	return 0;
444 }
445 
446 static int hx8369_lcd_init(struct lcd_device *lcdev)
447 {
448 	int ret;
449 
450 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_extension_command,
451 				ARRAY_SIZE(hx8369_seq_extension_command));
452 	if (ret < 0)
453 		return ret;
454 	usleep_range(10000, 12000);
455 
456 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_display_related,
457 				ARRAY_SIZE(hx8369_seq_display_related));
458 	if (ret < 0)
459 		return ret;
460 
461 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_panel_waveform_cycle,
462 				ARRAY_SIZE(hx8369_seq_panel_waveform_cycle));
463 	if (ret < 0)
464 		return ret;
465 
466 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_set_address_mode,
467 				ARRAY_SIZE(hx8369_seq_set_address_mode));
468 	if (ret < 0)
469 		return ret;
470 
471 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_vcom,
472 				ARRAY_SIZE(hx8369_seq_vcom));
473 	if (ret < 0)
474 		return ret;
475 
476 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_gip,
477 				ARRAY_SIZE(hx8369_seq_gip));
478 	if (ret < 0)
479 		return ret;
480 
481 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_power,
482 				ARRAY_SIZE(hx8369_seq_power));
483 	if (ret < 0)
484 		return ret;
485 
486 	ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
487 	if (ret < 0)
488 		return ret;
489 
490 	/*
491 	 * The controller needs 120ms to fully recover from exiting sleep mode
492 	 */
493 	msleep(120);
494 
495 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_gamma_curve_related,
496 				ARRAY_SIZE(hx8369_seq_gamma_curve_related));
497 	if (ret < 0)
498 		return ret;
499 
500 	ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
501 	if (ret < 0)
502 		return ret;
503 	usleep_range(1000, 1200);
504 
505 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_write_CABC_control,
506 				ARRAY_SIZE(hx8369_seq_write_CABC_control));
507 	if (ret < 0)
508 		return ret;
509 	usleep_range(10000, 12000);
510 
511 	ret = hx8357_spi_write_array(lcdev,
512 			hx8369_seq_write_CABC_control_setting,
513 			ARRAY_SIZE(hx8369_seq_write_CABC_control_setting));
514 	if (ret < 0)
515 		return ret;
516 
517 	ret = hx8357_spi_write_array(lcdev,
518 			hx8369_seq_write_CABC_min_brightness,
519 			ARRAY_SIZE(hx8369_seq_write_CABC_min_brightness));
520 	if (ret < 0)
521 		return ret;
522 	usleep_range(10000, 12000);
523 
524 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_set_display_brightness,
525 				ARRAY_SIZE(hx8369_seq_set_display_brightness));
526 	if (ret < 0)
527 		return ret;
528 
529 	ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
530 	if (ret < 0)
531 		return ret;
532 
533 	return 0;
534 }
535 
536 #define POWER_IS_ON(pwr)	((pwr) <= FB_BLANK_NORMAL)
537 
538 static int hx8357_set_power(struct lcd_device *lcdev, int power)
539 {
540 	struct hx8357_data *lcd = lcd_get_data(lcdev);
541 	int ret = 0;
542 
543 	if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->state))
544 		ret = hx8357_exit_standby(lcdev);
545 	else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->state))
546 		ret = hx8357_enter_standby(lcdev);
547 
548 	if (ret == 0)
549 		lcd->state = power;
550 	else
551 		dev_warn(&lcdev->dev, "failed to set power mode %d\n", power);
552 
553 	return ret;
554 }
555 
556 static int hx8357_get_power(struct lcd_device *lcdev)
557 {
558 	struct hx8357_data *lcd = lcd_get_data(lcdev);
559 
560 	return lcd->state;
561 }
562 
563 static struct lcd_ops hx8357_ops = {
564 	.set_power	= hx8357_set_power,
565 	.get_power	= hx8357_get_power,
566 };
567 
568 static const struct of_device_id hx8357_dt_ids[] = {
569 	{
570 		.compatible = "himax,hx8357",
571 		.data = hx8357_lcd_init,
572 	},
573 	{
574 		.compatible = "himax,hx8369",
575 		.data = hx8369_lcd_init,
576 	},
577 	{},
578 };
579 MODULE_DEVICE_TABLE(of, hx8357_dt_ids);
580 
581 static int hx8357_probe(struct spi_device *spi)
582 {
583 	struct lcd_device *lcdev;
584 	struct hx8357_data *lcd;
585 	const struct of_device_id *match;
586 	int i, ret;
587 
588 	lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL);
589 	if (!lcd)
590 		return -ENOMEM;
591 
592 	ret = spi_setup(spi);
593 	if (ret < 0) {
594 		dev_err(&spi->dev, "SPI setup failed.\n");
595 		return ret;
596 	}
597 
598 	lcd->spi = spi;
599 
600 	match = of_match_device(hx8357_dt_ids, &spi->dev);
601 	if (!match || !match->data)
602 		return -EINVAL;
603 
604 	lcd->reset = of_get_named_gpio(spi->dev.of_node, "gpios-reset", 0);
605 	if (!gpio_is_valid(lcd->reset)) {
606 		dev_err(&spi->dev, "Missing dt property: gpios-reset\n");
607 		return -EINVAL;
608 	}
609 
610 	ret = devm_gpio_request_one(&spi->dev, lcd->reset,
611 				    GPIOF_OUT_INIT_HIGH,
612 				    "hx8357-reset");
613 	if (ret) {
614 		dev_err(&spi->dev,
615 			"failed to request gpio %d: %d\n",
616 			lcd->reset, ret);
617 		return -EINVAL;
618 	}
619 
620 	if (of_property_present(spi->dev.of_node, "im-gpios")) {
621 		lcd->use_im_pins = 1;
622 
623 		for (i = 0; i < HX8357_NUM_IM_PINS; i++) {
624 			lcd->im_pins[i] = of_get_named_gpio(spi->dev.of_node,
625 							    "im-gpios", i);
626 			if (lcd->im_pins[i] == -EPROBE_DEFER) {
627 				dev_info(&spi->dev, "GPIO requested is not here yet, deferring the probe\n");
628 				return -EPROBE_DEFER;
629 			}
630 			if (!gpio_is_valid(lcd->im_pins[i])) {
631 				dev_err(&spi->dev, "Missing dt property: im-gpios\n");
632 				return -EINVAL;
633 			}
634 
635 			ret = devm_gpio_request_one(&spi->dev, lcd->im_pins[i],
636 						    GPIOF_OUT_INIT_LOW,
637 						    "im_pins");
638 			if (ret) {
639 				dev_err(&spi->dev, "failed to request gpio %d: %d\n",
640 					lcd->im_pins[i], ret);
641 				return -EINVAL;
642 			}
643 		}
644 	} else {
645 		lcd->use_im_pins = 0;
646 	}
647 
648 	lcdev = devm_lcd_device_register(&spi->dev, "mxsfb", &spi->dev, lcd,
649 					&hx8357_ops);
650 	if (IS_ERR(lcdev)) {
651 		ret = PTR_ERR(lcdev);
652 		return ret;
653 	}
654 	spi_set_drvdata(spi, lcdev);
655 
656 	hx8357_lcd_reset(lcdev);
657 
658 	ret = ((int (*)(struct lcd_device *))match->data)(lcdev);
659 	if (ret) {
660 		dev_err(&spi->dev, "Couldn't initialize panel\n");
661 		return ret;
662 	}
663 
664 	dev_info(&spi->dev, "Panel probed\n");
665 
666 	return 0;
667 }
668 
669 static struct spi_driver hx8357_driver = {
670 	.probe  = hx8357_probe,
671 	.driver = {
672 		.name = "hx8357",
673 		.of_match_table = hx8357_dt_ids,
674 	},
675 };
676 
677 module_spi_driver(hx8357_driver);
678 
679 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
680 MODULE_DESCRIPTION("Himax HX-8357 LCD Driver");
681 MODULE_LICENSE("GPL");
682