]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/video/backlight/hx8357.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-jammy-kernel.git] / drivers / video / backlight / hx8357.c
CommitLineData
c51cb3f5 1// SPDX-License-Identifier: GPL-2.0-or-later
8a6c1dd5
MR
2/*
3 * Driver for the Himax HX-8357 LCD Controller
4 *
5 * Copyright 2012 Free Electrons
8a6c1dd5
MR
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
fb525668
AB
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
8a6c1dd5
MR
85struct hx8357_data {
86 unsigned im_pins[HX8357_NUM_IM_PINS];
87 unsigned reset;
88 struct spi_device *spi;
89 int state;
ccf9901f 90 bool use_im_pins;
8a6c1dd5
MR
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
fb525668
AB
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
8a6c1dd5
MR
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
fb525668
AB
289 /*
290 * The controller needs 120ms when entering in sleep mode before we can
291 * send the command to go off sleep mode
292 */
8a6c1dd5
MR
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
fb525668
AB
306 /*
307 * The controller needs 120ms when exiting from sleep mode before we
308 * can send the command to enter in sleep mode
309 */
8a6c1dd5
MR
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
fb525668
AB
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
8a6c1dd5
MR
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 */
ccf9901f
MR
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 }
8a6c1dd5 348
8a6c1dd5
MR
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
fb525668
AB
428 /*
429 * The controller needs 120ms to fully recover from exiting sleep mode
430 */
8a6c1dd5
MR
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
fb525668
AB
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
8a6c1dd5
MR
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
fb525668
AB
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
8a6c1dd5
MR
581static int hx8357_probe(struct spi_device *spi)
582{
583 struct lcd_device *lcdev;
584 struct hx8357_data *lcd;
fb525668 585 const struct of_device_id *match;
8a6c1dd5
MR
586 int i, ret;
587
588 lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL);
aff70f9a 589 if (!lcd)
8a6c1dd5 590 return -ENOMEM;
8a6c1dd5
MR
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
fb525668
AB
600 match = of_match_device(hx8357_dt_ids, &spi->dev);
601 if (!match || !match->data)
602 return -EINVAL;
603
8a6c1dd5
MR
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
ccf9901f
MR
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 }
8a6c1dd5 643 }
ccf9901f
MR
644 } else {
645 lcd->use_im_pins = 0;
8a6c1dd5
MR
646 }
647
ea5092c8
JH
648 lcdev = devm_lcd_device_register(&spi->dev, "mxsfb", &spi->dev, lcd,
649 &hx8357_ops);
8a6c1dd5
MR
650 if (IS_ERR(lcdev)) {
651 ret = PTR_ERR(lcdev);
652 return ret;
653 }
654 spi_set_drvdata(spi, lcdev);
655
fb525668
AB
656 hx8357_lcd_reset(lcdev);
657
658 ret = ((int (*)(struct lcd_device *))match->data)(lcdev);
8a6c1dd5
MR
659 if (ret) {
660 dev_err(&spi->dev, "Couldn't initialize panel\n");
ea5092c8 661 return ret;
8a6c1dd5
MR
662 }
663
664 dev_info(&spi->dev, "Panel probed\n");
665
666 return 0;
8a6c1dd5
MR
667}
668
8a6c1dd5
MR
669static struct spi_driver hx8357_driver = {
670 .probe = hx8357_probe,
8a6c1dd5
MR
671 .driver = {
672 .name = "hx8357",
c962f7b9 673 .of_match_table = hx8357_dt_ids,
8a6c1dd5
MR
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");