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