Loading...
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");
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 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
202static 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
228static 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
253static 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
263static 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
278static 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
284static 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
291static 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
343static 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
355static const struct of_device_id hx83112a_of_match[] = {
356 { .compatible = "djn,9a-3r063-1102b" },
357 { /* sentinel */ }
358};
359MODULE_DEVICE_TABLE(of, hx83112a_of_match);
360
361static 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};
369module_mipi_dsi_driver(hx83112a_driver);
370
371MODULE_DESCRIPTION("DRM driver for hx83112a-equipped DSI panels");
372MODULE_LICENSE("GPL");