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
86struct 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
94static u8 hx8357_seq_power[] = {
95	HX8357_SET_POWER, 0x44, 0x41, 0x06,
96};
97
98static u8 hx8357_seq_vcom[] = {
99	HX8357_SET_VCOM, 0x40, 0x10,
100};
101
102static u8 hx8357_seq_power_normal[] = {
103	HX8357_SET_POWER_NORMAL, 0x05, 0x12,
104};
105
106static u8 hx8357_seq_panel_driving[] = {
107	HX8357_SET_PANEL_DRIVING, 0x14, 0x3b, 0x00, 0x02, 0x11,
108};
109
110static u8 hx8357_seq_display_frame[] = {
111	HX8357_SET_DISPLAY_FRAME, 0x0c,
112};
113
114static u8 hx8357_seq_panel_related[] = {
115	HX8357_SET_PANEL_RELATED, 0x01,
116};
117
118static u8 hx8357_seq_undefined1[] = {
119	0xea, 0x03, 0x00, 0x00,
120};
121
122static u8 hx8357_seq_undefined2[] = {
123	0xeb, 0x40, 0x54, 0x26, 0xdb,
124};
125
126static u8 hx8357_seq_gamma[] = {
127	HX8357_SET_GAMMA, 0x00, 0x15, 0x00, 0x22, 0x00,
128	0x08, 0x77, 0x26, 0x77, 0x22, 0x04, 0x00,
129};
130
131static u8 hx8357_seq_address_mode[] = {
132	HX8357_SET_ADDRESS_MODE, 0xc0,
133};
134
135static 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
141static u8 hx8357_seq_column_address[] = {
142	HX8357_SET_COLUMN_ADDRESS, 0x00, 0x00, 0x01, 0x3f,
143};
144
145static u8 hx8357_seq_page_address[] = {
146	HX8357_SET_PAGE_ADDRESS, 0x00, 0x00, 0x01, 0xdf,
147};
148
149static u8 hx8357_seq_rgb[] = {
150	HX8357_SET_RGB, 0x02,
151};
152
153static 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
159static u8 hx8369_seq_write_CABC_min_brightness[] = {
160	HX8369_WRITE_CABC_MIN_BRIGHTNESS, 0x00,
161};
162
163static u8 hx8369_seq_write_CABC_control[] = {
164	HX8369_WRITE_CABC_DISPLAY_VALUE, 0x24,
165};
166
167static u8 hx8369_seq_set_display_brightness[] = {
168	HX8369_SET_DISPLAY_BRIGHTNESS, 0xFF,
169};
170
171static u8 hx8369_seq_write_CABC_control_setting[] = {
172	HX8369_WRITE_CABC_BRIGHT_CTRL, 0x02,
173};
174
175static u8 hx8369_seq_extension_command[] = {
176	HX8369_SET_EXTENSION_COMMAND, 0xff, 0x83, 0x69,
177};
178
179static 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
184static u8 hx8369_seq_panel_waveform_cycle[] = {
185	HX8369_SET_DISPLAY_WAVEFORM_CYC, 0x0a, 0x1d, 0x80, 0x06, 0x02,
186};
187
188static u8 hx8369_seq_set_address_mode[] = {
189	HX8357_SET_ADDRESS_MODE, 0x00,
190};
191
192static u8 hx8369_seq_vcom[] = {
193	HX8369_SET_VCOM, 0x3e, 0x3e,
194};
195
196static 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
202static 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
207static 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
214static 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
264static 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
270static 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
276static 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
299static 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
320static 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
335static 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
447static 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
539static 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
557static 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
564static struct lcd_ops hx8357_ops = {
565	.set_power	= hx8357_set_power,
566	.get_power	= hx8357_get_power,
567};
568
569static 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};
580MODULE_DEVICE_TABLE(of, hx8357_dt_ids);
581
582static 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
670static struct spi_driver hx8357_driver = {
671	.probe  = hx8357_probe,
672	.driver = {
673		.name = "hx8357",
674		.of_match_table = hx8357_dt_ids,
675	},
676};
677
678module_spi_driver(hx8357_driver);
679
680MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
681MODULE_DESCRIPTION("Himax HX-8357 LCD Driver");
682MODULE_LICENSE("GPL");
683