xref: /linux/drivers/gpu/drm/panel/panel-himax-hx83121a.c (revision 889600e21e3be388a6817c2a0dac0411df860751)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Himax HX83121A DriverIC panels driver
4  * Copyright (c) 2024-2026 Pengyu Luo <mitltlatltl@gmail.com>
5  *
6  * Multiple panels handling based on panel-novatek-nt36523.c
7  */
8 
9 #include <linux/backlight.h>
10 #include <linux/delay.h>
11 #include <linux/gpio/consumer.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/of_graph.h>
15 #include <linux/regulator/consumer.h>
16 
17 #include <drm/display/drm_dsc.h>
18 #include <drm/display/drm_dsc_helper.h>
19 #include <drm/drm_mipi_dsi.h>
20 #include <drm/drm_modes.h>
21 #include <drm/drm_panel.h>
22 
23 #include <video/mipi_display.h>
24 
25 static bool enable_dsc;
26 module_param(enable_dsc, bool, 0);
27 MODULE_PARM_DESC(enable_dsc, "enable DSC on the panel (default: false)");
28 
29 struct himax {
30 	struct drm_panel panel;
31 	struct mipi_dsi_device *dsi[2];
32 	const struct panel_desc *desc;
33 	struct drm_dsc_config dsc;
34 	struct gpio_desc *reset_gpio;
35 	struct regulator_bulk_data *supplies;
36 	struct regulator *bl_supply;
37 	struct backlight_device *backlight;
38 	bool backlight_enabled;
39 };
40 
41 struct panel_desc {
42 	unsigned int width_mm;
43 	unsigned int height_mm;
44 	unsigned int bpc;
45 	unsigned int lanes;
46 	enum mipi_dsi_pixel_format format;
47 	unsigned long mode_flags;
48 	const struct drm_dsc_config *dsc_cfg;
49 	const struct drm_display_mode *dsc_modes;
50 	unsigned int num_dsc_modes;
51 
52 	const struct drm_display_mode *modes;
53 	unsigned int num_modes;
54 
55 	int (*init_sequence_dsc)(struct mipi_dsi_multi_context *dsi_ctx);
56 	int (*init_sequence)(struct mipi_dsi_multi_context *dsi_ctx);
57 
58 	bool is_dual_dsi;
59 	bool has_dcs_backlight;
60 };
61 
62 static const struct regulator_bulk_data himax_supplies[] = {
63 	{ .supply = "vddi" },
64 	{ .supply = "avdd" },
65 	{ .supply = "avee" },
66 };
67 
to_himax(struct drm_panel * panel)68 static inline struct himax *to_himax(struct drm_panel *panel)
69 {
70 	return container_of(panel, struct himax, panel);
71 }
72 
to_primary_dsi(struct himax * ctx)73 static inline struct mipi_dsi_device *to_primary_dsi(struct himax *ctx)
74 {
75 	/* Sync on DSI1 for dual dsi */
76 	return ctx->desc->is_dual_dsi ? ctx->dsi[1] : ctx->dsi[0];
77 }
78 
himax_reset(struct himax * ctx)79 static void himax_reset(struct himax *ctx)
80 {
81 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
82 	usleep_range(4000, 4100);
83 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
84 	msleep(20);
85 }
86 
himax_prepare(struct drm_panel * panel)87 static int himax_prepare(struct drm_panel *panel)
88 {
89 	struct himax *ctx = to_himax(panel);
90 	struct mipi_dsi_device *dsi = to_primary_dsi(ctx);
91 	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
92 	struct drm_dsc_picture_parameter_set pps;
93 	int ret;
94 
95 	ret = regulator_bulk_enable(ARRAY_SIZE(himax_supplies),
96 				    ctx->supplies);
97 	if (ret < 0)
98 		return ret;
99 
100 	himax_reset(ctx);
101 
102 	if (enable_dsc && ctx->desc->init_sequence_dsc)
103 		ret = ctx->desc->init_sequence_dsc(&dsi_ctx);
104 	else if (ctx->desc->init_sequence)
105 		ret = ctx->desc->init_sequence(&dsi_ctx);
106 	else
107 		ret = -EOPNOTSUPP;
108 
109 	if (ret < 0) {
110 		gpiod_set_value_cansleep(ctx->reset_gpio, 1);
111 		regulator_bulk_disable(ARRAY_SIZE(himax_supplies),
112 				       ctx->supplies);
113 		return ret;
114 	}
115 
116 	if (enable_dsc) {
117 		drm_dsc_pps_payload_pack(&pps, &ctx->dsc);
118 		mipi_dsi_picture_parameter_set_multi(&dsi_ctx, &pps);
119 		mipi_dsi_compression_mode_multi(&dsi_ctx, true);
120 	}
121 
122 	return backlight_enable(ctx->backlight);
123 }
124 
himax_off(struct mipi_dsi_multi_context * dsi_ctx)125 static int himax_off(struct mipi_dsi_multi_context *dsi_ctx)
126 {
127 	mipi_dsi_dcs_enter_sleep_mode_multi(dsi_ctx);
128 	mipi_dsi_msleep(dsi_ctx, 120);
129 
130 	return dsi_ctx->accum_err;
131 }
132 
himax_unprepare(struct drm_panel * panel)133 static int himax_unprepare(struct drm_panel *panel)
134 {
135 	struct himax *ctx = to_himax(panel);
136 	struct mipi_dsi_device *dsi = to_primary_dsi(ctx);
137 	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
138 	struct device *dev = &dsi->dev;
139 	int ret;
140 
141 	ret = himax_off(&dsi_ctx);
142 	if (ret < 0)
143 		dev_err(dev, "panel failed to off: %d\n", ret);
144 
145 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
146 	regulator_bulk_disable(ARRAY_SIZE(himax_supplies), ctx->supplies);
147 
148 	return 0;
149 }
150 
himax_get_modes(struct drm_panel * panel,struct drm_connector * connector)151 static int himax_get_modes(struct drm_panel *panel,
152 			   struct drm_connector *connector)
153 {
154 	struct himax *ctx = to_himax(panel);
155 	const struct panel_desc *desc = ctx->desc;
156 	const struct drm_display_mode *modes;
157 	int num_modes;
158 	int i;
159 
160 	modes = enable_dsc ? desc->dsc_modes : desc->modes;
161 	num_modes = enable_dsc ? desc->num_dsc_modes : desc->num_modes;
162 
163 	for (i = 0; i < num_modes; i++) {
164 		const struct drm_display_mode *m = &modes[i];
165 		struct drm_display_mode *mode;
166 
167 		mode = drm_mode_duplicate(connector->dev, m);
168 		if (!mode) {
169 			dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
170 				m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
171 			return -ENOMEM;
172 		}
173 
174 		mode->type = DRM_MODE_TYPE_DRIVER;
175 		if (i == 0)
176 			mode->type |= DRM_MODE_TYPE_PREFERRED;
177 
178 		drm_mode_set_name(mode);
179 		drm_mode_probed_add(connector, mode);
180 	}
181 
182 	connector->display_info.width_mm = desc->width_mm;
183 	connector->display_info.height_mm = desc->height_mm;
184 	connector->display_info.bpc = desc->bpc;
185 
186 	return num_modes;
187 }
188 
189 static const struct drm_panel_funcs himax_panel_funcs = {
190 	.prepare = himax_prepare,
191 	.unprepare = himax_unprepare,
192 	.get_modes = himax_get_modes,
193 };
194 
himax_bl_update_status(struct backlight_device * bl)195 static int himax_bl_update_status(struct backlight_device *bl)
196 {
197 	struct himax *ctx = bl_get_data(bl);
198 	u16 brightness = backlight_get_brightness(bl);
199 	int ret = 0;
200 
201 	if (!brightness) {
202 		if (ctx->backlight_enabled)
203 			ret = regulator_disable(ctx->bl_supply);
204 		if (ret)
205 			return ret;
206 
207 		ctx->backlight_enabled = false;
208 
209 		return 0;
210 	}
211 
212 	/* TODO: brightness to raw map table */
213 	if (!ctx->backlight_enabled)
214 		ret = regulator_enable(ctx->bl_supply);
215 	if (ret)
216 		return ret;
217 
218 	ctx->backlight_enabled = true;
219 
220 	return mipi_dsi_dcs_set_display_brightness_large(to_primary_dsi(ctx),
221 							 brightness);
222 }
223 
224 static const struct backlight_ops himax_bl_ops = {
225 	.options = BL_CORE_SUSPENDRESUME,
226 	.update_status = himax_bl_update_status,
227 };
228 
229 static struct backlight_device *
himax_create_backlight(struct himax * ctx)230 himax_create_backlight(struct himax *ctx)
231 {
232 	struct device *dev = &to_primary_dsi(ctx)->dev;
233 	const struct backlight_properties props = {
234 		.type = BACKLIGHT_RAW,
235 		.brightness = 512,
236 		.max_brightness = 4095,
237 		.scale = BACKLIGHT_SCALE_NON_LINEAR,
238 	};
239 
240 	return devm_backlight_device_register(dev, dev_name(dev), dev, ctx,
241 					      &himax_bl_ops, &props);
242 }
243 
boe_ppc357db1_4_dsc_init_seq(struct mipi_dsi_multi_context * dsi_ctx)244 static int boe_ppc357db1_4_dsc_init_seq(struct mipi_dsi_multi_context *dsi_ctx)
245 {
246 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x83, 0x12, 0x1a, 0x55, 0x00);
247 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
248 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x00);
249 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03);
250 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x01);
251 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
252 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc7);
253 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0x98);
254 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
255 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02);
256 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7,
257 				     0x01, 0x07, 0x01, 0x07, 0x01, 0x07, 0x06, 0x06,
258 				     0x06, 0x16, 0x00, 0x16, 0x81, 0x02, 0x40, 0x00,
259 				     0x1a, 0x4a, 0x05, 0x04, 0x03, 0x02, 0x01);
260 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01);
261 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc6);
262 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd2, 0x00, 0x30);
263 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
264 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc9);
265 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, 0x04);
266 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
267 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc6);
268 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x42);
269 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
270 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
271 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xd0);
272 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0xf5);
273 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
274 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xcd,
275 				     0x81, 0x00, 0x80, 0x77, 0x00, 0x01, 0x00);
276 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01);
277 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4,
278 				     0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1,
279 				     0xc7, 0xb2, 0xa0, 0x90, 0x81, 0x75, 0x69, 0x5f,
280 				     0x55, 0x4c, 0x44, 0x3d, 0x36, 0x2f, 0x2a, 0x24,
281 				     0x1e, 0x19, 0x14, 0x10, 0x09, 0x08, 0x07, 0x54,
282 				     0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55);
283 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03);
284 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4,
285 				     0xaa, 0xd4, 0xff, 0x2a, 0x55, 0x7f, 0xaa, 0xd4,
286 				     0xff, 0xea, 0xff, 0x03);
287 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
288 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc8);
289 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x25);
290 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
291 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x01, 0x35, 0x00);
292 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x5f);
293 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0x00, 0x00);
294 
295 	mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
296 	mipi_dsi_msleep(dsi_ctx, 140);
297 	mipi_dsi_dcs_set_display_on_multi(dsi_ctx);
298 
299 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01);
300 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
301 	mipi_dsi_msleep(dsi_ctx, 20);
302 
303 	return dsi_ctx->accum_err;
304 }
305 
boe_ppc357db1_4_init_seq(struct mipi_dsi_multi_context * dsi_ctx)306 static int boe_ppc357db1_4_init_seq(struct mipi_dsi_multi_context *dsi_ctx)
307 {
308 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x83, 0x12, 0x1a, 0x55, 0x00);
309 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
310 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd1, 0x37, 0x03, 0x0c, 0xfd);
311 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x20);
312 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03);
313 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x00);
314 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
315 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc7);
316 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0xa6);
317 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
318 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02);
319 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7,
320 				     0x01, 0x07, 0x01, 0x07, 0x01, 0x07, 0x06, 0x06,
321 				     0x06, 0x16, 0x00, 0x16, 0x81, 0x02, 0x40, 0x00,
322 				     0x1a, 0x4a, 0x05, 0x04, 0x03, 0x02, 0x01);
323 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2,
324 				     0x02, 0x68, 0x02, 0x68, 0x02, 0x68, 0x02, 0x68,
325 				     0x02, 0x6f, 0x03, 0x04, 0x2d, 0x09, 0x09, 0x00,
326 				     0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00,
327 				     0x01, 0x10, 0x10, 0x1c, 0x25, 0x3c, 0x00, 0x23,
328 				     0x5d, 0x02, 0x02, 0x00, 0x00, 0x58, 0x01, 0xac,
329 				     0x0f, 0xa9, 0x10, 0x00, 0x2d, 0x6f, 0x00, 0x70,
330 				     0x00, 0x0a, 0xcb, 0x01);
331 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01);
332 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc6);
333 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd2, 0x09, 0x85);
334 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
335 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc9);
336 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, 0x04);
337 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
338 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
339 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xd0);
340 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0xf5);
341 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
342 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01);
343 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4,
344 				     0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1,
345 				     0xc7, 0xb2, 0xa0, 0x90, 0x81, 0x75, 0x69, 0x5f,
346 				     0x55, 0x4c, 0x44, 0x3d, 0x36, 0x2f, 0x2a, 0x24,
347 				     0x1e, 0x19, 0x14, 0x10, 0x09, 0x08, 0x07, 0x54,
348 				     0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55);
349 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03);
350 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4,
351 				     0xaa, 0xd4, 0xff, 0x2a, 0x55, 0x7f, 0xaa, 0xd4,
352 				     0xff, 0xea, 0xff, 0x03);
353 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
354 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc8);
355 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x25);
356 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
357 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x01, 0x35, 0x00);
358 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x5f);
359 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0x00, 0x00);
360 
361 	mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
362 	mipi_dsi_msleep(dsi_ctx, 140);
363 	mipi_dsi_dcs_set_display_on_multi(dsi_ctx);
364 
365 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01);
366 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
367 	mipi_dsi_msleep(dsi_ctx, 31);
368 
369 	return dsi_ctx->accum_err;
370 }
371 
csot_ppc357db1_4_dsc_init_seq(struct mipi_dsi_multi_context * dsi_ctx)372 static int csot_ppc357db1_4_dsc_init_seq(struct mipi_dsi_multi_context *dsi_ctx)
373 {
374 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x83, 0x12, 0x1a, 0x55, 0x00);
375 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
376 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
377 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1,
378 				     0x1c, 0x6b, 0x6b, 0x27, 0xe7, 0x00, 0x1b, 0x25,
379 				     0x21, 0x21, 0x2d, 0x2d, 0x17, 0x33, 0x31, 0x40,
380 				     0xcd, 0xff, 0x1a, 0x05, 0x15, 0x98, 0x00, 0x88,
381 				     0x7f, 0xff, 0xff, 0xcf, 0x1a, 0xcc, 0x02, 0x00);
382 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd1, 0x37, 0x03, 0x0c, 0xfd);
383 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2,
384 				     0x00, 0x6a, 0x40, 0x00, 0x00, 0x14, 0x98, 0x60,
385 				     0x3c, 0x02, 0x80, 0x21, 0x21, 0x00, 0x00, 0xf0,
386 				     0x27);
387 	/*
388 	 * NOTE: Register 0xE2 configuration (based on downstream reference):
389 	 * - 0x00: 120Hz with DSC enabled
390 	 * - 0x10: 60Hz with DSC enabled
391 	 * - 0x20: 60Hz with DSC disabled
392 	 *
393 	 * Both 0x00 and 0x10 are compatible with 60Hz/120Hz when DSC is active.
394 	 * We use a fixed DSC-on value to remain refresh-rate agnostic.
395 	 */
396 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x00);
397 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc0, 0x23, 0x23, 0xcc, 0x22, 0x99, 0xd8);
398 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb4,
399 				     0x46, 0x06, 0x0c, 0xbe, 0x0c, 0xbe, 0x09, 0x46,
400 				     0x0f, 0x57, 0x0f, 0x57, 0x03, 0x4a, 0x00, 0x00,
401 				     0x04, 0x0c, 0x00, 0x18, 0x01, 0x06, 0x08, 0x00,
402 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
403 				     0x00, 0x00, 0xff, 0x00, 0xff, 0x10, 0x00, 0x02,
404 				     0x14, 0x14, 0x14, 0x14);
405 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03);
406 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x01, 0x3f);
407 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
408 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xe2);
409 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 0x49);
410 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
411 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3,
412 				     0x00, 0xc0, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04,
413 				     0x16, 0x02, 0x07, 0x07, 0x07, 0x31, 0x13, 0x19,
414 				     0x12, 0x12, 0x03, 0x03, 0x03, 0x32, 0x10, 0x18,
415 				     0x00, 0x11, 0x32, 0x10, 0x03, 0x00, 0x03, 0x32,
416 				     0x10, 0x03, 0x00, 0x03, 0x00, 0x00, 0xff, 0x00);
417 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1,
418 				     0x11, 0x00, 0x00, 0x89, 0x30, 0x80, 0x0a, 0x00,
419 				     0x03, 0x20, 0x00, 0x14, 0x03, 0x20, 0x03, 0x20,
420 				     0x02, 0x00, 0x02, 0x91, 0x00, 0x20, 0x02, 0x47,
421 				     0x00, 0x0b, 0x00, 0x0c, 0x05, 0x0e, 0x03, 0x68,
422 				     0x18, 0x00, 0x10, 0xe0, 0x03, 0x0c, 0x20, 0x00,
423 				     0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
424 				     0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
425 				     0x7d, 0x7e, 0x01, 0x02, 0x01, 0x00, 0x09);
426 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7,
427 				     0x17, 0x08, 0x08, 0x2c, 0x46, 0x1e, 0x02, 0x23,
428 				     0x5d, 0x02, 0xc9, 0x00, 0x00, 0x00, 0x00, 0x12,
429 				     0x05, 0x02, 0x02, 0x07, 0x10, 0x10, 0x00, 0x1d,
430 				     0xb9, 0x23, 0xb9, 0x00, 0x33, 0x02, 0x88);
431 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01);
432 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7,
433 				     0x02, 0x00, 0xb2, 0x01, 0x56, 0x07, 0x56, 0x08,
434 				     0x48, 0x14, 0xfd, 0x26);
435 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02);
436 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7,
437 				     0x08, 0x08, 0x01, 0x03, 0x01, 0x03, 0x07, 0x02,
438 				     0x02, 0x47, 0x00, 0x47, 0x81, 0x02, 0x40, 0x00,
439 				     0x18, 0x4a, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
440 				     0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00,
441 				     0x00, 0x00);
442 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
443 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbf,
444 				     0xfd, 0x00, 0x80, 0x9c, 0x36, 0x00, 0x81, 0x0c);
445 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xcd,
446 				     0x81, 0x00, 0x80, 0x77, 0x00, 0x01, 0x00);
447 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01);
448 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4,
449 				     0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1,
450 				     0xc7, 0xb2, 0xa0, 0x90, 0x81, 0x75, 0x69, 0x5f,
451 				     0x55, 0x4c, 0x44, 0x3d, 0x36, 0x2f, 0x2a, 0x24,
452 				     0x1e, 0x19, 0x14, 0x10, 0x09, 0x08, 0x07, 0x54,
453 				     0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55);
454 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03);
455 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4,
456 				     0xaa, 0xd4, 0xff, 0x2a, 0x55, 0x7f, 0xaa, 0xd4,
457 				     0xff, 0xea, 0xff, 0x03);
458 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
459 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x01, 0x35, 0x00);
460 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x5f);
461 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0x00, 0x00);
462 
463 	mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
464 	mipi_dsi_msleep(dsi_ctx, 140);
465 	mipi_dsi_dcs_set_display_on_multi(dsi_ctx);
466 
467 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01);
468 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
469 	mipi_dsi_msleep(dsi_ctx, 20);
470 
471 	return dsi_ctx->accum_err;
472 }
473 
csot_ppc357db1_4_init_seq(struct mipi_dsi_multi_context * dsi_ctx)474 static int csot_ppc357db1_4_init_seq(struct mipi_dsi_multi_context *dsi_ctx)
475 {
476 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x83, 0x12, 0x1a, 0x55, 0x00);
477 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
478 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
479 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1,
480 				     0x1c, 0x6b, 0x6b, 0x27, 0xe7, 0x00, 0x1b, 0x11,
481 				     0x21, 0x21, 0x2d, 0x2d, 0x17, 0x33, 0x31, 0x40,
482 				     0xcd, 0xff, 0x1a, 0x05, 0x15, 0x98, 0x00, 0x88,
483 				     0x7f, 0xff, 0xff, 0xcf, 0x1a, 0xcc, 0x02, 0x00);
484 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd1, 0x37, 0x03, 0x0c, 0xfd);
485 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x20);
486 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2,
487 				     0x00, 0x6a, 0x40, 0x00, 0x00, 0x14, 0x98, 0x60,
488 				     0x3c, 0x02, 0x80, 0x21, 0x21, 0x00, 0x00, 0x10,
489 				     0x27);
490 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03);
491 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x00, 0x3f);
492 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
493 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xe2);
494 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7, 0x49);
495 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
496 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3,
497 				     0x00, 0xc0, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04,
498 				     0x16, 0x02, 0x07, 0x07, 0x07, 0x31, 0x13, 0x16,
499 				     0x12, 0x12, 0x03, 0x03, 0x03, 0x32, 0x10, 0x15,
500 				     0x00, 0x11, 0x32, 0x10, 0x03, 0x00, 0x03, 0x32,
501 				     0x10, 0x03, 0x00, 0x03, 0x00, 0x00, 0xff, 0x00);
502 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02);
503 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2,
504 				     0x80, 0x05, 0x1c, 0xbe, 0x09, 0x8d, 0x0f, 0x57,
505 				     0x03, 0x87, 0x06, 0x10, 0x32, 0x06, 0x15, 0x00,
506 				     0x00, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00,
507 				     0x01, 0x10, 0x10, 0x16, 0x28, 0x3c, 0x03, 0x23,
508 				     0x5d, 0x02, 0x02, 0x00, 0x00, 0x48, 0x01, 0xac,
509 				     0x0f, 0xab, 0x10, 0x00, 0x32, 0x87, 0x00, 0xa1,
510 				     0x00, 0x0a, 0xcb, 0x00);
511 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01);
512 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7,
513 				     0x02, 0x00, 0xb2, 0x01, 0x56, 0x07, 0x56, 0x08,
514 				     0x48, 0x14, 0x00, 0x26);
515 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x02);
516 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe7,
517 				     0x05, 0x05, 0x01, 0x05, 0x01, 0x05, 0x04, 0x04,
518 				     0x04, 0x24, 0x00, 0x24, 0x81, 0x02, 0x40, 0x00,
519 				     0x32, 0x87, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00,
520 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
521 				     0x00, 0x00);
522 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
523 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xd0);
524 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0xf0);
525 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
526 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbf,
527 				     0xfd, 0x00, 0x80, 0x9c, 0x10, 0x00, 0x81, 0x0c);
528 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01);
529 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4,
530 				     0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1,
531 				     0xc7, 0xb2, 0xa0, 0x90, 0x81, 0x75, 0x69, 0x5f,
532 				     0x55, 0x4c, 0x44, 0x3d, 0x36, 0x2f, 0x2a, 0x24,
533 				     0x1e, 0x19, 0x14, 0x10, 0x09, 0x08, 0x07, 0x54,
534 				     0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55);
535 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x03);
536 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe4,
537 				     0xaa, 0xd4, 0xff, 0x2a, 0x55, 0x7f, 0xaa, 0xd4,
538 				     0xff, 0xea, 0xff, 0x03);
539 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
540 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0xc8);
541 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x25);
542 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe9, 0x3f);
543 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x01, 0x35, 0x00);
544 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd9, 0x5f);
545 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0x00, 0x00);
546 
547 	mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
548 	mipi_dsi_msleep(dsi_ctx, 140);
549 	mipi_dsi_dcs_set_display_on_multi(dsi_ctx);
550 
551 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x01);
552 	mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
553 	mipi_dsi_msleep(dsi_ctx, 31);
554 
555 	return dsi_ctx->accum_err;
556 }
557 
558 static struct drm_dsc_config ppc357db1_4_dsc_cfg = {
559 	.dsc_version_major = 1,
560 	.dsc_version_minor = 1,
561 	.slice_height = 20,
562 	.slice_width = 800,
563 	.slice_count = 1,
564 	.bits_per_component = 8,
565 	.bits_per_pixel = 8 << 4,
566 	.block_pred_enable = true,
567 };
568 
569 static const struct drm_display_mode ppc357db1_4_dsc_modes[] = {
570 	{
571 		.clock = (800 + 60 + 40 + 40) * 2 * (2560 + 154 + 4 + 18) * 120 / 1000,
572 		.hdisplay = 800 * 2,
573 		.hsync_start = (800 + 60) * 2,
574 		.hsync_end = (800 + 60 + 40) * 2,
575 		.htotal = (800 + 60 + 40 + 40) * 2,
576 		.vdisplay = 2560,
577 		.vsync_start = 2560 + 154,
578 		.vsync_end = 2560 + 154 + 4,
579 		.vtotal = 2560 + 154 + 4 + 18,
580 	},
581 	{
582 		.clock = (800 + 60 + 40 + 40) * 2 * (2560 + 2890 + 4 + 18) * 60 / 1000,
583 		.hdisplay = 800 * 2,
584 		.hsync_start = (800 + 60) * 2,
585 		.hsync_end = (800 + 60 + 40) * 2,
586 		.htotal = (800 + 60 + 40 + 40) * 2,
587 		.vdisplay = 2560,
588 		.vsync_start = 2560 + 2890,
589 		.vsync_end = 2560 + 2890 + 4,
590 		.vtotal = 2560 + 2890 + 4 + 18,
591 	},
592 };
593 
594 static const struct drm_display_mode ppc357db1_4_modes[] = {
595 	{
596 		.clock = (800 + 60 + 20 + 40) * 2 * (2560 + 154 + 4 + 18) * 60 / 1000,
597 		.hdisplay = 800 * 2,
598 		.hsync_start = (800 + 60) * 2,
599 		.hsync_end = (800 + 60 + 20) * 2,
600 		.htotal = (800 + 60 + 20 + 40) * 2,
601 		.vdisplay = 2560,
602 		.vsync_start = 2560 + 168,
603 		.vsync_end = 2560 + 168 + 4,
604 		.vtotal = 2560 + 168 + 4 + 18,
605 	},
606 };
607 
himax_probe(struct mipi_dsi_device * dsi)608 static int himax_probe(struct mipi_dsi_device *dsi)
609 {
610 	struct mipi_dsi_device_info dsi_info = {"dsi-secondary", 0, NULL};
611 	struct mipi_dsi_host *dsi1_host;
612 	struct device *dev = &dsi->dev;
613 	const struct panel_desc *desc;
614 	struct device_node *dsi1;
615 	struct himax *ctx;
616 	int num_dsi = 1;
617 	int ret, i;
618 
619 	ctx = devm_drm_panel_alloc(dev, struct himax, panel, &himax_panel_funcs,
620 				   DRM_MODE_CONNECTOR_DSI);
621 	if (IS_ERR(ctx))
622 		return PTR_ERR(ctx);
623 
624 	ret = devm_regulator_bulk_get_const(&dsi->dev,
625 					    ARRAY_SIZE(himax_supplies),
626 					    himax_supplies, &ctx->supplies);
627 	if (ret < 0)
628 		return ret;
629 
630 	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
631 	if (IS_ERR(ctx->reset_gpio))
632 		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
633 				     "Failed to get reset-gpios\n");
634 
635 	desc = of_device_get_match_data(dev);
636 	if (!desc)
637 		return -ENODEV;
638 	ctx->desc = desc;
639 	ctx->dsc = *desc->dsc_cfg;
640 
641 	if (desc->is_dual_dsi) {
642 		num_dsi = 2;
643 		dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1);
644 		if (!dsi1) {
645 			dev_err(dev, "cannot get secondary DSI node.\n");
646 			return -ENODEV;
647 		}
648 
649 		dsi1_host = of_find_mipi_dsi_host_by_node(dsi1);
650 		of_node_put(dsi1);
651 		if (!dsi1_host)
652 			return dev_err_probe(dev, -EPROBE_DEFER,
653 					     "cannot get secondary DSI host\n");
654 
655 		ctx->dsi[1] = devm_mipi_dsi_device_register_full(dev, dsi1_host,
656 								 &dsi_info);
657 		if (IS_ERR(ctx->dsi[1])) {
658 			dev_err(dev, "cannot get secondary DSI device\n");
659 			return PTR_ERR(ctx->dsi[1]);
660 		}
661 
662 		mipi_dsi_set_drvdata(ctx->dsi[1], ctx);
663 	}
664 
665 	ctx->dsi[0] = dsi;
666 	mipi_dsi_set_drvdata(dsi, ctx);
667 
668 	ctx->panel.prepare_prev_first = true;
669 
670 	if (desc->has_dcs_backlight) {
671 		ctx->bl_supply = devm_regulator_get_optional(dev, "bl");
672 		if (IS_ERR(ctx->bl_supply))
673 			return dev_err_probe(dev, PTR_ERR(ctx->bl_supply),
674 					     "Failed to get backlight supply\n");
675 		ctx->backlight = himax_create_backlight(ctx);
676 		if (IS_ERR(ctx->backlight))
677 			return dev_err_probe(dev, PTR_ERR(ctx->backlight),
678 					     "Failed to create backlight\n");
679 	} else {
680 		ret = drm_panel_of_backlight(&ctx->panel);
681 		if (ret)
682 			return dev_err_probe(dev, ret, "Failed to get backlight\n");
683 	}
684 
685 	drm_panel_add(&ctx->panel);
686 
687 	for (i = 0; i < num_dsi; i++) {
688 		ctx->dsi[i]->lanes = desc->lanes;
689 		ctx->dsi[i]->format = desc->format;
690 		ctx->dsi[i]->mode_flags = desc->mode_flags;
691 		ctx->dsi[i]->dsc = enable_dsc ? &ctx->dsc : NULL;
692 		ret = devm_mipi_dsi_attach(dev, ctx->dsi[i]);
693 		if (ret < 0) {
694 			drm_panel_remove(&ctx->panel);
695 			return dev_err_probe(dev, ret,
696 					     "Failed to attach to DSI host\n");
697 		}
698 	}
699 
700 	return 0;
701 }
702 
himax_remove(struct mipi_dsi_device * dsi)703 static void himax_remove(struct mipi_dsi_device *dsi)
704 {
705 	struct himax *ctx = mipi_dsi_get_drvdata(dsi);
706 
707 	drm_panel_remove(&ctx->panel);
708 }
709 
710 /* Model name: BOE PPC357DB1-4 */
711 static const struct panel_desc boe_ppc357db1_4_desc = {
712 	.width_mm = 266,
713 	.height_mm = 166,
714 	.lanes = 4,
715 	.format = MIPI_DSI_FMT_RGB888,
716 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS |
717 		      MIPI_DSI_MODE_LPM,
718 	.dsc_cfg = &ppc357db1_4_dsc_cfg,
719 	.dsc_modes = ppc357db1_4_dsc_modes,
720 	.num_dsc_modes = ARRAY_SIZE(ppc357db1_4_dsc_modes),
721 	.modes = ppc357db1_4_modes,
722 	.num_modes = ARRAY_SIZE(ppc357db1_4_modes),
723 	.init_sequence_dsc = boe_ppc357db1_4_dsc_init_seq,
724 	.init_sequence = boe_ppc357db1_4_init_seq,
725 	.is_dual_dsi = true,
726 	.has_dcs_backlight = true,
727 };
728 
729 /* Model name: CSOT PPC357DB1-4 */
730 static const struct panel_desc csot_ppc357db1_4_desc = {
731 	.width_mm = 266,
732 	.height_mm = 166,
733 	.lanes = 4,
734 	.format = MIPI_DSI_FMT_RGB888,
735 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS |
736 		      MIPI_DSI_MODE_LPM,
737 	.dsc_cfg = &ppc357db1_4_dsc_cfg,
738 	.dsc_modes = ppc357db1_4_dsc_modes,
739 	.num_dsc_modes = ARRAY_SIZE(ppc357db1_4_dsc_modes),
740 	.modes = ppc357db1_4_modes,
741 	.num_modes = ARRAY_SIZE(ppc357db1_4_modes),
742 	.init_sequence_dsc = csot_ppc357db1_4_dsc_init_seq,
743 	.init_sequence = csot_ppc357db1_4_init_seq,
744 	.is_dual_dsi = true,
745 	.has_dcs_backlight = true,
746 };
747 
748 /*
749  * Known panels with HX83121A:
750  * CSOT PNC357DB1-4: on MI Book S 12.4
751  * CSOT PPC357DB1-1: on SAMSUNG Galaxy Tab S7 FE
752  * BOE/CSOT PPC357DB1-4: on HUAWEI Matebook E Go
753  * CSOT PPC357DB1-5: on MI Pad 5 Pro 12.4
754  */
755 
756 static const struct of_device_id himax_of_match[] = {
757 	{ .compatible = "boe,ppc357db1-4", .data = &boe_ppc357db1_4_desc },
758 	{ .compatible = "csot,ppc357db1-4", .data = &csot_ppc357db1_4_desc },
759 	{ /* sentinel */ }
760 };
761 MODULE_DEVICE_TABLE(of, himax_of_match);
762 
763 static struct mipi_dsi_driver himax_driver = {
764 	.probe = himax_probe,
765 	.remove = himax_remove,
766 	.driver = {
767 		.name = "panel-himax-hx83121a",
768 		.of_match_table = himax_of_match,
769 	},
770 };
771 module_mipi_dsi_driver(himax_driver);
772 
773 MODULE_AUTHOR("Pengyu Luo <mitltlatltl0@gmail.com>");
774 MODULE_DESCRIPTION("Himax HX83121A DriverIC panels driver");
775 MODULE_LICENSE("GPL");
776