1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
4  */
5 
6 #include <linux/backlight.h>
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 <video/mipi_display.h>
14 
15 #include <drm/drm_crtc.h>
16 #include <drm/drm_device.h>
17 #include <drm/drm_mipi_dsi.h>
18 #include <drm/drm_modes.h>
19 #include <drm/drm_panel.h>
20 #include <drm/drm_print.h>
21 
22 struct kingdisplay_panel {
23 	struct drm_panel base;
24 	struct mipi_dsi_device *link;
25 
26 	struct backlight_device *backlight;
27 	struct regulator *supply;
28 	struct gpio_desc *enable_gpio;
29 
30 	bool prepared;
31 	bool enabled;
32 };
33 
34 struct kingdisplay_panel_cmd {
35 	char cmd;
36 	char data;
37 };
38 
39 /*
40  * According to the discussion on
41  * https://review.coreboot.org/#/c/coreboot/+/22472/
42  * the panel init array is not part of the panels datasheet but instead
43  * just came in this form from the panel vendor.
44  */
45 static const struct kingdisplay_panel_cmd init_code[] = {
46 	/* voltage setting */
47 	{ 0xB0, 0x00 },
48 	{ 0xB2, 0x02 },
49 	{ 0xB3, 0x11 },
50 	{ 0xB4, 0x00 },
51 	{ 0xB6, 0x80 },
52 	/* VCOM disable */
53 	{ 0xB7, 0x02 },
54 	{ 0xB8, 0x80 },
55 	{ 0xBA, 0x43 },
56 	/* VCOM setting */
57 	{ 0xBB, 0x53 },
58 	/* VSP setting */
59 	{ 0xBC, 0x0A },
60 	/* VSN setting */
61 	{ 0xBD, 0x4A },
62 	/* VGH setting */
63 	{ 0xBE, 0x2F },
64 	/* VGL setting */
65 	{ 0xBF, 0x1A },
66 	{ 0xF0, 0x39 },
67 	{ 0xF1, 0x22 },
68 	/* Gamma setting */
69 	{ 0xB0, 0x02 },
70 	{ 0xC0, 0x00 },
71 	{ 0xC1, 0x01 },
72 	{ 0xC2, 0x0B },
73 	{ 0xC3, 0x15 },
74 	{ 0xC4, 0x22 },
75 	{ 0xC5, 0x11 },
76 	{ 0xC6, 0x15 },
77 	{ 0xC7, 0x19 },
78 	{ 0xC8, 0x1A },
79 	{ 0xC9, 0x16 },
80 	{ 0xCA, 0x18 },
81 	{ 0xCB, 0x13 },
82 	{ 0xCC, 0x18 },
83 	{ 0xCD, 0x13 },
84 	{ 0xCE, 0x1C },
85 	{ 0xCF, 0x19 },
86 	{ 0xD0, 0x21 },
87 	{ 0xD1, 0x2C },
88 	{ 0xD2, 0x2F },
89 	{ 0xD3, 0x30 },
90 	{ 0xD4, 0x19 },
91 	{ 0xD5, 0x1F },
92 	{ 0xD6, 0x00 },
93 	{ 0xD7, 0x01 },
94 	{ 0xD8, 0x0B },
95 	{ 0xD9, 0x15 },
96 	{ 0xDA, 0x22 },
97 	{ 0xDB, 0x11 },
98 	{ 0xDC, 0x15 },
99 	{ 0xDD, 0x19 },
100 	{ 0xDE, 0x1A },
101 	{ 0xDF, 0x16 },
102 	{ 0xE0, 0x18 },
103 	{ 0xE1, 0x13 },
104 	{ 0xE2, 0x18 },
105 	{ 0xE3, 0x13 },
106 	{ 0xE4, 0x1C },
107 	{ 0xE5, 0x19 },
108 	{ 0xE6, 0x21 },
109 	{ 0xE7, 0x2C },
110 	{ 0xE8, 0x2F },
111 	{ 0xE9, 0x30 },
112 	{ 0xEA, 0x19 },
113 	{ 0xEB, 0x1F },
114 	/* GOA MUX setting */
115 	{ 0xB0, 0x01 },
116 	{ 0xC0, 0x10 },
117 	{ 0xC1, 0x0F },
118 	{ 0xC2, 0x0E },
119 	{ 0xC3, 0x0D },
120 	{ 0xC4, 0x0C },
121 	{ 0xC5, 0x0B },
122 	{ 0xC6, 0x0A },
123 	{ 0xC7, 0x09 },
124 	{ 0xC8, 0x08 },
125 	{ 0xC9, 0x07 },
126 	{ 0xCA, 0x06 },
127 	{ 0xCB, 0x05 },
128 	{ 0xCC, 0x00 },
129 	{ 0xCD, 0x01 },
130 	{ 0xCE, 0x02 },
131 	{ 0xCF, 0x03 },
132 	{ 0xD0, 0x04 },
133 	{ 0xD6, 0x10 },
134 	{ 0xD7, 0x0F },
135 	{ 0xD8, 0x0E },
136 	{ 0xD9, 0x0D },
137 	{ 0xDA, 0x0C },
138 	{ 0xDB, 0x0B },
139 	{ 0xDC, 0x0A },
140 	{ 0xDD, 0x09 },
141 	{ 0xDE, 0x08 },
142 	{ 0xDF, 0x07 },
143 	{ 0xE0, 0x06 },
144 	{ 0xE1, 0x05 },
145 	{ 0xE2, 0x00 },
146 	{ 0xE3, 0x01 },
147 	{ 0xE4, 0x02 },
148 	{ 0xE5, 0x03 },
149 	{ 0xE6, 0x04 },
150 	{ 0xE7, 0x00 },
151 	{ 0xEC, 0xC0 },
152 	/* GOA timing setting */
153 	{ 0xB0, 0x03 },
154 	{ 0xC0, 0x01 },
155 	{ 0xC2, 0x6F },
156 	{ 0xC3, 0x6F },
157 	{ 0xC5, 0x36 },
158 	{ 0xC8, 0x08 },
159 	{ 0xC9, 0x04 },
160 	{ 0xCA, 0x41 },
161 	{ 0xCC, 0x43 },
162 	{ 0xCF, 0x60 },
163 	{ 0xD2, 0x04 },
164 	{ 0xD3, 0x04 },
165 	{ 0xD4, 0x03 },
166 	{ 0xD5, 0x02 },
167 	{ 0xD6, 0x01 },
168 	{ 0xD7, 0x00 },
169 	{ 0xDB, 0x01 },
170 	{ 0xDE, 0x36 },
171 	{ 0xE6, 0x6F },
172 	{ 0xE7, 0x6F },
173 	/* GOE setting */
174 	{ 0xB0, 0x06 },
175 	{ 0xB8, 0xA5 },
176 	{ 0xC0, 0xA5 },
177 	{ 0xD5, 0x3F },
178 };
179 
180 static inline
181 struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
182 {
183 	return container_of(panel, struct kingdisplay_panel, base);
184 }
185 
186 static int kingdisplay_panel_disable(struct drm_panel *panel)
187 {
188 	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
189 	int err;
190 
191 	if (!kingdisplay->enabled)
192 		return 0;
193 
194 	backlight_disable(kingdisplay->backlight);
195 
196 	err = mipi_dsi_dcs_set_display_off(kingdisplay->link);
197 	if (err < 0)
198 		DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
199 			      err);
200 
201 	kingdisplay->enabled = false;
202 
203 	return 0;
204 }
205 
206 static int kingdisplay_panel_unprepare(struct drm_panel *panel)
207 {
208 	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
209 	int err;
210 
211 	if (!kingdisplay->prepared)
212 		return 0;
213 
214 	err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link);
215 	if (err < 0) {
216 		DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
217 			      err);
218 		return err;
219 	}
220 
221 	/* T15: 120ms */
222 	msleep(120);
223 
224 	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
225 
226 	err = regulator_disable(kingdisplay->supply);
227 	if (err < 0)
228 		return err;
229 
230 	kingdisplay->prepared = false;
231 
232 	return 0;
233 }
234 
235 static int kingdisplay_panel_prepare(struct drm_panel *panel)
236 {
237 	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
238 	int err, regulator_err;
239 	unsigned int i;
240 
241 	if (kingdisplay->prepared)
242 		return 0;
243 
244 	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
245 
246 	err = regulator_enable(kingdisplay->supply);
247 	if (err < 0)
248 		return err;
249 
250 	/* T2: 15ms */
251 	usleep_range(15000, 16000);
252 
253 	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
254 
255 	/* T4: 15ms */
256 	usleep_range(15000, 16000);
257 
258 	for (i = 0; i < ARRAY_SIZE(init_code); i++) {
259 		err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i],
260 					sizeof(struct kingdisplay_panel_cmd));
261 		if (err < 0) {
262 			DRM_DEV_ERROR(panel->dev, "failed write init cmds: %d\n",
263 				      err);
264 			goto poweroff;
265 		}
266 	}
267 
268 	err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link);
269 	if (err < 0) {
270 		DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n",
271 			      err);
272 		goto poweroff;
273 	}
274 
275 	/* T6: 120ms */
276 	msleep(120);
277 
278 	err = mipi_dsi_dcs_set_display_on(kingdisplay->link);
279 	if (err < 0) {
280 		DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n",
281 			      err);
282 		goto poweroff;
283 	}
284 
285 	/* T7: 10ms */
286 	usleep_range(10000, 11000);
287 
288 	kingdisplay->prepared = true;
289 
290 	return 0;
291 
292 poweroff:
293 	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
294 
295 	regulator_err = regulator_disable(kingdisplay->supply);
296 	if (regulator_err)
297 		DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n",
298 			      regulator_err);
299 
300 	return err;
301 }
302 
303 static int kingdisplay_panel_enable(struct drm_panel *panel)
304 {
305 	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
306 	int ret;
307 
308 	if (kingdisplay->enabled)
309 		return 0;
310 
311 	ret = backlight_enable(kingdisplay->backlight);
312 	if (ret) {
313 		DRM_DEV_ERROR(panel->drm->dev,
314 			      "Failed to enable backlight %d\n", ret);
315 		return ret;
316 	}
317 
318 	kingdisplay->enabled = true;
319 
320 	return 0;
321 }
322 
323 static const struct drm_display_mode default_mode = {
324 	.clock = 229000,
325 	.hdisplay = 1536,
326 	.hsync_start = 1536 + 100,
327 	.hsync_end = 1536 + 100 + 24,
328 	.htotal = 1536 + 100 + 24 + 100,
329 	.vdisplay = 2048,
330 	.vsync_start = 2048 + 95,
331 	.vsync_end = 2048 + 95 + 2,
332 	.vtotal = 2048 + 95 + 2 + 23,
333 	.vrefresh = 60,
334 };
335 
336 static int kingdisplay_panel_get_modes(struct drm_panel *panel)
337 {
338 	struct drm_display_mode *mode;
339 
340 	mode = drm_mode_duplicate(panel->drm, &default_mode);
341 	if (!mode) {
342 		DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
343 			      default_mode.hdisplay, default_mode.vdisplay,
344 			      default_mode.vrefresh);
345 		return -ENOMEM;
346 	}
347 
348 	drm_mode_set_name(mode);
349 
350 	drm_mode_probed_add(panel->connector, mode);
351 
352 	panel->connector->display_info.width_mm = 147;
353 	panel->connector->display_info.height_mm = 196;
354 	panel->connector->display_info.bpc = 8;
355 
356 	return 1;
357 }
358 
359 static const struct drm_panel_funcs kingdisplay_panel_funcs = {
360 	.disable = kingdisplay_panel_disable,
361 	.unprepare = kingdisplay_panel_unprepare,
362 	.prepare = kingdisplay_panel_prepare,
363 	.enable = kingdisplay_panel_enable,
364 	.get_modes = kingdisplay_panel_get_modes,
365 };
366 
367 static const struct of_device_id kingdisplay_of_match[] = {
368 	{ .compatible = "kingdisplay,kd097d04", },
369 	{ }
370 };
371 MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
372 
373 static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
374 {
375 	struct device *dev = &kingdisplay->link->dev;
376 	int err;
377 
378 	kingdisplay->supply = devm_regulator_get(dev, "power");
379 	if (IS_ERR(kingdisplay->supply))
380 		return PTR_ERR(kingdisplay->supply);
381 
382 	kingdisplay->enable_gpio = devm_gpiod_get_optional(dev, "enable",
383 							   GPIOD_OUT_HIGH);
384 	if (IS_ERR(kingdisplay->enable_gpio)) {
385 		err = PTR_ERR(kingdisplay->enable_gpio);
386 		dev_dbg(dev, "failed to get enable gpio: %d\n", err);
387 		kingdisplay->enable_gpio = NULL;
388 	}
389 
390 	kingdisplay->backlight = devm_of_find_backlight(dev);
391 	if (IS_ERR(kingdisplay->backlight))
392 		return PTR_ERR(kingdisplay->backlight);
393 
394 	drm_panel_init(&kingdisplay->base);
395 	kingdisplay->base.funcs = &kingdisplay_panel_funcs;
396 	kingdisplay->base.dev = &kingdisplay->link->dev;
397 
398 	return drm_panel_add(&kingdisplay->base);
399 }
400 
401 static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay)
402 {
403 	drm_panel_remove(&kingdisplay->base);
404 }
405 
406 static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
407 {
408 	struct kingdisplay_panel *kingdisplay;
409 	int err;
410 
411 	dsi->lanes = 4;
412 	dsi->format = MIPI_DSI_FMT_RGB888;
413 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
414 			  MIPI_DSI_MODE_LPM;
415 
416 	kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
417 	if (!kingdisplay)
418 		return -ENOMEM;
419 
420 	mipi_dsi_set_drvdata(dsi, kingdisplay);
421 	kingdisplay->link = dsi;
422 
423 	err = kingdisplay_panel_add(kingdisplay);
424 	if (err < 0)
425 		return err;
426 
427 	return mipi_dsi_attach(dsi);
428 }
429 
430 static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
431 {
432 	struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
433 	int err;
434 
435 	err = kingdisplay_panel_unprepare(&kingdisplay->base);
436 	if (err < 0)
437 		DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n",
438 			      err);
439 
440 	err = kingdisplay_panel_disable(&kingdisplay->base);
441 	if (err < 0)
442 		DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err);
443 
444 	err = mipi_dsi_detach(dsi);
445 	if (err < 0)
446 		DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n",
447 			      err);
448 
449 	kingdisplay_panel_del(kingdisplay);
450 
451 	return 0;
452 }
453 
454 static void kingdisplay_panel_shutdown(struct mipi_dsi_device *dsi)
455 {
456 	struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
457 
458 	kingdisplay_panel_unprepare(&kingdisplay->base);
459 	kingdisplay_panel_disable(&kingdisplay->base);
460 }
461 
462 static struct mipi_dsi_driver kingdisplay_panel_driver = {
463 	.driver = {
464 		.name = "panel-kingdisplay-kd097d04",
465 		.of_match_table = kingdisplay_of_match,
466 	},
467 	.probe = kingdisplay_panel_probe,
468 	.remove = kingdisplay_panel_remove,
469 	.shutdown = kingdisplay_panel_shutdown,
470 };
471 module_mipi_dsi_driver(kingdisplay_panel_driver);
472 
473 MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
474 MODULE_AUTHOR("Nickey Yang <nickey.yang@rock-chips.com>");
475 MODULE_DESCRIPTION("kingdisplay KD097D04 panel driver");
476 MODULE_LICENSE("GPL v2");
477