1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree.
4 * Copyright (c) 2025 Luca Weiss <luca@lucaweiss.eu>
5 */
6
7 #include <linux/backlight.h>
8 #include <linux/delay.h>
9 #include <linux/gpio/consumer.h>
10 #include <linux/module.h>
11 #include <linux/regulator/consumer.h>
12
13 #include <video/mipi_display.h>
14
15 #include <drm/drm_mipi_dsi.h>
16 #include <drm/drm_modes.h>
17 #include <drm/drm_panel.h>
18 #include <drm/drm_probe_helper.h>
19
20 /* Manufacturer specific DSI commands */
21 #define HX83112B_SETPOWER1 0xb1
22 #define HX83112B_SETDISP 0xb2
23 #define HX83112B_SETDRV 0xb4
24 #define HX83112B_SETEXTC 0xb9
25 #define HX83112B_SETBANK 0xbd
26 #define HX83112B_SETDGCLUT 0xc1
27 #define HX83112B_SETDISMO 0xc2
28 #define HX83112B_UNKNOWN1 0xc6
29 #define HX83112B_SETPANEL 0xcc
30 #define HX83112B_UNKNOWN2 0xd1
31 #define HX83112B_SETPOWER2 0xd2
32 #define HX83112B_SETGIP0 0xd3
33 #define HX83112B_SETGIP1 0xd5
34 #define HX83112B_SETGIP2 0xd6
35 #define HX83112B_SETGIP3 0xd8
36 #define HX83112B_SETIDLE 0xdd
37 #define HX83112B_UNKNOWN3 0xe7
38 #define HX83112B_UNKNOWN4 0xe9
39
40 struct hx83112b_panel {
41 struct drm_panel panel;
42 struct mipi_dsi_device *dsi;
43 struct regulator_bulk_data *supplies;
44 struct gpio_desc *reset_gpio;
45 };
46
47 static const struct regulator_bulk_data hx83112b_supplies[] = {
48 { .supply = "iovcc" },
49 { .supply = "vsn" },
50 { .supply = "vsp" },
51 };
52
to_hx83112b_panel(struct drm_panel * panel)53 static inline struct hx83112b_panel *to_hx83112b_panel(struct drm_panel *panel)
54 {
55 return container_of(panel, struct hx83112b_panel, panel);
56 }
57
hx83112b_reset(struct hx83112b_panel * ctx)58 static void hx83112b_reset(struct hx83112b_panel *ctx)
59 {
60 gpiod_set_value_cansleep(ctx->reset_gpio, 0);
61 usleep_range(10000, 11000);
62 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
63 usleep_range(10000, 11000);
64 gpiod_set_value_cansleep(ctx->reset_gpio, 0);
65 usleep_range(10000, 11000);
66 }
67
hx83112b_on(struct hx83112b_panel * ctx)68 static int hx83112b_on(struct hx83112b_panel *ctx)
69 {
70 struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
71
72 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETEXTC, 0x83, 0x11, 0x2b);
73 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01);
74 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISMO, 0x08, 0x70);
75 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03);
76 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0x04, 0x38, 0x08, 0x70);
77 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
78 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPOWER1,
79 0xf8, 0x27, 0x27, 0x00, 0x00, 0x0b, 0x0e,
80 0x0b, 0x0e, 0x33);
81 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPOWER2, 0x2d, 0x2d);
82 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP,
83 0x80, 0x02, 0x18, 0x80, 0x70, 0x00, 0x08,
84 0x1c, 0x08, 0x11, 0x05);
85 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xd1);
86 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0x00, 0x08);
87 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
88 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02);
89 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0xb5, 0x0a);
90 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
91 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETIDLE,
92 0x00, 0x00, 0x08, 0x1c, 0x08, 0x34, 0x34,
93 0x88);
94 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDRV,
95 0x65, 0x6b, 0x00, 0x00, 0xd0, 0xd4, 0x36,
96 0xcf, 0x06, 0xce, 0x00, 0xce, 0x00, 0x00,
97 0x00, 0x07, 0x00, 0x2a, 0x07, 0x01, 0x07,
98 0x00, 0x00, 0x2a);
99 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03);
100 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc3);
101 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDRV, 0x01, 0x67, 0x2a);
102 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
103 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
104 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, 0x01);
105 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01);
106 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT,
107 0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef,
108 0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda,
109 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe,
110 0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85,
111 0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e,
112 0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07,
113 0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25,
114 0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b,
115 0x00);
116 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02);
117 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT,
118 0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef,
119 0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda,
120 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe,
121 0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85,
122 0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e,
123 0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07,
124 0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25,
125 0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b,
126 0x00);
127 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03);
128 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT,
129 0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef,
130 0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda,
131 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe,
132 0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85,
133 0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e,
134 0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07,
135 0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25,
136 0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b,
137 0x00);
138 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
139 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISMO, 0xc8);
140 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPANEL, 0x08);
141 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0,
142 0x81, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
143 0x04, 0x00, 0x01, 0x13, 0x40, 0x04, 0x09,
144 0x09, 0x0b, 0x0b, 0x32, 0x10, 0x08, 0x00,
145 0x08, 0x32, 0x10, 0x08, 0x00, 0x08, 0x32,
146 0x10, 0x08, 0x00, 0x08, 0x00, 0x00, 0x0a,
147 0x08, 0x7b);
148 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc5);
149 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN1, 0xf7);
150 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
151 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xd4);
152 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN1, 0x6e);
153 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
154 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xef);
155 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, 0x0c);
156 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
157 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01);
158 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc8);
159 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, 0xa1);
160 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
161 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
162 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP1,
163 0x18, 0x18, 0x19, 0x18, 0x18, 0x20, 0x18,
164 0x18, 0x18, 0x10, 0x10, 0x18, 0x18, 0x00,
165 0x00, 0x18, 0x18, 0x01, 0x01, 0x18, 0x18,
166 0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18,
167 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x35,
168 0x35, 0x36, 0x36, 0x37, 0x37, 0x18, 0x18,
169 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xfc,
170 0xfc, 0x00, 0x00, 0xfc, 0xfc, 0x00, 0x00);
171 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP2,
172 0x18, 0x18, 0x19, 0x18, 0x18, 0x20, 0x19,
173 0x18, 0x18, 0x10, 0x10, 0x18, 0x18, 0x00,
174 0x00, 0x18, 0x18, 0x01, 0x01, 0x18, 0x18,
175 0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18,
176 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x35,
177 0x35, 0x36, 0x36, 0x37, 0x37, 0x18, 0x18,
178 0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
179 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3,
180 0xaa, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa,
181 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 0xaa,
182 0xab, 0xaf, 0xef, 0xaa, 0xaa, 0xaa, 0xaa,
183 0xaf, 0xea, 0xaa);
184 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01);
185 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3,
186 0xaa, 0xaa, 0xab, 0xaf, 0xea, 0xaa, 0xaa,
187 0xaa, 0xae, 0xaf, 0xea, 0xaa);
188 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02);
189 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3,
190 0xaa, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa,
191 0xaa, 0xaa, 0xaf, 0xea, 0xaa);
192 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03);
193 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3,
194 0xba, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa,
195 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xba, 0xaa,
196 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 0xaa, 0xaa,
197 0xaf, 0xea, 0xaa);
198 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
199 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xe4);
200 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 0x17, 0x69);
201 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
202 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3,
203 0x09, 0x09, 0x00, 0x07, 0xe8, 0x00, 0x26,
204 0x00, 0x07, 0x00, 0x00, 0xe8, 0x32, 0x00,
205 0xe9, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x01,
206 0x01, 0x00, 0x12, 0x04);
207 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01);
208 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3,
209 0x02, 0x00, 0x01, 0x20, 0x01, 0x18, 0x08,
210 0xa8, 0x09);
211 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02);
212 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 0x20, 0x20, 0x00);
213 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03);
214 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3,
215 0x00, 0xdc, 0x11, 0x70, 0x00, 0x20);
216 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc9);
217 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3,
218 0x2a, 0xce, 0x02, 0x70, 0x01, 0x04);
219 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00);
220 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00);
221 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN2, 0x27);
222 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
223 mipi_dsi_msleep(&dsi_ctx, 120);
224 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
225 mipi_dsi_msleep(&dsi_ctx, 20);
226 mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x0000);
227 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY,
228 0x24);
229 mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
230
231 return dsi_ctx.accum_err;
232 }
233
hx83112b_off(struct hx83112b_panel * ctx)234 static int hx83112b_off(struct hx83112b_panel *ctx)
235 {
236 struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
237
238 mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
239 mipi_dsi_msleep(&dsi_ctx, 20);
240 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
241 mipi_dsi_msleep(&dsi_ctx, 120);
242
243 return dsi_ctx.accum_err;
244 }
245
hx83112b_prepare(struct drm_panel * panel)246 static int hx83112b_prepare(struct drm_panel *panel)
247 {
248 struct hx83112b_panel *ctx = to_hx83112b_panel(panel);
249 struct device *dev = &ctx->dsi->dev;
250 int ret;
251
252 ret = regulator_bulk_enable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies);
253 if (ret < 0) {
254 dev_err(dev, "Failed to enable regulators: %d\n", ret);
255 return ret;
256 }
257
258 hx83112b_reset(ctx);
259
260 ret = hx83112b_on(ctx);
261 if (ret < 0) {
262 dev_err(dev, "Failed to initialize panel: %d\n", ret);
263 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
264 regulator_bulk_disable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies);
265 return ret;
266 }
267
268 return 0;
269 }
270
hx83112b_unprepare(struct drm_panel * panel)271 static int hx83112b_unprepare(struct drm_panel *panel)
272 {
273 struct hx83112b_panel *ctx = to_hx83112b_panel(panel);
274 struct device *dev = &ctx->dsi->dev;
275 int ret;
276
277 ret = hx83112b_off(ctx);
278 if (ret < 0)
279 dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
280
281 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
282 regulator_bulk_disable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies);
283
284 return 0;
285 }
286
287 static const struct drm_display_mode hx83112b_mode = {
288 .clock = (1080 + 40 + 4 + 12) * (2160 + 32 + 2 + 2) * 60 / 1000,
289 .hdisplay = 1080,
290 .hsync_start = 1080 + 40,
291 .hsync_end = 1080 + 40 + 4,
292 .htotal = 1080 + 40 + 4 + 12,
293 .vdisplay = 2160,
294 .vsync_start = 2160 + 32,
295 .vsync_end = 2160 + 32 + 2,
296 .vtotal = 2160 + 32 + 2 + 2,
297 .width_mm = 65,
298 .height_mm = 128,
299 .type = DRM_MODE_TYPE_DRIVER,
300 };
301
hx83112b_get_modes(struct drm_panel * panel,struct drm_connector * connector)302 static int hx83112b_get_modes(struct drm_panel *panel,
303 struct drm_connector *connector)
304 {
305 return drm_connector_helper_get_modes_fixed(connector, &hx83112b_mode);
306 }
307
308 static const struct drm_panel_funcs hx83112b_panel_funcs = {
309 .prepare = hx83112b_prepare,
310 .unprepare = hx83112b_unprepare,
311 .get_modes = hx83112b_get_modes,
312 };
313
hx83112b_bl_update_status(struct backlight_device * bl)314 static int hx83112b_bl_update_status(struct backlight_device *bl)
315 {
316 struct mipi_dsi_device *dsi = bl_get_data(bl);
317 u16 brightness = backlight_get_brightness(bl);
318 int ret;
319
320 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
321
322 ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
323 if (ret < 0)
324 return ret;
325
326 dsi->mode_flags |= MIPI_DSI_MODE_LPM;
327
328 return 0;
329 }
330
331 static const struct backlight_ops hx83112b_bl_ops = {
332 .update_status = hx83112b_bl_update_status,
333 };
334
335 static struct backlight_device *
hx83112b_create_backlight(struct mipi_dsi_device * dsi)336 hx83112b_create_backlight(struct mipi_dsi_device *dsi)
337 {
338 struct device *dev = &dsi->dev;
339 const struct backlight_properties props = {
340 .type = BACKLIGHT_RAW,
341 .brightness = 4095,
342 .max_brightness = 4095,
343 };
344
345 return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
346 &hx83112b_bl_ops, &props);
347 }
348
hx83112b_probe(struct mipi_dsi_device * dsi)349 static int hx83112b_probe(struct mipi_dsi_device *dsi)
350 {
351 struct device *dev = &dsi->dev;
352 struct hx83112b_panel *ctx;
353 int ret;
354
355 ctx = devm_drm_panel_alloc(dev, struct hx83112b_panel, panel,
356 &hx83112b_panel_funcs,
357 DRM_MODE_CONNECTOR_DSI);
358 if (IS_ERR(ctx))
359 return PTR_ERR(ctx);
360
361 ret = devm_regulator_bulk_get_const(dev,
362 ARRAY_SIZE(hx83112b_supplies),
363 hx83112b_supplies,
364 &ctx->supplies);
365 if (ret < 0)
366 return ret;
367
368 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
369 if (IS_ERR(ctx->reset_gpio))
370 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
371 "Failed to get reset-gpios\n");
372
373 ctx->dsi = dsi;
374 mipi_dsi_set_drvdata(dsi, ctx);
375
376 dsi->lanes = 4;
377 dsi->format = MIPI_DSI_FMT_RGB888;
378 dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST |
379 MIPI_DSI_CLOCK_NON_CONTINUOUS |
380 MIPI_DSI_MODE_VIDEO_NO_HSA | MIPI_DSI_MODE_LPM;
381
382 ctx->panel.prepare_prev_first = true;
383
384 ctx->panel.backlight = hx83112b_create_backlight(dsi);
385 if (IS_ERR(ctx->panel.backlight))
386 return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
387 "Failed to create backlight\n");
388
389 drm_panel_add(&ctx->panel);
390
391 ret = mipi_dsi_attach(dsi);
392 if (ret < 0) {
393 drm_panel_remove(&ctx->panel);
394 return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
395 }
396
397 return 0;
398 }
399
hx83112b_remove(struct mipi_dsi_device * dsi)400 static void hx83112b_remove(struct mipi_dsi_device *dsi)
401 {
402 struct hx83112b_panel *ctx = mipi_dsi_get_drvdata(dsi);
403 int ret;
404
405 ret = mipi_dsi_detach(dsi);
406 if (ret < 0)
407 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
408
409 drm_panel_remove(&ctx->panel);
410 }
411
412 static const struct of_device_id hx83112b_of_match[] = {
413 { .compatible = "djn,98-03057-6598b-i" },
414 { /* sentinel */ }
415 };
416 MODULE_DEVICE_TABLE(of, hx83112b_of_match);
417
418 static struct mipi_dsi_driver hx83112b_driver = {
419 .probe = hx83112b_probe,
420 .remove = hx83112b_remove,
421 .driver = {
422 .name = "panel-himax-hx83112b",
423 .of_match_table = hx83112b_of_match,
424 },
425 };
426 module_mipi_dsi_driver(hx83112b_driver);
427
428 MODULE_DESCRIPTION("DRM driver for hx83112b-equipped DSI panels");
429 MODULE_LICENSE("GPL");
430