diff options
Diffstat (limited to 'drivers/gpu/drm/panel/panel-sitronix-st7789v.c')
-rw-r--r-- | drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 449 |
1 files changed, 449 insertions, 0 deletions
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 | |||
114 | struct 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 | |||
122 | enum st7789v_prefix { | ||
123 | ST7789V_COMMAND = 0, | ||
124 | ST7789V_DATA = 1, | ||
125 | }; | ||
126 | |||
127 | static inline struct st7789v *panel_to_st7789v(struct drm_panel *panel) | ||
128 | { | ||
129 | return container_of(panel, struct st7789v, panel); | ||
130 | } | ||
131 | |||
132 | static 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 | |||
149 | static int st7789v_write_command(struct st7789v *ctx, u8 cmd) | ||
150 | { | ||
151 | return st7789v_spi_write(ctx, ST7789V_COMMAND, cmd); | ||
152 | } | ||
153 | |||
154 | static int st7789v_write_data(struct st7789v *ctx, u8 cmd) | ||
155 | { | ||
156 | return st7789v_spi_write(ctx, ST7789V_DATA, cmd); | ||
157 | } | ||
158 | |||
159 | static 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 | |||
172 | static 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 | |||
196 | static 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 | |||
321 | static 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 | |||
334 | static 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 | |||
350 | static 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 | |||
362 | static 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 | |||
370 | static 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 | |||
411 | err_free_backlight: | ||
412 | if (ctx->backlight) | ||
413 | put_device(&ctx->backlight->dev); | ||
414 | |||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | static 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 | |||
431 | static const struct of_device_id st7789v_of_match[] = { | ||
432 | { .compatible = "sitronix,st7789v" }, | ||
433 | { } | ||
434 | }; | ||
435 | MODULE_DEVICE_TABLE(of, st7789v_of_match); | ||
436 | |||
437 | static 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 | }; | ||
445 | module_spi_driver(st7789v_driver); | ||
446 | |||
447 | MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); | ||
448 | MODULE_DESCRIPTION("Sitronix st7789v LCD Driver"); | ||
449 | MODULE_LICENSE("GPL v2"); | ||