xref: /linux/drivers/gpu/drm/panel/panel-himax-hx83112a.c (revision 4b660dbd9ee2059850fd30e0df420ca7a38a1856)
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) 2024 Luca Weiss <luca.weiss@fairphone.com>
5  */
6 
7 #include <linux/delay.h>
8 #include <linux/gpio/consumer.h>
9 #include <linux/module.h>
10 #include <linux/of.h>
11 #include <linux/regulator/consumer.h>
12 
13 #include <drm/drm_mipi_dsi.h>
14 #include <drm/drm_modes.h>
15 #include <drm/drm_panel.h>
16 #include <drm/drm_probe_helper.h>
17 
18 /* Manufacturer specific DSI commands */
19 #define HX83112A_SETPOWER1	0xb1
20 #define HX83112A_SETDISP	0xb2
21 #define HX83112A_SETDRV		0xb4
22 #define HX83112A_SETEXTC	0xb9
23 #define HX83112A_SETBANK	0xbd
24 #define HX83112A_SETPTBA	0xbf
25 #define HX83112A_SETDGCLUT	0xc1
26 #define HX83112A_SETTCON	0xc7
27 #define HX83112A_SETCLOCK	0xcb
28 #define HX83112A_SETPANEL	0xcc
29 #define HX83112A_SETPOWER2	0xd2
30 #define HX83112A_SETGIP0	0xd3
31 #define HX83112A_SETGIP1	0xd5
32 #define HX83112A_SETGIP2	0xd6
33 #define HX83112A_SETGIP3	0xd8
34 #define HX83112A_SETTP1		0xe7
35 #define HX83112A_UNKNOWN1	0xe9
36 
37 struct hx83112a_panel {
38 	struct drm_panel panel;
39 	struct mipi_dsi_device *dsi;
40 	struct regulator_bulk_data supplies[3];
41 	struct gpio_desc *reset_gpio;
42 };
43 
44 static inline struct hx83112a_panel *to_hx83112a_panel(struct drm_panel *panel)
45 {
46 	return container_of(panel, struct hx83112a_panel, panel);
47 }
48 
49 static void hx83112a_reset(struct hx83112a_panel *ctx)
50 {
51 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
52 	msleep(20);
53 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
54 	msleep(20);
55 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
56 	msleep(50);
57 }
58 
59 static int hx83112a_on(struct hx83112a_panel *ctx)
60 {
61 	struct mipi_dsi_device *dsi = ctx->dsi;
62 	struct device *dev = &dsi->dev;
63 	int ret;
64 
65 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
66 
67 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETEXTC, 0x83, 0x11, 0x2a);
68 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPOWER1,
69 			       0x08, 0x28, 0x28, 0x83, 0x83, 0x4c, 0x4f, 0x33);
70 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDISP,
71 			       0x00, 0x02, 0x00, 0x90, 0x24, 0x00, 0x08, 0x19,
72 			       0xea, 0x11, 0x11, 0x00, 0x11, 0xa3);
73 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDRV,
74 			       0x58, 0x68, 0x58, 0x68, 0x0f, 0xef, 0x0b, 0xc0,
75 			       0x0b, 0xc0, 0x0b, 0xc0, 0x00, 0xff, 0x00, 0xff,
76 			       0x00, 0x00, 0x14, 0x15, 0x00, 0x29, 0x11, 0x07,
77 			       0x12, 0x00, 0x29);
78 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02);
79 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDRV,
80 			       0x00, 0x12, 0x12, 0x11, 0x88, 0x12, 0x12, 0x00,
81 			       0x53);
82 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
83 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x03);
84 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT,
85 			       0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6,
86 			       0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6,
87 			       0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d,
88 			       0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49,
89 			       0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a,
90 			       0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3,
91 			       0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad,
92 			       0x40);
93 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02);
94 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT,
95 			       0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6,
96 			       0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6,
97 			       0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d,
98 			       0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49,
99 			       0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a,
100 			       0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3,
101 			       0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad,
102 			       0x40);
103 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01);
104 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT,
105 			       0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6,
106 			       0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6,
107 			       0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d,
108 			       0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49,
109 			       0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a,
110 			       0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3,
111 			       0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad,
112 			       0x40);
113 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
114 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT, 0x01);
115 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTCON,
116 			       0x70, 0x00, 0x04, 0xe0, 0x33, 0x00);
117 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPANEL, 0x08);
118 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPOWER2, 0x2b, 0x2b);
119 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP0,
120 			       0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08,
121 			       0x08, 0x03, 0x03, 0x22, 0x18, 0x07, 0x07, 0x07,
122 			       0x07, 0x32, 0x10, 0x06, 0x00, 0x06, 0x32, 0x10,
123 			       0x07, 0x00, 0x07, 0x32, 0x19, 0x31, 0x09, 0x31,
124 			       0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x08,
125 			       0x09, 0x30, 0x00, 0x00, 0x00, 0x06, 0x0d, 0x00,
126 			       0x0f);
127 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01);
128 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP0,
129 			       0x00, 0x00, 0x19, 0x10, 0x00, 0x0a, 0x00, 0x81);
130 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
131 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP1,
132 			       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
133 			       0xc0, 0xc0, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18,
134 			       0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x3f, 0x3f,
135 			       0x28, 0x28, 0x24, 0x24, 0x02, 0x03, 0x02, 0x03,
136 			       0x00, 0x01, 0x00, 0x01, 0x31, 0x31, 0x31, 0x31,
137 			       0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f);
138 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP2,
139 			       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
140 			       0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19,
141 			       0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x3f, 0x3f,
142 			       0x24, 0x24, 0x28, 0x28, 0x01, 0x00, 0x01, 0x00,
143 			       0x03, 0x02, 0x03, 0x02, 0x31, 0x31, 0x31, 0x31,
144 			       0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f);
145 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3,
146 			       0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea,
147 			       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa,
148 			       0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa, 0xaa, 0xaa);
149 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01);
150 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3,
151 			       0xaa, 0x2e, 0x28, 0x00, 0x00, 0x00, 0xaa, 0x2e,
152 			       0x28, 0x00, 0x00, 0x00, 0xaa, 0xee, 0xaa, 0xaa,
153 			       0xaa, 0xaa, 0xaa, 0xee, 0xaa, 0xaa, 0xaa, 0xaa);
154 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02);
155 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3,
156 			       0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xff,
157 			       0xff, 0xff, 0xff, 0xff);
158 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x03);
159 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3,
160 			       0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
161 			       0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff,
162 			       0xff, 0xff, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff);
163 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
164 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1,
165 			       0x0e, 0x0e, 0x1e, 0x65, 0x1c, 0x65, 0x00, 0x50,
166 			       0x20, 0x20, 0x00, 0x00, 0x02, 0x02, 0x02, 0x05,
167 			       0x14, 0x14, 0x32, 0xb9, 0x23, 0xb9, 0x08);
168 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01);
169 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1,
170 			       0x02, 0x00, 0xa8, 0x01, 0xa8, 0x0d, 0xa4, 0x0e);
171 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02);
172 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1,
173 			       0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00,
174 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
176 			       0x00, 0x00, 0x00, 0x02, 0x00);
177 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00);
178 	mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0xc3);
179 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETCLOCK, 0xd1, 0xd6);
180 	mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0x3f);
181 	mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0xc6);
182 	mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPTBA, 0x37);
183 	mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0x3f);
184 
185 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
186 	if (ret < 0) {
187 		dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
188 		return ret;
189 	}
190 	msleep(150);
191 
192 	ret = mipi_dsi_dcs_set_display_on(dsi);
193 	if (ret < 0) {
194 		dev_err(dev, "Failed to set display on: %d\n", ret);
195 		return ret;
196 	}
197 	msleep(50);
198 
199 	return 0;
200 }
201 
202 static int hx83112a_disable(struct drm_panel *panel)
203 {
204 	struct hx83112a_panel *ctx = to_hx83112a_panel(panel);
205 	struct mipi_dsi_device *dsi = ctx->dsi;
206 	struct device *dev = &dsi->dev;
207 	int ret;
208 
209 	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
210 
211 	ret = mipi_dsi_dcs_set_display_off(dsi);
212 	if (ret < 0) {
213 		dev_err(dev, "Failed to set display off: %d\n", ret);
214 		return ret;
215 	}
216 	msleep(20);
217 
218 	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
219 	if (ret < 0) {
220 		dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
221 		return ret;
222 	}
223 	msleep(120);
224 
225 	return 0;
226 }
227 
228 static int hx83112a_prepare(struct drm_panel *panel)
229 {
230 	struct hx83112a_panel *ctx = to_hx83112a_panel(panel);
231 	struct device *dev = &ctx->dsi->dev;
232 	int ret;
233 
234 	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
235 	if (ret < 0) {
236 		dev_err(dev, "Failed to enable regulators: %d\n", ret);
237 		return ret;
238 	}
239 
240 	hx83112a_reset(ctx);
241 
242 	ret = hx83112a_on(ctx);
243 	if (ret < 0) {
244 		dev_err(dev, "Failed to initialize panel: %d\n", ret);
245 		gpiod_set_value_cansleep(ctx->reset_gpio, 1);
246 		regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
247 		return ret;
248 	}
249 
250 	return 0;
251 }
252 
253 static int hx83112a_unprepare(struct drm_panel *panel)
254 {
255 	struct hx83112a_panel *ctx = to_hx83112a_panel(panel);
256 
257 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
258 	regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
259 
260 	return 0;
261 }
262 
263 static const struct drm_display_mode hx83112a_mode = {
264 	.clock = (1080 + 28 + 8 + 8) * (2340 + 27 + 5 + 5) * 60 / 1000,
265 	.hdisplay = 1080,
266 	.hsync_start = 1080 + 28,
267 	.hsync_end = 1080 + 28 + 8,
268 	.htotal = 1080 + 28 + 8 + 8,
269 	.vdisplay = 2340,
270 	.vsync_start = 2340 + 27,
271 	.vsync_end = 2340 + 27 + 5,
272 	.vtotal = 2340 + 27 + 5 + 5,
273 	.width_mm = 67,
274 	.height_mm = 145,
275 	.type = DRM_MODE_TYPE_DRIVER,
276 };
277 
278 static int hx83112a_get_modes(struct drm_panel *panel,
279 				  struct drm_connector *connector)
280 {
281 	return drm_connector_helper_get_modes_fixed(connector, &hx83112a_mode);
282 }
283 
284 static const struct drm_panel_funcs hx83112a_panel_funcs = {
285 	.prepare = hx83112a_prepare,
286 	.unprepare = hx83112a_unprepare,
287 	.disable = hx83112a_disable,
288 	.get_modes = hx83112a_get_modes,
289 };
290 
291 static int hx83112a_probe(struct mipi_dsi_device *dsi)
292 {
293 	struct device *dev = &dsi->dev;
294 	struct hx83112a_panel *ctx;
295 	int ret;
296 
297 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
298 	if (!ctx)
299 		return -ENOMEM;
300 
301 	ctx->supplies[0].supply = "vdd1";
302 	ctx->supplies[1].supply = "vsn";
303 	ctx->supplies[2].supply = "vsp";
304 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
305 				      ctx->supplies);
306 	if (ret < 0)
307 		return dev_err_probe(dev, ret, "Failed to get regulators\n");
308 
309 	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
310 	if (IS_ERR(ctx->reset_gpio))
311 		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
312 				     "Failed to get reset-gpios\n");
313 
314 	ctx->dsi = dsi;
315 	mipi_dsi_set_drvdata(dsi, ctx);
316 
317 	dsi->lanes = 4;
318 	dsi->format = MIPI_DSI_FMT_RGB888;
319 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
320 			  MIPI_DSI_MODE_VIDEO_HSE |
321 			  MIPI_DSI_CLOCK_NON_CONTINUOUS;
322 
323 	drm_panel_init(&ctx->panel, dev, &hx83112a_panel_funcs,
324 		       DRM_MODE_CONNECTOR_DSI);
325 	ctx->panel.prepare_prev_first = true;
326 
327 	ret = drm_panel_of_backlight(&ctx->panel);
328 	if (ret)
329 		return dev_err_probe(dev, ret, "Failed to get backlight\n");
330 
331 	drm_panel_add(&ctx->panel);
332 
333 	ret = mipi_dsi_attach(dsi);
334 	if (ret < 0) {
335 		dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
336 		drm_panel_remove(&ctx->panel);
337 		return ret;
338 	}
339 
340 	return 0;
341 }
342 
343 static void hx83112a_remove(struct mipi_dsi_device *dsi)
344 {
345 	struct hx83112a_panel *ctx = mipi_dsi_get_drvdata(dsi);
346 	int ret;
347 
348 	ret = mipi_dsi_detach(dsi);
349 	if (ret < 0)
350 		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
351 
352 	drm_panel_remove(&ctx->panel);
353 }
354 
355 static const struct of_device_id hx83112a_of_match[] = {
356 	{ .compatible = "djn,9a-3r063-1102b" },
357 	{ /* sentinel */ }
358 };
359 MODULE_DEVICE_TABLE(of, hx83112a_of_match);
360 
361 static struct mipi_dsi_driver hx83112a_driver = {
362 	.probe = hx83112a_probe,
363 	.remove = hx83112a_remove,
364 	.driver = {
365 		.name = "panel-himax-hx83112a",
366 		.of_match_table = hx83112a_of_match,
367 	},
368 };
369 module_mipi_dsi_driver(hx83112a_driver);
370 
371 MODULE_DESCRIPTION("DRM driver for hx83112a-equipped DSI panels");
372 MODULE_LICENSE("GPL");
373