1 // SPDX-License-Identifier: GPL-2.0-only
3 * Ilitek ILI9806E TFT LCD drm_panel driver.
5 * Copyright (C) 2022 Raspberry Pi Ltd
7 * Derived from drivers/drm/gpu/panel/panel-sitronix-st7789v.c
8 * Copyright (C) 2017 Free Electrons
11 #include <drm/drm_modes.h>
12 #include <drm/drm_panel.h>
14 #include <linux/bitops.h>
15 #include <linux/gpio/consumer.h>
16 #include <linux/media-bus-format.h>
17 #include <linux/module.h>
18 #include <linux/of_device.h>
19 #include <linux/regmap.h>
20 #include <linux/regulator/consumer.h>
21 #include <linux/spi/spi.h>
23 #include <video/mipi_display.h>
24 #include <video/of_videomode.h>
25 #include <video/videomode.h>
28 struct drm_panel panel;
29 struct spi_device *spi;
30 struct gpio_desc *reset;
31 struct regulator *power;
35 #define ILI9806_DATA BIT(8)
37 #define ILI9806_MAX_MSG_LEN 6
41 u16 msg[ILI9806_MAX_MSG_LEN];
44 #define ILI9806_SET_PAGE(page) \
49 ILI9806_DATA | 0xFF, \
50 ILI9806_DATA | 0x98, \
51 ILI9806_DATA | 0x06, \
52 ILI9806_DATA | 0x04, \
53 ILI9806_DATA | (page) \
57 #define ILI9806_SET_REG_PARAM(reg, data) \
62 ILI9806_DATA | (data), \
66 #define ILI9806_SET_REG(reg) \
72 static const struct ili9806e_msg panel_init[] = {
76 * SEPT_SDIO = 0 (spi interface transfer through SDA pin)
77 * SDO_STATUS = 1 (always output, but without output tri-state)
79 ILI9806_SET_REG_PARAM(0x08, 0x10),
81 * VSPL = 1 (vertical sync polarity)
82 * HSPL = 0 (horizontal sync polarity)
83 * DPL = 0 (PCLK polarity)
84 * EPL = 1 (data enable polarity)
86 ILI9806_SET_REG_PARAM(0x21, 0x0d),
87 /* resolution control (0x02 = 480x800) */
88 ILI9806_SET_REG_PARAM(0x30, 0x02),
89 /* display inversion control (0x00 = column inversion) */
90 ILI9806_SET_REG_PARAM(0x31, 0x00),
92 * EXB1T = 0 (internal charge pump)
93 * EXT_CPCK_SEL = 1 (pump clock control signal = output 2 x waveform)
94 * BT = 0 (DDVDH / DDVDL voltage = VCI x 2 / VCI x -2)
96 ILI9806_SET_REG_PARAM(0x40, 0x10),
98 * DDVDH_CLP = 5.6 (DDVDH clamp leve)
99 * DDVDL_CLP = -5.6 (DDVDL clamp leve)
101 ILI9806_SET_REG_PARAM(0x41, 0x55),
103 * VGH_CP = 2DDVDH - DDVDL (step up factor for VGH)
104 * VGL_CP = DDVDL + VCL - VCIP (step up factor for VGL)
106 ILI9806_SET_REG_PARAM(0x42, 0x02),
108 * VGH_CLPEN = 0 (disable VGH clamp level)
109 * VGH_CLP = 9 (15.0 VGH clamp level - but this is disabled so not used?)
111 ILI9806_SET_REG_PARAM(0x43, 0x84),
113 * VGL_CLPEN = 0 (disable VGL clamp level)
114 * VGL_CLP = 9 (-11.0 VGL clamp level - but this is disabled so not used?)
116 ILI9806_SET_REG_PARAM(0x44, 0x84),
119 * VREG1OUT voltage for positive gamma?
121 ILI9806_SET_REG_PARAM(0x50, 0x78),
123 * VREG2OUT voltage for negative gamma?
125 ILI9806_SET_REG_PARAM(0x51, 0x78),
127 ILI9806_SET_REG_PARAM(0x52, 0x00),
128 ILI9806_SET_REG_PARAM(0x53, 0x77),
129 ILI9806_SET_REG_PARAM(0x57, 0x60),
130 ILI9806_SET_REG_PARAM(0x60, 0x07),
131 ILI9806_SET_REG_PARAM(0x61, 0x00),
132 ILI9806_SET_REG_PARAM(0x62, 0x08),
133 ILI9806_SET_REG_PARAM(0x63, 0x00),
134 ILI9806_SET_REG_PARAM(0xA0, 0x00),
135 ILI9806_SET_REG_PARAM(0xA1, 0x07),
136 ILI9806_SET_REG_PARAM(0xA2, 0x0C),
137 ILI9806_SET_REG_PARAM(0xA3, 0x0B),
138 ILI9806_SET_REG_PARAM(0xA4, 0x03),
139 ILI9806_SET_REG_PARAM(0xA5, 0x07),
140 ILI9806_SET_REG_PARAM(0xA6, 0x06),
141 ILI9806_SET_REG_PARAM(0xA7, 0x04),
142 ILI9806_SET_REG_PARAM(0xA8, 0x08),
143 ILI9806_SET_REG_PARAM(0xA9, 0x0C),
144 ILI9806_SET_REG_PARAM(0xAA, 0x13),
145 ILI9806_SET_REG_PARAM(0xAB, 0x06),
146 ILI9806_SET_REG_PARAM(0xAC, 0x0D),
147 ILI9806_SET_REG_PARAM(0xAD, 0x19),
148 ILI9806_SET_REG_PARAM(0xAE, 0x10),
149 ILI9806_SET_REG_PARAM(0xAF, 0x00),
150 /* negative gamma control
151 * set the gray scale voltage to adjust the gamma characteristics of the panel
153 ILI9806_SET_REG_PARAM(0xC0, 0x00),
154 ILI9806_SET_REG_PARAM(0xC1, 0x07),
155 ILI9806_SET_REG_PARAM(0xC2, 0x0C),
156 ILI9806_SET_REG_PARAM(0xC3, 0x0B),
157 ILI9806_SET_REG_PARAM(0xC4, 0x03),
158 ILI9806_SET_REG_PARAM(0xC5, 0x07),
159 ILI9806_SET_REG_PARAM(0xC6, 0x07),
160 ILI9806_SET_REG_PARAM(0xC7, 0x04),
161 ILI9806_SET_REG_PARAM(0xC8, 0x08),
162 ILI9806_SET_REG_PARAM(0xC9, 0x0C),
163 ILI9806_SET_REG_PARAM(0xCA, 0x13),
164 ILI9806_SET_REG_PARAM(0xCB, 0x06),
165 ILI9806_SET_REG_PARAM(0xCC, 0x0D),
166 ILI9806_SET_REG_PARAM(0xCD, 0x18),
167 ILI9806_SET_REG_PARAM(0xCE, 0x10),
168 ILI9806_SET_REG_PARAM(0xCF, 0x00),
172 ILI9806_SET_REG_PARAM(0x00, 0x20),
173 ILI9806_SET_REG_PARAM(0x01, 0x0A),
174 ILI9806_SET_REG_PARAM(0x02, 0x00),
175 ILI9806_SET_REG_PARAM(0x03, 0x00),
176 ILI9806_SET_REG_PARAM(0x04, 0x01),
177 ILI9806_SET_REG_PARAM(0x05, 0x01),
178 ILI9806_SET_REG_PARAM(0x06, 0x98),
179 ILI9806_SET_REG_PARAM(0x07, 0x06),
180 ILI9806_SET_REG_PARAM(0x08, 0x01),
181 ILI9806_SET_REG_PARAM(0x09, 0x80),
182 ILI9806_SET_REG_PARAM(0x0A, 0x00),
183 ILI9806_SET_REG_PARAM(0x0B, 0x00),
184 ILI9806_SET_REG_PARAM(0x0C, 0x01),
185 ILI9806_SET_REG_PARAM(0x0D, 0x01),
186 ILI9806_SET_REG_PARAM(0x0E, 0x00),
187 ILI9806_SET_REG_PARAM(0x0F, 0x00),
188 ILI9806_SET_REG_PARAM(0x10, 0xF0),
189 ILI9806_SET_REG_PARAM(0x11, 0xF4),
190 ILI9806_SET_REG_PARAM(0x12, 0x01),
191 ILI9806_SET_REG_PARAM(0x13, 0x00),
192 ILI9806_SET_REG_PARAM(0x14, 0x00),
193 ILI9806_SET_REG_PARAM(0x15, 0xC0),
194 ILI9806_SET_REG_PARAM(0x16, 0x08),
195 ILI9806_SET_REG_PARAM(0x17, 0x00),
196 ILI9806_SET_REG_PARAM(0x18, 0x00),
197 ILI9806_SET_REG_PARAM(0x19, 0x00),
198 ILI9806_SET_REG_PARAM(0x1A, 0x00),
199 ILI9806_SET_REG_PARAM(0x1B, 0x00),
200 ILI9806_SET_REG_PARAM(0x1C, 0x00),
201 ILI9806_SET_REG_PARAM(0x1D, 0x00),
202 ILI9806_SET_REG_PARAM(0x20, 0x01),
203 ILI9806_SET_REG_PARAM(0x21, 0x23),
204 ILI9806_SET_REG_PARAM(0x22, 0x45),
205 ILI9806_SET_REG_PARAM(0x23, 0x67),
206 ILI9806_SET_REG_PARAM(0x24, 0x01),
207 ILI9806_SET_REG_PARAM(0x25, 0x23),
208 ILI9806_SET_REG_PARAM(0x26, 0x45),
209 ILI9806_SET_REG_PARAM(0x27, 0x67),
210 ILI9806_SET_REG_PARAM(0x30, 0x11),
211 ILI9806_SET_REG_PARAM(0x31, 0x11),
212 ILI9806_SET_REG_PARAM(0x32, 0x00),
213 ILI9806_SET_REG_PARAM(0x33, 0xEE),
214 ILI9806_SET_REG_PARAM(0x34, 0xFF),
215 ILI9806_SET_REG_PARAM(0x35, 0xBB),
216 ILI9806_SET_REG_PARAM(0x36, 0xAA),
217 ILI9806_SET_REG_PARAM(0x37, 0xDD),
218 ILI9806_SET_REG_PARAM(0x38, 0xCC),
219 ILI9806_SET_REG_PARAM(0x39, 0x66),
220 ILI9806_SET_REG_PARAM(0x3A, 0x77),
221 ILI9806_SET_REG_PARAM(0x3B, 0x22),
222 ILI9806_SET_REG_PARAM(0x3C, 0x22),
223 ILI9806_SET_REG_PARAM(0x3D, 0x22),
224 ILI9806_SET_REG_PARAM(0x3E, 0x22),
225 ILI9806_SET_REG_PARAM(0x3F, 0x22),
226 ILI9806_SET_REG_PARAM(0x40, 0x22),
227 /* register doesn't exist on page 6? */
228 ILI9806_SET_REG_PARAM(0x52, 0x10),
229 /* doesn't make sense, not valid according to datasheet */
230 ILI9806_SET_REG_PARAM(0x53, 0x10),
231 /* doesn't make sense, not valid according to datasheet */
232 ILI9806_SET_REG_PARAM(0x54, 0x13),
237 ILI9806_SET_REG_PARAM(0x18, 0x1D),
239 ILI9806_SET_REG_PARAM(0x17, 0x22),
240 /* register doesn't exist on page 7? */
241 ILI9806_SET_REG_PARAM(0x02, 0x77),
242 /* register doesn't exist on page 7? */
243 ILI9806_SET_REG_PARAM(0x26, 0xB2),
244 /* register doesn't exist on page 7? */
245 ILI9806_SET_REG_PARAM(0xE1, 0x79),
249 ILI9806_SET_REG_PARAM(MIPI_DCS_SET_PIXEL_FORMAT,
250 MIPI_DCS_PIXEL_FMT_18BIT << 4),
251 ILI9806_SET_REG_PARAM(MIPI_DCS_SET_TEAR_ON, 0x00),
252 ILI9806_SET_REG(MIPI_DCS_EXIT_SLEEP_MODE),
255 #define NUM_INIT_REGS ARRAY_SIZE(panel_init)
257 static inline struct ili9806 *panel_to_ili9806(struct drm_panel *panel)
259 return container_of(panel, struct ili9806, panel);
262 static int ili9806_write_msg(struct ili9806 *ctx, const struct ili9806e_msg *msg)
264 struct spi_transfer xfer = { };
265 struct spi_message spi;
266 //u16 txbuf[] = { msg->, ILI9806_DATA | data };
268 spi_message_init(&spi);
270 xfer.tx_buf = msg->msg;
271 xfer.bits_per_word = 9;
272 xfer.len = sizeof(u16) * msg->len;
274 spi_message_add_tail(&xfer, &spi);
275 return spi_sync(ctx->spi, &spi);
278 static int ili9806e_write_msg_list(struct ili9806 *ctx,
279 const struct ili9806e_msg msgs[],
280 unsigned int num_msgs)
284 for (i = 0; i < num_msgs; i++) {
285 ret = ili9806_write_msg(ctx, &msgs[i]);
293 static const struct drm_display_mode ili9806e_480x800_mode = {
296 .hsync_start = 480 + 10,
297 .hsync_end = 480 + 10 + 16,
298 .htotal = 480 + 10 + 16 + 59,
300 .vsync_start = 800 + 15,
301 .vsync_end = 800 + 15 + 113,
302 .vtotal = 800 + 15 + 113 + 15,
303 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
306 static int ili9806_get_modes(struct drm_panel *panel,
307 struct drm_connector *connector)
309 struct ili9806 *ctx = panel_to_ili9806(panel);
310 struct drm_display_mode *mode;
312 mode = drm_mode_duplicate(connector->dev, &ili9806e_480x800_mode);
314 dev_err(panel->dev, "failed to add mode %ux%ux@%u\n",
315 ili9806e_480x800_mode.hdisplay,
316 ili9806e_480x800_mode.vdisplay,
317 drm_mode_vrefresh(&ili9806e_480x800_mode));
321 drm_mode_set_name(mode);
323 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
324 drm_mode_probed_add(connector, mode);
326 connector->display_info.width_mm = 61;
327 connector->display_info.height_mm = 103;
328 drm_display_info_set_bus_formats(&connector->display_info,
329 &ctx->bus_format, 1);
330 connector->display_info.bus_flags =
331 DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
336 static int ili9806_prepare(struct drm_panel *panel)
338 struct ili9806 *ctx = panel_to_ili9806(panel);
341 ret = regulator_enable(ctx->power);
345 ret = ili9806e_write_msg_list(ctx, panel_init, NUM_INIT_REGS);
350 static int ili9806_enable(struct drm_panel *panel)
352 struct ili9806 *ctx = panel_to_ili9806(panel);
353 const struct ili9806e_msg msg = ILI9806_SET_REG(MIPI_DCS_SET_DISPLAY_ON);
356 ret = ili9806_write_msg(ctx, &msg);
361 static int ili9806_disable(struct drm_panel *panel)
363 struct ili9806 *ctx = panel_to_ili9806(panel);
364 const struct ili9806e_msg msg = ILI9806_SET_REG(MIPI_DCS_SET_DISPLAY_OFF);
367 ret = ili9806_write_msg(ctx, &msg);
372 static int ili9806_unprepare(struct drm_panel *panel)
374 struct ili9806 *ctx = panel_to_ili9806(panel);
375 const struct ili9806e_msg msg = ILI9806_SET_REG(MIPI_DCS_ENTER_SLEEP_MODE);
378 ret = ili9806_write_msg(ctx, &msg);
383 static const struct drm_panel_funcs ili9806_drm_funcs = {
384 .disable = ili9806_disable,
385 .enable = ili9806_enable,
386 .get_modes = ili9806_get_modes,
387 .prepare = ili9806_prepare,
388 .unprepare = ili9806_unprepare,
391 static const struct of_device_id ili9806_of_match[] = {
392 { .compatible = "txw,txw397017s2",
393 .data = (void *)MEDIA_BUS_FMT_RGB888_1X24,
395 .compatible = "pimoroni,hyperpixel4",
396 .data = (void *)MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
398 .compatible = "ilitek,ili9806e",
399 .data = (void *)MEDIA_BUS_FMT_RGB888_1X24,
404 MODULE_DEVICE_TABLE(of, ili9806_of_match);
406 static int ili9806_probe(struct spi_device *spi)
408 const struct ili9806e_msg panel_reset[] = {
410 ILI9806_SET_REG_PARAM(0x01, 0x00)
412 const struct of_device_id *id;
416 ctx = devm_kzalloc(&spi->dev, sizeof(*ctx), GFP_KERNEL);
420 id = of_match_node(ili9806_of_match, spi->dev.of_node);
424 ctx->bus_format = (u32)(uintptr_t)id->data;
426 spi_set_drvdata(spi, ctx);
429 drm_panel_init(&ctx->panel, &spi->dev, &ili9806_drm_funcs,
430 DRM_MODE_CONNECTOR_DPI);
432 ctx->power = devm_regulator_get(&spi->dev, "power");
433 if (IS_ERR(ctx->power))
434 return PTR_ERR(ctx->power);
436 ctx->reset = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW);
437 if (IS_ERR(ctx->reset)) {
438 dev_err(&spi->dev, "Couldn't get our reset line\n");
439 return PTR_ERR(ctx->reset);
443 ili9806e_write_msg_list(ctx, panel_reset, ARRAY_SIZE(panel_reset));
446 ret = drm_panel_of_backlight(&ctx->panel);
450 drm_panel_add(&ctx->panel);
455 static void ili9806_remove(struct spi_device *spi)
457 struct ili9806 *ctx = spi_get_drvdata(spi);
459 drm_panel_remove(&ctx->panel);
462 static const struct spi_device_id ili9806_ids[] = {
463 { "txw397017s2", 0 },
465 { "hyperpixel4", 0 },
469 MODULE_DEVICE_TABLE(spi, ili9806_ids);
471 static struct spi_driver ili9806_driver = {
472 .probe = ili9806_probe,
473 .remove = ili9806_remove,
476 .of_match_table = ili9806_of_match,
478 .id_table = ili9806_ids,
480 module_spi_driver(ili9806_driver);
482 MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com>");
483 MODULE_DESCRIPTION("ili9806 LCD panel driver");
484 MODULE_LICENSE("GPL v2");