2 * Driver for the Himax HX-8357 LCD Controller
4 * Copyright 2012 Free Electrons
6 * Licensed under the GPLv2 or later.
9 #include <linux/delay.h>
10 #include <linux/lcd.h>
11 #include <linux/module.h>
13 #include <linux/of_device.h>
14 #include <linux/of_gpio.h>
15 #include <linux/spi/spi.h>
17 #define HX8357_NUM_IM_PINS 3
19 #define HX8357_SWRESET 0x01
20 #define HX8357_GET_RED_CHANNEL 0x06
21 #define HX8357_GET_GREEN_CHANNEL 0x07
22 #define HX8357_GET_BLUE_CHANNEL 0x08
23 #define HX8357_GET_POWER_MODE 0x0a
24 #define HX8357_GET_MADCTL 0x0b
25 #define HX8357_GET_PIXEL_FORMAT 0x0c
26 #define HX8357_GET_DISPLAY_MODE 0x0d
27 #define HX8357_GET_SIGNAL_MODE 0x0e
28 #define HX8357_GET_DIAGNOSTIC_RESULT 0x0f
29 #define HX8357_ENTER_SLEEP_MODE 0x10
30 #define HX8357_EXIT_SLEEP_MODE 0x11
31 #define HX8357_ENTER_PARTIAL_MODE 0x12
32 #define HX8357_ENTER_NORMAL_MODE 0x13
33 #define HX8357_EXIT_INVERSION_MODE 0x20
34 #define HX8357_ENTER_INVERSION_MODE 0x21
35 #define HX8357_SET_DISPLAY_OFF 0x28
36 #define HX8357_SET_DISPLAY_ON 0x29
37 #define HX8357_SET_COLUMN_ADDRESS 0x2a
38 #define HX8357_SET_PAGE_ADDRESS 0x2b
39 #define HX8357_WRITE_MEMORY_START 0x2c
40 #define HX8357_READ_MEMORY_START 0x2e
41 #define HX8357_SET_PARTIAL_AREA 0x30
42 #define HX8357_SET_SCROLL_AREA 0x33
43 #define HX8357_SET_TEAR_OFF 0x34
44 #define HX8357_SET_TEAR_ON 0x35
45 #define HX8357_SET_ADDRESS_MODE 0x36
46 #define HX8357_SET_SCROLL_START 0x37
47 #define HX8357_EXIT_IDLE_MODE 0x38
48 #define HX8357_ENTER_IDLE_MODE 0x39
49 #define HX8357_SET_PIXEL_FORMAT 0x3a
50 #define HX8357_SET_PIXEL_FORMAT_DBI_3BIT (0x1)
51 #define HX8357_SET_PIXEL_FORMAT_DBI_16BIT (0x5)
52 #define HX8357_SET_PIXEL_FORMAT_DBI_18BIT (0x6)
53 #define HX8357_SET_PIXEL_FORMAT_DPI_3BIT (0x1 << 4)
54 #define HX8357_SET_PIXEL_FORMAT_DPI_16BIT (0x5 << 4)
55 #define HX8357_SET_PIXEL_FORMAT_DPI_18BIT (0x6 << 4)
56 #define HX8357_WRITE_MEMORY_CONTINUE 0x3c
57 #define HX8357_READ_MEMORY_CONTINUE 0x3e
58 #define HX8357_SET_TEAR_SCAN_LINES 0x44
59 #define HX8357_GET_SCAN_LINES 0x45
60 #define HX8357_READ_DDB_START 0xa1
61 #define HX8357_SET_DISPLAY_MODE 0xb4
62 #define HX8357_SET_DISPLAY_MODE_RGB_THROUGH (0x3)
63 #define HX8357_SET_DISPLAY_MODE_RGB_INTERFACE (1 << 4)
64 #define HX8357_SET_PANEL_DRIVING 0xc0
65 #define HX8357_SET_DISPLAY_FRAME 0xc5
66 #define HX8357_SET_RGB 0xc6
67 #define HX8357_SET_RGB_ENABLE_HIGH (1 << 1)
68 #define HX8357_SET_GAMMA 0xc8
69 #define HX8357_SET_POWER 0xd0
70 #define HX8357_SET_VCOM 0xd1
71 #define HX8357_SET_POWER_NORMAL 0xd2
72 #define HX8357_SET_PANEL_RELATED 0xe9
74 #define HX8369_SET_DISPLAY_BRIGHTNESS 0x51
75 #define HX8369_WRITE_CABC_DISPLAY_VALUE 0x53
76 #define HX8369_WRITE_CABC_BRIGHT_CTRL 0x55
77 #define HX8369_WRITE_CABC_MIN_BRIGHTNESS 0x5e
78 #define HX8369_SET_POWER 0xb1
79 #define HX8369_SET_DISPLAY_MODE 0xb2
80 #define HX8369_SET_DISPLAY_WAVEFORM_CYC 0xb4
81 #define HX8369_SET_VCOM 0xb6
82 #define HX8369_SET_EXTENSION_COMMAND 0xb9
83 #define HX8369_SET_GIP 0xd5
84 #define HX8369_SET_GAMMA_CURVE_RELATED 0xe0
87 unsigned im_pins
[HX8357_NUM_IM_PINS
];
89 struct spi_device
*spi
;
94 static u8 hx8357_seq_power
[] = {
95 HX8357_SET_POWER
, 0x44, 0x41, 0x06,
98 static u8 hx8357_seq_vcom
[] = {
99 HX8357_SET_VCOM
, 0x40, 0x10,
102 static u8 hx8357_seq_power_normal
[] = {
103 HX8357_SET_POWER_NORMAL
, 0x05, 0x12,
106 static u8 hx8357_seq_panel_driving
[] = {
107 HX8357_SET_PANEL_DRIVING
, 0x14, 0x3b, 0x00, 0x02, 0x11,
110 static u8 hx8357_seq_display_frame
[] = {
111 HX8357_SET_DISPLAY_FRAME
, 0x0c,
114 static u8 hx8357_seq_panel_related
[] = {
115 HX8357_SET_PANEL_RELATED
, 0x01,
118 static u8 hx8357_seq_undefined1
[] = {
119 0xea, 0x03, 0x00, 0x00,
122 static u8 hx8357_seq_undefined2
[] = {
123 0xeb, 0x40, 0x54, 0x26, 0xdb,
126 static u8 hx8357_seq_gamma
[] = {
127 HX8357_SET_GAMMA
, 0x00, 0x15, 0x00, 0x22, 0x00,
128 0x08, 0x77, 0x26, 0x77, 0x22, 0x04, 0x00,
131 static u8 hx8357_seq_address_mode
[] = {
132 HX8357_SET_ADDRESS_MODE
, 0xc0,
135 static u8 hx8357_seq_pixel_format
[] = {
136 HX8357_SET_PIXEL_FORMAT
,
137 HX8357_SET_PIXEL_FORMAT_DPI_18BIT
|
138 HX8357_SET_PIXEL_FORMAT_DBI_18BIT
,
141 static u8 hx8357_seq_column_address
[] = {
142 HX8357_SET_COLUMN_ADDRESS
, 0x00, 0x00, 0x01, 0x3f,
145 static u8 hx8357_seq_page_address
[] = {
146 HX8357_SET_PAGE_ADDRESS
, 0x00, 0x00, 0x01, 0xdf,
149 static u8 hx8357_seq_rgb
[] = {
150 HX8357_SET_RGB
, 0x02,
153 static u8 hx8357_seq_display_mode
[] = {
154 HX8357_SET_DISPLAY_MODE
,
155 HX8357_SET_DISPLAY_MODE_RGB_THROUGH
|
156 HX8357_SET_DISPLAY_MODE_RGB_INTERFACE
,
159 static u8 hx8369_seq_write_CABC_min_brightness
[] = {
160 HX8369_WRITE_CABC_MIN_BRIGHTNESS
, 0x00,
163 static u8 hx8369_seq_write_CABC_control
[] = {
164 HX8369_WRITE_CABC_DISPLAY_VALUE
, 0x24,
167 static u8 hx8369_seq_set_display_brightness
[] = {
168 HX8369_SET_DISPLAY_BRIGHTNESS
, 0xFF,
171 static u8 hx8369_seq_write_CABC_control_setting
[] = {
172 HX8369_WRITE_CABC_BRIGHT_CTRL
, 0x02,
175 static u8 hx8369_seq_extension_command
[] = {
176 HX8369_SET_EXTENSION_COMMAND
, 0xff, 0x83, 0x69,
179 static u8 hx8369_seq_display_related
[] = {
180 HX8369_SET_DISPLAY_MODE
, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00,
181 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x01,
184 static u8 hx8369_seq_panel_waveform_cycle
[] = {
185 HX8369_SET_DISPLAY_WAVEFORM_CYC
, 0x0a, 0x1d, 0x80, 0x06, 0x02,
188 static u8 hx8369_seq_set_address_mode
[] = {
189 HX8357_SET_ADDRESS_MODE
, 0x00,
192 static u8 hx8369_seq_vcom
[] = {
193 HX8369_SET_VCOM
, 0x3e, 0x3e,
196 static u8 hx8369_seq_gip
[] = {
197 HX8369_SET_GIP
, 0x00, 0x01, 0x03, 0x25, 0x01, 0x02, 0x28, 0x70,
198 0x11, 0x13, 0x00, 0x00, 0x40, 0x26, 0x51, 0x37, 0x00, 0x00, 0x71,
199 0x35, 0x60, 0x24, 0x07, 0x0f, 0x04, 0x04,
202 static u8 hx8369_seq_power
[] = {
203 HX8369_SET_POWER
, 0x01, 0x00, 0x34, 0x03, 0x00, 0x11, 0x11, 0x32,
204 0x2f, 0x3f, 0x3f, 0x01, 0x3a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
207 static u8 hx8369_seq_gamma_curve_related
[] = {
208 HX8369_SET_GAMMA_CURVE_RELATED
, 0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d,
209 0x2e, 0x4a, 0x08, 0x0e, 0x0f, 0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
210 0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d, 0x2e, 0x4a, 0x08, 0x0e, 0x0f,
211 0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
214 static int hx8357_spi_write_then_read(struct lcd_device
*lcdev
,
215 u8
*txbuf
, u16 txlen
,
216 u8
*rxbuf
, u16 rxlen
)
218 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
219 struct spi_message msg
;
220 struct spi_transfer xfer
[2];
221 u16
*local_txbuf
= NULL
;
224 memset(xfer
, 0, sizeof(xfer
));
225 spi_message_init(&msg
);
230 local_txbuf
= kcalloc(txlen
, sizeof(*local_txbuf
), GFP_KERNEL
);
235 for (i
= 0; i
< txlen
; i
++) {
236 local_txbuf
[i
] = txbuf
[i
];
238 local_txbuf
[i
] |= 1 << 8;
241 xfer
[0].len
= 2 * txlen
;
242 xfer
[0].bits_per_word
= 9;
243 xfer
[0].tx_buf
= local_txbuf
;
244 spi_message_add_tail(&xfer
[0], &msg
);
249 xfer
[1].bits_per_word
= 8;
250 xfer
[1].rx_buf
= rxbuf
;
251 spi_message_add_tail(&xfer
[1], &msg
);
254 ret
= spi_sync(lcd
->spi
, &msg
);
256 dev_err(&lcdev
->dev
, "Couldn't send SPI data\n");
264 static inline int hx8357_spi_write_array(struct lcd_device
*lcdev
,
267 return hx8357_spi_write_then_read(lcdev
, value
, len
, NULL
, 0);
270 static inline int hx8357_spi_write_byte(struct lcd_device
*lcdev
,
273 return hx8357_spi_write_then_read(lcdev
, &value
, 1, NULL
, 0);
276 static int hx8357_enter_standby(struct lcd_device
*lcdev
)
280 ret
= hx8357_spi_write_byte(lcdev
, HX8357_SET_DISPLAY_OFF
);
284 usleep_range(10000, 12000);
286 ret
= hx8357_spi_write_byte(lcdev
, HX8357_ENTER_SLEEP_MODE
);
291 * The controller needs 120ms when entering in sleep mode before we can
292 * send the command to go off sleep mode
299 static int hx8357_exit_standby(struct lcd_device
*lcdev
)
303 ret
= hx8357_spi_write_byte(lcdev
, HX8357_EXIT_SLEEP_MODE
);
308 * The controller needs 120ms when exiting from sleep mode before we
309 * can send the command to enter in sleep mode
313 ret
= hx8357_spi_write_byte(lcdev
, HX8357_SET_DISPLAY_ON
);
320 static void hx8357_lcd_reset(struct lcd_device
*lcdev
)
322 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
324 /* Reset the screen */
325 gpio_set_value(lcd
->reset
, 1);
326 usleep_range(10000, 12000);
327 gpio_set_value(lcd
->reset
, 0);
328 usleep_range(10000, 12000);
329 gpio_set_value(lcd
->reset
, 1);
331 /* The controller needs 120ms to recover from reset */
335 static int hx8357_lcd_init(struct lcd_device
*lcdev
)
337 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
341 * Set the interface selection pins to SPI mode, with three
344 if (lcd
->use_im_pins
) {
345 gpio_set_value_cansleep(lcd
->im_pins
[0], 1);
346 gpio_set_value_cansleep(lcd
->im_pins
[1], 0);
347 gpio_set_value_cansleep(lcd
->im_pins
[2], 1);
350 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_power
,
351 ARRAY_SIZE(hx8357_seq_power
));
355 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_vcom
,
356 ARRAY_SIZE(hx8357_seq_vcom
));
360 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_power_normal
,
361 ARRAY_SIZE(hx8357_seq_power_normal
));
365 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_panel_driving
,
366 ARRAY_SIZE(hx8357_seq_panel_driving
));
370 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_display_frame
,
371 ARRAY_SIZE(hx8357_seq_display_frame
));
375 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_panel_related
,
376 ARRAY_SIZE(hx8357_seq_panel_related
));
380 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_undefined1
,
381 ARRAY_SIZE(hx8357_seq_undefined1
));
385 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_undefined2
,
386 ARRAY_SIZE(hx8357_seq_undefined2
));
390 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_gamma
,
391 ARRAY_SIZE(hx8357_seq_gamma
));
395 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_address_mode
,
396 ARRAY_SIZE(hx8357_seq_address_mode
));
400 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_pixel_format
,
401 ARRAY_SIZE(hx8357_seq_pixel_format
));
405 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_column_address
,
406 ARRAY_SIZE(hx8357_seq_column_address
));
410 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_page_address
,
411 ARRAY_SIZE(hx8357_seq_page_address
));
415 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_rgb
,
416 ARRAY_SIZE(hx8357_seq_rgb
));
420 ret
= hx8357_spi_write_array(lcdev
, hx8357_seq_display_mode
,
421 ARRAY_SIZE(hx8357_seq_display_mode
));
425 ret
= hx8357_spi_write_byte(lcdev
, HX8357_EXIT_SLEEP_MODE
);
430 * The controller needs 120ms to fully recover from exiting sleep mode
434 ret
= hx8357_spi_write_byte(lcdev
, HX8357_SET_DISPLAY_ON
);
438 usleep_range(5000, 7000);
440 ret
= hx8357_spi_write_byte(lcdev
, HX8357_WRITE_MEMORY_START
);
447 static int hx8369_lcd_init(struct lcd_device
*lcdev
)
451 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_extension_command
,
452 ARRAY_SIZE(hx8369_seq_extension_command
));
455 usleep_range(10000, 12000);
457 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_display_related
,
458 ARRAY_SIZE(hx8369_seq_display_related
));
462 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_panel_waveform_cycle
,
463 ARRAY_SIZE(hx8369_seq_panel_waveform_cycle
));
467 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_set_address_mode
,
468 ARRAY_SIZE(hx8369_seq_set_address_mode
));
472 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_vcom
,
473 ARRAY_SIZE(hx8369_seq_vcom
));
477 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_gip
,
478 ARRAY_SIZE(hx8369_seq_gip
));
482 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_power
,
483 ARRAY_SIZE(hx8369_seq_power
));
487 ret
= hx8357_spi_write_byte(lcdev
, HX8357_EXIT_SLEEP_MODE
);
492 * The controller needs 120ms to fully recover from exiting sleep mode
496 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_gamma_curve_related
,
497 ARRAY_SIZE(hx8369_seq_gamma_curve_related
));
501 ret
= hx8357_spi_write_byte(lcdev
, HX8357_EXIT_SLEEP_MODE
);
504 usleep_range(1000, 1200);
506 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_write_CABC_control
,
507 ARRAY_SIZE(hx8369_seq_write_CABC_control
));
510 usleep_range(10000, 12000);
512 ret
= hx8357_spi_write_array(lcdev
,
513 hx8369_seq_write_CABC_control_setting
,
514 ARRAY_SIZE(hx8369_seq_write_CABC_control_setting
));
518 ret
= hx8357_spi_write_array(lcdev
,
519 hx8369_seq_write_CABC_min_brightness
,
520 ARRAY_SIZE(hx8369_seq_write_CABC_min_brightness
));
523 usleep_range(10000, 12000);
525 ret
= hx8357_spi_write_array(lcdev
, hx8369_seq_set_display_brightness
,
526 ARRAY_SIZE(hx8369_seq_set_display_brightness
));
530 ret
= hx8357_spi_write_byte(lcdev
, HX8357_SET_DISPLAY_ON
);
537 #define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
539 static int hx8357_set_power(struct lcd_device
*lcdev
, int power
)
541 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
544 if (POWER_IS_ON(power
) && !POWER_IS_ON(lcd
->state
))
545 ret
= hx8357_exit_standby(lcdev
);
546 else if (!POWER_IS_ON(power
) && POWER_IS_ON(lcd
->state
))
547 ret
= hx8357_enter_standby(lcdev
);
552 dev_warn(&lcdev
->dev
, "failed to set power mode %d\n", power
);
557 static int hx8357_get_power(struct lcd_device
*lcdev
)
559 struct hx8357_data
*lcd
= lcd_get_data(lcdev
);
564 static struct lcd_ops hx8357_ops
= {
565 .set_power
= hx8357_set_power
,
566 .get_power
= hx8357_get_power
,
569 static const struct of_device_id hx8357_dt_ids
[] = {
571 .compatible
= "himax,hx8357",
572 .data
= hx8357_lcd_init
,
575 .compatible
= "himax,hx8369",
576 .data
= hx8369_lcd_init
,
580 MODULE_DEVICE_TABLE(of
, hx8357_dt_ids
);
582 static int hx8357_probe(struct spi_device
*spi
)
584 struct lcd_device
*lcdev
;
585 struct hx8357_data
*lcd
;
586 const struct of_device_id
*match
;
589 lcd
= devm_kzalloc(&spi
->dev
, sizeof(*lcd
), GFP_KERNEL
);
591 dev_err(&spi
->dev
, "Couldn't allocate lcd internal structure!\n");
595 ret
= spi_setup(spi
);
597 dev_err(&spi
->dev
, "SPI setup failed.\n");
603 match
= of_match_device(hx8357_dt_ids
, &spi
->dev
);
604 if (!match
|| !match
->data
)
607 lcd
->reset
= of_get_named_gpio(spi
->dev
.of_node
, "gpios-reset", 0);
608 if (!gpio_is_valid(lcd
->reset
)) {
609 dev_err(&spi
->dev
, "Missing dt property: gpios-reset\n");
613 ret
= devm_gpio_request_one(&spi
->dev
, lcd
->reset
,
618 "failed to request gpio %d: %d\n",
623 if (of_find_property(spi
->dev
.of_node
, "im-gpios", NULL
)) {
624 lcd
->use_im_pins
= 1;
626 for (i
= 0; i
< HX8357_NUM_IM_PINS
; i
++) {
627 lcd
->im_pins
[i
] = of_get_named_gpio(spi
->dev
.of_node
,
629 if (lcd
->im_pins
[i
] == -EPROBE_DEFER
) {
630 dev_info(&spi
->dev
, "GPIO requested is not here yet, deferring the probe\n");
631 return -EPROBE_DEFER
;
633 if (!gpio_is_valid(lcd
->im_pins
[i
])) {
634 dev_err(&spi
->dev
, "Missing dt property: im-gpios\n");
638 ret
= devm_gpio_request_one(&spi
->dev
, lcd
->im_pins
[i
],
642 dev_err(&spi
->dev
, "failed to request gpio %d: %d\n",
643 lcd
->im_pins
[i
], ret
);
648 lcd
->use_im_pins
= 0;
651 lcdev
= devm_lcd_device_register(&spi
->dev
, "mxsfb", &spi
->dev
, lcd
,
654 ret
= PTR_ERR(lcdev
);
657 spi_set_drvdata(spi
, lcdev
);
659 hx8357_lcd_reset(lcdev
);
661 ret
= ((int (*)(struct lcd_device
*))match
->data
)(lcdev
);
663 dev_err(&spi
->dev
, "Couldn't initialize panel\n");
667 dev_info(&spi
->dev
, "Panel probed\n");
672 static struct spi_driver hx8357_driver
= {
673 .probe
= hx8357_probe
,
676 .of_match_table
= hx8357_dt_ids
,
680 module_spi_driver(hx8357_driver
);
682 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
683 MODULE_DESCRIPTION("Himax HX-8357 LCD Driver");
684 MODULE_LICENSE("GPL");