1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2023 Alexander Warnecke <awarnecke002@hotmail.com>
4 * Copyright (c) 2023 Manuel Traut <manut@mecka.net>
5 * Copyright (c) 2023 Dang Huynh <danct12@riseup.net>
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
boe_th101mb31ig002_reset(struct boe_th101mb31ig002 * ctx)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
boe_th101mb31ig002_enable(struct boe_th101mb31ig002 * ctx)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
starry_er88577_init_cmd(struct boe_th101mb31ig002 * ctx)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
boe_th101mb31ig002_disable(struct drm_panel * panel)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
boe_th101mb31ig002_unprepare(struct drm_panel * panel)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
boe_th101mb31ig002_prepare(struct drm_panel * panel)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
boe_th101mb31ig002_get_modes(struct drm_panel * panel,struct drm_connector * connector)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
boe_th101mb31ig002_get_orientation(struct drm_panel * panel)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
boe_th101mb31ig002_dsi_probe(struct mipi_dsi_device * dsi)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
boe_th101mb31ig002_dsi_remove(struct mipi_dsi_device * dsi)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 <awarnecke002@hotmail.com>");
438 MODULE_DESCRIPTION("BOE TH101MB31IG002-28A MIPI-DSI LCD panel");
439 MODULE_LICENSE("GPL");
440