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