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>
10 #include <linux/module.h>
12 #include <linux/of_device.h>
13 #include <linux/of_gpio.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 unsigned im_pins
[HX8357_NUM_IM_PINS
];
88 struct spi_device
*spi
;
93 static u8 hx8357_seq_power
[] = {
94 HX8357_SET_POWER
, 0x44, 0x41, 0x06,
97 static u8 hx8357_seq_vcom
[] = {
98 HX8357_SET_VCOM
, 0x40, 0x10,
101 static u8 hx8357_seq_power_normal
[] = {
102 HX8357_SET_POWER_NORMAL
, 0x05, 0x12,
105 static u8 hx8357_seq_panel_driving
[] = {
106 HX8357_SET_PANEL_DRIVING
, 0x14, 0x3b, 0x00, 0x02, 0x11,
109 static u8 hx8357_seq_display_frame
[] = {
110 HX8357_SET_DISPLAY_FRAME
, 0x0c,
113 static u8 hx8357_seq_panel_related
[] = {
114 HX8357_SET_PANEL_RELATED
, 0x01,
117 static u8 hx8357_seq_undefined1
[] = {
118 0xea, 0x03, 0x00, 0x00,
121 static u8 hx8357_seq_undefined2
[] = {
122 0xeb, 0x40, 0x54, 0x26, 0xdb,
125 static u8 hx8357_seq_gamma
[] = {
126 HX8357_SET_GAMMA
, 0x00, 0x15, 0x00, 0x22, 0x00,
127 0x08, 0x77, 0x26, 0x77, 0x22, 0x04, 0x00,
130 static u8 hx8357_seq_address_mode
[] = {
131 HX8357_SET_ADDRESS_MODE
, 0xc0,
134 static u8 hx8357_seq_pixel_format
[] = {
135 HX8357_SET_PIXEL_FORMAT
,
136 HX8357_SET_PIXEL_FORMAT_DPI_18BIT
|
137 HX8357_SET_PIXEL_FORMAT_DBI_18BIT
,
140 static u8 hx8357_seq_column_address
[] = {
141 HX8357_SET_COLUMN_ADDRESS
, 0x00, 0x00, 0x01, 0x3f,
144 static u8 hx8357_seq_page_address
[] = {
145 HX8357_SET_PAGE_ADDRESS
, 0x00, 0x00, 0x01, 0xdf,
148 static u8 hx8357_seq_rgb
[] = {
149 HX8357_SET_RGB
, 0x02,
152 static u8 hx8357_seq_display_mode
[] = {
153 HX8357_SET_DISPLAY_MODE
,
154 HX8357_SET_DISPLAY_MODE_RGB_THROUGH
|
155 HX8357_SET_DISPLAY_MODE_RGB_INTERFACE
,
158 static u8 hx8369_seq_write_CABC_min_brightness
[] = {
159 HX8369_WRITE_CABC_MIN_BRIGHTNESS
, 0x00,
162 static u8 hx8369_seq_write_CABC_control
[] = {
163 HX8369_WRITE_CABC_DISPLAY_VALUE
, 0x24,
166 static u8 hx8369_seq_set_display_brightness
[] = {
167 HX8369_SET_DISPLAY_BRIGHTNESS
, 0xFF,
170 static u8 hx8369_seq_write_CABC_control_setting
[] = {
171 HX8369_WRITE_CABC_BRIGHT_CTRL
, 0x02,
174 static u8 hx8369_seq_extension_command
[] = {
175 HX8369_SET_EXTENSION_COMMAND
, 0xff, 0x83, 0x69,
178 static 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,
183 static u8 hx8369_seq_panel_waveform_cycle
[] = {
184 HX8369_SET_DISPLAY_WAVEFORM_CYC
, 0x0a, 0x1d, 0x80, 0x06, 0x02,
187 static u8 hx8369_seq_set_address_mode
[] = {
188 HX8357_SET_ADDRESS_MODE
, 0x00,
191 static u8 hx8369_seq_vcom
[] = {
192 HX8369_SET_VCOM
, 0x3e, 0x3e,
195 static 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,
201 static 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,
206 static 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,
213 static int hx8357_spi_write_then_read(struct lcd_device
*lcdev
,
214 u8
*txbuf
, u16 txlen
,
215 u8
*rxbuf
, u16 rxlen
)
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
;
223 memset(xfer
, 0, sizeof(xfer
));
224 spi_message_init(&msg
);
229 local_txbuf
= kcalloc(txlen
, sizeof(*local_txbuf
), GFP_KERNEL
);
234 for (i
= 0; i
< txlen
; i
++) {
235 local_txbuf
[i
] = txbuf
[i
];
237 local_txbuf
[i
] |= 1 << 8;
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
);
248 xfer
[1].bits_per_word
= 8;
249 xfer
[1].rx_buf
= rxbuf
;
250 spi_message_add_tail(&xfer
[1], &msg
);
253 ret
= spi_sync(lcd
->spi
, &msg
);
255 dev_err(&lcdev
->dev
, "Couldn't send SPI data\n");
263 static inline int hx8357_spi_write_array(struct lcd_device
*lcdev
,
266 return hx8357_spi_write_then_read(lcdev
, value
, len
, NULL
, 0);
269 static inline int hx8357_spi_write_byte(struct lcd_device
*lcdev
,
272 return hx8357_spi_write_then_read(lcdev
, &value
, 1, NULL
, 0);
275 static int hx8357_enter_standby(struct lcd_device
*lcdev
)
279 ret
= hx8357_spi_write_byte(lcdev
, HX8357_SET_DISPLAY_OFF
);
283 usleep_range(10000, 12000);
285 ret
= hx8357_spi_write_byte(lcdev
, HX8357_ENTER_SLEEP_MODE
);
290 * The controller needs 120ms when entering in sleep mode before we can
291 * send the command to go off sleep mode
298 static int hx8357_exit_standby(struct lcd_device
*lcdev
)
302 ret
= hx8357_spi_write_byte(lcdev
, HX8357_EXIT_SLEEP_MODE
);
307 * The controller needs 120ms when exiting from sleep mode before we
308 * can send the command to enter in sleep mode
312 ret
= hx8357_spi_write_byte(lcdev
, HX8357_SET_DISPLAY_ON
);
319 static void hx8357_lcd_reset(struct lcd_device
*lcdev
)
321 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
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);
330 /* The controller needs 120ms to recover from reset */
334 static int hx8357_lcd_init(struct lcd_device
*lcdev
)
336 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
340 * Set the interface selection pins to SPI mode, with three
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);
349 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_power
,
350 ARRAY_SIZE(hx8357_seq_power
));
354 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_vcom
,
355 ARRAY_SIZE(hx8357_seq_vcom
));
359 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_power_normal
,
360 ARRAY_SIZE(hx8357_seq_power_normal
));
364 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_panel_driving
,
365 ARRAY_SIZE(hx8357_seq_panel_driving
));
369 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_display_frame
,
370 ARRAY_SIZE(hx8357_seq_display_frame
));
374 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_panel_related
,
375 ARRAY_SIZE(hx8357_seq_panel_related
));
379 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_undefined1
,
380 ARRAY_SIZE(hx8357_seq_undefined1
));
384 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_undefined2
,
385 ARRAY_SIZE(hx8357_seq_undefined2
));
389 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_gamma
,
390 ARRAY_SIZE(hx8357_seq_gamma
));
394 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_address_mode
,
395 ARRAY_SIZE(hx8357_seq_address_mode
));
399 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_pixel_format
,
400 ARRAY_SIZE(hx8357_seq_pixel_format
));
404 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_column_address
,
405 ARRAY_SIZE(hx8357_seq_column_address
));
409 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_page_address
,
410 ARRAY_SIZE(hx8357_seq_page_address
));
414 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_rgb
,
415 ARRAY_SIZE(hx8357_seq_rgb
));
419 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_display_mode
,
420 ARRAY_SIZE(hx8357_seq_display_mode
));
424 ret
= hx8357_spi_write_byte(lcdev
, HX8357_EXIT_SLEEP_MODE
);
429 * The controller needs 120ms to fully recover from exiting sleep mode
433 ret
= hx8357_spi_write_byte(lcdev
, HX8357_SET_DISPLAY_ON
);
437 usleep_range(5000, 7000);
439 ret
= hx8357_spi_write_byte(lcdev
, HX8357_WRITE_MEMORY_START
);
446 static int hx8369_lcd_init(struct lcd_device
*lcdev
)
450 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_extension_command
,
451 ARRAY_SIZE(hx8369_seq_extension_command
));
454 usleep_range(10000, 12000);
456 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_display_related
,
457 ARRAY_SIZE(hx8369_seq_display_related
));
461 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_panel_waveform_cycle
,
462 ARRAY_SIZE(hx8369_seq_panel_waveform_cycle
));
466 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_set_address_mode
,
467 ARRAY_SIZE(hx8369_seq_set_address_mode
));
471 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_vcom
,
472 ARRAY_SIZE(hx8369_seq_vcom
));
476 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_gip
,
477 ARRAY_SIZE(hx8369_seq_gip
));
481 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_power
,
482 ARRAY_SIZE(hx8369_seq_power
));
486 ret
= hx8357_spi_write_byte(lcdev
, HX8357_EXIT_SLEEP_MODE
);
491 * The controller needs 120ms to fully recover from exiting sleep mode
495 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_gamma_curve_related
,
496 ARRAY_SIZE(hx8369_seq_gamma_curve_related
));
500 ret
= hx8357_spi_write_byte(lcdev
, HX8357_EXIT_SLEEP_MODE
);
503 usleep_range(1000, 1200);
505 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_write_CABC_control
,
506 ARRAY_SIZE(hx8369_seq_write_CABC_control
));
509 usleep_range(10000, 12000);
511 ret
= hx8357_spi_write_array(lcdev
,
512 hx8369_seq_write_CABC_control_setting
,
513 ARRAY_SIZE(hx8369_seq_write_CABC_control_setting
));
517 ret
= hx8357_spi_write_array(lcdev
,
518 hx8369_seq_write_CABC_min_brightness
,
519 ARRAY_SIZE(hx8369_seq_write_CABC_min_brightness
));
522 usleep_range(10000, 12000);
524 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_set_display_brightness
,
525 ARRAY_SIZE(hx8369_seq_set_display_brightness
));
529 ret
= hx8357_spi_write_byte(lcdev
, HX8357_SET_DISPLAY_ON
);
536 #define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
538 static int hx8357_set_power(struct lcd_device
*lcdev
, int power
)
540 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
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
);
551 dev_warn(&lcdev
->dev
, "failed to set power mode %d\n", power
);
556 static int hx8357_get_power(struct lcd_device
*lcdev
)
558 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
563 static struct lcd_ops hx8357_ops
= {
564 .set_power
= hx8357_set_power
,
565 .get_power
= hx8357_get_power
,
568 static const struct of_device_id hx8357_dt_ids
[] = {
570 .compatible
= "himax,hx8357",
571 .data
= hx8357_lcd_init
,
574 .compatible
= "himax,hx8369",
575 .data
= hx8369_lcd_init
,
579 MODULE_DEVICE_TABLE(of
, hx8357_dt_ids
);
581 static int hx8357_probe(struct spi_device
*spi
)
583 struct lcd_device
*lcdev
;
584 struct hx8357_data
*lcd
;
585 const struct of_device_id
*match
;
588 lcd
= devm_kzalloc(&spi
->dev
, sizeof(*lcd
), GFP_KERNEL
);
592 ret
= spi_setup(spi
);
594 dev_err(&spi
->dev
, "SPI setup failed.\n");
600 match
= of_match_device(hx8357_dt_ids
, &spi
->dev
);
601 if (!match
|| !match
->data
)
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");
610 ret
= devm_gpio_request_one(&spi
->dev
, lcd
->reset
,
615 "failed to request gpio %d: %d\n",
620 if (of_find_property(spi
->dev
.of_node
, "im-gpios", NULL
)) {
621 lcd
->use_im_pins
= 1;
623 for (i
= 0; i
< HX8357_NUM_IM_PINS
; i
++) {
624 lcd
->im_pins
[i
] = of_get_named_gpio(spi
->dev
.of_node
,
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
;
630 if (!gpio_is_valid(lcd
->im_pins
[i
])) {
631 dev_err(&spi
->dev
, "Missing dt property: im-gpios\n");
635 ret
= devm_gpio_request_one(&spi
->dev
, lcd
->im_pins
[i
],
639 dev_err(&spi
->dev
, "failed to request gpio %d: %d\n",
640 lcd
->im_pins
[i
], ret
);
645 lcd
->use_im_pins
= 0;
648 lcdev
= devm_lcd_device_register(&spi
->dev
, "mxsfb", &spi
->dev
, lcd
,
651 ret
= PTR_ERR(lcdev
);
654 spi_set_drvdata(spi
, lcdev
);
656 hx8357_lcd_reset(lcdev
);
658 ret
= ((int (*)(struct lcd_device
*))match
->data
)(lcdev
);
660 dev_err(&spi
->dev
, "Couldn't initialize panel\n");
664 dev_info(&spi
->dev
, "Panel probed\n");
669 static struct spi_driver hx8357_driver
= {
670 .probe
= hx8357_probe
,
673 .of_match_table
= hx8357_dt_ids
,
677 module_spi_driver(hx8357_driver
);
679 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
680 MODULE_DESCRIPTION("Himax HX-8357 LCD Driver");
681 MODULE_LICENSE("GPL");