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