xref: /linux/drivers/gpu/drm/panel/panel-novatek-nt35950.c (revision be239684b18e1cdcafcf8c7face4a2f562c745ad)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Novatek NT35950 DriverIC panels driver
4  *
5  * Copyright (c) 2021 AngeloGioacchino Del Regno
6  *                    <angelogioacchino.delregno@somainline.org>
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_graph.h>
13 #include <linux/regulator/consumer.h>
14 
15 #include <drm/drm_connector.h>
16 #include <drm/drm_crtc.h>
17 #include <drm/drm_mipi_dsi.h>
18 #include <drm/drm_modes.h>
19 #include <drm/drm_panel.h>
20 
21 #define MCS_CMD_MAUCCTR			0xf0 /* Manufacturer command enable */
22 #define MCS_PARAM_SCALER_FUNCTION	0x58 /* Scale-up function */
23 #define MCS_PARAM_SCALEUP_MODE		0xc9
24  #define MCS_SCALEUP_SIMPLE		0x0
25  #define MCS_SCALEUP_BILINEAR		BIT(0)
26  #define MCS_SCALEUP_DUPLICATE		(BIT(0) | BIT(4))
27 
28 /* VESA Display Stream Compression param */
29 #define MCS_PARAM_VESA_DSC_ON		0x03
30 
31 /* Data Compression mode */
32 #define MCS_PARAM_DATA_COMPRESSION	0x90
33  #define MCS_DATA_COMPRESSION_NONE	0x00
34  #define MCS_DATA_COMPRESSION_FBC	0x02
35  #define MCS_DATA_COMPRESSION_DSC	0x03
36 
37 /* Display Output control */
38 #define MCS_PARAM_DISP_OUTPUT_CTRL	0xb4
39  #define MCS_DISP_OUT_SRAM_EN		BIT(0)
40  #define MCS_DISP_OUT_VIDEO_MODE	BIT(4)
41 
42 /* VESA Display Stream Compression setting */
43 #define MCS_PARAM_VESA_DSC_SETTING	0xc0
44 
45 /* SubPixel Rendering (SPR) */
46 #define MCS_PARAM_SPR_EN		0xe3
47 #define MCS_PARAM_SPR_MODE		0xef
48  #define MCS_SPR_MODE_YYG_RAINBOW_RGB	0x01
49 
50 #define NT35950_VREG_MAX		4
51 
52 struct nt35950 {
53 	struct drm_panel panel;
54 	struct drm_connector *connector;
55 	struct mipi_dsi_device *dsi[2];
56 	struct regulator_bulk_data vregs[NT35950_VREG_MAX];
57 	struct gpio_desc *reset_gpio;
58 	const struct nt35950_panel_desc *desc;
59 
60 	int cur_mode;
61 	u8 last_page;
62 };
63 
64 struct nt35950_panel_mode {
65 	const struct drm_display_mode mode;
66 
67 	bool enable_sram;
68 	bool is_video_mode;
69 	u8 scaler_on;
70 	u8 scaler_mode;
71 	u8 compression;
72 	u8 spr_en;
73 	u8 spr_mode;
74 };
75 
76 struct nt35950_panel_desc {
77 	const char *model_name;
78 	const struct mipi_dsi_device_info dsi_info;
79 	const struct nt35950_panel_mode *mode_data;
80 
81 	bool is_dual_dsi;
82 	u8 num_lanes;
83 	u8 num_modes;
84 };
85 
86 static inline struct nt35950 *to_nt35950(struct drm_panel *panel)
87 {
88 	return container_of(panel, struct nt35950, panel);
89 }
90 
91 static void nt35950_reset(struct nt35950 *nt)
92 {
93 	gpiod_set_value_cansleep(nt->reset_gpio, 1);
94 	usleep_range(12000, 13000);
95 	gpiod_set_value_cansleep(nt->reset_gpio, 0);
96 	usleep_range(300, 400);
97 	gpiod_set_value_cansleep(nt->reset_gpio, 1);
98 	usleep_range(12000, 13000);
99 }
100 
101 /*
102  * nt35950_set_cmd2_page - Select manufacturer control (CMD2) page
103  * @nt:   Main driver structure
104  * @page: Page number (0-7)
105  *
106  * Return: Number of transferred bytes or negative number on error
107  */
108 static int nt35950_set_cmd2_page(struct nt35950 *nt, u8 page)
109 {
110 	const u8 mauc_cmd2_page[] = { MCS_CMD_MAUCCTR, 0x55, 0xaa, 0x52,
111 				      0x08, page };
112 	int ret;
113 
114 	ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], mauc_cmd2_page,
115 					ARRAY_SIZE(mauc_cmd2_page));
116 	if (ret < 0)
117 		return ret;
118 
119 	nt->last_page = page;
120 	return 0;
121 }
122 
123 /*
124  * nt35950_set_data_compression - Set data compression mode
125  * @nt:        Main driver structure
126  * @comp_mode: Compression mode
127  *
128  * Return: Number of transferred bytes or negative number on error
129  */
130 static int nt35950_set_data_compression(struct nt35950 *nt, u8 comp_mode)
131 {
132 	u8 cmd_data_compression[] = { MCS_PARAM_DATA_COMPRESSION, comp_mode };
133 	u8 cmd_vesa_dsc_on[] = { MCS_PARAM_VESA_DSC_ON, !!comp_mode };
134 	u8 cmd_vesa_dsc_setting[] = { MCS_PARAM_VESA_DSC_SETTING, 0x03 };
135 	u8 last_page = nt->last_page;
136 	int ret;
137 
138 	/* Set CMD2 Page 0 if we're not there yet */
139 	if (last_page != 0) {
140 		ret = nt35950_set_cmd2_page(nt, 0);
141 		if (ret < 0)
142 			return ret;
143 	}
144 
145 	ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_data_compression,
146 					ARRAY_SIZE(cmd_data_compression));
147 	if (ret < 0)
148 		return ret;
149 
150 	ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_vesa_dsc_on,
151 					ARRAY_SIZE(cmd_vesa_dsc_on));
152 	if (ret < 0)
153 		return ret;
154 
155 	/* Set the vesa dsc setting on Page 4 */
156 	ret = nt35950_set_cmd2_page(nt, 4);
157 	if (ret < 0)
158 		return ret;
159 
160 	/* Display Stream Compression setting, always 0x03 */
161 	ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_vesa_dsc_setting,
162 					ARRAY_SIZE(cmd_vesa_dsc_setting));
163 	if (ret < 0)
164 		return ret;
165 
166 	/* Get back to the previously set page */
167 	return nt35950_set_cmd2_page(nt, last_page);
168 }
169 
170 /*
171  * nt35950_set_scaler - Enable/disable resolution upscaling
172  * @nt:        Main driver structure
173  * @scale_up:  Scale up function control
174  *
175  * Return: Number of transferred bytes or negative number on error
176  */
177 static int nt35950_set_scaler(struct nt35950 *nt, u8 scale_up)
178 {
179 	u8 cmd_scaler[] = { MCS_PARAM_SCALER_FUNCTION, scale_up };
180 
181 	return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_scaler,
182 					 ARRAY_SIZE(cmd_scaler));
183 }
184 
185 /*
186  * nt35950_set_scale_mode - Resolution upscaling mode
187  * @nt:   Main driver structure
188  * @mode: Scaler mode (MCS_DATA_COMPRESSION_*)
189  *
190  * Return: Number of transferred bytes or negative number on error
191  */
192 static int nt35950_set_scale_mode(struct nt35950 *nt, u8 mode)
193 {
194 	u8 cmd_scaler[] = { MCS_PARAM_SCALEUP_MODE, mode };
195 
196 	return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_scaler,
197 					 ARRAY_SIZE(cmd_scaler));
198 }
199 
200 /*
201  * nt35950_inject_black_image - Display a completely black image
202  * @nt:   Main driver structure
203  *
204  * After IC setup, the attached panel may show random data
205  * due to driveric behavior changes (resolution, compression,
206  * scaling, etc). This function, called after parameters setup,
207  * makes the driver ic to output a completely black image to
208  * the display.
209  * It makes sense to push a black image before sending the sleep-out
210  * and display-on commands.
211  *
212  * Return: Number of transferred bytes or negative number on error
213  */
214 static int nt35950_inject_black_image(struct nt35950 *nt)
215 {
216 	const u8 cmd0_black_img[] = { 0x6f, 0x01 };
217 	const u8 cmd1_black_img[] = { 0xf3, 0x10 };
218 	u8 cmd_test[] = { 0xff, 0xaa, 0x55, 0xa5, 0x80 };
219 	int ret;
220 
221 	/* Enable test command */
222 	ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_test, ARRAY_SIZE(cmd_test));
223 	if (ret < 0)
224 		return ret;
225 
226 	/* Send a black image */
227 	ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd0_black_img,
228 					ARRAY_SIZE(cmd0_black_img));
229 	if (ret < 0)
230 		return ret;
231 	ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd1_black_img,
232 					ARRAY_SIZE(cmd1_black_img));
233 	if (ret < 0)
234 		return ret;
235 
236 	/* Disable test command */
237 	cmd_test[ARRAY_SIZE(cmd_test) - 1] = 0x00;
238 	return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_test, ARRAY_SIZE(cmd_test));
239 }
240 
241 /*
242  * nt35950_set_dispout - Set Display Output register parameters
243  * @nt:    Main driver structure
244  *
245  * Return: Number of transferred bytes or negative number on error
246  */
247 static int nt35950_set_dispout(struct nt35950 *nt)
248 {
249 	u8 cmd_dispout[] = { MCS_PARAM_DISP_OUTPUT_CTRL, 0x00 };
250 	const struct nt35950_panel_mode *mode_data = nt->desc->mode_data;
251 
252 	if (mode_data[nt->cur_mode].is_video_mode)
253 		cmd_dispout[1] |= MCS_DISP_OUT_VIDEO_MODE;
254 	if (mode_data[nt->cur_mode].enable_sram)
255 		cmd_dispout[1] |= MCS_DISP_OUT_SRAM_EN;
256 
257 	return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_dispout,
258 					 ARRAY_SIZE(cmd_dispout));
259 }
260 
261 static int nt35950_get_current_mode(struct nt35950 *nt)
262 {
263 	struct drm_connector *connector = nt->connector;
264 	struct drm_crtc_state *crtc_state;
265 	int i;
266 
267 	/* Return the default (first) mode if no info available yet */
268 	if (!connector->state || !connector->state->crtc)
269 		return 0;
270 
271 	crtc_state = connector->state->crtc->state;
272 
273 	for (i = 0; i < nt->desc->num_modes; i++) {
274 		if (drm_mode_match(&crtc_state->mode,
275 				   &nt->desc->mode_data[i].mode,
276 				   DRM_MODE_MATCH_TIMINGS | DRM_MODE_MATCH_CLOCK))
277 			return i;
278 	}
279 
280 	return 0;
281 }
282 
283 static int nt35950_on(struct nt35950 *nt)
284 {
285 	const struct nt35950_panel_mode *mode_data = nt->desc->mode_data;
286 	struct mipi_dsi_device *dsi = nt->dsi[0];
287 	struct device *dev = &dsi->dev;
288 	int ret;
289 
290 	nt->cur_mode = nt35950_get_current_mode(nt);
291 	nt->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM;
292 	nt->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
293 
294 	ret = nt35950_set_cmd2_page(nt, 0);
295 	if (ret < 0)
296 		return ret;
297 
298 	ret = nt35950_set_data_compression(nt, mode_data[nt->cur_mode].compression);
299 	if (ret < 0)
300 		return ret;
301 
302 	ret = nt35950_set_scale_mode(nt, mode_data[nt->cur_mode].scaler_mode);
303 	if (ret < 0)
304 		return ret;
305 
306 	ret = nt35950_set_scaler(nt, mode_data[nt->cur_mode].scaler_on);
307 	if (ret < 0)
308 		return ret;
309 
310 	ret = nt35950_set_dispout(nt);
311 	if (ret < 0)
312 		return ret;
313 
314 	ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
315 	if (ret < 0) {
316 		dev_err(dev, "Failed to set tear on: %d\n", ret);
317 		return ret;
318 	}
319 
320 	ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0);
321 	if (ret < 0) {
322 		dev_err(dev, "Failed to set tear scanline: %d\n", ret);
323 		return ret;
324 	}
325 
326 	/* CMD2 Page 1 */
327 	ret = nt35950_set_cmd2_page(nt, 1);
328 	if (ret < 0)
329 		return ret;
330 
331 	/* Unknown command */
332 	mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x88, 0x88);
333 
334 	/* CMD2 Page 7 */
335 	ret = nt35950_set_cmd2_page(nt, 7);
336 	if (ret < 0)
337 		return ret;
338 
339 	/* Enable SubPixel Rendering */
340 	mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_EN, 0x01);
341 
342 	/* SPR Mode: YYG Rainbow-RGB */
343 	mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_MODE, MCS_SPR_MODE_YYG_RAINBOW_RGB);
344 
345 	/* CMD3 */
346 	ret = nt35950_inject_black_image(nt);
347 	if (ret < 0)
348 		return ret;
349 
350 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
351 	if (ret < 0)
352 		return ret;
353 	msleep(120);
354 
355 	ret = mipi_dsi_dcs_set_display_on(dsi);
356 	if (ret < 0)
357 		return ret;
358 	msleep(120);
359 
360 	nt->dsi[0]->mode_flags &= ~MIPI_DSI_MODE_LPM;
361 	nt->dsi[1]->mode_flags &= ~MIPI_DSI_MODE_LPM;
362 
363 	return 0;
364 }
365 
366 static int nt35950_off(struct nt35950 *nt)
367 {
368 	struct device *dev = &nt->dsi[0]->dev;
369 	int ret;
370 
371 	ret = mipi_dsi_dcs_set_display_off(nt->dsi[0]);
372 	if (ret < 0) {
373 		dev_err(dev, "Failed to set display off: %d\n", ret);
374 		goto set_lpm;
375 	}
376 	usleep_range(10000, 11000);
377 
378 	ret = mipi_dsi_dcs_enter_sleep_mode(nt->dsi[0]);
379 	if (ret < 0) {
380 		dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
381 		goto set_lpm;
382 	}
383 	msleep(150);
384 
385 set_lpm:
386 	nt->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM;
387 	nt->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
388 
389 	return 0;
390 }
391 
392 static int nt35950_sharp_init_vregs(struct nt35950 *nt, struct device *dev)
393 {
394 	int ret;
395 
396 	nt->vregs[0].supply = "vddio";
397 	nt->vregs[1].supply = "avdd";
398 	nt->vregs[2].supply = "avee";
399 	nt->vregs[3].supply = "dvdd";
400 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(nt->vregs),
401 				      nt->vregs);
402 	if (ret < 0)
403 		return ret;
404 
405 	ret = regulator_is_supported_voltage(nt->vregs[0].consumer,
406 					     1750000, 1950000);
407 	if (!ret)
408 		return -EINVAL;
409 	ret = regulator_is_supported_voltage(nt->vregs[1].consumer,
410 					     5200000, 5900000);
411 	if (!ret)
412 		return -EINVAL;
413 	/* AVEE is negative: -5.90V to -5.20V */
414 	ret = regulator_is_supported_voltage(nt->vregs[2].consumer,
415 					     5200000, 5900000);
416 	if (!ret)
417 		return -EINVAL;
418 
419 	ret = regulator_is_supported_voltage(nt->vregs[3].consumer,
420 					     1300000, 1400000);
421 	if (!ret)
422 		return -EINVAL;
423 
424 	return 0;
425 }
426 
427 static int nt35950_prepare(struct drm_panel *panel)
428 {
429 	struct nt35950 *nt = to_nt35950(panel);
430 	struct device *dev = &nt->dsi[0]->dev;
431 	int ret;
432 
433 	ret = regulator_enable(nt->vregs[0].consumer);
434 	if (ret)
435 		return ret;
436 	usleep_range(2000, 5000);
437 
438 	ret = regulator_enable(nt->vregs[3].consumer);
439 	if (ret)
440 		goto end;
441 	usleep_range(15000, 18000);
442 
443 	ret = regulator_enable(nt->vregs[1].consumer);
444 	if (ret)
445 		goto end;
446 
447 	ret = regulator_enable(nt->vregs[2].consumer);
448 	if (ret)
449 		goto end;
450 	usleep_range(12000, 13000);
451 
452 	nt35950_reset(nt);
453 
454 	ret = nt35950_on(nt);
455 	if (ret < 0) {
456 		dev_err(dev, "Failed to initialize panel: %d\n", ret);
457 		goto end;
458 	}
459 
460 end:
461 	if (ret < 0) {
462 		regulator_bulk_disable(ARRAY_SIZE(nt->vregs), nt->vregs);
463 		return ret;
464 	}
465 
466 	return 0;
467 }
468 
469 static int nt35950_unprepare(struct drm_panel *panel)
470 {
471 	struct nt35950 *nt = to_nt35950(panel);
472 	struct device *dev = &nt->dsi[0]->dev;
473 	int ret;
474 
475 	ret = nt35950_off(nt);
476 	if (ret < 0)
477 		dev_err(dev, "Failed to deinitialize panel: %d\n", ret);
478 
479 	gpiod_set_value_cansleep(nt->reset_gpio, 0);
480 	regulator_bulk_disable(ARRAY_SIZE(nt->vregs), nt->vregs);
481 
482 	return 0;
483 }
484 
485 static int nt35950_get_modes(struct drm_panel *panel,
486 			     struct drm_connector *connector)
487 {
488 	struct nt35950 *nt = to_nt35950(panel);
489 	int i;
490 
491 	for (i = 0; i < nt->desc->num_modes; i++) {
492 		struct drm_display_mode *mode;
493 
494 		mode = drm_mode_duplicate(connector->dev,
495 					  &nt->desc->mode_data[i].mode);
496 		if (!mode)
497 			return -ENOMEM;
498 
499 		drm_mode_set_name(mode);
500 
501 		mode->type |= DRM_MODE_TYPE_DRIVER;
502 		if (nt->desc->num_modes == 1)
503 			mode->type |= DRM_MODE_TYPE_PREFERRED;
504 
505 		drm_mode_probed_add(connector, mode);
506 	}
507 
508 	connector->display_info.bpc = 8;
509 	connector->display_info.height_mm = nt->desc->mode_data[0].mode.height_mm;
510 	connector->display_info.width_mm = nt->desc->mode_data[0].mode.width_mm;
511 	nt->connector = connector;
512 
513 	return nt->desc->num_modes;
514 }
515 
516 static const struct drm_panel_funcs nt35950_panel_funcs = {
517 	.prepare = nt35950_prepare,
518 	.unprepare = nt35950_unprepare,
519 	.get_modes = nt35950_get_modes,
520 };
521 
522 static int nt35950_probe(struct mipi_dsi_device *dsi)
523 {
524 	struct device *dev = &dsi->dev;
525 	struct device_node *dsi_r;
526 	struct mipi_dsi_host *dsi_r_host;
527 	struct nt35950 *nt;
528 	const struct mipi_dsi_device_info *info;
529 	int i, num_dsis = 1, ret;
530 
531 	nt = devm_kzalloc(dev, sizeof(*nt), GFP_KERNEL);
532 	if (!nt)
533 		return -ENOMEM;
534 
535 	ret = nt35950_sharp_init_vregs(nt, dev);
536 	if (ret)
537 		return dev_err_probe(dev, ret, "Regulator init failure.\n");
538 
539 	nt->desc = of_device_get_match_data(dev);
540 	if (!nt->desc)
541 		return -ENODEV;
542 
543 	nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
544 	if (IS_ERR(nt->reset_gpio)) {
545 		return dev_err_probe(dev, PTR_ERR(nt->reset_gpio),
546 				     "Failed to get reset gpio\n");
547 	}
548 
549 	/* If the panel is connected on two DSIs then DSI0 left, DSI1 right */
550 	if (nt->desc->is_dual_dsi) {
551 		info = &nt->desc->dsi_info;
552 		dsi_r = of_graph_get_remote_node(dsi->dev.of_node, 1, -1);
553 		if (!dsi_r) {
554 			dev_err(dev, "Cannot get secondary DSI node.\n");
555 			return -ENODEV;
556 		}
557 		dsi_r_host = of_find_mipi_dsi_host_by_node(dsi_r);
558 		of_node_put(dsi_r);
559 		if (!dsi_r_host) {
560 			dev_err(dev, "Cannot get secondary DSI host\n");
561 			return -EPROBE_DEFER;
562 		}
563 
564 		nt->dsi[1] = mipi_dsi_device_register_full(dsi_r_host, info);
565 		if (!nt->dsi[1]) {
566 			dev_err(dev, "Cannot get secondary DSI node\n");
567 			return -ENODEV;
568 		}
569 		num_dsis++;
570 	}
571 
572 	nt->dsi[0] = dsi;
573 	mipi_dsi_set_drvdata(dsi, nt);
574 
575 	drm_panel_init(&nt->panel, dev, &nt35950_panel_funcs,
576 		       DRM_MODE_CONNECTOR_DSI);
577 
578 	ret = drm_panel_of_backlight(&nt->panel);
579 	if (ret) {
580 		if (num_dsis == 2)
581 			mipi_dsi_device_unregister(nt->dsi[1]);
582 
583 		return dev_err_probe(dev, ret, "Failed to get backlight\n");
584 	}
585 
586 	drm_panel_add(&nt->panel);
587 
588 	for (i = 0; i < num_dsis; i++) {
589 		nt->dsi[i]->lanes = nt->desc->num_lanes;
590 		nt->dsi[i]->format = MIPI_DSI_FMT_RGB888;
591 
592 		nt->dsi[i]->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS |
593 					 MIPI_DSI_MODE_LPM;
594 
595 		if (nt->desc->mode_data[0].is_video_mode)
596 			nt->dsi[i]->mode_flags |= MIPI_DSI_MODE_VIDEO;
597 
598 		ret = mipi_dsi_attach(nt->dsi[i]);
599 		if (ret < 0) {
600 			/* If we fail to attach to either host, we're done */
601 			if (num_dsis == 2)
602 				mipi_dsi_device_unregister(nt->dsi[1]);
603 
604 			return dev_err_probe(dev, ret,
605 					     "Cannot attach to DSI%d host.\n", i);
606 		}
607 	}
608 
609 	/* Make sure to set RESX LOW before starting the power-on sequence */
610 	gpiod_set_value_cansleep(nt->reset_gpio, 0);
611 	return 0;
612 }
613 
614 static void nt35950_remove(struct mipi_dsi_device *dsi)
615 {
616 	struct nt35950 *nt = mipi_dsi_get_drvdata(dsi);
617 	int ret;
618 
619 	ret = mipi_dsi_detach(nt->dsi[0]);
620 	if (ret < 0)
621 		dev_err(&dsi->dev,
622 			"Failed to detach from DSI0 host: %d\n", ret);
623 
624 	if (nt->dsi[1]) {
625 		ret = mipi_dsi_detach(nt->dsi[1]);
626 		if (ret < 0)
627 			dev_err(&dsi->dev,
628 				"Failed to detach from DSI1 host: %d\n", ret);
629 		mipi_dsi_device_unregister(nt->dsi[1]);
630 	}
631 
632 	drm_panel_remove(&nt->panel);
633 }
634 
635 static const struct nt35950_panel_mode sharp_ls055d1sx04_modes[] = {
636 	{
637 		/* 1920x1080 60Hz no compression */
638 		.mode = {
639 			.clock = 214537,
640 			.hdisplay = 1080,
641 			.hsync_start = 1080 + 400,
642 			.hsync_end = 1080 + 400 + 40,
643 			.htotal = 1080 + 400 + 40 + 300,
644 			.vdisplay = 1920,
645 			.vsync_start = 1920 + 12,
646 			.vsync_end = 1920 + 12 + 2,
647 			.vtotal = 1920 + 12 + 2 + 10,
648 			.width_mm = 68,
649 			.height_mm = 121,
650 		},
651 		.compression = MCS_DATA_COMPRESSION_NONE,
652 		.enable_sram = true,
653 		.is_video_mode = false,
654 		.scaler_on = 1,
655 		.scaler_mode = MCS_SCALEUP_DUPLICATE,
656 	},
657 	/* TODO: Add 2160x3840 60Hz when DSC is supported */
658 };
659 
660 static const struct nt35950_panel_desc sharp_ls055d1sx04 = {
661 	.model_name = "Sharp LS055D1SX04",
662 	.dsi_info = {
663 		.type = "LS055D1SX04",
664 		.channel = 0,
665 		.node = NULL,
666 	},
667 	.mode_data = sharp_ls055d1sx04_modes,
668 	.num_modes = ARRAY_SIZE(sharp_ls055d1sx04_modes),
669 	.is_dual_dsi = true,
670 	.num_lanes = 4,
671 };
672 
673 static const struct of_device_id nt35950_of_match[] = {
674 	{ .compatible = "sharp,ls055d1sx04", .data = &sharp_ls055d1sx04 },
675 	{  }
676 };
677 MODULE_DEVICE_TABLE(of, nt35950_of_match);
678 
679 static struct mipi_dsi_driver nt35950_driver = {
680 	.probe = nt35950_probe,
681 	.remove = nt35950_remove,
682 	.driver = {
683 		.name = "panel-novatek-nt35950",
684 		.of_match_table = nt35950_of_match,
685 	},
686 };
687 module_mipi_dsi_driver(nt35950_driver);
688 
689 MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>");
690 MODULE_DESCRIPTION("Novatek NT35950 DriverIC panels driver");
691 MODULE_LICENSE("GPL v2");
692