xref: /linux/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c (revision fc2d791a43d3880496d1c729b8bd74d2c19cb4e7)
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 
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 	struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
225 	int ret;
226 
227 	ret = regulator_enable(ctx->power);
228 	if (ret) {
229 		dev_err(dev, "Failed to enable power supply: %d\n", ret);
230 		return ret;
231 	}
232 
233 	if (ctx->desc->vcioo_to_lp11_delay_ms)
234 		msleep(ctx->desc->vcioo_to_lp11_delay_ms);
235 
236 	if (ctx->desc->lp11_before_reset) {
237 		mipi_dsi_dcs_nop_multi(&dsi_ctx);
238 		if (dsi_ctx.accum_err)
239 			return dsi_ctx.accum_err;
240 	}
241 
242 	if (ctx->desc->lp11_to_reset_delay_ms)
243 		msleep(ctx->desc->lp11_to_reset_delay_ms);
244 
245 	gpiod_set_value_cansleep(ctx->enable, 1);
246 	msleep(50);
247 	boe_th101mb31ig002_reset(ctx);
248 
249 	ret = ctx->desc->init(ctx);
250 	if (ret)
251 		return ret;
252 
253 	return 0;
254 }
255 
256 static const struct drm_display_mode boe_th101mb31ig002_default_mode = {
257 	.clock		= 73500,
258 	.hdisplay	= 800,
259 	.hsync_start	= 800 + 64,
260 	.hsync_end	= 800 + 64 + 16,
261 	.htotal		= 800 + 64 + 16 + 64,
262 	.vdisplay	= 1280,
263 	.vsync_start	= 1280 + 2,
264 	.vsync_end	= 1280 + 2 + 4,
265 	.vtotal		= 1280 + 2 + 4 + 12,
266 	.width_mm	= 135,
267 	.height_mm	= 216,
268 	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
269 };
270 
271 static const struct panel_desc boe_th101mb31ig002_desc = {
272 	.modes = &boe_th101mb31ig002_default_mode,
273 	.lanes = 4,
274 	.format = MIPI_DSI_FMT_RGB888,
275 	.mode_flags = MIPI_DSI_MODE_VIDEO_BURST |
276 			  MIPI_DSI_MODE_NO_EOT_PACKET |
277 			  MIPI_DSI_MODE_LPM,
278 	.init = boe_th101mb31ig002_enable,
279 };
280 
281 static const struct drm_display_mode starry_er88577_default_mode = {
282 	.clock	= (800 + 25 + 25 + 25) * (1280 + 20 + 4 + 12) * 60 / 1000,
283 	.hdisplay = 800,
284 	.hsync_start = 800 + 25,
285 	.hsync_end = 800 + 25 + 25,
286 	.htotal = 800 + 25 + 25 + 25,
287 	.vdisplay = 1280,
288 	.vsync_start = 1280 + 20,
289 	.vsync_end = 1280 + 20 + 4,
290 	.vtotal = 1280 + 20 + 4 + 12,
291 	.width_mm = 135,
292 	.height_mm = 216,
293 	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
294 };
295 
296 static const struct panel_desc starry_er88577_desc = {
297 	.modes = &starry_er88577_default_mode,
298 	.lanes = 4,
299 	.format = MIPI_DSI_FMT_RGB888,
300 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
301 		      MIPI_DSI_MODE_LPM,
302 	.init = starry_er88577_init_cmd,
303 	.lp11_before_reset = true,
304 	.vcioo_to_lp11_delay_ms = 5,
305 	.lp11_to_reset_delay_ms = 50,
306 	.backlight_off_to_display_off_delay_ms = 100,
307 	.enter_sleep_to_reset_down_delay_ms = 100,
308 	.power_off_delay_ms = 1000,
309 };
310 
311 static int boe_th101mb31ig002_get_modes(struct drm_panel *panel,
312 					struct drm_connector *connector)
313 {
314 	struct boe_th101mb31ig002 *ctx = container_of(panel,
315 						      struct boe_th101mb31ig002,
316 						      panel);
317 	const struct drm_display_mode *desc_mode = ctx->desc->modes;
318 
319 	connector->display_info.bpc = 8;
320 	/*
321 	 * TODO: Remove once all drm drivers call
322 	 * drm_connector_set_orientation_from_panel()
323 	 */
324 	drm_connector_set_panel_orientation(connector, ctx->orientation);
325 
326 	return drm_connector_helper_get_modes_fixed(connector, desc_mode);
327 }
328 
329 static enum drm_panel_orientation
330 boe_th101mb31ig002_get_orientation(struct drm_panel *panel)
331 {
332 	struct boe_th101mb31ig002 *ctx = container_of(panel,
333 						      struct boe_th101mb31ig002,
334 						      panel);
335 
336 	return ctx->orientation;
337 }
338 
339 static const struct drm_panel_funcs boe_th101mb31ig002_funcs = {
340 	.prepare = boe_th101mb31ig002_prepare,
341 	.unprepare = boe_th101mb31ig002_unprepare,
342 	.disable = boe_th101mb31ig002_disable,
343 	.get_modes = boe_th101mb31ig002_get_modes,
344 	.get_orientation = boe_th101mb31ig002_get_orientation,
345 };
346 
347 static int boe_th101mb31ig002_dsi_probe(struct mipi_dsi_device *dsi)
348 {
349 	struct boe_th101mb31ig002 *ctx;
350 	const struct panel_desc *desc;
351 	int ret;
352 
353 	ctx = devm_drm_panel_alloc(&dsi->dev, struct boe_th101mb31ig002, panel,
354 				   &boe_th101mb31ig002_funcs,
355 				   DRM_MODE_CONNECTOR_DSI);
356 	if (IS_ERR(ctx))
357 		return PTR_ERR(ctx);
358 
359 	mipi_dsi_set_drvdata(dsi, ctx);
360 	ctx->dsi = dsi;
361 
362 	desc = of_device_get_match_data(&dsi->dev);
363 	dsi->lanes = desc->lanes;
364 	dsi->format = desc->format;
365 	dsi->mode_flags = desc->mode_flags;
366 	ctx->desc = desc;
367 
368 	ctx->power = devm_regulator_get(&dsi->dev, "power");
369 	if (IS_ERR(ctx->power))
370 		return dev_err_probe(&dsi->dev, PTR_ERR(ctx->power),
371 				     "Failed to get power regulator\n");
372 
373 	ctx->enable = devm_gpiod_get(&dsi->dev, "enable", GPIOD_OUT_LOW);
374 	if (IS_ERR(ctx->enable))
375 		return dev_err_probe(&dsi->dev, PTR_ERR(ctx->enable),
376 				     "Failed to get enable GPIO\n");
377 
378 	ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_HIGH);
379 	if (IS_ERR(ctx->reset))
380 		return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset),
381 				     "Failed to get reset GPIO\n");
382 
383 	ret = of_drm_get_panel_orientation(dsi->dev.of_node,
384 					   &ctx->orientation);
385 	if (ret)
386 		return dev_err_probe(&dsi->dev, ret,
387 				     "Failed to get orientation\n");
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 <awarnecke002@hotmail.com>");
438 MODULE_DESCRIPTION("BOE TH101MB31IG002-28A MIPI-DSI LCD panel");
439 MODULE_LICENSE("GPL");
440