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