1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Rockteck jh057n00900 5.5" MIPI-DSI panel driver
4  *
5  * Copyright (C) Purism SPC 2019
6  */
7 
8 #include <drm/drm_mipi_dsi.h>
9 #include <drm/drm_modes.h>
10 #include <drm/drm_panel.h>
11 #include <drm/drm_print.h>
12 #include <linux/backlight.h>
13 #include <linux/debugfs.h>
14 #include <linux/delay.h>
15 #include <linux/gpio/consumer.h>
16 #include <linux/media-bus-format.h>
17 #include <linux/module.h>
18 #include <linux/regulator/consumer.h>
19 #include <video/display_timing.h>
20 #include <video/mipi_display.h>
21 
22 #define DRV_NAME "panel-rocktech-jh057n00900"
23 
24 /* Manufacturer specific Commands send via DSI */
25 #define ST7703_CMD_ALL_PIXEL_OFF 0x22
26 #define ST7703_CMD_ALL_PIXEL_ON	 0x23
27 #define ST7703_CMD_SETDISP	 0xB2
28 #define ST7703_CMD_SETRGBIF	 0xB3
29 #define ST7703_CMD_SETCYC	 0xB4
30 #define ST7703_CMD_SETBGP	 0xB5
31 #define ST7703_CMD_SETVCOM	 0xB6
32 #define ST7703_CMD_SETOTP	 0xB7
33 #define ST7703_CMD_SETPOWER_EXT	 0xB8
34 #define ST7703_CMD_SETEXTC	 0xB9
35 #define ST7703_CMD_SETMIPI	 0xBA
36 #define ST7703_CMD_SETVDC	 0xBC
37 #define ST7703_CMD_UNKNOWN0	 0xBF
38 #define ST7703_CMD_SETSCR	 0xC0
39 #define ST7703_CMD_SETPOWER	 0xC1
40 #define ST7703_CMD_SETPANEL	 0xCC
41 #define ST7703_CMD_SETGAMMA	 0xE0
42 #define ST7703_CMD_SETEQ	 0xE3
43 #define ST7703_CMD_SETGIP1	 0xE9
44 #define ST7703_CMD_SETGIP2	 0xEA
45 
46 struct jh057n {
47 	struct device *dev;
48 	struct drm_panel panel;
49 	struct gpio_desc *reset_gpio;
50 	struct backlight_device *backlight;
51 	struct regulator *vcc;
52 	struct regulator *iovcc;
53 	bool prepared;
54 
55 	struct dentry *debugfs;
56 };
57 
panel_to_jh057n(struct drm_panel * panel)58 static inline struct jh057n *panel_to_jh057n(struct drm_panel *panel)
59 {
60 	return container_of(panel, struct jh057n, panel);
61 }
62 
63 #define dsi_generic_write_seq(dsi, seq...) do {				\
64 		static const u8 d[] = { seq };				\
65 		int ret;						\
66 		ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));	\
67 		if (ret < 0)						\
68 			return ret;					\
69 	} while (0)
70 
jh057n_init_sequence(struct jh057n * ctx)71 static int jh057n_init_sequence(struct jh057n *ctx)
72 {
73 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
74 	struct device *dev = ctx->dev;
75 	int ret;
76 
77 	/*
78 	 * Init sequence was supplied by the panel vendor. Most of the commands
79 	 * resemble the ST7703 but the number of parameters often don't match
80 	 * so it's likely a clone.
81 	 */
82 	dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
83 			      0xF1, 0x12, 0x83);
84 	dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
85 			      0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
86 			      0x00, 0x00);
87 	dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
88 			      0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
89 			      0x00);
90 	dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
91 	dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
92 	dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
93 	dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
94 	dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
95 			      0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
96 			      0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
97 	dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
98 	msleep(20);
99 
100 	dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
101 	dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN0, 0x02, 0x11, 0x00);
102 	dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
103 			      0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
104 			      0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
105 			      0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
106 			      0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
107 			      0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
108 			      0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
109 			      0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110 			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
111 	dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
112 			      0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113 			      0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
114 			      0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
115 			      0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
116 			      0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
117 			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
119 			      0xA5, 0x00, 0x00, 0x00, 0x00);
120 	dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
121 			      0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
122 			      0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
123 			      0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
124 			      0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
125 			      0x11, 0x18);
126 	msleep(20);
127 
128 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
129 	if (ret < 0) {
130 		DRM_DEV_ERROR(dev, "Failed to exit sleep mode: %d\n", ret);
131 		return ret;
132 	}
133 	/* Panel is operational 120 msec after reset */
134 	msleep(60);
135 	ret = mipi_dsi_dcs_set_display_on(dsi);
136 	if (ret)
137 		return ret;
138 
139 	DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n");
140 	return 0;
141 }
142 
jh057n_enable(struct drm_panel * panel)143 static int jh057n_enable(struct drm_panel *panel)
144 {
145 	struct jh057n *ctx = panel_to_jh057n(panel);
146 	int ret;
147 
148 	ret = jh057n_init_sequence(ctx);
149 	if (ret < 0) {
150 		DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n",
151 			      ret);
152 		return ret;
153 	}
154 
155 	return backlight_enable(ctx->backlight);
156 }
157 
jh057n_disable(struct drm_panel * panel)158 static int jh057n_disable(struct drm_panel *panel)
159 {
160 	struct jh057n *ctx = panel_to_jh057n(panel);
161 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
162 
163 	backlight_disable(ctx->backlight);
164 	return mipi_dsi_dcs_set_display_off(dsi);
165 }
166 
jh057n_unprepare(struct drm_panel * panel)167 static int jh057n_unprepare(struct drm_panel *panel)
168 {
169 	struct jh057n *ctx = panel_to_jh057n(panel);
170 
171 	if (!ctx->prepared)
172 		return 0;
173 
174 	regulator_disable(ctx->iovcc);
175 	regulator_disable(ctx->vcc);
176 	ctx->prepared = false;
177 
178 	return 0;
179 }
180 
jh057n_prepare(struct drm_panel * panel)181 static int jh057n_prepare(struct drm_panel *panel)
182 {
183 	struct jh057n *ctx = panel_to_jh057n(panel);
184 	int ret;
185 
186 	if (ctx->prepared)
187 		return 0;
188 
189 	DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n");
190 	ret = regulator_enable(ctx->vcc);
191 	if (ret < 0) {
192 		DRM_DEV_ERROR(ctx->dev,
193 			      "Failed to enable vcc supply: %d\n", ret);
194 		return ret;
195 	}
196 	ret = regulator_enable(ctx->iovcc);
197 	if (ret < 0) {
198 		DRM_DEV_ERROR(ctx->dev,
199 			      "Failed to enable iovcc supply: %d\n", ret);
200 		goto disable_vcc;
201 	}
202 
203 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
204 	usleep_range(20, 40);
205 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
206 	msleep(20);
207 
208 	ctx->prepared = true;
209 
210 	return 0;
211 
212 disable_vcc:
213 	regulator_disable(ctx->vcc);
214 	return ret;
215 }
216 
217 static const struct drm_display_mode default_mode = {
218 	.hdisplay    = 720,
219 	.hsync_start = 720 + 90,
220 	.hsync_end   = 720 + 90 + 20,
221 	.htotal	     = 720 + 90 + 20 + 20,
222 	.vdisplay    = 1440,
223 	.vsync_start = 1440 + 20,
224 	.vsync_end   = 1440 + 20 + 4,
225 	.vtotal	     = 1440 + 20 + 4 + 12,
226 	.vrefresh    = 60,
227 	.clock	     = 75276,
228 	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
229 	.width_mm    = 65,
230 	.height_mm   = 130,
231 };
232 
jh057n_get_modes(struct drm_panel * panel)233 static int jh057n_get_modes(struct drm_panel *panel)
234 {
235 	struct jh057n *ctx = panel_to_jh057n(panel);
236 	struct drm_display_mode *mode;
237 
238 	mode = drm_mode_duplicate(panel->drm, &default_mode);
239 	if (!mode) {
240 		DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n",
241 			      default_mode.hdisplay, default_mode.vdisplay,
242 			      default_mode.vrefresh);
243 		return -ENOMEM;
244 	}
245 
246 	drm_mode_set_name(mode);
247 
248 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
249 	panel->connector->display_info.width_mm = mode->width_mm;
250 	panel->connector->display_info.height_mm = mode->height_mm;
251 	drm_mode_probed_add(panel->connector, mode);
252 
253 	return 1;
254 }
255 
256 static const struct drm_panel_funcs jh057n_drm_funcs = {
257 	.disable   = jh057n_disable,
258 	.unprepare = jh057n_unprepare,
259 	.prepare   = jh057n_prepare,
260 	.enable	   = jh057n_enable,
261 	.get_modes = jh057n_get_modes,
262 };
263 
allpixelson_set(void * data,u64 val)264 static int allpixelson_set(void *data, u64 val)
265 {
266 	struct jh057n *ctx = data;
267 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
268 
269 	DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on\n");
270 	dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
271 	msleep(val * 1000);
272 	/* Reset the panel to get video back */
273 	drm_panel_disable(&ctx->panel);
274 	drm_panel_unprepare(&ctx->panel);
275 	drm_panel_prepare(&ctx->panel);
276 	drm_panel_enable(&ctx->panel);
277 
278 	return 0;
279 }
280 
281 DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
282 			allpixelson_set, "%llu\n");
283 
jh057n_debugfs_init(struct jh057n * ctx)284 static void jh057n_debugfs_init(struct jh057n *ctx)
285 {
286 	ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
287 
288 	debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
289 			    &allpixelson_fops);
290 }
291 
jh057n_debugfs_remove(struct jh057n * ctx)292 static void jh057n_debugfs_remove(struct jh057n *ctx)
293 {
294 	debugfs_remove_recursive(ctx->debugfs);
295 	ctx->debugfs = NULL;
296 }
297 
jh057n_probe(struct mipi_dsi_device * dsi)298 static int jh057n_probe(struct mipi_dsi_device *dsi)
299 {
300 	struct device *dev = &dsi->dev;
301 	struct jh057n *ctx;
302 	int ret;
303 
304 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
305 	if (!ctx)
306 		return -ENOMEM;
307 
308 	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
309 	if (IS_ERR(ctx->reset_gpio)) {
310 		DRM_DEV_ERROR(dev, "cannot get reset gpio\n");
311 		return PTR_ERR(ctx->reset_gpio);
312 	}
313 
314 	mipi_dsi_set_drvdata(dsi, ctx);
315 
316 	ctx->dev = dev;
317 
318 	dsi->lanes = 4;
319 	dsi->format = MIPI_DSI_FMT_RGB888;
320 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
321 		MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
322 
323 	ctx->backlight = devm_of_find_backlight(dev);
324 	if (IS_ERR(ctx->backlight))
325 		return PTR_ERR(ctx->backlight);
326 
327 	ctx->vcc = devm_regulator_get(dev, "vcc");
328 	if (IS_ERR(ctx->vcc)) {
329 		ret = PTR_ERR(ctx->vcc);
330 		if (ret != -EPROBE_DEFER)
331 			DRM_DEV_ERROR(dev,
332 				      "Failed to request vcc regulator: %d\n",
333 				      ret);
334 		return ret;
335 	}
336 	ctx->iovcc = devm_regulator_get(dev, "iovcc");
337 	if (IS_ERR(ctx->iovcc)) {
338 		ret = PTR_ERR(ctx->iovcc);
339 		if (ret != -EPROBE_DEFER)
340 			DRM_DEV_ERROR(dev,
341 				      "Failed to request iovcc regulator: %d\n",
342 				      ret);
343 		return ret;
344 	}
345 
346 	drm_panel_init(&ctx->panel);
347 	ctx->panel.dev = dev;
348 	ctx->panel.funcs = &jh057n_drm_funcs;
349 
350 	drm_panel_add(&ctx->panel);
351 
352 	ret = mipi_dsi_attach(dsi);
353 	if (ret < 0) {
354 		DRM_DEV_ERROR(dev,
355 			      "mipi_dsi_attach failed (%d). Is host ready?\n",
356 			      ret);
357 		drm_panel_remove(&ctx->panel);
358 		return ret;
359 	}
360 
361 	DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
362 		     default_mode.hdisplay, default_mode.vdisplay,
363 		     default_mode.vrefresh,
364 		     mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
365 
366 	jh057n_debugfs_init(ctx);
367 	return 0;
368 }
369 
jh057n_shutdown(struct mipi_dsi_device * dsi)370 static void jh057n_shutdown(struct mipi_dsi_device *dsi)
371 {
372 	struct jh057n *ctx = mipi_dsi_get_drvdata(dsi);
373 	int ret;
374 
375 	ret = drm_panel_unprepare(&ctx->panel);
376 	if (ret < 0)
377 		DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n",
378 			      ret);
379 
380 	ret = drm_panel_disable(&ctx->panel);
381 	if (ret < 0)
382 		DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n",
383 			      ret);
384 }
385 
jh057n_remove(struct mipi_dsi_device * dsi)386 static int jh057n_remove(struct mipi_dsi_device *dsi)
387 {
388 	struct jh057n *ctx = mipi_dsi_get_drvdata(dsi);
389 	int ret;
390 
391 	jh057n_shutdown(dsi);
392 
393 	ret = mipi_dsi_detach(dsi);
394 	if (ret < 0)
395 		DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n",
396 			      ret);
397 
398 	drm_panel_remove(&ctx->panel);
399 
400 	jh057n_debugfs_remove(ctx);
401 
402 	return 0;
403 }
404 
405 static const struct of_device_id jh057n_of_match[] = {
406 	{ .compatible = "rocktech,jh057n00900" },
407 	{ /* sentinel */ }
408 };
409 MODULE_DEVICE_TABLE(of, jh057n_of_match);
410 
411 static struct mipi_dsi_driver jh057n_driver = {
412 	.probe	= jh057n_probe,
413 	.remove = jh057n_remove,
414 	.shutdown = jh057n_shutdown,
415 	.driver = {
416 		.name = DRV_NAME,
417 		.of_match_table = jh057n_of_match,
418 	},
419 };
420 module_mipi_dsi_driver(jh057n_driver);
421 
422 MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
423 MODULE_DESCRIPTION("DRM driver for Rocktech JH057N00900 MIPI DSI panel");
424 MODULE_LICENSE("GPL v2");
425