ea7313e97b22737382ea5effbd30f9e6d1773dd6
[openwrt/staging/hauke.git] /
1 From 6e9d09063a883bd69c84a95f6e854a7dbe7720af Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Tue, 1 Feb 2022 15:27:01 +0000
4 Subject: [PATCH] drm/panel/panel-sitronix-st7701: Support SPI config
5 and RGB data
6
7 The ST7701 supports numerous different interface mechanisms for
8 MIPI DSI, RGB, or SPI. The driver was only implementing DSI input,
9 so add RGB parallel input with SPI configuration.
10
11 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
12 ---
13 drivers/gpu/drm/panel/panel-sitronix-st7701.c | 382 ++++++++++++++++--
14 1 file changed, 359 insertions(+), 23 deletions(-)
15
16 --- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c
17 +++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c
18 @@ -7,15 +7,20 @@
19 #include <drm/drm_mipi_dsi.h>
20 #include <drm/drm_modes.h>
21 #include <drm/drm_panel.h>
22 +#include <drm/drm_print.h>
23
24 #include <linux/gpio/consumer.h>
25 #include <linux/delay.h>
26 +#include <linux/media-bus-format.h>
27 #include <linux/module.h>
28 #include <linux/of_device.h>
29 #include <linux/regulator/consumer.h>
30 +#include <linux/spi/spi.h>
31
32 #include <video/mipi_display.h>
33
34 +#define SPI_DATA_FLAG 0x100
35 +
36 /* Command2 BKx selection command */
37 #define DSI_CMD2BKX_SEL 0xFF
38
39 @@ -46,9 +51,14 @@
40 * 11 = CMD2BK1, Command2 BK1
41 * 00 = Command2 disable
42 */
43 +#define DSI_CMD2BK3_SEL 0x13
44 #define DSI_CMD2BK1_SEL 0x11
45 #define DSI_CMD2BK0_SEL 0x10
46 #define DSI_CMD2BKX_SEL_NONE 0x00
47 +#define SPI_CMD2BK3_SEL (SPI_DATA_FLAG | DSI_CMD2BK3_SEL)
48 +#define SPI_CMD2BK1_SEL (SPI_DATA_FLAG | DSI_CMD2BK1_SEL)
49 +#define SPI_CMD2BK0_SEL (SPI_DATA_FLAG | DSI_CMD2BK0_SEL)
50 +#define SPI_CMD2BKX_SEL_NONE (SPI_DATA_FLAG | DSI_CMD2BKX_SEL_NONE)
51
52 /* Command2, BK0 bytes */
53 #define DSI_LINESET_LINE 0x69
54 @@ -86,19 +96,34 @@
55 #define DSI_MIPISET1_EOT_EN BIT(3)
56 #define DSI_CMD2_BK1_MIPISET1_SET (BIT(7) | DSI_MIPISET1_EOT_EN)
57
58 +struct st7701;
59 +
60 +enum st7701_ctrl_if {
61 + ST7701_CTRL_DSI,
62 + ST7701_CTRL_SPI,
63 +};
64 +
65 struct st7701_panel_desc {
66 const struct drm_display_mode *mode;
67 unsigned int lanes;
68 unsigned long flags;
69 enum mipi_dsi_pixel_format format;
70 + u32 mediabus_format;
71 const char *const *supply_names;
72 unsigned int num_supplies;
73 unsigned int panel_sleep_delay;
74 + void (*init_sequence)(struct st7701 *st7701);
75 + unsigned int conn_type;
76 + enum st7701_ctrl_if interface;
77 + u32 bus_flags;
78 };
79
80 struct st7701 {
81 struct drm_panel panel;
82 struct mipi_dsi_device *dsi;
83 + struct spi_device *spi;
84 + const struct device *dev;
85 +
86 const struct st7701_panel_desc *desc;
87
88 struct regulator_bulk_data *supplies;
89 @@ -123,7 +148,23 @@ static inline int st7701_dsi_write(struc
90 st7701_dsi_write(st7701, d, ARRAY_SIZE(d)); \
91 }
92
93 -static void st7701_init_sequence(struct st7701 *st7701)
94 +#define ST7701_SPI(st7701, seq...) \
95 + { \
96 + const u16 d[] = { seq }; \
97 + struct spi_transfer xfer = { }; \
98 + struct spi_message spi; \
99 + \
100 + spi_message_init(&spi); \
101 + \
102 + xfer.tx_buf = d; \
103 + xfer.bits_per_word = 9; \
104 + xfer.len = sizeof(u16) * ARRAY_SIZE(d); \
105 + \
106 + spi_message_add_tail(&xfer, &spi); \
107 + spi_sync((st7701)->spi, &spi); \
108 + }
109 +
110 +static void ts8550b_init_sequence(struct st7701 *st7701)
111 {
112 const struct drm_display_mode *mode = st7701->desc->mode;
113
114 @@ -194,6 +235,111 @@ static void st7701_init_sequence(struct
115 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE);
116 }
117
118 +static void txw210001b0_init_sequence(struct st7701 *st7701)
119 +{
120 + ST7701_SPI(st7701, MIPI_DCS_SOFT_RESET);
121 +
122 + usleep_range(5000, 7000);
123 +
124 + ST7701_SPI(st7701, DSI_CMD2BKX_SEL,
125 + 0x177, 0x101, 0x100, 0x100, SPI_CMD2BK0_SEL);
126 +
127 + ST7701_SPI(st7701, DSI_CMD2_BK0_LNESET, 0x13B, 0x100);
128 +
129 + ST7701_SPI(st7701, DSI_CMD2_BK0_PORCTRL, 0x10B, 0x102);
130 +
131 + ST7701_SPI(st7701, DSI_CMD2_BK0_INVSEL, 0x100, 0x102);
132 +
133 + ST7701_SPI(st7701, 0xCC, 0x110);
134 +
135 + /*
136 + * Gamma option B:
137 + * Positive Voltage Gamma Control
138 + */
139 + ST7701_SPI(st7701, DSI_CMD2_BK0_PVGAMCTRL,
140 + 0x102, 0x113, 0x11B, 0x10D, 0x110, 0x105, 0x108, 0x107,
141 + 0x107, 0x124, 0x104, 0x111, 0x10E, 0x12C, 0x133, 0x11D);
142 +
143 + /* Negative Voltage Gamma Control */
144 + ST7701_SPI(st7701, DSI_CMD2_BK0_NVGAMCTRL,
145 + 0x105, 0x113, 0x11B, 0x10D, 0x111, 0x105, 0x108, 0x107,
146 + 0x107, 0x124, 0x104, 0x111, 0x10E, 0x12C, 0x133, 0x11D);
147 +
148 + ST7701_SPI(st7701, DSI_CMD2BKX_SEL,
149 + 0x177, 0x101, 0x100, 0x100, SPI_CMD2BK1_SEL);
150 +
151 + ST7701_SPI(st7701, DSI_CMD2_BK1_VRHS, 0x15D);
152 +
153 + ST7701_SPI(st7701, DSI_CMD2_BK1_VCOM, 0x143);
154 +
155 + ST7701_SPI(st7701, DSI_CMD2_BK1_VGHSS, 0x181);
156 +
157 + ST7701_SPI(st7701, DSI_CMD2_BK1_TESTCMD, 0x180);
158 +
159 + ST7701_SPI(st7701, DSI_CMD2_BK1_VGLS, 0x143);
160 +
161 + ST7701_SPI(st7701, DSI_CMD2_BK1_PWCTLR1, 0x185);
162 +
163 + ST7701_SPI(st7701, DSI_CMD2_BK1_PWCTLR2, 0x120);
164 +
165 + ST7701_SPI(st7701, DSI_CMD2_BK1_SPD1, 0x178);
166 +
167 + ST7701_SPI(st7701, DSI_CMD2_BK1_SPD2, 0x178);
168 +
169 + ST7701_SPI(st7701, DSI_CMD2_BK1_MIPISET1, 0x188);
170 +
171 + ST7701_SPI(st7701, 0xE0, 0x100, 0x100, 0x102);
172 +
173 + ST7701_SPI(st7701, 0xE1,
174 + 0x103, 0x1A0, 0x100, 0x100, 0x104, 0x1A0, 0x100, 0x100,
175 + 0x100, 0x120, 0x120);
176 +
177 + ST7701_SPI(st7701, 0xE2,
178 + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100,
179 + 0x100, 0x100, 0x100, 0x100, 0x100);
180 +
181 + ST7701_SPI(st7701, 0xE3, 0x100, 0x100, 0x111, 0x100);
182 +
183 + ST7701_SPI(st7701, 0xE4, 0x122, 0x100);
184 +
185 + ST7701_SPI(st7701, 0xE5,
186 + 0x105, 0x1EC, 0x1A0, 0x1A0, 0x107, 0x1EE, 0x1A0, 0x1A0,
187 + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100);
188 +
189 + ST7701_SPI(st7701, 0xE6, 0x100, 0x100, 0x111, 0x100);
190 +
191 + ST7701_SPI(st7701, 0xE7, 0x122, 0x100);
192 +
193 + ST7701_SPI(st7701, 0xE8,
194 + 0x106, 0x1ED, 0x1A0, 0x1A0, 0x108, 0x1EF, 0x1A0, 0x1A0,
195 + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100);
196 +
197 + ST7701_SPI(st7701, 0xEB,
198 + 0x100, 0x100, 0x140, 0x140, 0x100, 0x100, 0x100);
199 +
200 + ST7701_SPI(st7701, 0xED,
201 + 0x1FF, 0x1FF, 0x1FF, 0x1BA, 0x10A, 0x1BF, 0x145, 0x1FF,
202 + 0x1FF, 0x154, 0x1FB, 0x1A0, 0x1AB, 0x1FF, 0x1FF, 0x1FF);
203 +
204 + ST7701_SPI(st7701, 0xEF, 0x110, 0x10D, 0x104, 0x108, 0x13F, 0x11F);
205 +
206 + ST7701_SPI(st7701, DSI_CMD2BKX_SEL,
207 + 0x177, 0x101, 0x100, 0x100, SPI_CMD2BK3_SEL);
208 +
209 + ST7701_SPI(st7701, 0xEF, 0x108);
210 +
211 + ST7701_SPI(st7701, DSI_CMD2BKX_SEL,
212 + 0x177, 0x101, 0x100, 0x100, SPI_CMD2BKX_SEL_NONE);
213 +
214 + ST7701_SPI(st7701, 0xCD, 0x108); /* RGB format COLCTRL */
215 +
216 + ST7701_SPI(st7701, 0x36, 0x108); /* MadCtl */
217 +
218 + ST7701_SPI(st7701, 0x3A, 0x166); /* Colmod */
219 +
220 + ST7701_SPI(st7701, MIPI_DCS_EXIT_SLEEP_MODE);
221 +}
222 +
223 static int st7701_prepare(struct drm_panel *panel)
224 {
225 struct st7701 *st7701 = panel_to_st7701(panel);
226 @@ -210,7 +356,7 @@ static int st7701_prepare(struct drm_pan
227 gpiod_set_value(st7701->reset, 1);
228 msleep(150);
229
230 - st7701_init_sequence(st7701);
231 + st7701->desc->init_sequence(st7701);
232
233 return 0;
234 }
235 @@ -219,7 +365,15 @@ static int st7701_enable(struct drm_pane
236 {
237 struct st7701 *st7701 = panel_to_st7701(panel);
238
239 - ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_ON, 0x00);
240 + switch (st7701->desc->interface) {
241 + case ST7701_CTRL_DSI:
242 + ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_ON, 0x00);
243 + break;
244 + case ST7701_CTRL_SPI:
245 + ST7701_SPI(st7701, MIPI_DCS_SET_DISPLAY_ON);
246 + msleep(30);
247 + break;
248 + }
249
250 return 0;
251 }
252 @@ -228,7 +382,14 @@ static int st7701_disable(struct drm_pan
253 {
254 struct st7701 *st7701 = panel_to_st7701(panel);
255
256 - ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_OFF, 0x00);
257 + switch (st7701->desc->interface) {
258 + case ST7701_CTRL_DSI:
259 + ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_OFF, 0x00);
260 + break;
261 + case ST7701_CTRL_SPI:
262 + ST7701_SPI(st7701, MIPI_DCS_SET_DISPLAY_OFF);
263 + break;
264 + }
265
266 return 0;
267 }
268 @@ -237,7 +398,14 @@ static int st7701_unprepare(struct drm_p
269 {
270 struct st7701 *st7701 = panel_to_st7701(panel);
271
272 - ST7701_DSI(st7701, MIPI_DCS_ENTER_SLEEP_MODE, 0x00);
273 + switch (st7701->desc->interface) {
274 + case ST7701_CTRL_DSI:
275 + ST7701_DSI(st7701, MIPI_DCS_ENTER_SLEEP_MODE, 0x00);
276 + break;
277 + case ST7701_CTRL_SPI:
278 + ST7701_SPI(st7701, MIPI_DCS_ENTER_SLEEP_MODE);
279 + break;
280 + }
281
282 msleep(st7701->sleep_delay);
283
284 @@ -268,7 +436,7 @@ static int st7701_get_modes(struct drm_p
285
286 mode = drm_mode_duplicate(connector->dev, desc_mode);
287 if (!mode) {
288 - dev_err(&st7701->dsi->dev, "failed to add mode %ux%u@%u\n",
289 + dev_err(st7701->dev, "failed to add mode %ux%u@%u\n",
290 desc_mode->hdisplay, desc_mode->vdisplay,
291 drm_mode_vrefresh(desc_mode));
292 return -ENOMEM;
293 @@ -277,9 +445,18 @@ static int st7701_get_modes(struct drm_p
294 drm_mode_set_name(mode);
295 drm_mode_probed_add(connector, mode);
296
297 + if (st7701->desc->mediabus_format)
298 + drm_display_info_set_bus_formats(&connector->display_info,
299 + &st7701->desc->mediabus_format,
300 + 1);
301 + connector->display_info.bus_flags = 0;
302 +
303 connector->display_info.width_mm = desc_mode->width_mm;
304 connector->display_info.height_mm = desc_mode->height_mm;
305
306 + if (st7701->desc->bus_flags)
307 + connector->display_info.bus_flags = st7701->desc->bus_flags;
308 +
309 return 1;
310 }
311
312 @@ -323,24 +500,68 @@ static const struct st7701_panel_desc ts
313 .supply_names = ts8550b_supply_names,
314 .num_supplies = ARRAY_SIZE(ts8550b_supply_names),
315 .panel_sleep_delay = 80, /* panel need extra 80ms for sleep out cmd */
316 + .init_sequence = ts8550b_init_sequence,
317 + .conn_type = DRM_MODE_CONNECTOR_DSI,
318 + .interface = ST7701_CTRL_DSI,
319 };
320
321 -static int st7701_dsi_probe(struct mipi_dsi_device *dsi)
322 +static const struct drm_display_mode txw210001b0_mode = {
323 + .clock = 19200,
324 +
325 + .hdisplay = 480,
326 + .hsync_start = 480 + 10,
327 + .hsync_end = 480 + 10 + 16,
328 + .htotal = 480 + 10 + 16 + 56,
329 +
330 + .vdisplay = 480,
331 + .vsync_start = 480 + 15,
332 + .vsync_end = 480 + 15 + 60,
333 + .vtotal = 480 + 15 + 60 + 15,
334 +
335 + .width_mm = 53,
336 + .height_mm = 53,
337 + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
338 +
339 + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
340 +};
341 +
342 +static const struct st7701_panel_desc txw210001b0_desc = {
343 + .mode = &txw210001b0_mode,
344 + .mediabus_format = MEDIA_BUS_FMT_RGB888_1X24,
345 + .supply_names = ts8550b_supply_names,
346 + .num_supplies = ARRAY_SIZE(ts8550b_supply_names),
347 + .init_sequence = txw210001b0_init_sequence,
348 + .conn_type = DRM_MODE_CONNECTOR_DPI,
349 + .interface = ST7701_CTRL_SPI,
350 + .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
351 +};
352 +
353 +static const struct st7701_panel_desc hyperpixel2r_desc = {
354 + .mode = &txw210001b0_mode,
355 + .mediabus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
356 + .supply_names = ts8550b_supply_names,
357 + .num_supplies = ARRAY_SIZE(ts8550b_supply_names),
358 + .init_sequence = txw210001b0_init_sequence,
359 + .conn_type = DRM_MODE_CONNECTOR_DPI,
360 + .interface = ST7701_CTRL_SPI,
361 + .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
362 +};
363 +
364 +static int st7701_probe(struct device *dev, struct st7701 **ret_st7701)
365 {
366 const struct st7701_panel_desc *desc;
367 struct st7701 *st7701;
368 int ret, i;
369
370 - st7701 = devm_kzalloc(&dsi->dev, sizeof(*st7701), GFP_KERNEL);
371 + st7701 = devm_kzalloc(dev, sizeof(*st7701), GFP_KERNEL);
372 if (!st7701)
373 return -ENOMEM;
374
375 - desc = of_device_get_match_data(&dsi->dev);
376 - dsi->mode_flags = desc->flags;
377 - dsi->format = desc->format;
378 - dsi->lanes = desc->lanes;
379 + desc = of_device_get_match_data(dev);
380 + if (!desc)
381 + return -EINVAL;
382
383 - st7701->supplies = devm_kcalloc(&dsi->dev, desc->num_supplies,
384 + st7701->supplies = devm_kcalloc(dev, desc->num_supplies,
385 sizeof(*st7701->supplies),
386 GFP_KERNEL);
387 if (!st7701->supplies)
388 @@ -349,19 +570,19 @@ static int st7701_dsi_probe(struct mipi_
389 for (i = 0; i < desc->num_supplies; i++)
390 st7701->supplies[i].supply = desc->supply_names[i];
391
392 - ret = devm_regulator_bulk_get(&dsi->dev, desc->num_supplies,
393 + ret = devm_regulator_bulk_get(dev, desc->num_supplies,
394 st7701->supplies);
395 if (ret < 0)
396 return ret;
397
398 - st7701->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
399 + st7701->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
400 if (IS_ERR(st7701->reset)) {
401 - dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
402 + dev_err(dev, "Couldn't get our reset GPIO\n");
403 return PTR_ERR(st7701->reset);
404 }
405
406 - drm_panel_init(&st7701->panel, &dsi->dev, &st7701_funcs,
407 - DRM_MODE_CONNECTOR_DSI);
408 + drm_panel_init(&st7701->panel, dev, &st7701_funcs,
409 + desc->conn_type);
410
411 /**
412 * Once sleep out has been issued, ST7701 IC required to wait 120ms
413 @@ -380,9 +601,30 @@ static int st7701_dsi_probe(struct mipi_
414
415 drm_panel_add(&st7701->panel);
416
417 + st7701->desc = desc;
418 + st7701->dev = dev;
419 +
420 + *ret_st7701 = st7701;
421 +
422 + return 0;
423 +}
424 +
425 +static int st7701_dsi_probe(struct mipi_dsi_device *dsi)
426 +{
427 + struct st7701 *st7701;
428 + int ret;
429 +
430 + ret = st7701_probe(&dsi->dev, &st7701);
431 +
432 + if (ret)
433 + return ret;
434 +
435 + dsi->mode_flags = st7701->desc->flags;
436 + dsi->format = st7701->desc->format;
437 + dsi->lanes = st7701->desc->lanes;
438 +
439 mipi_dsi_set_drvdata(dsi, st7701);
440 st7701->dsi = dsi;
441 - st7701->desc = desc;
442
443 ret = mipi_dsi_attach(dsi);
444 if (ret)
445 @@ -405,21 +647,115 @@ static int st7701_dsi_remove(struct mipi
446 return 0;
447 }
448
449 -static const struct of_device_id st7701_of_match[] = {
450 +static const struct of_device_id st7701_dsi_of_match[] = {
451 { .compatible = "techstar,ts8550b", .data = &ts8550b_desc },
452 { }
453 };
454 -MODULE_DEVICE_TABLE(of, st7701_of_match);
455 +MODULE_DEVICE_TABLE(of, st7701_dsi_of_match);
456
457 static struct mipi_dsi_driver st7701_dsi_driver = {
458 .probe = st7701_dsi_probe,
459 .remove = st7701_dsi_remove,
460 .driver = {
461 .name = "st7701",
462 - .of_match_table = st7701_of_match,
463 + .of_match_table = st7701_dsi_of_match,
464 },
465 };
466 -module_mipi_dsi_driver(st7701_dsi_driver);
467 +
468 +/* SPI display probe */
469 +static const struct of_device_id st7701_spi_of_match[] = {
470 + { .compatible = "txw,txw210001b0",
471 + .data = &txw210001b0_desc,
472 + }, {
473 + .compatible = "pimoroni,hyperpixel2round",
474 + .data = &hyperpixel2r_desc,
475 + }, {
476 + /* sentinel */
477 + }
478 +};
479 +MODULE_DEVICE_TABLE(of, st7701_spi_of_match);
480 +
481 +static int st7701_spi_probe(struct spi_device *spi)
482 +{
483 + struct st7701 *st7701;
484 + int ret;
485 +
486 + spi->mode = SPI_MODE_3;
487 + spi->bits_per_word = 9;
488 + ret = spi_setup(spi);
489 + if (ret < 0) {
490 + dev_err(&spi->dev, "failed to setup SPI: %d\n", ret);
491 + return ret;
492 + }
493 +
494 + ret = st7701_probe(&spi->dev, &st7701);
495 +
496 + if (ret)
497 + return ret;
498 +
499 + spi_set_drvdata(spi, st7701);
500 + st7701->spi = spi;
501 +
502 + return 0;
503 +}
504 +
505 +static int st7701_spi_remove(struct spi_device *spi)
506 +{
507 + struct st7701 *ctx = spi_get_drvdata(spi);
508 +
509 + drm_panel_remove(&ctx->panel);
510 +
511 + return 0;
512 +}
513 +
514 +static const struct spi_device_id st7701_spi_ids[] = {
515 + { "txw210001b0", 0 },
516 + { "hyperpixel2round", 0 },
517 + { /* sentinel */ }
518 +};
519 +MODULE_DEVICE_TABLE(spi, st7701_spi_ids);
520 +
521 +static struct spi_driver st7701_spi_driver = {
522 + .probe = st7701_spi_probe,
523 + .remove = st7701_spi_remove,
524 + .driver = {
525 + .name = "st7701",
526 + .of_match_table = st7701_spi_of_match,
527 + },
528 + .id_table = st7701_spi_ids,
529 +};
530 +
531 +static int __init panel_st7701_init(void)
532 +{
533 + int err;
534 +
535 + err = spi_register_driver(&st7701_spi_driver);
536 + if (err < 0)
537 + return err;
538 +
539 + if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
540 + err = mipi_dsi_driver_register(&st7701_dsi_driver);
541 + if (err < 0)
542 + goto err_did_spi_register;
543 + }
544 +
545 + return 0;
546 +
547 +err_did_spi_register:
548 + spi_unregister_driver(&st7701_spi_driver);
549 +
550 + return err;
551 +}
552 +module_init(panel_st7701_init);
553 +
554 +static void __exit panel_st7701_exit(void)
555 +{
556 + if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
557 + mipi_dsi_driver_unregister(&st7701_dsi_driver);
558 +
559 + spi_unregister_driver(&st7701_spi_driver);
560 +}
561 +module_exit(panel_st7701_exit);
562
563 MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
564 MODULE_DESCRIPTION("Sitronix ST7701 LCD Panel Driver");