Loading...
Note: File does not exist in v3.1.
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
37struct 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
44static inline struct hx83112a_panel *to_hx83112a_panel(struct drm_panel *panel)
45{
46 return container_of(panel, struct hx83112a_panel, panel);
47}
48
49static 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
59static 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
192static 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
208static 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
228static 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
238static 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
253static 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
259static 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
266static 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
318static 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
330static const struct of_device_id hx83112a_of_match[] = {
331 { .compatible = "djn,9a-3r063-1102b" },
332 { /* sentinel */ }
333};
334MODULE_DEVICE_TABLE(of, hx83112a_of_match);
335
336static 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};
344module_mipi_dsi_driver(hx83112a_driver);
345
346MODULE_DESCRIPTION("DRM driver for hx83112a-equipped DSI panels");
347MODULE_LICENSE("GPL");