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
52struct 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
64struct 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
76struct 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
86static inline struct nt35950 *to_nt35950(struct drm_panel *panel)
87{
88	return container_of(panel, struct nt35950, panel);
89}
90
91static 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 */
108static 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 */
130static 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 */
177static 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 */
192static 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 */
214static 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 */
247static 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
261static 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
283static 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
366static 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
385set_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
392static 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
427static 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
460end:
461	if (ret < 0) {
462		regulator_bulk_disable(ARRAY_SIZE(nt->vregs), nt->vregs);
463		return ret;
464	}
465
466	return 0;
467}
468
469static 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
485static 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
516static const struct drm_panel_funcs nt35950_panel_funcs = {
517	.prepare = nt35950_prepare,
518	.unprepare = nt35950_unprepare,
519	.get_modes = nt35950_get_modes,
520};
521
522static 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
614static 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
635static 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
660static 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
673static const struct of_device_id nt35950_of_match[] = {
674	{ .compatible = "sharp,ls055d1sx04", .data = &sharp_ls055d1sx04 },
675	{  }
676};
677MODULE_DEVICE_TABLE(of, nt35950_of_match);
678
679static 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};
687module_mipi_dsi_driver(nt35950_driver);
688
689MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>");
690MODULE_DESCRIPTION("Novatek NT35950 DriverIC panels driver");
691MODULE_LICENSE("GPL v2");
692