Linux Audio

Check our new training course

Buildroot integration, development and maintenance

Need a Buildroot system for your embedded project?
Loading...
v6.13.7
  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");
v6.9.4
  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");