1*9a314ea5SDavid Wronek // SPDX-License-Identifier: GPL-2.0-only
2*9a314ea5SDavid Wronek /*
3*9a314ea5SDavid Wronek * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree.
4*9a314ea5SDavid Wronek * Copyright (c) 2024 David Wronek <david@mainlining.org>
5*9a314ea5SDavid Wronek */
6*9a314ea5SDavid Wronek
7*9a314ea5SDavid Wronek #include <linux/backlight.h>
8*9a314ea5SDavid Wronek #include <linux/delay.h>
9*9a314ea5SDavid Wronek #include <linux/gpio/consumer.h>
10*9a314ea5SDavid Wronek #include <linux/module.h>
11*9a314ea5SDavid Wronek #include <linux/of.h>
12*9a314ea5SDavid Wronek #include <linux/of_device.h>
13*9a314ea5SDavid Wronek #include <linux/of_graph.h>
14*9a314ea5SDavid Wronek #include <linux/regulator/consumer.h>
15*9a314ea5SDavid Wronek
16*9a314ea5SDavid Wronek #include <video/mipi_display.h>
17*9a314ea5SDavid Wronek
18*9a314ea5SDavid Wronek #include <drm/drm_mipi_dsi.h>
19*9a314ea5SDavid Wronek #include <drm/drm_modes.h>
20*9a314ea5SDavid Wronek #include <drm/drm_panel.h>
21*9a314ea5SDavid Wronek #include <drm/drm_probe_helper.h>
22*9a314ea5SDavid Wronek
23*9a314ea5SDavid Wronek struct rm69380_panel {
24*9a314ea5SDavid Wronek struct drm_panel panel;
25*9a314ea5SDavid Wronek struct mipi_dsi_device *dsi[2];
26*9a314ea5SDavid Wronek struct regulator_bulk_data supplies[2];
27*9a314ea5SDavid Wronek struct gpio_desc *reset_gpio;
28*9a314ea5SDavid Wronek };
29*9a314ea5SDavid Wronek
30*9a314ea5SDavid Wronek static inline
to_rm69380_panel(struct drm_panel * panel)31*9a314ea5SDavid Wronek struct rm69380_panel *to_rm69380_panel(struct drm_panel *panel)
32*9a314ea5SDavid Wronek {
33*9a314ea5SDavid Wronek return container_of(panel, struct rm69380_panel, panel);
34*9a314ea5SDavid Wronek }
35*9a314ea5SDavid Wronek
rm69380_reset(struct rm69380_panel * ctx)36*9a314ea5SDavid Wronek static void rm69380_reset(struct rm69380_panel *ctx)
37*9a314ea5SDavid Wronek {
38*9a314ea5SDavid Wronek gpiod_set_value_cansleep(ctx->reset_gpio, 0);
39*9a314ea5SDavid Wronek usleep_range(15000, 16000);
40*9a314ea5SDavid Wronek gpiod_set_value_cansleep(ctx->reset_gpio, 1);
41*9a314ea5SDavid Wronek usleep_range(10000, 11000);
42*9a314ea5SDavid Wronek gpiod_set_value_cansleep(ctx->reset_gpio, 0);
43*9a314ea5SDavid Wronek msleep(30);
44*9a314ea5SDavid Wronek }
45*9a314ea5SDavid Wronek
rm69380_on(struct rm69380_panel * ctx)46*9a314ea5SDavid Wronek static int rm69380_on(struct rm69380_panel *ctx)
47*9a314ea5SDavid Wronek {
48*9a314ea5SDavid Wronek struct mipi_dsi_device *dsi = ctx->dsi[0];
49*9a314ea5SDavid Wronek struct device *dev = &dsi->dev;
50*9a314ea5SDavid Wronek int ret;
51*9a314ea5SDavid Wronek
52*9a314ea5SDavid Wronek dsi->mode_flags |= MIPI_DSI_MODE_LPM;
53*9a314ea5SDavid Wronek if (ctx->dsi[1])
54*9a314ea5SDavid Wronek ctx->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
55*9a314ea5SDavid Wronek
56*9a314ea5SDavid Wronek mipi_dsi_dcs_write_seq(dsi, 0xfe, 0xd4);
57*9a314ea5SDavid Wronek mipi_dsi_dcs_write_seq(dsi, 0x00, 0x80);
58*9a314ea5SDavid Wronek mipi_dsi_dcs_write_seq(dsi, 0xfe, 0xd0);
59*9a314ea5SDavid Wronek mipi_dsi_dcs_write_seq(dsi, 0x48, 0x00);
60*9a314ea5SDavid Wronek mipi_dsi_dcs_write_seq(dsi, 0xfe, 0x26);
61*9a314ea5SDavid Wronek mipi_dsi_dcs_write_seq(dsi, 0x75, 0x3f);
62*9a314ea5SDavid Wronek mipi_dsi_dcs_write_seq(dsi, 0x1d, 0x1a);
63*9a314ea5SDavid Wronek mipi_dsi_dcs_write_seq(dsi, 0xfe, 0x00);
64*9a314ea5SDavid Wronek mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x28);
65*9a314ea5SDavid Wronek mipi_dsi_dcs_write_seq(dsi, 0xc2, 0x08);
66*9a314ea5SDavid Wronek
67*9a314ea5SDavid Wronek ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
68*9a314ea5SDavid Wronek if (ret < 0) {
69*9a314ea5SDavid Wronek dev_err(dev, "Failed to set tear on: %d\n", ret);
70*9a314ea5SDavid Wronek return ret;
71*9a314ea5SDavid Wronek }
72*9a314ea5SDavid Wronek
73*9a314ea5SDavid Wronek ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
74*9a314ea5SDavid Wronek if (ret < 0) {
75*9a314ea5SDavid Wronek dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
76*9a314ea5SDavid Wronek return ret;
77*9a314ea5SDavid Wronek }
78*9a314ea5SDavid Wronek msleep(20);
79*9a314ea5SDavid Wronek
80*9a314ea5SDavid Wronek ret = mipi_dsi_dcs_set_display_on(dsi);
81*9a314ea5SDavid Wronek if (ret < 0) {
82*9a314ea5SDavid Wronek dev_err(dev, "Failed to set display on: %d\n", ret);
83*9a314ea5SDavid Wronek return ret;
84*9a314ea5SDavid Wronek }
85*9a314ea5SDavid Wronek msleep(36);
86*9a314ea5SDavid Wronek
87*9a314ea5SDavid Wronek return 0;
88*9a314ea5SDavid Wronek }
89*9a314ea5SDavid Wronek
rm69380_off(struct rm69380_panel * ctx)90*9a314ea5SDavid Wronek static int rm69380_off(struct rm69380_panel *ctx)
91*9a314ea5SDavid Wronek {
92*9a314ea5SDavid Wronek struct mipi_dsi_device *dsi = ctx->dsi[0];
93*9a314ea5SDavid Wronek struct device *dev = &dsi->dev;
94*9a314ea5SDavid Wronek int ret;
95*9a314ea5SDavid Wronek
96*9a314ea5SDavid Wronek dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
97*9a314ea5SDavid Wronek if (ctx->dsi[1])
98*9a314ea5SDavid Wronek ctx->dsi[1]->mode_flags &= ~MIPI_DSI_MODE_LPM;
99*9a314ea5SDavid Wronek
100*9a314ea5SDavid Wronek ret = mipi_dsi_dcs_set_display_off(dsi);
101*9a314ea5SDavid Wronek if (ret < 0) {
102*9a314ea5SDavid Wronek dev_err(dev, "Failed to set display off: %d\n", ret);
103*9a314ea5SDavid Wronek return ret;
104*9a314ea5SDavid Wronek }
105*9a314ea5SDavid Wronek msleep(35);
106*9a314ea5SDavid Wronek
107*9a314ea5SDavid Wronek ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
108*9a314ea5SDavid Wronek if (ret < 0) {
109*9a314ea5SDavid Wronek dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
110*9a314ea5SDavid Wronek return ret;
111*9a314ea5SDavid Wronek }
112*9a314ea5SDavid Wronek msleep(20);
113*9a314ea5SDavid Wronek
114*9a314ea5SDavid Wronek return 0;
115*9a314ea5SDavid Wronek }
116*9a314ea5SDavid Wronek
rm69380_prepare(struct drm_panel * panel)117*9a314ea5SDavid Wronek static int rm69380_prepare(struct drm_panel *panel)
118*9a314ea5SDavid Wronek {
119*9a314ea5SDavid Wronek struct rm69380_panel *ctx = to_rm69380_panel(panel);
120*9a314ea5SDavid Wronek struct device *dev = &ctx->dsi[0]->dev;
121*9a314ea5SDavid Wronek int ret;
122*9a314ea5SDavid Wronek
123*9a314ea5SDavid Wronek ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
124*9a314ea5SDavid Wronek if (ret < 0) {
125*9a314ea5SDavid Wronek dev_err(dev, "Failed to enable regulators: %d\n", ret);
126*9a314ea5SDavid Wronek return ret;
127*9a314ea5SDavid Wronek }
128*9a314ea5SDavid Wronek
129*9a314ea5SDavid Wronek rm69380_reset(ctx);
130*9a314ea5SDavid Wronek
131*9a314ea5SDavid Wronek ret = rm69380_on(ctx);
132*9a314ea5SDavid Wronek if (ret < 0) {
133*9a314ea5SDavid Wronek dev_err(dev, "Failed to initialize panel: %d\n", ret);
134*9a314ea5SDavid Wronek gpiod_set_value_cansleep(ctx->reset_gpio, 1);
135*9a314ea5SDavid Wronek regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
136*9a314ea5SDavid Wronek return ret;
137*9a314ea5SDavid Wronek }
138*9a314ea5SDavid Wronek
139*9a314ea5SDavid Wronek return 0;
140*9a314ea5SDavid Wronek }
141*9a314ea5SDavid Wronek
rm69380_unprepare(struct drm_panel * panel)142*9a314ea5SDavid Wronek static int rm69380_unprepare(struct drm_panel *panel)
143*9a314ea5SDavid Wronek {
144*9a314ea5SDavid Wronek struct rm69380_panel *ctx = to_rm69380_panel(panel);
145*9a314ea5SDavid Wronek struct device *dev = &ctx->dsi[0]->dev;
146*9a314ea5SDavid Wronek int ret;
147*9a314ea5SDavid Wronek
148*9a314ea5SDavid Wronek ret = rm69380_off(ctx);
149*9a314ea5SDavid Wronek if (ret < 0)
150*9a314ea5SDavid Wronek dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
151*9a314ea5SDavid Wronek
152*9a314ea5SDavid Wronek gpiod_set_value_cansleep(ctx->reset_gpio, 1);
153*9a314ea5SDavid Wronek regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
154*9a314ea5SDavid Wronek
155*9a314ea5SDavid Wronek return 0;
156*9a314ea5SDavid Wronek }
157*9a314ea5SDavid Wronek
158*9a314ea5SDavid Wronek static const struct drm_display_mode rm69380_mode = {
159*9a314ea5SDavid Wronek .clock = (2560 + 32 + 12 + 38) * (1600 + 20 + 4 + 8) * 90 / 1000,
160*9a314ea5SDavid Wronek .hdisplay = 2560,
161*9a314ea5SDavid Wronek .hsync_start = 2560 + 32,
162*9a314ea5SDavid Wronek .hsync_end = 2560 + 32 + 12,
163*9a314ea5SDavid Wronek .htotal = 2560 + 32 + 12 + 38,
164*9a314ea5SDavid Wronek .vdisplay = 1600,
165*9a314ea5SDavid Wronek .vsync_start = 1600 + 20,
166*9a314ea5SDavid Wronek .vsync_end = 1600 + 20 + 4,
167*9a314ea5SDavid Wronek .vtotal = 1600 + 20 + 4 + 8,
168*9a314ea5SDavid Wronek .width_mm = 248,
169*9a314ea5SDavid Wronek .height_mm = 155,
170*9a314ea5SDavid Wronek .type = DRM_MODE_TYPE_DRIVER,
171*9a314ea5SDavid Wronek };
172*9a314ea5SDavid Wronek
rm69380_get_modes(struct drm_panel * panel,struct drm_connector * connector)173*9a314ea5SDavid Wronek static int rm69380_get_modes(struct drm_panel *panel,
174*9a314ea5SDavid Wronek struct drm_connector *connector)
175*9a314ea5SDavid Wronek {
176*9a314ea5SDavid Wronek return drm_connector_helper_get_modes_fixed(connector, &rm69380_mode);
177*9a314ea5SDavid Wronek }
178*9a314ea5SDavid Wronek
179*9a314ea5SDavid Wronek static const struct drm_panel_funcs rm69380_panel_funcs = {
180*9a314ea5SDavid Wronek .prepare = rm69380_prepare,
181*9a314ea5SDavid Wronek .unprepare = rm69380_unprepare,
182*9a314ea5SDavid Wronek .get_modes = rm69380_get_modes,
183*9a314ea5SDavid Wronek };
184*9a314ea5SDavid Wronek
rm69380_bl_update_status(struct backlight_device * bl)185*9a314ea5SDavid Wronek static int rm69380_bl_update_status(struct backlight_device *bl)
186*9a314ea5SDavid Wronek {
187*9a314ea5SDavid Wronek struct mipi_dsi_device *dsi = bl_get_data(bl);
188*9a314ea5SDavid Wronek u16 brightness = backlight_get_brightness(bl);
189*9a314ea5SDavid Wronek int ret;
190*9a314ea5SDavid Wronek
191*9a314ea5SDavid Wronek dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
192*9a314ea5SDavid Wronek
193*9a314ea5SDavid Wronek ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
194*9a314ea5SDavid Wronek if (ret < 0)
195*9a314ea5SDavid Wronek return ret;
196*9a314ea5SDavid Wronek
197*9a314ea5SDavid Wronek dsi->mode_flags |= MIPI_DSI_MODE_LPM;
198*9a314ea5SDavid Wronek
199*9a314ea5SDavid Wronek return 0;
200*9a314ea5SDavid Wronek }
201*9a314ea5SDavid Wronek
rm69380_bl_get_brightness(struct backlight_device * bl)202*9a314ea5SDavid Wronek static int rm69380_bl_get_brightness(struct backlight_device *bl)
203*9a314ea5SDavid Wronek {
204*9a314ea5SDavid Wronek struct mipi_dsi_device *dsi = bl_get_data(bl);
205*9a314ea5SDavid Wronek u16 brightness;
206*9a314ea5SDavid Wronek int ret;
207*9a314ea5SDavid Wronek
208*9a314ea5SDavid Wronek dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
209*9a314ea5SDavid Wronek
210*9a314ea5SDavid Wronek ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness);
211*9a314ea5SDavid Wronek if (ret < 0)
212*9a314ea5SDavid Wronek return ret;
213*9a314ea5SDavid Wronek
214*9a314ea5SDavid Wronek dsi->mode_flags |= MIPI_DSI_MODE_LPM;
215*9a314ea5SDavid Wronek
216*9a314ea5SDavid Wronek return brightness;
217*9a314ea5SDavid Wronek }
218*9a314ea5SDavid Wronek
219*9a314ea5SDavid Wronek static const struct backlight_ops rm69380_bl_ops = {
220*9a314ea5SDavid Wronek .update_status = rm69380_bl_update_status,
221*9a314ea5SDavid Wronek .get_brightness = rm69380_bl_get_brightness,
222*9a314ea5SDavid Wronek };
223*9a314ea5SDavid Wronek
224*9a314ea5SDavid Wronek static struct backlight_device *
rm69380_create_backlight(struct mipi_dsi_device * dsi)225*9a314ea5SDavid Wronek rm69380_create_backlight(struct mipi_dsi_device *dsi)
226*9a314ea5SDavid Wronek {
227*9a314ea5SDavid Wronek struct device *dev = &dsi->dev;
228*9a314ea5SDavid Wronek const struct backlight_properties props = {
229*9a314ea5SDavid Wronek .type = BACKLIGHT_RAW,
230*9a314ea5SDavid Wronek .brightness = 511,
231*9a314ea5SDavid Wronek .max_brightness = 2047,
232*9a314ea5SDavid Wronek };
233*9a314ea5SDavid Wronek
234*9a314ea5SDavid Wronek return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
235*9a314ea5SDavid Wronek &rm69380_bl_ops, &props);
236*9a314ea5SDavid Wronek }
237*9a314ea5SDavid Wronek
rm69380_probe(struct mipi_dsi_device * dsi)238*9a314ea5SDavid Wronek static int rm69380_probe(struct mipi_dsi_device *dsi)
239*9a314ea5SDavid Wronek {
240*9a314ea5SDavid Wronek struct mipi_dsi_host *dsi_sec_host;
241*9a314ea5SDavid Wronek struct rm69380_panel *ctx;
242*9a314ea5SDavid Wronek struct device *dev = &dsi->dev;
243*9a314ea5SDavid Wronek struct device_node *dsi_sec;
244*9a314ea5SDavid Wronek int ret, i;
245*9a314ea5SDavid Wronek
246*9a314ea5SDavid Wronek ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
247*9a314ea5SDavid Wronek if (!ctx)
248*9a314ea5SDavid Wronek return -ENOMEM;
249*9a314ea5SDavid Wronek
250*9a314ea5SDavid Wronek ctx->supplies[0].supply = "vddio";
251*9a314ea5SDavid Wronek ctx->supplies[1].supply = "avdd";
252*9a314ea5SDavid Wronek ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
253*9a314ea5SDavid Wronek ctx->supplies);
254*9a314ea5SDavid Wronek if (ret < 0)
255*9a314ea5SDavid Wronek return dev_err_probe(dev, ret, "Failed to get regulators\n");
256*9a314ea5SDavid Wronek
257*9a314ea5SDavid Wronek ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
258*9a314ea5SDavid Wronek if (IS_ERR(ctx->reset_gpio))
259*9a314ea5SDavid Wronek return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
260*9a314ea5SDavid Wronek "Failed to get reset-gpios\n");
261*9a314ea5SDavid Wronek
262*9a314ea5SDavid Wronek dsi_sec = of_graph_get_remote_node(dsi->dev.of_node, 1, -1);
263*9a314ea5SDavid Wronek
264*9a314ea5SDavid Wronek if (dsi_sec) {
265*9a314ea5SDavid Wronek const struct mipi_dsi_device_info info = { "RM69380 DSI1", 0,
266*9a314ea5SDavid Wronek dsi_sec };
267*9a314ea5SDavid Wronek
268*9a314ea5SDavid Wronek dsi_sec_host = of_find_mipi_dsi_host_by_node(dsi_sec);
269*9a314ea5SDavid Wronek of_node_put(dsi_sec);
270*9a314ea5SDavid Wronek if (!dsi_sec_host)
271*9a314ea5SDavid Wronek return dev_err_probe(dev, -EPROBE_DEFER,
272*9a314ea5SDavid Wronek "Cannot get secondary DSI host\n");
273*9a314ea5SDavid Wronek
274*9a314ea5SDavid Wronek ctx->dsi[1] =
275*9a314ea5SDavid Wronek devm_mipi_dsi_device_register_full(dev, dsi_sec_host, &info);
276*9a314ea5SDavid Wronek if (IS_ERR(ctx->dsi[1]))
277*9a314ea5SDavid Wronek return dev_err_probe(dev, PTR_ERR(ctx->dsi[1]),
278*9a314ea5SDavid Wronek "Cannot get secondary DSI node\n");
279*9a314ea5SDavid Wronek
280*9a314ea5SDavid Wronek mipi_dsi_set_drvdata(ctx->dsi[1], ctx);
281*9a314ea5SDavid Wronek }
282*9a314ea5SDavid Wronek
283*9a314ea5SDavid Wronek ctx->dsi[0] = dsi;
284*9a314ea5SDavid Wronek mipi_dsi_set_drvdata(dsi, ctx);
285*9a314ea5SDavid Wronek
286*9a314ea5SDavid Wronek drm_panel_init(&ctx->panel, dev, &rm69380_panel_funcs,
287*9a314ea5SDavid Wronek DRM_MODE_CONNECTOR_DSI);
288*9a314ea5SDavid Wronek ctx->panel.prepare_prev_first = true;
289*9a314ea5SDavid Wronek
290*9a314ea5SDavid Wronek ctx->panel.backlight = rm69380_create_backlight(dsi);
291*9a314ea5SDavid Wronek if (IS_ERR(ctx->panel.backlight))
292*9a314ea5SDavid Wronek return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
293*9a314ea5SDavid Wronek "Failed to create backlight\n");
294*9a314ea5SDavid Wronek
295*9a314ea5SDavid Wronek drm_panel_add(&ctx->panel);
296*9a314ea5SDavid Wronek
297*9a314ea5SDavid Wronek for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
298*9a314ea5SDavid Wronek if (!ctx->dsi[i])
299*9a314ea5SDavid Wronek continue;
300*9a314ea5SDavid Wronek
301*9a314ea5SDavid Wronek dev_dbg(&ctx->dsi[i]->dev, "Binding DSI %d\n", i);
302*9a314ea5SDavid Wronek
303*9a314ea5SDavid Wronek ctx->dsi[i]->lanes = 4;
304*9a314ea5SDavid Wronek ctx->dsi[i]->format = MIPI_DSI_FMT_RGB888;
305*9a314ea5SDavid Wronek ctx->dsi[i]->mode_flags = MIPI_DSI_MODE_VIDEO_BURST |
306*9a314ea5SDavid Wronek MIPI_DSI_CLOCK_NON_CONTINUOUS;
307*9a314ea5SDavid Wronek
308*9a314ea5SDavid Wronek ret = devm_mipi_dsi_attach(dev, ctx->dsi[i]);
309*9a314ea5SDavid Wronek if (ret < 0) {
310*9a314ea5SDavid Wronek drm_panel_remove(&ctx->panel);
311*9a314ea5SDavid Wronek return dev_err_probe(dev, ret,
312*9a314ea5SDavid Wronek "Failed to attach to DSI%d\n", i);
313*9a314ea5SDavid Wronek }
314*9a314ea5SDavid Wronek }
315*9a314ea5SDavid Wronek
316*9a314ea5SDavid Wronek return 0;
317*9a314ea5SDavid Wronek }
318*9a314ea5SDavid Wronek
rm69380_remove(struct mipi_dsi_device * dsi)319*9a314ea5SDavid Wronek static void rm69380_remove(struct mipi_dsi_device *dsi)
320*9a314ea5SDavid Wronek {
321*9a314ea5SDavid Wronek struct rm69380_panel *ctx = mipi_dsi_get_drvdata(dsi);
322*9a314ea5SDavid Wronek
323*9a314ea5SDavid Wronek drm_panel_remove(&ctx->panel);
324*9a314ea5SDavid Wronek }
325*9a314ea5SDavid Wronek
326*9a314ea5SDavid Wronek static const struct of_device_id rm69380_of_match[] = {
327*9a314ea5SDavid Wronek { .compatible = "lenovo,j716f-edo-rm69380" },
328*9a314ea5SDavid Wronek { /* sentinel */ }
329*9a314ea5SDavid Wronek };
330*9a314ea5SDavid Wronek MODULE_DEVICE_TABLE(of, rm69380_of_match);
331*9a314ea5SDavid Wronek
332*9a314ea5SDavid Wronek static struct mipi_dsi_driver rm69380_panel_driver = {
333*9a314ea5SDavid Wronek .probe = rm69380_probe,
334*9a314ea5SDavid Wronek .remove = rm69380_remove,
335*9a314ea5SDavid Wronek .driver = {
336*9a314ea5SDavid Wronek .name = "panel-raydium-rm69380",
337*9a314ea5SDavid Wronek .of_match_table = rm69380_of_match,
338*9a314ea5SDavid Wronek },
339*9a314ea5SDavid Wronek };
340*9a314ea5SDavid Wronek module_mipi_dsi_driver(rm69380_panel_driver);
341*9a314ea5SDavid Wronek
342*9a314ea5SDavid Wronek MODULE_AUTHOR("David Wronek <david@mainlining.org");
343*9a314ea5SDavid Wronek MODULE_DESCRIPTION("DRM driver for Raydium RM69380-equipped DSI panels");
344*9a314ea5SDavid Wronek MODULE_LICENSE("GPL");
345