1*22de25f8SKonrad Dybcio // SPDX-License-Identifier: GPL-2.0-only
2*22de25f8SKonrad Dybcio /*
3*22de25f8SKonrad Dybcio  * Copyright (c) 2022 Konrad Dybcio <konrad.dybcio@somainline.org>
4*22de25f8SKonrad Dybcio  *
5*22de25f8SKonrad Dybcio  * Generated with linux-mdss-dsi-panel-driver-generator with a
6*22de25f8SKonrad Dybcio  * substantial amount of manual adjustments.
7*22de25f8SKonrad Dybcio  *
8*22de25f8SKonrad Dybcio  * SONY Downstream kernel calls this one:
9*22de25f8SKonrad Dybcio  * - "JDI ID3" for Akari  (XZ2)
10*22de25f8SKonrad Dybcio  * - "JDI ID4" for Apollo (XZ2 Compact)
11*22de25f8SKonrad Dybcio  */
12*22de25f8SKonrad Dybcio 
13*22de25f8SKonrad Dybcio #include <linux/delay.h>
14*22de25f8SKonrad Dybcio #include <linux/gpio/consumer.h>
15*22de25f8SKonrad Dybcio #include <linux/module.h>
16*22de25f8SKonrad Dybcio #include <linux/of.h>
17*22de25f8SKonrad Dybcio #include <linux/regulator/consumer.h>
18*22de25f8SKonrad Dybcio 
19*22de25f8SKonrad Dybcio #include <video/mipi_display.h>
20*22de25f8SKonrad Dybcio 
21*22de25f8SKonrad Dybcio #include <drm/drm_mipi_dsi.h>
22*22de25f8SKonrad Dybcio #include <drm/drm_modes.h>
23*22de25f8SKonrad Dybcio #include <drm/drm_panel.h>
24*22de25f8SKonrad Dybcio 
25*22de25f8SKonrad Dybcio enum {
26*22de25f8SKonrad Dybcio 	TYPE_TAMA_60HZ,
27*22de25f8SKonrad Dybcio 	/*
28*22de25f8SKonrad Dybcio 	 * Leaving room for expansion - SONY very often uses
29*22de25f8SKonrad Dybcio 	 * *truly reliably* overclockable panels on their flagships!
30*22de25f8SKonrad Dybcio 	 */
31*22de25f8SKonrad Dybcio };
32*22de25f8SKonrad Dybcio 
33*22de25f8SKonrad Dybcio struct sony_td4353_jdi {
34*22de25f8SKonrad Dybcio 	struct drm_panel panel;
35*22de25f8SKonrad Dybcio 	struct mipi_dsi_device *dsi;
36*22de25f8SKonrad Dybcio 	struct regulator_bulk_data supplies[3];
37*22de25f8SKonrad Dybcio 	struct gpio_desc *panel_reset_gpio;
38*22de25f8SKonrad Dybcio 	struct gpio_desc *touch_reset_gpio;
39*22de25f8SKonrad Dybcio 	bool prepared;
40*22de25f8SKonrad Dybcio 	int type;
41*22de25f8SKonrad Dybcio };
42*22de25f8SKonrad Dybcio 
to_sony_td4353_jdi(struct drm_panel * panel)43*22de25f8SKonrad Dybcio static inline struct sony_td4353_jdi *to_sony_td4353_jdi(struct drm_panel *panel)
44*22de25f8SKonrad Dybcio {
45*22de25f8SKonrad Dybcio 	return container_of(panel, struct sony_td4353_jdi, panel);
46*22de25f8SKonrad Dybcio }
47*22de25f8SKonrad Dybcio 
sony_td4353_jdi_on(struct sony_td4353_jdi * ctx)48*22de25f8SKonrad Dybcio static int sony_td4353_jdi_on(struct sony_td4353_jdi *ctx)
49*22de25f8SKonrad Dybcio {
50*22de25f8SKonrad Dybcio 	struct mipi_dsi_device *dsi = ctx->dsi;
51*22de25f8SKonrad Dybcio 	struct device *dev = &dsi->dev;
52*22de25f8SKonrad Dybcio 	int ret;
53*22de25f8SKonrad Dybcio 
54*22de25f8SKonrad Dybcio 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
55*22de25f8SKonrad Dybcio 
56*22de25f8SKonrad Dybcio 	ret = mipi_dsi_dcs_set_column_address(dsi, 0x0000, 1080 - 1);
57*22de25f8SKonrad Dybcio 	if (ret < 0) {
58*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to set column address: %d\n", ret);
59*22de25f8SKonrad Dybcio 		return ret;
60*22de25f8SKonrad Dybcio 	}
61*22de25f8SKonrad Dybcio 
62*22de25f8SKonrad Dybcio 	ret = mipi_dsi_dcs_set_page_address(dsi, 0x0000, 2160 - 1);
63*22de25f8SKonrad Dybcio 	if (ret < 0) {
64*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to set page address: %d\n", ret);
65*22de25f8SKonrad Dybcio 		return ret;
66*22de25f8SKonrad Dybcio 	}
67*22de25f8SKonrad Dybcio 
68*22de25f8SKonrad Dybcio 	ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0);
69*22de25f8SKonrad Dybcio 	if (ret < 0) {
70*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to set tear scanline: %d\n", ret);
71*22de25f8SKonrad Dybcio 		return ret;
72*22de25f8SKonrad Dybcio 	}
73*22de25f8SKonrad Dybcio 
74*22de25f8SKonrad Dybcio 	ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
75*22de25f8SKonrad Dybcio 	if (ret < 0) {
76*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to set tear on: %d\n", ret);
77*22de25f8SKonrad Dybcio 		return ret;
78*22de25f8SKonrad Dybcio 	}
79*22de25f8SKonrad Dybcio 
80*22de25f8SKonrad Dybcio 	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
81*22de25f8SKonrad Dybcio 
82*22de25f8SKonrad Dybcio 	ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77);
83*22de25f8SKonrad Dybcio 	if (ret < 0) {
84*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to set pixel format: %d\n", ret);
85*22de25f8SKonrad Dybcio 		return ret;
86*22de25f8SKonrad Dybcio 	}
87*22de25f8SKonrad Dybcio 
88*22de25f8SKonrad Dybcio 	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS,
89*22de25f8SKonrad Dybcio 			  0x00, 0x00, 0x08, 0x6f);
90*22de25f8SKonrad Dybcio 
91*22de25f8SKonrad Dybcio 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
92*22de25f8SKonrad Dybcio 	if (ret < 0) {
93*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
94*22de25f8SKonrad Dybcio 		return ret;
95*22de25f8SKonrad Dybcio 	}
96*22de25f8SKonrad Dybcio 	msleep(70);
97*22de25f8SKonrad Dybcio 
98*22de25f8SKonrad Dybcio 	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_MEMORY_START);
99*22de25f8SKonrad Dybcio 
100*22de25f8SKonrad Dybcio 	ret = mipi_dsi_dcs_set_display_on(dsi);
101*22de25f8SKonrad Dybcio 	if (ret < 0) {
102*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to turn display on: %d\n", ret);
103*22de25f8SKonrad Dybcio 		return ret;
104*22de25f8SKonrad Dybcio 	}
105*22de25f8SKonrad Dybcio 
106*22de25f8SKonrad Dybcio 	return 0;
107*22de25f8SKonrad Dybcio }
108*22de25f8SKonrad Dybcio 
sony_td4353_jdi_off(struct sony_td4353_jdi * ctx)109*22de25f8SKonrad Dybcio static int sony_td4353_jdi_off(struct sony_td4353_jdi *ctx)
110*22de25f8SKonrad Dybcio {
111*22de25f8SKonrad Dybcio 	struct mipi_dsi_device *dsi = ctx->dsi;
112*22de25f8SKonrad Dybcio 	struct device *dev = &dsi->dev;
113*22de25f8SKonrad Dybcio 	int ret;
114*22de25f8SKonrad Dybcio 
115*22de25f8SKonrad Dybcio 	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
116*22de25f8SKonrad Dybcio 
117*22de25f8SKonrad Dybcio 	ret = mipi_dsi_dcs_set_display_off(dsi);
118*22de25f8SKonrad Dybcio 	if (ret < 0) {
119*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to set display off: %d\n", ret);
120*22de25f8SKonrad Dybcio 		return ret;
121*22de25f8SKonrad Dybcio 	}
122*22de25f8SKonrad Dybcio 	msleep(22);
123*22de25f8SKonrad Dybcio 
124*22de25f8SKonrad Dybcio 	ret = mipi_dsi_dcs_set_tear_off(dsi);
125*22de25f8SKonrad Dybcio 	if (ret < 0) {
126*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to set tear off: %d\n", ret);
127*22de25f8SKonrad Dybcio 		return ret;
128*22de25f8SKonrad Dybcio 	}
129*22de25f8SKonrad Dybcio 
130*22de25f8SKonrad Dybcio 	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
131*22de25f8SKonrad Dybcio 	if (ret < 0) {
132*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
133*22de25f8SKonrad Dybcio 		return ret;
134*22de25f8SKonrad Dybcio 	}
135*22de25f8SKonrad Dybcio 	msleep(80);
136*22de25f8SKonrad Dybcio 
137*22de25f8SKonrad Dybcio 	return 0;
138*22de25f8SKonrad Dybcio }
139*22de25f8SKonrad Dybcio 
sony_td4353_assert_reset_gpios(struct sony_td4353_jdi * ctx,int mode)140*22de25f8SKonrad Dybcio static void sony_td4353_assert_reset_gpios(struct sony_td4353_jdi *ctx, int mode)
141*22de25f8SKonrad Dybcio {
142*22de25f8SKonrad Dybcio 	gpiod_set_value_cansleep(ctx->touch_reset_gpio, mode);
143*22de25f8SKonrad Dybcio 	gpiod_set_value_cansleep(ctx->panel_reset_gpio, mode);
144*22de25f8SKonrad Dybcio 	usleep_range(5000, 5100);
145*22de25f8SKonrad Dybcio }
146*22de25f8SKonrad Dybcio 
sony_td4353_jdi_prepare(struct drm_panel * panel)147*22de25f8SKonrad Dybcio static int sony_td4353_jdi_prepare(struct drm_panel *panel)
148*22de25f8SKonrad Dybcio {
149*22de25f8SKonrad Dybcio 	struct sony_td4353_jdi *ctx = to_sony_td4353_jdi(panel);
150*22de25f8SKonrad Dybcio 	struct device *dev = &ctx->dsi->dev;
151*22de25f8SKonrad Dybcio 	int ret;
152*22de25f8SKonrad Dybcio 
153*22de25f8SKonrad Dybcio 	if (ctx->prepared)
154*22de25f8SKonrad Dybcio 		return 0;
155*22de25f8SKonrad Dybcio 
156*22de25f8SKonrad Dybcio 	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
157*22de25f8SKonrad Dybcio 	if (ret < 0) {
158*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to enable regulators: %d\n", ret);
159*22de25f8SKonrad Dybcio 		return ret;
160*22de25f8SKonrad Dybcio 	}
161*22de25f8SKonrad Dybcio 
162*22de25f8SKonrad Dybcio 	msleep(100);
163*22de25f8SKonrad Dybcio 
164*22de25f8SKonrad Dybcio 	sony_td4353_assert_reset_gpios(ctx, 1);
165*22de25f8SKonrad Dybcio 
166*22de25f8SKonrad Dybcio 	ret = sony_td4353_jdi_on(ctx);
167*22de25f8SKonrad Dybcio 	if (ret < 0) {
168*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to power on panel: %d\n", ret);
169*22de25f8SKonrad Dybcio 		sony_td4353_assert_reset_gpios(ctx, 0);
170*22de25f8SKonrad Dybcio 		regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
171*22de25f8SKonrad Dybcio 		return ret;
172*22de25f8SKonrad Dybcio 	}
173*22de25f8SKonrad Dybcio 
174*22de25f8SKonrad Dybcio 	ctx->prepared = true;
175*22de25f8SKonrad Dybcio 	return 0;
176*22de25f8SKonrad Dybcio }
177*22de25f8SKonrad Dybcio 
sony_td4353_jdi_unprepare(struct drm_panel * panel)178*22de25f8SKonrad Dybcio static int sony_td4353_jdi_unprepare(struct drm_panel *panel)
179*22de25f8SKonrad Dybcio {
180*22de25f8SKonrad Dybcio 	struct sony_td4353_jdi *ctx = to_sony_td4353_jdi(panel);
181*22de25f8SKonrad Dybcio 	struct device *dev = &ctx->dsi->dev;
182*22de25f8SKonrad Dybcio 	int ret;
183*22de25f8SKonrad Dybcio 
184*22de25f8SKonrad Dybcio 	if (!ctx->prepared)
185*22de25f8SKonrad Dybcio 		return 0;
186*22de25f8SKonrad Dybcio 
187*22de25f8SKonrad Dybcio 	ret = sony_td4353_jdi_off(ctx);
188*22de25f8SKonrad Dybcio 	if (ret < 0)
189*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to power off panel: %d\n", ret);
190*22de25f8SKonrad Dybcio 
191*22de25f8SKonrad Dybcio 	sony_td4353_assert_reset_gpios(ctx, 0);
192*22de25f8SKonrad Dybcio 	regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
193*22de25f8SKonrad Dybcio 
194*22de25f8SKonrad Dybcio 	ctx->prepared = false;
195*22de25f8SKonrad Dybcio 	return 0;
196*22de25f8SKonrad Dybcio }
197*22de25f8SKonrad Dybcio 
198*22de25f8SKonrad Dybcio static const struct drm_display_mode sony_td4353_jdi_mode_tama_60hz = {
199*22de25f8SKonrad Dybcio 	.clock = (1080 + 4 + 8 + 8) * (2160 + 259 + 8 + 8) * 60 / 1000,
200*22de25f8SKonrad Dybcio 	.hdisplay = 1080,
201*22de25f8SKonrad Dybcio 	.hsync_start = 1080 + 4,
202*22de25f8SKonrad Dybcio 	.hsync_end = 1080 + 4 + 8,
203*22de25f8SKonrad Dybcio 	.htotal = 1080 + 4 + 8 + 8,
204*22de25f8SKonrad Dybcio 	.vdisplay = 2160,
205*22de25f8SKonrad Dybcio 	.vsync_start = 2160 + 259,
206*22de25f8SKonrad Dybcio 	.vsync_end = 2160 + 259 + 8,
207*22de25f8SKonrad Dybcio 	.vtotal = 2160 + 259 + 8 + 8,
208*22de25f8SKonrad Dybcio 	.width_mm = 64,
209*22de25f8SKonrad Dybcio 	.height_mm = 128,
210*22de25f8SKonrad Dybcio };
211*22de25f8SKonrad Dybcio 
sony_td4353_jdi_get_modes(struct drm_panel * panel,struct drm_connector * connector)212*22de25f8SKonrad Dybcio static int sony_td4353_jdi_get_modes(struct drm_panel *panel,
213*22de25f8SKonrad Dybcio 				   struct drm_connector *connector)
214*22de25f8SKonrad Dybcio {
215*22de25f8SKonrad Dybcio 	struct sony_td4353_jdi *ctx = to_sony_td4353_jdi(panel);
216*22de25f8SKonrad Dybcio 	struct drm_display_mode *mode = NULL;
217*22de25f8SKonrad Dybcio 
218*22de25f8SKonrad Dybcio 	if (ctx->type == TYPE_TAMA_60HZ)
219*22de25f8SKonrad Dybcio 		mode = drm_mode_duplicate(connector->dev, &sony_td4353_jdi_mode_tama_60hz);
220*22de25f8SKonrad Dybcio 	else
221*22de25f8SKonrad Dybcio 		return -EINVAL;
222*22de25f8SKonrad Dybcio 
223*22de25f8SKonrad Dybcio 	if (!mode)
224*22de25f8SKonrad Dybcio 		return -ENOMEM;
225*22de25f8SKonrad Dybcio 
226*22de25f8SKonrad Dybcio 	drm_mode_set_name(mode);
227*22de25f8SKonrad Dybcio 
228*22de25f8SKonrad Dybcio 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
229*22de25f8SKonrad Dybcio 	connector->display_info.width_mm = mode->width_mm;
230*22de25f8SKonrad Dybcio 	connector->display_info.height_mm = mode->height_mm;
231*22de25f8SKonrad Dybcio 	drm_mode_probed_add(connector, mode);
232*22de25f8SKonrad Dybcio 
233*22de25f8SKonrad Dybcio 	return 1;
234*22de25f8SKonrad Dybcio }
235*22de25f8SKonrad Dybcio 
236*22de25f8SKonrad Dybcio static const struct drm_panel_funcs sony_td4353_jdi_panel_funcs = {
237*22de25f8SKonrad Dybcio 	.prepare = sony_td4353_jdi_prepare,
238*22de25f8SKonrad Dybcio 	.unprepare = sony_td4353_jdi_unprepare,
239*22de25f8SKonrad Dybcio 	.get_modes = sony_td4353_jdi_get_modes,
240*22de25f8SKonrad Dybcio };
241*22de25f8SKonrad Dybcio 
sony_td4353_jdi_probe(struct mipi_dsi_device * dsi)242*22de25f8SKonrad Dybcio static int sony_td4353_jdi_probe(struct mipi_dsi_device *dsi)
243*22de25f8SKonrad Dybcio {
244*22de25f8SKonrad Dybcio 	struct device *dev = &dsi->dev;
245*22de25f8SKonrad Dybcio 	struct sony_td4353_jdi *ctx;
246*22de25f8SKonrad Dybcio 	int ret;
247*22de25f8SKonrad Dybcio 
248*22de25f8SKonrad Dybcio 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
249*22de25f8SKonrad Dybcio 	if (!ctx)
250*22de25f8SKonrad Dybcio 		return -ENOMEM;
251*22de25f8SKonrad Dybcio 
252*22de25f8SKonrad Dybcio 	ctx->type = (uintptr_t)of_device_get_match_data(dev);
253*22de25f8SKonrad Dybcio 
254*22de25f8SKonrad Dybcio 	ctx->supplies[0].supply = "vddio";
255*22de25f8SKonrad Dybcio 	ctx->supplies[1].supply = "vsp";
256*22de25f8SKonrad Dybcio 	ctx->supplies[2].supply = "vsn";
257*22de25f8SKonrad Dybcio 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
258*22de25f8SKonrad Dybcio 				      ctx->supplies);
259*22de25f8SKonrad Dybcio 	if (ret < 0)
260*22de25f8SKonrad Dybcio 		return dev_err_probe(dev, ret, "Failed to get regulators\n");
261*22de25f8SKonrad Dybcio 
262*22de25f8SKonrad Dybcio 	ctx->panel_reset_gpio = devm_gpiod_get(dev, "panel-reset", GPIOD_ASIS);
263*22de25f8SKonrad Dybcio 	if (IS_ERR(ctx->panel_reset_gpio))
264*22de25f8SKonrad Dybcio 		return dev_err_probe(dev, PTR_ERR(ctx->panel_reset_gpio),
265*22de25f8SKonrad Dybcio 				     "Failed to get panel-reset-gpios\n");
266*22de25f8SKonrad Dybcio 
267*22de25f8SKonrad Dybcio 	ctx->touch_reset_gpio = devm_gpiod_get(dev, "touch-reset", GPIOD_ASIS);
268*22de25f8SKonrad Dybcio 	if (IS_ERR(ctx->touch_reset_gpio))
269*22de25f8SKonrad Dybcio 		return dev_err_probe(dev, PTR_ERR(ctx->touch_reset_gpio),
270*22de25f8SKonrad Dybcio 				     "Failed to get touch-reset-gpios\n");
271*22de25f8SKonrad Dybcio 
272*22de25f8SKonrad Dybcio 	ctx->dsi = dsi;
273*22de25f8SKonrad Dybcio 	mipi_dsi_set_drvdata(dsi, ctx);
274*22de25f8SKonrad Dybcio 
275*22de25f8SKonrad Dybcio 	dsi->lanes = 4;
276*22de25f8SKonrad Dybcio 	dsi->format = MIPI_DSI_FMT_RGB888;
277*22de25f8SKonrad Dybcio 	dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS;
278*22de25f8SKonrad Dybcio 
279*22de25f8SKonrad Dybcio 	drm_panel_init(&ctx->panel, dev, &sony_td4353_jdi_panel_funcs,
280*22de25f8SKonrad Dybcio 		       DRM_MODE_CONNECTOR_DSI);
281*22de25f8SKonrad Dybcio 
282*22de25f8SKonrad Dybcio 	ret = drm_panel_of_backlight(&ctx->panel);
283*22de25f8SKonrad Dybcio 	if (ret)
284*22de25f8SKonrad Dybcio 		return dev_err_probe(dev, ret, "Failed to get backlight\n");
285*22de25f8SKonrad Dybcio 
286*22de25f8SKonrad Dybcio 	drm_panel_add(&ctx->panel);
287*22de25f8SKonrad Dybcio 
288*22de25f8SKonrad Dybcio 	ret = mipi_dsi_attach(dsi);
289*22de25f8SKonrad Dybcio 	if (ret < 0) {
290*22de25f8SKonrad Dybcio 		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
291*22de25f8SKonrad Dybcio 		drm_panel_remove(&ctx->panel);
292*22de25f8SKonrad Dybcio 		return ret;
293*22de25f8SKonrad Dybcio 	}
294*22de25f8SKonrad Dybcio 
295*22de25f8SKonrad Dybcio 	return 0;
296*22de25f8SKonrad Dybcio }
297*22de25f8SKonrad Dybcio 
sony_td4353_jdi_remove(struct mipi_dsi_device * dsi)298*22de25f8SKonrad Dybcio static void sony_td4353_jdi_remove(struct mipi_dsi_device *dsi)
299*22de25f8SKonrad Dybcio {
300*22de25f8SKonrad Dybcio 	struct sony_td4353_jdi *ctx = mipi_dsi_get_drvdata(dsi);
301*22de25f8SKonrad Dybcio 	int ret;
302*22de25f8SKonrad Dybcio 
303*22de25f8SKonrad Dybcio 	ret = mipi_dsi_detach(dsi);
304*22de25f8SKonrad Dybcio 	if (ret < 0)
305*22de25f8SKonrad Dybcio 		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
306*22de25f8SKonrad Dybcio 
307*22de25f8SKonrad Dybcio 	drm_panel_remove(&ctx->panel);
308*22de25f8SKonrad Dybcio }
309*22de25f8SKonrad Dybcio 
310*22de25f8SKonrad Dybcio static const struct of_device_id sony_td4353_jdi_of_match[] = {
311*22de25f8SKonrad Dybcio 	{ .compatible = "sony,td4353-jdi-tama", .data = (void *)TYPE_TAMA_60HZ },
312*22de25f8SKonrad Dybcio 	{ /* sentinel */ }
313*22de25f8SKonrad Dybcio };
314*22de25f8SKonrad Dybcio MODULE_DEVICE_TABLE(of, sony_td4353_jdi_of_match);
315*22de25f8SKonrad Dybcio 
316*22de25f8SKonrad Dybcio static struct mipi_dsi_driver sony_td4353_jdi_driver = {
317*22de25f8SKonrad Dybcio 	.probe = sony_td4353_jdi_probe,
318*22de25f8SKonrad Dybcio 	.remove = sony_td4353_jdi_remove,
319*22de25f8SKonrad Dybcio 	.driver = {
320*22de25f8SKonrad Dybcio 		.name = "panel-sony-td4353-jdi",
321*22de25f8SKonrad Dybcio 		.of_match_table = sony_td4353_jdi_of_match,
322*22de25f8SKonrad Dybcio 	},
323*22de25f8SKonrad Dybcio };
324*22de25f8SKonrad Dybcio module_mipi_dsi_driver(sony_td4353_jdi_driver);
325*22de25f8SKonrad Dybcio 
326*22de25f8SKonrad Dybcio MODULE_AUTHOR("Konrad Dybcio <konrad.dybcio@somainline.org>");
327*22de25f8SKonrad Dybcio MODULE_DESCRIPTION("DRM panel driver for SONY Xperia XZ2/XZ2c JDI panel");
328*22de25f8SKonrad Dybcio MODULE_LICENSE("GPL");
329