aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/panel/Kconfig7
-rw-r--r--drivers/gpu/drm/panel/Makefile1
-rw-r--r--drivers/gpu/drm/panel/panel-sitronix-st7789v.c449
3 files changed, 457 insertions, 0 deletions
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index d913c834eb71..0756986caa2b 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -87,4 +87,11 @@ config DRM_PANEL_SHARP_LS043T1LE01
87 Say Y here if you want to enable support for Sharp LS043T1LE01 qHD 87 Say Y here if you want to enable support for Sharp LS043T1LE01 qHD
88 (540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard 88 (540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard
89 89
90config DRM_PANEL_SITRONIX_ST7789V
91 tristate "Sitronix ST7789V panel"
92 depends on OF && SPI
93 help
94 Say Y here if you want to enable support for the Sitronix
95 ST7789V controller for 240x320 LCD panels
96
90endmenu 97endmenu
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 1d483b03178b..3f2f926eddec 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
7obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o 7obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
8obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o 8obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
9obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o 9obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
10obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
new file mode 100644
index 000000000000..358c64ef1922
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -0,0 +1,449 @@
1/*
2 * Copyright (C) 2017 Free Electrons
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License version
6 * 2 as published by the Free Software Foundation.
7 */
8
9#include <linux/gpio/consumer.h>
10#include <linux/regulator/consumer.h>
11#include <linux/spi/spi.h>
12
13#include <drm/drmP.h>
14#include <drm/drm_panel.h>
15
16#include <video/mipi_display.h>
17
18#define ST7789V_COLMOD_RGB_FMT_18BITS (6 << 4)
19#define ST7789V_COLMOD_CTRL_FMT_18BITS (6 << 0)
20
21#define ST7789V_RAMCTRL_CMD 0xb0
22#define ST7789V_RAMCTRL_RM_RGB BIT(4)
23#define ST7789V_RAMCTRL_DM_RGB BIT(0)
24#define ST7789V_RAMCTRL_MAGIC (3 << 6)
25#define ST7789V_RAMCTRL_EPF(n) (((n) & 3) << 4)
26
27#define ST7789V_RGBCTRL_CMD 0xb1
28#define ST7789V_RGBCTRL_WO BIT(7)
29#define ST7789V_RGBCTRL_RCM(n) (((n) & 3) << 5)
30#define ST7789V_RGBCTRL_VSYNC_HIGH BIT(3)
31#define ST7789V_RGBCTRL_HSYNC_HIGH BIT(2)
32#define ST7789V_RGBCTRL_PCLK_HIGH BIT(1)
33#define ST7789V_RGBCTRL_VBP(n) ((n) & 0x7f)
34#define ST7789V_RGBCTRL_HBP(n) ((n) & 0x1f)
35
36#define ST7789V_PORCTRL_CMD 0xb2
37#define ST7789V_PORCTRL_IDLE_BP(n) (((n) & 0xf) << 4)
38#define ST7789V_PORCTRL_IDLE_FP(n) ((n) & 0xf)
39#define ST7789V_PORCTRL_PARTIAL_BP(n) (((n) & 0xf) << 4)
40#define ST7789V_PORCTRL_PARTIAL_FP(n) ((n) & 0xf)
41
42#define ST7789V_GCTRL_CMD 0xb7
43#define ST7789V_GCTRL_VGHS(n) (((n) & 7) << 4)
44#define ST7789V_GCTRL_VGLS(n) ((n) & 7)
45
46#define ST7789V_VCOMS_CMD 0xbb
47
48#define ST7789V_LCMCTRL_CMD 0xc0
49#define ST7789V_LCMCTRL_XBGR BIT(5)
50#define ST7789V_LCMCTRL_XMX BIT(3)
51#define ST7789V_LCMCTRL_XMH BIT(2)
52
53#define ST7789V_VDVVRHEN_CMD 0xc2
54#define ST7789V_VDVVRHEN_CMDEN BIT(0)
55
56#define ST7789V_VRHS_CMD 0xc3
57
58#define ST7789V_VDVS_CMD 0xc4
59
60#define ST7789V_FRCTRL2_CMD 0xc6
61
62#define ST7789V_PWCTRL1_CMD 0xd0
63#define ST7789V_PWCTRL1_MAGIC 0xa4
64#define ST7789V_PWCTRL1_AVDD(n) (((n) & 3) << 6)
65#define ST7789V_PWCTRL1_AVCL(n) (((n) & 3) << 4)
66#define ST7789V_PWCTRL1_VDS(n) ((n) & 3)
67
68#define ST7789V_PVGAMCTRL_CMD 0xe0
69#define ST7789V_PVGAMCTRL_JP0(n) (((n) & 3) << 4)
70#define ST7789V_PVGAMCTRL_JP1(n) (((n) & 3) << 4)
71#define ST7789V_PVGAMCTRL_VP0(n) ((n) & 0xf)
72#define ST7789V_PVGAMCTRL_VP1(n) ((n) & 0x3f)
73#define ST7789V_PVGAMCTRL_VP2(n) ((n) & 0x3f)
74#define ST7789V_PVGAMCTRL_VP4(n) ((n) & 0x1f)
75#define ST7789V_PVGAMCTRL_VP6(n) ((n) & 0x1f)
76#define ST7789V_PVGAMCTRL_VP13(n) ((n) & 0xf)
77#define ST7789V_PVGAMCTRL_VP20(n) ((n) & 0x7f)
78#define ST7789V_PVGAMCTRL_VP27(n) ((n) & 7)
79#define ST7789V_PVGAMCTRL_VP36(n) (((n) & 7) << 4)
80#define ST7789V_PVGAMCTRL_VP43(n) ((n) & 0x7f)
81#define ST7789V_PVGAMCTRL_VP50(n) ((n) & 0xf)
82#define ST7789V_PVGAMCTRL_VP57(n) ((n) & 0x1f)
83#define ST7789V_PVGAMCTRL_VP59(n) ((n) & 0x1f)
84#define ST7789V_PVGAMCTRL_VP61(n) ((n) & 0x3f)
85#define ST7789V_PVGAMCTRL_VP62(n) ((n) & 0x3f)
86#define ST7789V_PVGAMCTRL_VP63(n) (((n) & 0xf) << 4)
87
88#define ST7789V_NVGAMCTRL_CMD 0xe1
89#define ST7789V_NVGAMCTRL_JN0(n) (((n) & 3) << 4)
90#define ST7789V_NVGAMCTRL_JN1(n) (((n) & 3) << 4)
91#define ST7789V_NVGAMCTRL_VN0(n) ((n) & 0xf)
92#define ST7789V_NVGAMCTRL_VN1(n) ((n) & 0x3f)
93#define ST7789V_NVGAMCTRL_VN2(n) ((n) & 0x3f)
94#define ST7789V_NVGAMCTRL_VN4(n) ((n) & 0x1f)
95#define ST7789V_NVGAMCTRL_VN6(n) ((n) & 0x1f)
96#define ST7789V_NVGAMCTRL_VN13(n) ((n) & 0xf)
97#define ST7789V_NVGAMCTRL_VN20(n) ((n) & 0x7f)
98#define ST7789V_NVGAMCTRL_VN27(n) ((n) & 7)
99#define ST7789V_NVGAMCTRL_VN36(n) (((n) & 7) << 4)
100#define ST7789V_NVGAMCTRL_VN43(n) ((n) & 0x7f)
101#define ST7789V_NVGAMCTRL_VN50(n) ((n) & 0xf)
102#define ST7789V_NVGAMCTRL_VN57(n) ((n) & 0x1f)
103#define ST7789V_NVGAMCTRL_VN59(n) ((n) & 0x1f)
104#define ST7789V_NVGAMCTRL_VN61(n) ((n) & 0x3f)
105#define ST7789V_NVGAMCTRL_VN62(n) ((n) & 0x3f)
106#define ST7789V_NVGAMCTRL_VN63(n) (((n) & 0xf) << 4)
107
108#define ST7789V_TEST(val, func) \
109 do { \
110 if ((val = (func))) \
111 return val; \
112 } while (0)
113
114struct st7789v {
115 struct drm_panel panel;
116 struct spi_device *spi;
117 struct gpio_desc *reset;
118 struct backlight_device *backlight;
119 struct regulator *power;
120};
121
122enum st7789v_prefix {
123 ST7789V_COMMAND = 0,
124 ST7789V_DATA = 1,
125};
126
127static inline struct st7789v *panel_to_st7789v(struct drm_panel *panel)
128{
129 return container_of(panel, struct st7789v, panel);
130}
131
132static int st7789v_spi_write(struct st7789v *ctx, enum st7789v_prefix prefix,
133 u8 data)
134{
135 struct spi_transfer xfer = { };
136 struct spi_message msg;
137 u16 txbuf = ((prefix & 1) << 8) | data;
138
139 spi_message_init(&msg);
140
141 xfer.tx_buf = &txbuf;
142 xfer.bits_per_word = 9;
143 xfer.len = sizeof(txbuf);
144
145 spi_message_add_tail(&xfer, &msg);
146 return spi_sync(ctx->spi, &msg);
147}
148
149static int st7789v_write_command(struct st7789v *ctx, u8 cmd)
150{
151 return st7789v_spi_write(ctx, ST7789V_COMMAND, cmd);
152}
153
154static int st7789v_write_data(struct st7789v *ctx, u8 cmd)
155{
156 return st7789v_spi_write(ctx, ST7789V_DATA, cmd);
157}
158
159static const struct drm_display_mode default_mode = {
160 .clock = 7000,
161 .hdisplay = 240,
162 .hsync_start = 240 + 38,
163 .hsync_end = 240 + 38 + 10,
164 .htotal = 240 + 38 + 10 + 10,
165 .vdisplay = 320,
166 .vsync_start = 320 + 8,
167 .vsync_end = 320 + 8 + 4,
168 .vtotal = 320 + 8 + 4 + 4,
169 .vrefresh = 60,
170};
171
172static int st7789v_get_modes(struct drm_panel *panel)
173{
174 struct drm_connector *connector = panel->connector;
175 struct drm_display_mode *mode;
176
177 mode = drm_mode_duplicate(panel->drm, &default_mode);
178 if (!mode) {
179 dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
180 default_mode.hdisplay, default_mode.vdisplay,
181 default_mode.vrefresh);
182 return -ENOMEM;
183 }
184
185 drm_mode_set_name(mode);
186
187 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
188 drm_mode_probed_add(connector, mode);
189
190 panel->connector->display_info.width_mm = 61;
191 panel->connector->display_info.height_mm = 103;
192
193 return 1;
194}
195
196static int st7789v_prepare(struct drm_panel *panel)
197{
198 struct st7789v *ctx = panel_to_st7789v(panel);
199 int ret;
200
201 ret = regulator_enable(ctx->power);
202 if (ret)
203 return ret;
204
205 gpiod_set_value(ctx->reset, 1);
206 msleep(30);
207 gpiod_set_value(ctx->reset, 0);
208 msleep(120);
209
210 ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_EXIT_SLEEP_MODE));
211
212 /* We need to wait 120ms after a sleep out command */
213 msleep(120);
214
215 ST7789V_TEST(ret, st7789v_write_command(ctx,
216 MIPI_DCS_SET_ADDRESS_MODE));
217 ST7789V_TEST(ret, st7789v_write_data(ctx, 0));
218
219 ST7789V_TEST(ret, st7789v_write_command(ctx,
220 MIPI_DCS_SET_PIXEL_FORMAT));
221 ST7789V_TEST(ret, st7789v_write_data(ctx,
222 (MIPI_DCS_PIXEL_FMT_18BIT << 4) |
223 (MIPI_DCS_PIXEL_FMT_18BIT)));
224
225 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_PORCTRL_CMD));
226 ST7789V_TEST(ret, st7789v_write_data(ctx, 0xc));
227 ST7789V_TEST(ret, st7789v_write_data(ctx, 0xc));
228 ST7789V_TEST(ret, st7789v_write_data(ctx, 0));
229 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PORCTRL_IDLE_BP(3) |
230 ST7789V_PORCTRL_IDLE_FP(3)));
231 ST7789V_TEST(ret, st7789v_write_data(ctx,
232 ST7789V_PORCTRL_PARTIAL_BP(3) |
233 ST7789V_PORCTRL_PARTIAL_FP(3)));
234
235 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_GCTRL_CMD));
236 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_GCTRL_VGLS(5) |
237 ST7789V_GCTRL_VGHS(3)));
238
239 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_VCOMS_CMD));
240 ST7789V_TEST(ret, st7789v_write_data(ctx, 0x2b));
241
242 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_LCMCTRL_CMD));
243 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_LCMCTRL_XMH |
244 ST7789V_LCMCTRL_XMX |
245 ST7789V_LCMCTRL_XBGR));
246
247 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_VDVVRHEN_CMD));
248 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_VDVVRHEN_CMDEN));
249
250 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_VRHS_CMD));
251 ST7789V_TEST(ret, st7789v_write_data(ctx, 0xf));
252
253 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_VDVS_CMD));
254 ST7789V_TEST(ret, st7789v_write_data(ctx, 0x20));
255
256 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_FRCTRL2_CMD));
257 ST7789V_TEST(ret, st7789v_write_data(ctx, 0xf));
258
259 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_PWCTRL1_CMD));
260 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PWCTRL1_MAGIC));
261 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PWCTRL1_AVDD(2) |
262 ST7789V_PWCTRL1_AVCL(2) |
263 ST7789V_PWCTRL1_VDS(1)));
264
265 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_PVGAMCTRL_CMD));
266 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP63(0xd)));
267 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP1(0xca)));
268 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP2(0xe)));
269 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP4(8)));
270 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP6(9)));
271 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP13(7)));
272 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP20(0x2d)));
273 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP27(0xb) |
274 ST7789V_PVGAMCTRL_VP36(3)));
275 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP43(0x3d)));
276 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_JP1(3) |
277 ST7789V_PVGAMCTRL_VP50(4)));
278 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP57(0xa)));
279 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP59(0xa)));
280 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP61(0x1b)));
281 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP62(0x28)));
282
283 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_NVGAMCTRL_CMD));
284 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN63(0xd)));
285 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN1(0xca)));
286 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN2(0xf)));
287 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN4(8)));
288 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN6(8)));
289 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN13(7)));
290 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN20(0x2e)));
291 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN27(0xc) |
292 ST7789V_NVGAMCTRL_VN36(5)));
293 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN43(0x40)));
294 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_JN1(3) |
295 ST7789V_NVGAMCTRL_VN50(4)));
296 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN57(9)));
297 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN59(0xb)));
298 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN61(0x1b)));
299 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN62(0x28)));
300
301 ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_ENTER_INVERT_MODE));
302
303 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_RAMCTRL_CMD));
304 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RAMCTRL_DM_RGB |
305 ST7789V_RAMCTRL_RM_RGB));
306 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RAMCTRL_EPF(3) |
307 ST7789V_RAMCTRL_MAGIC));
308
309 ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_RGBCTRL_CMD));
310 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RGBCTRL_WO |
311 ST7789V_RGBCTRL_RCM(2) |
312 ST7789V_RGBCTRL_VSYNC_HIGH |
313 ST7789V_RGBCTRL_HSYNC_HIGH |
314 ST7789V_RGBCTRL_PCLK_HIGH));
315 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RGBCTRL_VBP(8)));
316 ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RGBCTRL_HBP(20)));
317
318 return 0;
319}
320
321static int st7789v_enable(struct drm_panel *panel)
322{
323 struct st7789v *ctx = panel_to_st7789v(panel);
324
325 if (ctx->backlight) {
326 ctx->backlight->props.state &= ~BL_CORE_FBBLANK;
327 ctx->backlight->props.power = FB_BLANK_UNBLANK;
328 backlight_update_status(ctx->backlight);
329 }
330
331 return st7789v_write_command(ctx, MIPI_DCS_SET_DISPLAY_ON);
332}
333
334static int st7789v_disable(struct drm_panel *panel)
335{
336 struct st7789v *ctx = panel_to_st7789v(panel);
337 int ret;
338
339 ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_SET_DISPLAY_OFF));
340
341 if (ctx->backlight) {
342 ctx->backlight->props.power = FB_BLANK_POWERDOWN;
343 ctx->backlight->props.state |= BL_CORE_FBBLANK;
344 backlight_update_status(ctx->backlight);
345 }
346
347 return 0;
348}
349
350static int st7789v_unprepare(struct drm_panel *panel)
351{
352 struct st7789v *ctx = panel_to_st7789v(panel);
353 int ret;
354
355 ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_ENTER_SLEEP_MODE));
356
357 regulator_disable(ctx->power);
358
359 return 0;
360}
361
362static const struct drm_panel_funcs st7789v_drm_funcs = {
363 .disable = st7789v_disable,
364 .enable = st7789v_enable,
365 .get_modes = st7789v_get_modes,
366 .prepare = st7789v_prepare,
367 .unprepare = st7789v_unprepare,
368};
369
370static int st7789v_probe(struct spi_device *spi)
371{
372 struct device_node *backlight;
373 struct st7789v *ctx;
374 int ret;
375
376 ctx = devm_kzalloc(&spi->dev, sizeof(*ctx), GFP_KERNEL);
377 if (!ctx)
378 return -ENOMEM;
379
380 spi_set_drvdata(spi, ctx);
381 ctx->spi = spi;
382
383 ctx->panel.dev = &spi->dev;
384 ctx->panel.funcs = &st7789v_drm_funcs;
385
386 ctx->power = devm_regulator_get(&spi->dev, "power");
387 if (IS_ERR(ctx->power))
388 return PTR_ERR(ctx->power);
389
390 ctx->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW);
391 if (IS_ERR(ctx->reset)) {
392 dev_err(&spi->dev, "Couldn't get our reset line\n");
393 return PTR_ERR(ctx->reset);
394 }
395
396 backlight = of_parse_phandle(spi->dev.of_node, "backlight", 0);
397 if (backlight) {
398 ctx->backlight = of_find_backlight_by_node(backlight);
399 of_node_put(backlight);
400
401 if (!ctx->backlight)
402 return -EPROBE_DEFER;
403 }
404
405 ret = drm_panel_add(&ctx->panel);
406 if (ret < 0)
407 goto err_free_backlight;
408
409 return 0;
410
411err_free_backlight:
412 if (ctx->backlight)
413 put_device(&ctx->backlight->dev);
414
415 return ret;
416}
417
418static int st7789v_remove(struct spi_device *spi)
419{
420 struct st7789v *ctx = spi_get_drvdata(spi);
421
422 drm_panel_detach(&ctx->panel);
423 drm_panel_remove(&ctx->panel);
424
425 if (ctx->backlight)
426 put_device(&ctx->backlight->dev);
427
428 return 0;
429}
430
431static const struct of_device_id st7789v_of_match[] = {
432 { .compatible = "sitronix,st7789v" },
433 { }
434};
435MODULE_DEVICE_TABLE(of, st7789v_of_match);
436
437static struct spi_driver st7789v_driver = {
438 .probe = st7789v_probe,
439 .remove = st7789v_remove,
440 .driver = {
441 .name = "st7789v",
442 .of_match_table = st7789v_of_match,
443 },
444};
445module_spi_driver(st7789v_driver);
446
447MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
448MODULE_DESCRIPTION("Sitronix st7789v LCD Driver");
449MODULE_LICENSE("GPL v2");