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