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