Linux Audio

Check our new training course

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");