d1: add new target
[openwrt/staging/mans0n.git] / target / linux / d1 / patches-6.1 / 0017-drm-panel-Add-driver-for-ST7701s-DPI-LCD-panel.patch
1 From 9d9b8bd567c30a821c82c27035243536c5234542 Mon Sep 17 00:00:00 2001
2 From: Samuel Holland <samuel@sholland.org>
3 Date: Tue, 29 Mar 2022 22:47:57 -0500
4 Subject: [PATCH 017/117] drm/panel: Add driver for ST7701s DPI LCD panel
5
6 Signed-off-by: Samuel Holland <samuel@sholland.org>
7 ---
8 drivers/gpu/drm/panel/Kconfig | 8 +
9 drivers/gpu/drm/panel/Makefile | 1 +
10 .../gpu/drm/panel/panel-sitronix-st7701s.c | 444 ++++++++++++++++++
11 3 files changed, 453 insertions(+)
12 create mode 100644 drivers/gpu/drm/panel/panel-sitronix-st7701s.c
13
14 --- a/drivers/gpu/drm/panel/Kconfig
15 +++ b/drivers/gpu/drm/panel/Kconfig
16 @@ -608,6 +608,14 @@ config DRM_PANEL_SITRONIX_ST7701
17 ST7701 controller for 480X864 LCD panels with MIPI/RGB/SPI
18 system interfaces.
19
20 +config DRM_PANEL_SITRONIX_ST7701S
21 + tristate "Sitronix ST7701s panel driver"
22 + depends on OF
23 + depends on BACKLIGHT_CLASS_DEVICE
24 + help
25 + Say Y here if you want to enable support for the Sitronix
26 + ST7701s controller with a SPI interface.
27 +
28 config DRM_PANEL_SITRONIX_ST7703
29 tristate "Sitronix ST7703 based MIPI touchscreen panels"
30 depends on OF
31 --- a/drivers/gpu/drm/panel/Makefile
32 +++ b/drivers/gpu/drm/panel/Makefile
33 @@ -61,6 +61,7 @@ obj-$(CONFIG_DRM_PANEL_SHARP_LS037V7DW01
34 obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
35 obj-$(CONFIG_DRM_PANEL_SHARP_LS060T1SX01) += panel-sharp-ls060t1sx01.o
36 obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701) += panel-sitronix-st7701.o
37 +obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701S) += panel-sitronix-st7701s.o
38 obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7703) += panel-sitronix-st7703.o
39 obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o
40 obj-$(CONFIG_DRM_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o
41 --- /dev/null
42 +++ b/drivers/gpu/drm/panel/panel-sitronix-st7701s.c
43 @@ -0,0 +1,444 @@
44 +// SPDX-License-Identifier: GPL-2.0-only
45 +/*
46 + * Copyright (C) 2017 Free Electrons
47 + */
48 +
49 +#include <linux/delay.h>
50 +#include <linux/gpio/consumer.h>
51 +#include <linux/module.h>
52 +#include <linux/spi/spi.h>
53 +
54 +#include <video/mipi_display.h>
55 +
56 +#include <drm/drm_device.h>
57 +#include <drm/drm_modes.h>
58 +#include <drm/drm_panel.h>
59 +
60 +struct st7701s {
61 + struct drm_panel panel;
62 + struct gpio_desc *reset;
63 + struct spi_device *spi;
64 +};
65 +
66 +enum {
67 + ST7789V_COMMAND = 0 << 8,
68 + ST7789V_DATA = 1 << 8,
69 +};
70 +
71 +#define LCD_WRITE_COMMAND(x) (ST7789V_COMMAND | (x))
72 +#define LCD_WRITE_DATA(x) (ST7789V_DATA | (x))
73 +
74 +static const u16 st7701s_init_sequence_1[] = {
75 + LCD_WRITE_COMMAND(0xFF),
76 + LCD_WRITE_DATA(0x77),
77 + LCD_WRITE_DATA(0x01),
78 + LCD_WRITE_DATA(0x00),
79 + LCD_WRITE_DATA(0x00),
80 + LCD_WRITE_DATA(0x10),
81 +
82 + LCD_WRITE_COMMAND(0xC0),
83 + LCD_WRITE_DATA(0x3B),
84 + LCD_WRITE_DATA(0x00),
85 +
86 + LCD_WRITE_COMMAND(0xC1),
87 + LCD_WRITE_DATA(0x0D),
88 + LCD_WRITE_DATA(0x02),
89 +
90 + LCD_WRITE_COMMAND(0xC2),
91 + LCD_WRITE_DATA(0x21),
92 + LCD_WRITE_DATA(0x08),
93 +
94 + // RGB Interface Setting
95 + // LCD_WRITE_COMMAND(0xC3),
96 + // LCD_WRITE_DATA(0x02),
97 +
98 + LCD_WRITE_COMMAND(0xCD),
99 + LCD_WRITE_DATA(0x18),//0F 08-OK D0-D18
100 +
101 + LCD_WRITE_COMMAND(0xB0),
102 + LCD_WRITE_DATA(0x00),
103 + LCD_WRITE_DATA(0x11),
104 + LCD_WRITE_DATA(0x18),
105 + LCD_WRITE_DATA(0x0E),
106 + LCD_WRITE_DATA(0x11),
107 + LCD_WRITE_DATA(0x06),
108 + LCD_WRITE_DATA(0x07),
109 + LCD_WRITE_DATA(0x08),
110 + LCD_WRITE_DATA(0x07),
111 + LCD_WRITE_DATA(0x22),
112 + LCD_WRITE_DATA(0x04),
113 + LCD_WRITE_DATA(0x12),
114 + LCD_WRITE_DATA(0x0F),
115 + LCD_WRITE_DATA(0xAA),
116 + LCD_WRITE_DATA(0x31),
117 + LCD_WRITE_DATA(0x18),
118 +
119 + LCD_WRITE_COMMAND(0xB1),
120 + LCD_WRITE_DATA(0x00),
121 + LCD_WRITE_DATA(0x11),
122 + LCD_WRITE_DATA(0x19),
123 + LCD_WRITE_DATA(0x0E),
124 + LCD_WRITE_DATA(0x12),
125 + LCD_WRITE_DATA(0x07),
126 + LCD_WRITE_DATA(0x08),
127 + LCD_WRITE_DATA(0x08),
128 + LCD_WRITE_DATA(0x08),
129 + LCD_WRITE_DATA(0x22),
130 + LCD_WRITE_DATA(0x04),
131 + LCD_WRITE_DATA(0x11),
132 + LCD_WRITE_DATA(0x11),
133 + LCD_WRITE_DATA(0xA9),
134 + LCD_WRITE_DATA(0x32),
135 + LCD_WRITE_DATA(0x18),
136 +
137 + LCD_WRITE_COMMAND(0xFF),
138 + LCD_WRITE_DATA(0x77),
139 + LCD_WRITE_DATA(0x01),
140 + LCD_WRITE_DATA(0x00),
141 + LCD_WRITE_DATA(0x00),
142 + LCD_WRITE_DATA(0x11),
143 +
144 + LCD_WRITE_COMMAND(0xB0),
145 + LCD_WRITE_DATA(0x60),
146 +
147 + LCD_WRITE_COMMAND(0xB1),
148 + LCD_WRITE_DATA(0x30),
149 +
150 + LCD_WRITE_COMMAND(0xB2),
151 + LCD_WRITE_DATA(0x87),
152 +
153 + LCD_WRITE_COMMAND(0xB3),
154 + LCD_WRITE_DATA(0x80),
155 +
156 + LCD_WRITE_COMMAND(0xB5),
157 + LCD_WRITE_DATA(0x49),
158 +
159 + LCD_WRITE_COMMAND(0xB7),
160 + LCD_WRITE_DATA(0x85),
161 +
162 + LCD_WRITE_COMMAND(0xB8),
163 + LCD_WRITE_DATA(0x21),
164 +
165 + LCD_WRITE_COMMAND(0xC1),
166 + LCD_WRITE_DATA(0x78),
167 +
168 + LCD_WRITE_COMMAND(0xC2),
169 + LCD_WRITE_DATA(0x78),
170 +};
171 +
172 +static const u16 st7701s_init_sequence_2[] = {
173 + LCD_WRITE_COMMAND(0xE0),
174 + LCD_WRITE_DATA(0x00),
175 + LCD_WRITE_DATA(0x1B),
176 + LCD_WRITE_DATA(0x02),
177 +
178 + LCD_WRITE_COMMAND(0xE1),
179 + LCD_WRITE_DATA(0x08),
180 + LCD_WRITE_DATA(0xA0),
181 + LCD_WRITE_DATA(0x00),
182 + LCD_WRITE_DATA(0x00),
183 + LCD_WRITE_DATA(0x07),
184 + LCD_WRITE_DATA(0xA0),
185 + LCD_WRITE_DATA(0x00),
186 + LCD_WRITE_DATA(0x00),
187 + LCD_WRITE_DATA(0x00),
188 + LCD_WRITE_DATA(0x44),
189 + LCD_WRITE_DATA(0x44),
190 +
191 + LCD_WRITE_COMMAND(0xE2),
192 + LCD_WRITE_DATA(0x11),
193 + LCD_WRITE_DATA(0x11),
194 + LCD_WRITE_DATA(0x44),
195 + LCD_WRITE_DATA(0x44),
196 + LCD_WRITE_DATA(0xED),
197 + LCD_WRITE_DATA(0xA0),
198 + LCD_WRITE_DATA(0x00),
199 + LCD_WRITE_DATA(0x00),
200 + LCD_WRITE_DATA(0xEC),
201 + LCD_WRITE_DATA(0xA0),
202 + LCD_WRITE_DATA(0x00),
203 + LCD_WRITE_DATA(0x00),
204 +
205 + LCD_WRITE_COMMAND(0xE3),
206 + LCD_WRITE_DATA(0x00),
207 + LCD_WRITE_DATA(0x00),
208 + LCD_WRITE_DATA(0x11),
209 + LCD_WRITE_DATA(0x11),
210 +
211 + LCD_WRITE_COMMAND(0xE4),
212 + LCD_WRITE_DATA(0x44),
213 + LCD_WRITE_DATA(0x44),
214 +
215 + LCD_WRITE_COMMAND(0xE5),
216 + LCD_WRITE_DATA(0x0A),
217 + LCD_WRITE_DATA(0xE9),
218 + LCD_WRITE_DATA(0xD8),
219 + LCD_WRITE_DATA(0xA0),
220 + LCD_WRITE_DATA(0x0C),
221 + LCD_WRITE_DATA(0xEB),
222 + LCD_WRITE_DATA(0xD8),
223 + LCD_WRITE_DATA(0xA0),
224 + LCD_WRITE_DATA(0x0E),
225 + LCD_WRITE_DATA(0xED),
226 + LCD_WRITE_DATA(0xD8),
227 + LCD_WRITE_DATA(0xA0),
228 + LCD_WRITE_DATA(0x10),
229 + LCD_WRITE_DATA(0xEF),
230 + LCD_WRITE_DATA(0xD8),
231 + LCD_WRITE_DATA(0xA0),
232 +
233 + LCD_WRITE_COMMAND(0xE6),
234 + LCD_WRITE_DATA(0x00),
235 + LCD_WRITE_DATA(0x00),
236 + LCD_WRITE_DATA(0x11),
237 + LCD_WRITE_DATA(0x11),
238 +
239 + LCD_WRITE_COMMAND(0xE7),
240 + LCD_WRITE_DATA(0x44),
241 + LCD_WRITE_DATA(0x44),
242 +
243 + LCD_WRITE_COMMAND(0xE8),
244 + LCD_WRITE_DATA(0x09),
245 + LCD_WRITE_DATA(0xE8),
246 + LCD_WRITE_DATA(0xD8),
247 + LCD_WRITE_DATA(0xA0),
248 + LCD_WRITE_DATA(0x0B),
249 + LCD_WRITE_DATA(0xEA),
250 + LCD_WRITE_DATA(0xD8),
251 + LCD_WRITE_DATA(0xA0),
252 + LCD_WRITE_DATA(0x0D),
253 + LCD_WRITE_DATA(0xEC),
254 + LCD_WRITE_DATA(0xD8),
255 + LCD_WRITE_DATA(0xA0),
256 + LCD_WRITE_DATA(0x0F),
257 + LCD_WRITE_DATA(0xEE),
258 + LCD_WRITE_DATA(0xD8),
259 + LCD_WRITE_DATA(0xA0),
260 +
261 + LCD_WRITE_COMMAND(0xEB),
262 + LCD_WRITE_DATA(0x02),
263 + LCD_WRITE_DATA(0x00),
264 + LCD_WRITE_DATA(0xE4),
265 + LCD_WRITE_DATA(0xE4),
266 + LCD_WRITE_DATA(0x88),
267 + LCD_WRITE_DATA(0x00),
268 + LCD_WRITE_DATA(0x40),
269 +
270 + LCD_WRITE_COMMAND(0xEC),
271 + LCD_WRITE_DATA(0x3C),
272 + LCD_WRITE_DATA(0x00),
273 +
274 + LCD_WRITE_COMMAND(0xED),
275 + LCD_WRITE_DATA(0xAB),
276 + LCD_WRITE_DATA(0x89),
277 + LCD_WRITE_DATA(0x76),
278 + LCD_WRITE_DATA(0x54),
279 + LCD_WRITE_DATA(0x02),
280 + LCD_WRITE_DATA(0xFF),
281 + LCD_WRITE_DATA(0xFF),
282 + LCD_WRITE_DATA(0xFF),
283 + LCD_WRITE_DATA(0xFF),
284 + LCD_WRITE_DATA(0xFF),
285 + LCD_WRITE_DATA(0xFF),
286 + LCD_WRITE_DATA(0x20),
287 + LCD_WRITE_DATA(0x45),
288 + LCD_WRITE_DATA(0x67),
289 + LCD_WRITE_DATA(0x98),
290 + LCD_WRITE_DATA(0xBA),
291 +
292 + LCD_WRITE_COMMAND(0xFF),
293 + LCD_WRITE_DATA(0x77),
294 + LCD_WRITE_DATA(0x01),
295 + LCD_WRITE_DATA(0x00),
296 + LCD_WRITE_DATA(0x00),
297 + LCD_WRITE_DATA(0x00),
298 +
299 + LCD_WRITE_COMMAND(MIPI_DCS_SET_PIXEL_FORMAT),
300 + LCD_WRITE_DATA(0x66),
301 +
302 + LCD_WRITE_COMMAND(MIPI_DCS_SET_ADDRESS_MODE),
303 + LCD_WRITE_DATA(0x00),
304 +
305 + LCD_WRITE_COMMAND(MIPI_DCS_ENTER_INVERT_MODE),
306 +
307 + LCD_WRITE_COMMAND(MIPI_DCS_EXIT_SLEEP_MODE),
308 +};
309 +
310 +static const u16 st7701s_enable_sequence[] = {
311 + LCD_WRITE_COMMAND(MIPI_DCS_SET_DISPLAY_ON),
312 +};
313 +
314 +static const u16 st7701s_disable_sequence[] = {
315 + LCD_WRITE_COMMAND(MIPI_DCS_SET_DISPLAY_OFF),
316 +};
317 +
318 +static inline struct st7701s *panel_to_st7701s(struct drm_panel *panel)
319 +{
320 + return container_of(panel, struct st7701s, panel);
321 +}
322 +
323 +static int st7701s_spi_write(struct st7701s *ctx, const u16 *data, size_t size)
324 +{
325 + struct spi_transfer xfer = { };
326 + struct spi_message msg;
327 +
328 + spi_message_init(&msg);
329 +
330 + xfer.tx_buf = data;
331 + xfer.bits_per_word = 9;
332 + xfer.len = size;
333 +
334 + spi_message_add_tail(&xfer, &msg);
335 + return spi_sync(ctx->spi, &msg);
336 +}
337 +
338 +static const struct drm_display_mode default_mode = {
339 + .clock = 19800,
340 + .hdisplay = 480,
341 + .hsync_start = 480 + 60,
342 + .hsync_end = 480 + 60 + 12,
343 + .htotal = 480 + 60 + 12 + 60,
344 + .vdisplay = 480,
345 + .vsync_start = 480 + 18,
346 + .vsync_end = 480 + 18 + 4,
347 + .vtotal = 480 + 18 + 4 + 18,
348 +};
349 +
350 +static int st7701s_get_modes(struct drm_panel *panel,
351 + struct drm_connector *connector)
352 +{
353 + struct drm_display_mode *mode;
354 +
355 + mode = drm_mode_duplicate(connector->dev, &default_mode);
356 + if (!mode)
357 + return -ENOMEM;
358 +
359 + drm_mode_set_name(mode);
360 +
361 + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
362 + drm_mode_probed_add(connector, mode);
363 +
364 + connector->display_info.width_mm = 70;
365 + connector->display_info.height_mm = 72;
366 +
367 + return 1;
368 +}
369 +
370 +static int st7701s_prepare(struct drm_panel *panel)
371 +{
372 + struct st7701s *ctx = panel_to_st7701s(panel);
373 +
374 + gpiod_set_value_cansleep(ctx->reset, 1);
375 + msleep(20);
376 +
377 + gpiod_set_value_cansleep(ctx->reset, 0);
378 + msleep(20);
379 +
380 + st7701s_spi_write(ctx, st7701s_init_sequence_1,
381 + sizeof(st7701s_init_sequence_1));
382 + msleep(20);
383 +
384 + st7701s_spi_write(ctx, st7701s_init_sequence_2,
385 + sizeof(st7701s_init_sequence_2));
386 + msleep(120);
387 +
388 + return 0;
389 +}
390 +
391 +static int st7701s_enable(struct drm_panel *panel)
392 +{
393 + struct st7701s *ctx = panel_to_st7701s(panel);
394 +
395 + st7701s_spi_write(ctx, st7701s_enable_sequence,
396 + sizeof(st7701s_enable_sequence));
397 + msleep(20);
398 +
399 + return 0;
400 +}
401 +
402 +static int st7701s_disable(struct drm_panel *panel)
403 +{
404 + struct st7701s *ctx = panel_to_st7701s(panel);
405 +
406 + st7701s_spi_write(ctx, st7701s_disable_sequence,
407 + sizeof(st7701s_disable_sequence));
408 +
409 + return 0;
410 +}
411 +
412 +static int st7701s_unprepare(struct drm_panel *panel)
413 +{
414 + return 0;
415 +}
416 +
417 +static const struct drm_panel_funcs st7701s_drm_funcs = {
418 + .disable = st7701s_disable,
419 + .enable = st7701s_enable,
420 + .get_modes = st7701s_get_modes,
421 + .prepare = st7701s_prepare,
422 + .unprepare = st7701s_unprepare,
423 +};
424 +
425 +static int st7701s_probe(struct spi_device *spi)
426 +{
427 + struct device *dev = &spi->dev;
428 + struct st7701s *ctx;
429 + int ret;
430 +
431 + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
432 + if (!ctx)
433 + return -ENOMEM;
434 +
435 + spi_set_drvdata(spi, ctx);
436 + ctx->spi = spi;
437 +
438 + ctx->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW);
439 + if (IS_ERR(ctx->reset)) {
440 + dev_err(&spi->dev, "Couldn't get our reset line\n");
441 + return PTR_ERR(ctx->reset);
442 + }
443 +
444 + drm_panel_init(&ctx->panel, dev, &st7701s_drm_funcs,
445 + DRM_MODE_CONNECTOR_DPI);
446 +
447 + ret = drm_panel_of_backlight(&ctx->panel);
448 + if (ret)
449 + return ret;
450 +
451 + drm_panel_add(&ctx->panel);
452 +
453 + return 0;
454 +}
455 +
456 +static void st7701s_remove(struct spi_device *spi)
457 +{
458 + struct st7701s *ctx = spi_get_drvdata(spi);
459 +
460 + drm_panel_remove(&ctx->panel);
461 +}
462 +
463 +static const struct of_device_id st7701s_of_match[] = {
464 + { .compatible = "sitronix,st7701s" },
465 + { }
466 +};
467 +MODULE_DEVICE_TABLE(of, st7701s_of_match);
468 +
469 +static const struct spi_device_id st7701s_ids[] = {
470 + { "st7701s" },
471 + { }
472 +};
473 +MODULE_DEVICE_TABLE(spi, st7701s_ids);
474 +
475 +static struct spi_driver st7701s_driver = {
476 + .probe = st7701s_probe,
477 + .remove = st7701s_remove,
478 + .driver = {
479 + .name = "st7701s",
480 + .of_match_table = st7701s_of_match,
481 + },
482 +};
483 +module_spi_driver(st7701s_driver);
484 +
485 +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
486 +MODULE_DESCRIPTION("Sitronix ST7701s LCD Driver");
487 +MODULE_LICENSE("GPL v2");