1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Driver for the Himax HX-8357 LCD Controller
5 * Copyright 2012 Free Electrons
8 #include <linux/delay.h>
9 #include <linux/gpio/consumer.h>
10 #include <linux/lcd.h>
11 #include <linux/mod_devicetable.h>
12 #include <linux/module.h>
13 #include <linux/property.h>
14 #include <linux/spi/spi.h>
16 #define HX8357_NUM_IM_PINS 3
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
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
86 struct gpio_descs
*im_pins
;
87 struct gpio_desc
*reset
;
88 struct spi_device
*spi
;
92 static u8 hx8357_seq_power
[] = {
93 HX8357_SET_POWER
, 0x44, 0x41, 0x06,
96 static u8 hx8357_seq_vcom
[] = {
97 HX8357_SET_VCOM
, 0x40, 0x10,
100 static u8 hx8357_seq_power_normal
[] = {
101 HX8357_SET_POWER_NORMAL
, 0x05, 0x12,
104 static u8 hx8357_seq_panel_driving
[] = {
105 HX8357_SET_PANEL_DRIVING
, 0x14, 0x3b, 0x00, 0x02, 0x11,
108 static u8 hx8357_seq_display_frame
[] = {
109 HX8357_SET_DISPLAY_FRAME
, 0x0c,
112 static u8 hx8357_seq_panel_related
[] = {
113 HX8357_SET_PANEL_RELATED
, 0x01,
116 static u8 hx8357_seq_undefined1
[] = {
117 0xea, 0x03, 0x00, 0x00,
120 static u8 hx8357_seq_undefined2
[] = {
121 0xeb, 0x40, 0x54, 0x26, 0xdb,
124 static u8 hx8357_seq_gamma
[] = {
125 HX8357_SET_GAMMA
, 0x00, 0x15, 0x00, 0x22, 0x00,
126 0x08, 0x77, 0x26, 0x77, 0x22, 0x04, 0x00,
129 static u8 hx8357_seq_address_mode
[] = {
130 HX8357_SET_ADDRESS_MODE
, 0xc0,
133 static u8 hx8357_seq_pixel_format
[] = {
134 HX8357_SET_PIXEL_FORMAT
,
135 HX8357_SET_PIXEL_FORMAT_DPI_18BIT
|
136 HX8357_SET_PIXEL_FORMAT_DBI_18BIT
,
139 static u8 hx8357_seq_column_address
[] = {
140 HX8357_SET_COLUMN_ADDRESS
, 0x00, 0x00, 0x01, 0x3f,
143 static u8 hx8357_seq_page_address
[] = {
144 HX8357_SET_PAGE_ADDRESS
, 0x00, 0x00, 0x01, 0xdf,
147 static u8 hx8357_seq_rgb
[] = {
148 HX8357_SET_RGB
, 0x02,
151 static u8 hx8357_seq_display_mode
[] = {
152 HX8357_SET_DISPLAY_MODE
,
153 HX8357_SET_DISPLAY_MODE_RGB_THROUGH
|
154 HX8357_SET_DISPLAY_MODE_RGB_INTERFACE
,
157 static u8 hx8369_seq_write_CABC_min_brightness
[] = {
158 HX8369_WRITE_CABC_MIN_BRIGHTNESS
, 0x00,
161 static u8 hx8369_seq_write_CABC_control
[] = {
162 HX8369_WRITE_CABC_DISPLAY_VALUE
, 0x24,
165 static u8 hx8369_seq_set_display_brightness
[] = {
166 HX8369_SET_DISPLAY_BRIGHTNESS
, 0xFF,
169 static u8 hx8369_seq_write_CABC_control_setting
[] = {
170 HX8369_WRITE_CABC_BRIGHT_CTRL
, 0x02,
173 static u8 hx8369_seq_extension_command
[] = {
174 HX8369_SET_EXTENSION_COMMAND
, 0xff, 0x83, 0x69,
177 static u8 hx8369_seq_display_related
[] = {
178 HX8369_SET_DISPLAY_MODE
, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00,
179 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x01,
182 static u8 hx8369_seq_panel_waveform_cycle
[] = {
183 HX8369_SET_DISPLAY_WAVEFORM_CYC
, 0x0a, 0x1d, 0x80, 0x06, 0x02,
186 static u8 hx8369_seq_set_address_mode
[] = {
187 HX8357_SET_ADDRESS_MODE
, 0x00,
190 static u8 hx8369_seq_vcom
[] = {
191 HX8369_SET_VCOM
, 0x3e, 0x3e,
194 static u8 hx8369_seq_gip
[] = {
195 HX8369_SET_GIP
, 0x00, 0x01, 0x03, 0x25, 0x01, 0x02, 0x28, 0x70,
196 0x11, 0x13, 0x00, 0x00, 0x40, 0x26, 0x51, 0x37, 0x00, 0x00, 0x71,
197 0x35, 0x60, 0x24, 0x07, 0x0f, 0x04, 0x04,
200 static u8 hx8369_seq_power
[] = {
201 HX8369_SET_POWER
, 0x01, 0x00, 0x34, 0x03, 0x00, 0x11, 0x11, 0x32,
202 0x2f, 0x3f, 0x3f, 0x01, 0x3a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
205 static u8 hx8369_seq_gamma_curve_related
[] = {
206 HX8369_SET_GAMMA_CURVE_RELATED
, 0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d,
207 0x2e, 0x4a, 0x08, 0x0e, 0x0f, 0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
208 0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d, 0x2e, 0x4a, 0x08, 0x0e, 0x0f,
209 0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
212 static int hx8357_spi_write_then_read(struct lcd_device
*lcdev
,
213 u8
*txbuf
, u16 txlen
,
214 u8
*rxbuf
, u16 rxlen
)
216 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
217 struct spi_message msg
;
218 struct spi_transfer xfer
[2];
219 u16
*local_txbuf
= NULL
;
222 memset(xfer
, 0, sizeof(xfer
));
223 spi_message_init(&msg
);
228 local_txbuf
= kcalloc(txlen
, sizeof(*local_txbuf
), GFP_KERNEL
);
233 for (i
= 0; i
< txlen
; i
++) {
234 local_txbuf
[i
] = txbuf
[i
];
236 local_txbuf
[i
] |= 1 << 8;
239 xfer
[0].len
= 2 * txlen
;
240 xfer
[0].bits_per_word
= 9;
241 xfer
[0].tx_buf
= local_txbuf
;
242 spi_message_add_tail(&xfer
[0], &msg
);
247 xfer
[1].bits_per_word
= 8;
248 xfer
[1].rx_buf
= rxbuf
;
249 spi_message_add_tail(&xfer
[1], &msg
);
252 ret
= spi_sync(lcd
->spi
, &msg
);
254 dev_err(&lcdev
->dev
, "Couldn't send SPI data\n");
262 static inline int hx8357_spi_write_array(struct lcd_device
*lcdev
,
265 return hx8357_spi_write_then_read(lcdev
, value
, len
, NULL
, 0);
268 static inline int hx8357_spi_write_byte(struct lcd_device
*lcdev
,
271 return hx8357_spi_write_then_read(lcdev
, &value
, 1, NULL
, 0);
274 static int hx8357_enter_standby(struct lcd_device
*lcdev
)
278 ret
= hx8357_spi_write_byte(lcdev
, HX8357_SET_DISPLAY_OFF
);
282 usleep_range(10000, 12000);
284 ret
= hx8357_spi_write_byte(lcdev
, HX8357_ENTER_SLEEP_MODE
);
289 * The controller needs 120ms when entering in sleep mode before we can
290 * send the command to go off sleep mode
297 static int hx8357_exit_standby(struct lcd_device
*lcdev
)
301 ret
= hx8357_spi_write_byte(lcdev
, HX8357_EXIT_SLEEP_MODE
);
306 * The controller needs 120ms when exiting from sleep mode before we
307 * can send the command to enter in sleep mode
311 ret
= hx8357_spi_write_byte(lcdev
, HX8357_SET_DISPLAY_ON
);
318 static void hx8357_lcd_reset(struct lcd_device
*lcdev
)
320 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
322 /* Reset the screen */
323 gpiod_set_value(lcd
->reset
, 0);
324 usleep_range(10000, 12000);
325 gpiod_set_value(lcd
->reset
, 1);
326 usleep_range(10000, 12000);
327 gpiod_set_value(lcd
->reset
, 0);
329 /* The controller needs 120ms to recover from reset */
333 static int hx8357_lcd_init(struct lcd_device
*lcdev
)
335 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
339 * Set the interface selection pins to SPI mode, with three
343 gpiod_set_value_cansleep(lcd
->im_pins
->desc
[0], 1);
344 gpiod_set_value_cansleep(lcd
->im_pins
->desc
[1], 0);
345 gpiod_set_value_cansleep(lcd
->im_pins
->desc
[2], 1);
348 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_power
,
349 ARRAY_SIZE(hx8357_seq_power
));
353 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_vcom
,
354 ARRAY_SIZE(hx8357_seq_vcom
));
358 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_power_normal
,
359 ARRAY_SIZE(hx8357_seq_power_normal
));
363 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_panel_driving
,
364 ARRAY_SIZE(hx8357_seq_panel_driving
));
368 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_display_frame
,
369 ARRAY_SIZE(hx8357_seq_display_frame
));
373 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_panel_related
,
374 ARRAY_SIZE(hx8357_seq_panel_related
));
378 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_undefined1
,
379 ARRAY_SIZE(hx8357_seq_undefined1
));
383 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_undefined2
,
384 ARRAY_SIZE(hx8357_seq_undefined2
));
388 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_gamma
,
389 ARRAY_SIZE(hx8357_seq_gamma
));
393 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_address_mode
,
394 ARRAY_SIZE(hx8357_seq_address_mode
));
398 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_pixel_format
,
399 ARRAY_SIZE(hx8357_seq_pixel_format
));
403 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_column_address
,
404 ARRAY_SIZE(hx8357_seq_column_address
));
408 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_page_address
,
409 ARRAY_SIZE(hx8357_seq_page_address
));
413 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_rgb
,
414 ARRAY_SIZE(hx8357_seq_rgb
));
418 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_display_mode
,
419 ARRAY_SIZE(hx8357_seq_display_mode
));
423 ret
= hx8357_spi_write_byte(lcdev
, HX8357_EXIT_SLEEP_MODE
);
428 * The controller needs 120ms to fully recover from exiting sleep mode
432 ret
= hx8357_spi_write_byte(lcdev
, HX8357_SET_DISPLAY_ON
);
436 usleep_range(5000, 7000);
438 ret
= hx8357_spi_write_byte(lcdev
, HX8357_WRITE_MEMORY_START
);
445 static int hx8369_lcd_init(struct lcd_device
*lcdev
)
449 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_extension_command
,
450 ARRAY_SIZE(hx8369_seq_extension_command
));
453 usleep_range(10000, 12000);
455 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_display_related
,
456 ARRAY_SIZE(hx8369_seq_display_related
));
460 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_panel_waveform_cycle
,
461 ARRAY_SIZE(hx8369_seq_panel_waveform_cycle
));
465 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_set_address_mode
,
466 ARRAY_SIZE(hx8369_seq_set_address_mode
));
470 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_vcom
,
471 ARRAY_SIZE(hx8369_seq_vcom
));
475 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_gip
,
476 ARRAY_SIZE(hx8369_seq_gip
));
480 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_power
,
481 ARRAY_SIZE(hx8369_seq_power
));
485 ret
= hx8357_spi_write_byte(lcdev
, HX8357_EXIT_SLEEP_MODE
);
490 * The controller needs 120ms to fully recover from exiting sleep mode
494 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_gamma_curve_related
,
495 ARRAY_SIZE(hx8369_seq_gamma_curve_related
));
499 ret
= hx8357_spi_write_byte(lcdev
, HX8357_EXIT_SLEEP_MODE
);
502 usleep_range(1000, 1200);
504 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_write_CABC_control
,
505 ARRAY_SIZE(hx8369_seq_write_CABC_control
));
508 usleep_range(10000, 12000);
510 ret
= hx8357_spi_write_array(lcdev
,
511 hx8369_seq_write_CABC_control_setting
,
512 ARRAY_SIZE(hx8369_seq_write_CABC_control_setting
));
516 ret
= hx8357_spi_write_array(lcdev
,
517 hx8369_seq_write_CABC_min_brightness
,
518 ARRAY_SIZE(hx8369_seq_write_CABC_min_brightness
));
521 usleep_range(10000, 12000);
523 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_set_display_brightness
,
524 ARRAY_SIZE(hx8369_seq_set_display_brightness
));
528 ret
= hx8357_spi_write_byte(lcdev
, HX8357_SET_DISPLAY_ON
);
535 #define POWER_IS_ON(pwr) ((pwr) <= LCD_POWER_REDUCED)
537 static int hx8357_set_power(struct lcd_device
*lcdev
, int power
)
539 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
542 if (POWER_IS_ON(power
) && !POWER_IS_ON(lcd
->state
))
543 ret
= hx8357_exit_standby(lcdev
);
544 else if (!POWER_IS_ON(power
) && POWER_IS_ON(lcd
->state
))
545 ret
= hx8357_enter_standby(lcdev
);
550 dev_warn(&lcdev
->dev
, "failed to set power mode %d\n", power
);
555 static int hx8357_get_power(struct lcd_device
*lcdev
)
557 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
562 static const struct lcd_ops hx8357_ops
= {
563 .set_power
= hx8357_set_power
,
564 .get_power
= hx8357_get_power
,
567 typedef int (*hx8357_init_fn
)(struct lcd_device
*);
569 static int hx8357_probe(struct spi_device
*spi
)
571 struct device
*dev
= &spi
->dev
;
572 struct lcd_device
*lcdev
;
573 struct hx8357_data
*lcd
;
574 hx8357_init_fn init_fn
;
577 lcd
= devm_kzalloc(dev
, sizeof(*lcd
), GFP_KERNEL
);
581 ret
= spi_setup(spi
);
583 return dev_err_probe(dev
, ret
, "SPI setup failed.\n");
587 init_fn
= device_get_match_data(dev
);
591 lcd
->reset
= devm_gpiod_get(dev
, "reset", GPIOD_OUT_LOW
);
592 if (IS_ERR(lcd
->reset
))
593 return dev_err_probe(dev
, PTR_ERR(lcd
->reset
), "failed to request reset GPIO\n");
594 gpiod_set_consumer_name(lcd
->reset
, "hx8357-reset");
596 lcd
->im_pins
= devm_gpiod_get_array_optional(dev
, "im", GPIOD_OUT_LOW
);
597 if (IS_ERR(lcd
->im_pins
))
598 return dev_err_probe(dev
, PTR_ERR(lcd
->im_pins
), "failed to request im GPIOs\n");
600 if (lcd
->im_pins
->ndescs
< HX8357_NUM_IM_PINS
)
601 return dev_err_probe(dev
, -EINVAL
, "not enough im GPIOs\n");
603 for (i
= 0; i
< HX8357_NUM_IM_PINS
; i
++)
604 gpiod_set_consumer_name(lcd
->im_pins
->desc
[i
], "im_pins");
607 lcdev
= devm_lcd_device_register(dev
, "mxsfb", dev
, lcd
, &hx8357_ops
);
609 ret
= PTR_ERR(lcdev
);
612 spi_set_drvdata(spi
, lcdev
);
614 hx8357_lcd_reset(lcdev
);
616 ret
= init_fn(lcdev
);
618 return dev_err_probe(dev
, ret
, "Couldn't initialize panel\n");
620 dev_info(dev
, "Panel probed\n");
625 static const struct of_device_id hx8357_dt_ids
[] = {
627 .compatible
= "himax,hx8357",
628 .data
= hx8357_lcd_init
,
631 .compatible
= "himax,hx8369",
632 .data
= hx8369_lcd_init
,
636 MODULE_DEVICE_TABLE(of
, hx8357_dt_ids
);
638 static struct spi_driver hx8357_driver
= {
639 .probe
= hx8357_probe
,
642 .of_match_table
= hx8357_dt_ids
,
646 module_spi_driver(hx8357_driver
);
648 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
649 MODULE_DESCRIPTION("Himax HX-8357 LCD Driver");
650 MODULE_LICENSE("GPL");