xref: /linux/drivers/gpu/drm/panel/panel-himax-hx83112b.c (revision d2c9a99135da931377240942d44f3dea104cedb8)
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