]> Git Repo - J-linux.git/blob - drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / gpu / drm / panel / panel-boe-th101mb31ig002-28a.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2023 Alexander Warnecke <[email protected]>
4  * Copyright (c) 2023 Manuel Traut <[email protected]>
5  * Copyright (c) 2023 Dang Huynh <[email protected]>
6  */
7
8 #include <linux/delay.h>
9 #include <linux/gpio/consumer.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/of_device.h>
13 #include <linux/regulator/consumer.h>
14
15 #include <drm/drm_connector.h>
16 #include <drm/drm_mipi_dsi.h>
17 #include <drm/drm_modes.h>
18 #include <drm/drm_panel.h>
19 #include <drm/drm_probe_helper.h>
20
21 struct boe_th101mb31ig002;
22
23 struct panel_desc {
24         const struct drm_display_mode *modes;
25         unsigned long mode_flags;
26         enum mipi_dsi_pixel_format format;
27         int (*init)(struct boe_th101mb31ig002 *ctx);
28         unsigned int lanes;
29         bool lp11_before_reset;
30         unsigned int vcioo_to_lp11_delay_ms;
31         unsigned int lp11_to_reset_delay_ms;
32         unsigned int backlight_off_to_display_off_delay_ms;
33         unsigned int enter_sleep_to_reset_down_delay_ms;
34         unsigned int power_off_delay_ms;
35 };
36
37 struct boe_th101mb31ig002 {
38         struct drm_panel panel;
39
40         struct mipi_dsi_device *dsi;
41
42         const struct panel_desc *desc;
43
44         struct regulator *power;
45         struct gpio_desc *enable;
46         struct gpio_desc *reset;
47
48         enum drm_panel_orientation orientation;
49 };
50
51 static void boe_th101mb31ig002_reset(struct boe_th101mb31ig002 *ctx)
52 {
53         gpiod_direction_output(ctx->reset, 0);
54         usleep_range(10, 100);
55         gpiod_direction_output(ctx->reset, 1);
56         usleep_range(10, 100);
57         gpiod_direction_output(ctx->reset, 0);
58         usleep_range(5000, 6000);
59 }
60
61 static int boe_th101mb31ig002_enable(struct boe_th101mb31ig002 *ctx)
62 {
63         struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
64
65         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0xab, 0xba);
66         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0xba, 0xab);
67         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x10, 0x01, 0x47, 0xff);
68         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x0c, 0x14, 0x04, 0x50, 0x50, 0x14);
69         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x56, 0x53, 0x00);
70         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x33, 0x30, 0x04);
71         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, 0xb0, 0x00, 0x00, 0x10, 0x00, 0x10,
72                                                0x00);
73         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb8, 0x05, 0x12, 0x29, 0x49, 0x48, 0x00,
74                                                0x00);
75         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x7c, 0x65, 0x55, 0x49, 0x46, 0x36,
76                                                0x3b, 0x24, 0x3d, 0x3c, 0x3d, 0x5c, 0x4c,
77                                                0x55, 0x47, 0x46, 0x39, 0x26, 0x06, 0x7c,
78                                                0x65, 0x55, 0x49, 0x46, 0x36, 0x3b, 0x24,
79                                                0x3d, 0x3c, 0x3d, 0x5c, 0x4c, 0x55, 0x47,
80                                                0x46, 0x39, 0x26, 0x06);
81         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xff, 0x87, 0x12, 0x34, 0x44, 0x44,
82                                                0x44, 0x44, 0x98, 0x04, 0x98, 0x04, 0x0f,
83                                                0x00, 0x00, 0xc1);
84         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x54, 0x94, 0x02, 0x85, 0x9f, 0x00,
85                                                0x7f, 0x00, 0x54, 0x00);
86         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x17, 0x09, 0x08, 0x89, 0x08, 0x11,
87                                                0x22, 0x20, 0x44, 0xff, 0x18, 0x00);
88         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x86, 0x46, 0x05, 0x05, 0x1c, 0x1c,
89                                                0x1d, 0x1d, 0x02, 0x1f, 0x1f, 0x1e, 0x1e,
90                                                0x0f, 0x0f, 0x0d, 0x0d, 0x13, 0x13, 0x11,
91                                                0x11, 0x00);
92         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc4, 0x07, 0x07, 0x04, 0x04, 0x1c, 0x1c,
93                                                0x1d, 0x1d, 0x02, 0x1f, 0x1f, 0x1e, 0x1e,
94                                                0x0e, 0x0e, 0x0c, 0x0c, 0x12, 0x12, 0x10,
95                                                0x10, 0x00);
96         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc6, 0x2a, 0x2a);
97         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc8, 0x21, 0x00, 0x31, 0x42, 0x34, 0x16);
98         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xca, 0xcb, 0x43);
99         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, 0x0e, 0x4b, 0x4b, 0x20, 0x19, 0x6b,
100                                                0x06, 0xb3);
101         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd2, 0xe3, 0x2b, 0x38, 0x00);
102         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x00, 0x01, 0x00, 0x0e, 0x04, 0x44,
103                                                0x08, 0x10, 0x00, 0x00, 0x00);
104         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff,
105                                                0xff, 0xff);
106         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x12, 0x03, 0x20, 0x00, 0xff);
107         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0x00);
108
109         mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
110
111         mipi_dsi_msleep(&dsi_ctx, 120);
112
113         mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
114
115         return dsi_ctx.accum_err;
116 }
117
118 static int starry_er88577_init_cmd(struct boe_th101mb31ig002 *ctx)
119 {
120         struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
121
122         msleep(70);
123
124         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0xab, 0xba);
125         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0xba, 0xab);
126         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x10, 0x01, 0x47, 0xff);
127         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x0c, 0x14, 0x04, 0x50, 0x50, 0x14);
128         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x56, 0x53, 0x00);
129         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x33, 0x30, 0x04);
130         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, 0xb0, 0x00, 0x00, 0x10, 0x00, 0x10,
131                                                0x00);
132         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb8, 0x05, 0x12, 0x29, 0x49, 0x40);
133         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x7c, 0x61, 0x4f, 0x42, 0x3e, 0x2d,
134                                                0x31, 0x1a, 0x33, 0x33, 0x33, 0x52, 0x40,
135                                                0x47, 0x38, 0x34, 0x26, 0x0e, 0x06, 0x7c,
136                                                0x61, 0x4f, 0x42, 0x3e, 0x2d, 0x31, 0x1a,
137                                                0x33, 0x33, 0x33, 0x52, 0x40, 0x47, 0x38,
138                                                0x34, 0x26, 0x0e, 0x06);
139         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0xcc, 0x76, 0x12, 0x34, 0x44, 0x44,
140                                                0x44, 0x44, 0x98, 0x04, 0x98, 0x04, 0x0f,
141                                                0x00, 0x00, 0xc1);
142         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x54, 0x94, 0x02, 0x85, 0x9f, 0x00,
143                                                0x6f, 0x00, 0x54, 0x00);
144         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x17, 0x09, 0x08, 0x89, 0x08, 0x11,
145                                                0x22, 0x20, 0x44, 0xff, 0x18, 0x00);
146         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x87, 0x47, 0x05, 0x05, 0x1c, 0x1c,
147                                                0x1d, 0x1d, 0x02, 0x1e, 0x1e, 0x1f, 0x1f,
148                                                0x0f, 0x0f, 0x0d, 0x0d, 0x13, 0x13, 0x11,
149                                                0x11, 0x24);
150         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc4, 0x06, 0x06, 0x04, 0x04, 0x1c, 0x1c,
151                                                0x1d, 0x1d, 0x02, 0x1e, 0x1e, 0x1f, 0x1f,
152                                                0x0e, 0x0e, 0x0c, 0x0c, 0x12, 0x12, 0x10,
153                                                0x10, 0x24);
154         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc8, 0x21, 0x00, 0x31, 0x42, 0x34, 0x16);
155         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xca, 0xcb, 0x43);
156         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, 0x0e, 0x4b, 0x4b, 0x20, 0x19, 0x6b,
157                                                0x06, 0xb3);
158         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd1, 0x40, 0x0d, 0xff, 0x0f);
159         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd2, 0xe3, 0x2b, 0x38, 0x08);
160         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd3, 0x00, 0x00, 0x00, 0x00,
161                                                0x00, 0x33, 0x20, 0x3a, 0xd5, 0x86, 0xf3);
162         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x00, 0x01, 0x00, 0x0e, 0x04, 0x44,
163                                                0x08, 0x10, 0x00, 0x00, 0x00);
164         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6, 0x80, 0x09, 0xff, 0xff, 0xff, 0xff,
165                                                0xff, 0xff);
166         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x12, 0x03, 0x20, 0x00, 0xff);
167         mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0x00);
168
169         mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
170
171         mipi_dsi_msleep(&dsi_ctx, 120);
172
173         mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
174
175         mipi_dsi_msleep(&dsi_ctx, 20);
176
177         return dsi_ctx.accum_err;
178 }
179
180 static int boe_th101mb31ig002_disable(struct drm_panel *panel)
181 {
182         struct boe_th101mb31ig002 *ctx = container_of(panel,
183                                                       struct boe_th101mb31ig002,
184                                                       panel);
185         struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
186
187         if (ctx->desc->backlight_off_to_display_off_delay_ms)
188                 mipi_dsi_msleep(&dsi_ctx, ctx->desc->backlight_off_to_display_off_delay_ms);
189
190         mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
191
192         mipi_dsi_msleep(&dsi_ctx, 120);
193
194         mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
195
196         if (ctx->desc->enter_sleep_to_reset_down_delay_ms)
197                 mipi_dsi_msleep(&dsi_ctx, ctx->desc->enter_sleep_to_reset_down_delay_ms);
198
199         return dsi_ctx.accum_err;
200 }
201
202 static int boe_th101mb31ig002_unprepare(struct drm_panel *panel)
203 {
204         struct boe_th101mb31ig002 *ctx = container_of(panel,
205                                                       struct boe_th101mb31ig002,
206                                                       panel);
207
208         gpiod_set_value_cansleep(ctx->reset, 1);
209         gpiod_set_value_cansleep(ctx->enable, 0);
210         regulator_disable(ctx->power);
211
212         if (ctx->desc->power_off_delay_ms)
213                 msleep(ctx->desc->power_off_delay_ms);
214
215         return 0;
216 }
217
218 static int boe_th101mb31ig002_prepare(struct drm_panel *panel)
219 {
220         struct boe_th101mb31ig002 *ctx = container_of(panel,
221                                                       struct boe_th101mb31ig002,
222                                                       panel);
223         struct device *dev = &ctx->dsi->dev;
224         int ret;
225
226         ret = regulator_enable(ctx->power);
227         if (ret) {
228                 dev_err(dev, "Failed to enable power supply: %d\n", ret);
229                 return ret;
230         }
231
232         if (ctx->desc->vcioo_to_lp11_delay_ms)
233                 msleep(ctx->desc->vcioo_to_lp11_delay_ms);
234
235         if (ctx->desc->lp11_before_reset) {
236                 ret = mipi_dsi_dcs_nop(ctx->dsi);
237                 if (ret)
238                         return ret;
239         }
240
241         if (ctx->desc->lp11_to_reset_delay_ms)
242                 msleep(ctx->desc->lp11_to_reset_delay_ms);
243
244         gpiod_set_value_cansleep(ctx->enable, 1);
245         msleep(50);
246         boe_th101mb31ig002_reset(ctx);
247
248         ret = ctx->desc->init(ctx);
249         if (ret)
250                 return ret;
251
252         return 0;
253 }
254
255 static const struct drm_display_mode boe_th101mb31ig002_default_mode = {
256         .clock          = 73500,
257         .hdisplay       = 800,
258         .hsync_start    = 800 + 64,
259         .hsync_end      = 800 + 64 + 16,
260         .htotal         = 800 + 64 + 16 + 64,
261         .vdisplay       = 1280,
262         .vsync_start    = 1280 + 2,
263         .vsync_end      = 1280 + 2 + 4,
264         .vtotal         = 1280 + 2 + 4 + 12,
265         .width_mm       = 135,
266         .height_mm      = 216,
267         .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
268 };
269
270 static const struct panel_desc boe_th101mb31ig002_desc = {
271         .modes = &boe_th101mb31ig002_default_mode,
272         .lanes = 4,
273         .format = MIPI_DSI_FMT_RGB888,
274         .mode_flags = MIPI_DSI_MODE_VIDEO_BURST |
275                           MIPI_DSI_MODE_NO_EOT_PACKET |
276                           MIPI_DSI_MODE_LPM,
277         .init = boe_th101mb31ig002_enable,
278 };
279
280 static const struct drm_display_mode starry_er88577_default_mode = {
281         .clock  = (800 + 25 + 25 + 25) * (1280 + 20 + 4 + 12) * 60 / 1000,
282         .hdisplay = 800,
283         .hsync_start = 800 + 25,
284         .hsync_end = 800 + 25 + 25,
285         .htotal = 800 + 25 + 25 + 25,
286         .vdisplay = 1280,
287         .vsync_start = 1280 + 20,
288         .vsync_end = 1280 + 20 + 4,
289         .vtotal = 1280 + 20 + 4 + 12,
290         .width_mm = 135,
291         .height_mm = 216,
292         .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
293 };
294
295 static const struct panel_desc starry_er88577_desc = {
296         .modes = &starry_er88577_default_mode,
297         .lanes = 4,
298         .format = MIPI_DSI_FMT_RGB888,
299         .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
300                       MIPI_DSI_MODE_LPM,
301         .init = starry_er88577_init_cmd,
302         .lp11_before_reset = true,
303         .vcioo_to_lp11_delay_ms = 5,
304         .lp11_to_reset_delay_ms = 50,
305         .backlight_off_to_display_off_delay_ms = 100,
306         .enter_sleep_to_reset_down_delay_ms = 100,
307         .power_off_delay_ms = 1000,
308 };
309
310 static int boe_th101mb31ig002_get_modes(struct drm_panel *panel,
311                                         struct drm_connector *connector)
312 {
313         struct boe_th101mb31ig002 *ctx = container_of(panel,
314                                                       struct boe_th101mb31ig002,
315                                                       panel);
316         const struct drm_display_mode *desc_mode = ctx->desc->modes;
317
318         connector->display_info.bpc = 8;
319         /*
320          * TODO: Remove once all drm drivers call
321          * drm_connector_set_orientation_from_panel()
322          */
323         drm_connector_set_panel_orientation(connector, ctx->orientation);
324
325         return drm_connector_helper_get_modes_fixed(connector, desc_mode);
326 }
327
328 static enum drm_panel_orientation
329 boe_th101mb31ig002_get_orientation(struct drm_panel *panel)
330 {
331         struct boe_th101mb31ig002 *ctx = container_of(panel,
332                                                       struct boe_th101mb31ig002,
333                                                       panel);
334
335         return ctx->orientation;
336 }
337
338 static const struct drm_panel_funcs boe_th101mb31ig002_funcs = {
339         .prepare = boe_th101mb31ig002_prepare,
340         .unprepare = boe_th101mb31ig002_unprepare,
341         .disable = boe_th101mb31ig002_disable,
342         .get_modes = boe_th101mb31ig002_get_modes,
343         .get_orientation = boe_th101mb31ig002_get_orientation,
344 };
345
346 static int boe_th101mb31ig002_dsi_probe(struct mipi_dsi_device *dsi)
347 {
348         struct boe_th101mb31ig002 *ctx;
349         const struct panel_desc *desc;
350         int ret;
351
352         ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
353         if (!ctx)
354                 return -ENOMEM;
355
356         mipi_dsi_set_drvdata(dsi, ctx);
357         ctx->dsi = dsi;
358
359         desc = of_device_get_match_data(&dsi->dev);
360         dsi->lanes = desc->lanes;
361         dsi->format = desc->format;
362         dsi->mode_flags = desc->mode_flags;
363         ctx->desc = desc;
364
365         ctx->power = devm_regulator_get(&dsi->dev, "power");
366         if (IS_ERR(ctx->power))
367                 return dev_err_probe(&dsi->dev, PTR_ERR(ctx->power),
368                                      "Failed to get power regulator\n");
369
370         ctx->enable = devm_gpiod_get(&dsi->dev, "enable", GPIOD_OUT_LOW);
371         if (IS_ERR(ctx->enable))
372                 return dev_err_probe(&dsi->dev, PTR_ERR(ctx->enable),
373                                      "Failed to get enable GPIO\n");
374
375         ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_HIGH);
376         if (IS_ERR(ctx->reset))
377                 return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset),
378                                      "Failed to get reset GPIO\n");
379
380         ret = of_drm_get_panel_orientation(dsi->dev.of_node,
381                                            &ctx->orientation);
382         if (ret)
383                 return dev_err_probe(&dsi->dev, ret,
384                                      "Failed to get orientation\n");
385
386         drm_panel_init(&ctx->panel, &dsi->dev, &boe_th101mb31ig002_funcs,
387                        DRM_MODE_CONNECTOR_DSI);
388
389         ret = drm_panel_of_backlight(&ctx->panel);
390         if (ret)
391                 return ret;
392
393         drm_panel_add(&ctx->panel);
394
395         ret = mipi_dsi_attach(dsi);
396         if (ret < 0) {
397                 dev_err_probe(&dsi->dev, ret,
398                               "Failed to attach panel to DSI host\n");
399                 drm_panel_remove(&ctx->panel);
400                 return ret;
401         }
402
403         return 0;
404 }
405
406 static void boe_th101mb31ig002_dsi_remove(struct mipi_dsi_device *dsi)
407 {
408         struct boe_th101mb31ig002 *ctx = mipi_dsi_get_drvdata(dsi);
409
410         mipi_dsi_detach(dsi);
411         drm_panel_remove(&ctx->panel);
412 }
413
414 static const struct of_device_id boe_th101mb31ig002_of_match[] = {
415         {
416                 .compatible = "boe,th101mb31ig002-28a",
417                 .data = &boe_th101mb31ig002_desc
418         },
419         {
420                 .compatible = "starry,er88577",
421                 .data = &starry_er88577_desc
422         },
423         { /* sentinel */ }
424 };
425 MODULE_DEVICE_TABLE(of, boe_th101mb31ig002_of_match);
426
427 static struct mipi_dsi_driver boe_th101mb31ig002_driver = {
428         .driver = {
429                 .name = "boe-th101mb31ig002-28a",
430                 .of_match_table = boe_th101mb31ig002_of_match,
431         },
432         .probe = boe_th101mb31ig002_dsi_probe,
433         .remove = boe_th101mb31ig002_dsi_remove,
434 };
435 module_mipi_dsi_driver(boe_th101mb31ig002_driver);
436
437 MODULE_AUTHOR("Alexander Warnecke <[email protected]>");
438 MODULE_DESCRIPTION("BOE TH101MB31IG002-28A MIPI-DSI LCD panel");
439 MODULE_LICENSE("GPL");
This page took 0.051855 seconds and 4 git commands to generate.