xref: /linux/drivers/video/backlight/hx8357.c (revision 71dfa617ea9f18e4585fe78364217cd32b1fc382)
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/gpio/consumer.h>
10 #include <linux/lcd.h>
11 #include <linux/mod_devicetable.h>
12 #include <linux/module.h>
13 #include <linux/property.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 	struct gpio_descs	*im_pins;
87 	struct gpio_desc	*reset;
88 	struct spi_device	*spi;
89 	int			state;
90 };
91 
92 static u8 hx8357_seq_power[] = {
93 	HX8357_SET_POWER, 0x44, 0x41, 0x06,
94 };
95 
96 static u8 hx8357_seq_vcom[] = {
97 	HX8357_SET_VCOM, 0x40, 0x10,
98 };
99 
100 static u8 hx8357_seq_power_normal[] = {
101 	HX8357_SET_POWER_NORMAL, 0x05, 0x12,
102 };
103 
104 static u8 hx8357_seq_panel_driving[] = {
105 	HX8357_SET_PANEL_DRIVING, 0x14, 0x3b, 0x00, 0x02, 0x11,
106 };
107 
108 static u8 hx8357_seq_display_frame[] = {
109 	HX8357_SET_DISPLAY_FRAME, 0x0c,
110 };
111 
112 static u8 hx8357_seq_panel_related[] = {
113 	HX8357_SET_PANEL_RELATED, 0x01,
114 };
115 
116 static u8 hx8357_seq_undefined1[] = {
117 	0xea, 0x03, 0x00, 0x00,
118 };
119 
120 static u8 hx8357_seq_undefined2[] = {
121 	0xeb, 0x40, 0x54, 0x26, 0xdb,
122 };
123 
124 static u8 hx8357_seq_gamma[] = {
125 	HX8357_SET_GAMMA, 0x00, 0x15, 0x00, 0x22, 0x00,
126 	0x08, 0x77, 0x26, 0x77, 0x22, 0x04, 0x00,
127 };
128 
129 static u8 hx8357_seq_address_mode[] = {
130 	HX8357_SET_ADDRESS_MODE, 0xc0,
131 };
132 
133 static u8 hx8357_seq_pixel_format[] = {
134 	HX8357_SET_PIXEL_FORMAT,
135 	HX8357_SET_PIXEL_FORMAT_DPI_18BIT |
136 	HX8357_SET_PIXEL_FORMAT_DBI_18BIT,
137 };
138 
139 static u8 hx8357_seq_column_address[] = {
140 	HX8357_SET_COLUMN_ADDRESS, 0x00, 0x00, 0x01, 0x3f,
141 };
142 
143 static u8 hx8357_seq_page_address[] = {
144 	HX8357_SET_PAGE_ADDRESS, 0x00, 0x00, 0x01, 0xdf,
145 };
146 
147 static u8 hx8357_seq_rgb[] = {
148 	HX8357_SET_RGB, 0x02,
149 };
150 
151 static u8 hx8357_seq_display_mode[] = {
152 	HX8357_SET_DISPLAY_MODE,
153 	HX8357_SET_DISPLAY_MODE_RGB_THROUGH |
154 	HX8357_SET_DISPLAY_MODE_RGB_INTERFACE,
155 };
156 
157 static u8 hx8369_seq_write_CABC_min_brightness[] = {
158 	HX8369_WRITE_CABC_MIN_BRIGHTNESS, 0x00,
159 };
160 
161 static u8 hx8369_seq_write_CABC_control[] = {
162 	HX8369_WRITE_CABC_DISPLAY_VALUE, 0x24,
163 };
164 
165 static u8 hx8369_seq_set_display_brightness[] = {
166 	HX8369_SET_DISPLAY_BRIGHTNESS, 0xFF,
167 };
168 
169 static u8 hx8369_seq_write_CABC_control_setting[] = {
170 	HX8369_WRITE_CABC_BRIGHT_CTRL, 0x02,
171 };
172 
173 static u8 hx8369_seq_extension_command[] = {
174 	HX8369_SET_EXTENSION_COMMAND, 0xff, 0x83, 0x69,
175 };
176 
177 static u8 hx8369_seq_display_related[] = {
178 	HX8369_SET_DISPLAY_MODE, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00,
179 	0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00,	0x01,
180 };
181 
182 static u8 hx8369_seq_panel_waveform_cycle[] = {
183 	HX8369_SET_DISPLAY_WAVEFORM_CYC, 0x0a, 0x1d, 0x80, 0x06, 0x02,
184 };
185 
186 static u8 hx8369_seq_set_address_mode[] = {
187 	HX8357_SET_ADDRESS_MODE, 0x00,
188 };
189 
190 static u8 hx8369_seq_vcom[] = {
191 	HX8369_SET_VCOM, 0x3e, 0x3e,
192 };
193 
194 static u8 hx8369_seq_gip[] = {
195 	HX8369_SET_GIP, 0x00, 0x01, 0x03, 0x25, 0x01, 0x02, 0x28, 0x70,
196 	0x11, 0x13, 0x00, 0x00, 0x40, 0x26, 0x51, 0x37, 0x00, 0x00, 0x71,
197 	0x35, 0x60, 0x24, 0x07, 0x0f, 0x04, 0x04,
198 };
199 
200 static u8 hx8369_seq_power[] = {
201 	HX8369_SET_POWER, 0x01, 0x00, 0x34, 0x03, 0x00, 0x11, 0x11, 0x32,
202 	0x2f, 0x3f, 0x3f, 0x01, 0x3a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
203 };
204 
205 static u8 hx8369_seq_gamma_curve_related[] = {
206 	HX8369_SET_GAMMA_CURVE_RELATED, 0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d,
207 	0x2e, 0x4a, 0x08, 0x0e, 0x0f, 0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
208 	0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d, 0x2e, 0x4a, 0x08, 0x0e, 0x0f,
209 	0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
210 };
211 
212 static int hx8357_spi_write_then_read(struct lcd_device *lcdev,
213 				u8 *txbuf, u16 txlen,
214 				u8 *rxbuf, u16 rxlen)
215 {
216 	struct hx8357_data *lcd = lcd_get_data(lcdev);
217 	struct spi_message msg;
218 	struct spi_transfer xfer[2];
219 	u16 *local_txbuf = NULL;
220 	int ret = 0;
221 
222 	memset(xfer, 0, sizeof(xfer));
223 	spi_message_init(&msg);
224 
225 	if (txlen) {
226 		int i;
227 
228 		local_txbuf = kcalloc(txlen, sizeof(*local_txbuf), GFP_KERNEL);
229 
230 		if (!local_txbuf)
231 			return -ENOMEM;
232 
233 		for (i = 0; i < txlen; i++) {
234 			local_txbuf[i] = txbuf[i];
235 			if (i > 0)
236 				local_txbuf[i] |= 1 << 8;
237 		}
238 
239 		xfer[0].len = 2 * txlen;
240 		xfer[0].bits_per_word = 9;
241 		xfer[0].tx_buf = local_txbuf;
242 		spi_message_add_tail(&xfer[0], &msg);
243 	}
244 
245 	if (rxlen) {
246 		xfer[1].len = rxlen;
247 		xfer[1].bits_per_word = 8;
248 		xfer[1].rx_buf = rxbuf;
249 		spi_message_add_tail(&xfer[1], &msg);
250 	}
251 
252 	ret = spi_sync(lcd->spi, &msg);
253 	if (ret < 0)
254 		dev_err(&lcdev->dev, "Couldn't send SPI data\n");
255 
256 	if (txlen)
257 		kfree(local_txbuf);
258 
259 	return ret;
260 }
261 
262 static inline int hx8357_spi_write_array(struct lcd_device *lcdev,
263 					u8 *value, u8 len)
264 {
265 	return hx8357_spi_write_then_read(lcdev, value, len, NULL, 0);
266 }
267 
268 static inline int hx8357_spi_write_byte(struct lcd_device *lcdev,
269 					u8 value)
270 {
271 	return hx8357_spi_write_then_read(lcdev, &value, 1, NULL, 0);
272 }
273 
274 static int hx8357_enter_standby(struct lcd_device *lcdev)
275 {
276 	int ret;
277 
278 	ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_OFF);
279 	if (ret < 0)
280 		return ret;
281 
282 	usleep_range(10000, 12000);
283 
284 	ret = hx8357_spi_write_byte(lcdev, HX8357_ENTER_SLEEP_MODE);
285 	if (ret < 0)
286 		return ret;
287 
288 	/*
289 	 * The controller needs 120ms when entering in sleep mode before we can
290 	 * send the command to go off sleep mode
291 	 */
292 	msleep(120);
293 
294 	return 0;
295 }
296 
297 static int hx8357_exit_standby(struct lcd_device *lcdev)
298 {
299 	int ret;
300 
301 	ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
302 	if (ret < 0)
303 		return ret;
304 
305 	/*
306 	 * The controller needs 120ms when exiting from sleep mode before we
307 	 * can send the command to enter in sleep mode
308 	 */
309 	msleep(120);
310 
311 	ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
312 	if (ret < 0)
313 		return ret;
314 
315 	return 0;
316 }
317 
318 static void hx8357_lcd_reset(struct lcd_device *lcdev)
319 {
320 	struct hx8357_data *lcd = lcd_get_data(lcdev);
321 
322 	/* Reset the screen */
323 	gpiod_set_value(lcd->reset, 0);
324 	usleep_range(10000, 12000);
325 	gpiod_set_value(lcd->reset, 1);
326 	usleep_range(10000, 12000);
327 	gpiod_set_value(lcd->reset, 0);
328 
329 	/* The controller needs 120ms to recover from reset */
330 	msleep(120);
331 }
332 
333 static int hx8357_lcd_init(struct lcd_device *lcdev)
334 {
335 	struct hx8357_data *lcd = lcd_get_data(lcdev);
336 	int ret;
337 
338 	/*
339 	 * Set the interface selection pins to SPI mode, with three
340 	 * wires
341 	 */
342 	if (lcd->im_pins) {
343 		gpiod_set_value_cansleep(lcd->im_pins->desc[0], 1);
344 		gpiod_set_value_cansleep(lcd->im_pins->desc[1], 0);
345 		gpiod_set_value_cansleep(lcd->im_pins->desc[2], 1);
346 	}
347 
348 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_power,
349 				ARRAY_SIZE(hx8357_seq_power));
350 	if (ret < 0)
351 		return ret;
352 
353 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_vcom,
354 				ARRAY_SIZE(hx8357_seq_vcom));
355 	if (ret < 0)
356 		return ret;
357 
358 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_power_normal,
359 				ARRAY_SIZE(hx8357_seq_power_normal));
360 	if (ret < 0)
361 		return ret;
362 
363 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_driving,
364 				ARRAY_SIZE(hx8357_seq_panel_driving));
365 	if (ret < 0)
366 		return ret;
367 
368 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_frame,
369 				ARRAY_SIZE(hx8357_seq_display_frame));
370 	if (ret < 0)
371 		return ret;
372 
373 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_related,
374 				ARRAY_SIZE(hx8357_seq_panel_related));
375 	if (ret < 0)
376 		return ret;
377 
378 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined1,
379 				ARRAY_SIZE(hx8357_seq_undefined1));
380 	if (ret < 0)
381 		return ret;
382 
383 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined2,
384 				ARRAY_SIZE(hx8357_seq_undefined2));
385 	if (ret < 0)
386 		return ret;
387 
388 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_gamma,
389 				ARRAY_SIZE(hx8357_seq_gamma));
390 	if (ret < 0)
391 		return ret;
392 
393 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_address_mode,
394 				ARRAY_SIZE(hx8357_seq_address_mode));
395 	if (ret < 0)
396 		return ret;
397 
398 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_pixel_format,
399 				ARRAY_SIZE(hx8357_seq_pixel_format));
400 	if (ret < 0)
401 		return ret;
402 
403 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_column_address,
404 				ARRAY_SIZE(hx8357_seq_column_address));
405 	if (ret < 0)
406 		return ret;
407 
408 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_page_address,
409 				ARRAY_SIZE(hx8357_seq_page_address));
410 	if (ret < 0)
411 		return ret;
412 
413 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_rgb,
414 				ARRAY_SIZE(hx8357_seq_rgb));
415 	if (ret < 0)
416 		return ret;
417 
418 	ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_mode,
419 				ARRAY_SIZE(hx8357_seq_display_mode));
420 	if (ret < 0)
421 		return ret;
422 
423 	ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
424 	if (ret < 0)
425 		return ret;
426 
427 	/*
428 	 * The controller needs 120ms to fully recover from exiting sleep mode
429 	 */
430 	msleep(120);
431 
432 	ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
433 	if (ret < 0)
434 		return ret;
435 
436 	usleep_range(5000, 7000);
437 
438 	ret = hx8357_spi_write_byte(lcdev, HX8357_WRITE_MEMORY_START);
439 	if (ret < 0)
440 		return ret;
441 
442 	return 0;
443 }
444 
445 static int hx8369_lcd_init(struct lcd_device *lcdev)
446 {
447 	int ret;
448 
449 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_extension_command,
450 				ARRAY_SIZE(hx8369_seq_extension_command));
451 	if (ret < 0)
452 		return ret;
453 	usleep_range(10000, 12000);
454 
455 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_display_related,
456 				ARRAY_SIZE(hx8369_seq_display_related));
457 	if (ret < 0)
458 		return ret;
459 
460 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_panel_waveform_cycle,
461 				ARRAY_SIZE(hx8369_seq_panel_waveform_cycle));
462 	if (ret < 0)
463 		return ret;
464 
465 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_set_address_mode,
466 				ARRAY_SIZE(hx8369_seq_set_address_mode));
467 	if (ret < 0)
468 		return ret;
469 
470 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_vcom,
471 				ARRAY_SIZE(hx8369_seq_vcom));
472 	if (ret < 0)
473 		return ret;
474 
475 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_gip,
476 				ARRAY_SIZE(hx8369_seq_gip));
477 	if (ret < 0)
478 		return ret;
479 
480 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_power,
481 				ARRAY_SIZE(hx8369_seq_power));
482 	if (ret < 0)
483 		return ret;
484 
485 	ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
486 	if (ret < 0)
487 		return ret;
488 
489 	/*
490 	 * The controller needs 120ms to fully recover from exiting sleep mode
491 	 */
492 	msleep(120);
493 
494 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_gamma_curve_related,
495 				ARRAY_SIZE(hx8369_seq_gamma_curve_related));
496 	if (ret < 0)
497 		return ret;
498 
499 	ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
500 	if (ret < 0)
501 		return ret;
502 	usleep_range(1000, 1200);
503 
504 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_write_CABC_control,
505 				ARRAY_SIZE(hx8369_seq_write_CABC_control));
506 	if (ret < 0)
507 		return ret;
508 	usleep_range(10000, 12000);
509 
510 	ret = hx8357_spi_write_array(lcdev,
511 			hx8369_seq_write_CABC_control_setting,
512 			ARRAY_SIZE(hx8369_seq_write_CABC_control_setting));
513 	if (ret < 0)
514 		return ret;
515 
516 	ret = hx8357_spi_write_array(lcdev,
517 			hx8369_seq_write_CABC_min_brightness,
518 			ARRAY_SIZE(hx8369_seq_write_CABC_min_brightness));
519 	if (ret < 0)
520 		return ret;
521 	usleep_range(10000, 12000);
522 
523 	ret = hx8357_spi_write_array(lcdev, hx8369_seq_set_display_brightness,
524 				ARRAY_SIZE(hx8369_seq_set_display_brightness));
525 	if (ret < 0)
526 		return ret;
527 
528 	ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
529 	if (ret < 0)
530 		return ret;
531 
532 	return 0;
533 }
534 
535 #define POWER_IS_ON(pwr)	((pwr) <= FB_BLANK_NORMAL)
536 
537 static int hx8357_set_power(struct lcd_device *lcdev, int power)
538 {
539 	struct hx8357_data *lcd = lcd_get_data(lcdev);
540 	int ret = 0;
541 
542 	if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->state))
543 		ret = hx8357_exit_standby(lcdev);
544 	else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->state))
545 		ret = hx8357_enter_standby(lcdev);
546 
547 	if (ret == 0)
548 		lcd->state = power;
549 	else
550 		dev_warn(&lcdev->dev, "failed to set power mode %d\n", power);
551 
552 	return ret;
553 }
554 
555 static int hx8357_get_power(struct lcd_device *lcdev)
556 {
557 	struct hx8357_data *lcd = lcd_get_data(lcdev);
558 
559 	return lcd->state;
560 }
561 
562 static struct lcd_ops hx8357_ops = {
563 	.set_power	= hx8357_set_power,
564 	.get_power	= hx8357_get_power,
565 };
566 
567 typedef int (*hx8357_init_fn)(struct lcd_device *);
568 
569 static int hx8357_probe(struct spi_device *spi)
570 {
571 	struct device *dev = &spi->dev;
572 	struct lcd_device *lcdev;
573 	struct hx8357_data *lcd;
574 	hx8357_init_fn init_fn;
575 	int i, ret;
576 
577 	lcd = devm_kzalloc(dev, sizeof(*lcd), GFP_KERNEL);
578 	if (!lcd)
579 		return -ENOMEM;
580 
581 	ret = spi_setup(spi);
582 	if (ret < 0)
583 		return dev_err_probe(dev, ret, "SPI setup failed.\n");
584 
585 	lcd->spi = spi;
586 
587 	init_fn = device_get_match_data(dev);
588 	if (!init_fn)
589 		return -EINVAL;
590 
591 	lcd->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
592 	if (IS_ERR(lcd->reset))
593 		return dev_err_probe(dev, PTR_ERR(lcd->reset), "failed to request reset GPIO\n");
594 	gpiod_set_consumer_name(lcd->reset, "hx8357-reset");
595 
596 	lcd->im_pins = devm_gpiod_get_array_optional(dev, "im", GPIOD_OUT_LOW);
597 	if (IS_ERR(lcd->im_pins))
598 		return dev_err_probe(dev, PTR_ERR(lcd->im_pins), "failed to request im GPIOs\n");
599 	if (lcd->im_pins) {
600 		if (lcd->im_pins->ndescs < HX8357_NUM_IM_PINS)
601 			return dev_err_probe(dev, -EINVAL, "not enough im GPIOs\n");
602 
603 		for (i = 0; i < HX8357_NUM_IM_PINS; i++)
604 			gpiod_set_consumer_name(lcd->im_pins->desc[i], "im_pins");
605 	}
606 
607 	lcdev = devm_lcd_device_register(dev, "mxsfb", dev, lcd, &hx8357_ops);
608 	if (IS_ERR(lcdev)) {
609 		ret = PTR_ERR(lcdev);
610 		return ret;
611 	}
612 	spi_set_drvdata(spi, lcdev);
613 
614 	hx8357_lcd_reset(lcdev);
615 
616 	ret = init_fn(lcdev);
617 	if (ret)
618 		return dev_err_probe(dev, ret, "Couldn't initialize panel\n");
619 
620 	dev_info(dev, "Panel probed\n");
621 
622 	return 0;
623 }
624 
625 static const struct of_device_id hx8357_dt_ids[] = {
626 	{
627 		.compatible = "himax,hx8357",
628 		.data = hx8357_lcd_init,
629 	},
630 	{
631 		.compatible = "himax,hx8369",
632 		.data = hx8369_lcd_init,
633 	},
634 	{}
635 };
636 MODULE_DEVICE_TABLE(of, hx8357_dt_ids);
637 
638 static struct spi_driver hx8357_driver = {
639 	.probe  = hx8357_probe,
640 	.driver = {
641 		.name = "hx8357",
642 		.of_match_table = hx8357_dt_ids,
643 	},
644 };
645 
646 module_spi_driver(hx8357_driver);
647 
648 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
649 MODULE_DESCRIPTION("Himax HX-8357 LCD Driver");
650 MODULE_LICENSE("GPL");
651