• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2016 InforceComputing
4  * Author: Vinay Simha BN <simhavcs@gmail.com>
5  *
6  * Copyright (C) 2016 Linaro Ltd
7  * Author: Sumit Semwal <sumit.semwal@linaro.org>
8  *
9  * From internet archives, the panel for Nexus 7 2nd Gen, 2013 model is a
10  * JDI model LT070ME05000, and its data sheet is at:
11  * http://panelone.net/en/7-0-inch/JDI_LT070ME05000_7.0_inch-datasheet
12  */
13 
14 #include <linux/backlight.h>
15 #include <linux/delay.h>
16 #include <linux/gpio/consumer.h>
17 #include <linux/module.h>
18 #include <linux/of.h>
19 #include <linux/regulator/consumer.h>
20 
21 #include <video/mipi_display.h>
22 
23 #include <drm/drm_crtc.h>
24 #include <drm/drm_mipi_dsi.h>
25 #include <drm/drm_modes.h>
26 #include <drm/drm_panel.h>
27 
28 static const char * const regulator_names[] = {
29 	"vddp",
30 	"iovcc"
31 };
32 
33 struct jdi_panel {
34 	struct drm_panel base;
35 	struct mipi_dsi_device *dsi;
36 
37 	struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];
38 
39 	struct gpio_desc *enable_gpio;
40 	struct gpio_desc *reset_gpio;
41 	struct gpio_desc *dcdc_en_gpio;
42 	struct backlight_device *backlight;
43 
44 	bool prepared;
45 	bool enabled;
46 
47 	const struct drm_display_mode *mode;
48 };
49 
to_jdi_panel(struct drm_panel * panel)50 static inline struct jdi_panel *to_jdi_panel(struct drm_panel *panel)
51 {
52 	return container_of(panel, struct jdi_panel, base);
53 }
54 
jdi_panel_init(struct jdi_panel * jdi)55 static int jdi_panel_init(struct jdi_panel *jdi)
56 {
57 	struct mipi_dsi_device *dsi = jdi->dsi;
58 	struct device *dev = &jdi->dsi->dev;
59 	int ret;
60 
61 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
62 
63 	ret = mipi_dsi_dcs_soft_reset(dsi);
64 	if (ret < 0)
65 		return ret;
66 
67 	usleep_range(10000, 20000);
68 
69 	ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
70 	if (ret < 0) {
71 		dev_err(dev, "failed to set pixel format: %d\n", ret);
72 		return ret;
73 	}
74 
75 	ret = mipi_dsi_dcs_set_column_address(dsi, 0, jdi->mode->hdisplay - 1);
76 	if (ret < 0) {
77 		dev_err(dev, "failed to set column address: %d\n", ret);
78 		return ret;
79 	}
80 
81 	ret = mipi_dsi_dcs_set_page_address(dsi, 0, jdi->mode->vdisplay - 1);
82 	if (ret < 0) {
83 		dev_err(dev, "failed to set page address: %d\n", ret);
84 		return ret;
85 	}
86 
87 	/*
88 	 * BIT(5) BCTRL = 1 Backlight Control Block On, Brightness registers
89 	 *                  are active
90 	 * BIT(3) BL = 1    Backlight Control On
91 	 * BIT(2) DD = 0    Display Dimming is Off
92 	 */
93 	ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
94 				 (u8[]){ 0x24 }, 1);
95 	if (ret < 0) {
96 		dev_err(dev, "failed to write control display: %d\n", ret);
97 		return ret;
98 	}
99 
100 	/* CABC off */
101 	ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_POWER_SAVE,
102 				 (u8[]){ 0x00 }, 1);
103 	if (ret < 0) {
104 		dev_err(dev, "failed to set cabc off: %d\n", ret);
105 		return ret;
106 	}
107 
108 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
109 	if (ret < 0) {
110 		dev_err(dev, "failed to set exit sleep mode: %d\n", ret);
111 		return ret;
112 	}
113 
114 	msleep(120);
115 
116 	ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x00}, 2);
117 	if (ret < 0) {
118 		dev_err(dev, "failed to set mcap: %d\n", ret);
119 		return ret;
120 	}
121 
122 	mdelay(10);
123 
124 	/* Interface setting, video mode */
125 	ret = mipi_dsi_generic_write(dsi, (u8[])
126 				     {0xB3, 0x26, 0x08, 0x00, 0x20, 0x00}, 6);
127 	if (ret < 0) {
128 		dev_err(dev, "failed to set display interface setting: %d\n"
129 			, ret);
130 		return ret;
131 	}
132 
133 	mdelay(20);
134 
135 	ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x03}, 2);
136 	if (ret < 0) {
137 		dev_err(dev, "failed to set default values for mcap: %d\n"
138 			, ret);
139 		return ret;
140 	}
141 
142 	return 0;
143 }
144 
jdi_panel_on(struct jdi_panel * jdi)145 static int jdi_panel_on(struct jdi_panel *jdi)
146 {
147 	struct mipi_dsi_device *dsi = jdi->dsi;
148 	struct device *dev = &jdi->dsi->dev;
149 	int ret;
150 
151 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
152 
153 	ret = mipi_dsi_dcs_set_display_on(dsi);
154 	if (ret < 0)
155 		dev_err(dev, "failed to set display on: %d\n", ret);
156 
157 	return ret;
158 }
159 
jdi_panel_off(struct jdi_panel * jdi)160 static void jdi_panel_off(struct jdi_panel *jdi)
161 {
162 	struct mipi_dsi_device *dsi = jdi->dsi;
163 	struct device *dev = &jdi->dsi->dev;
164 	int ret;
165 
166 	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
167 
168 	ret = mipi_dsi_dcs_set_display_off(dsi);
169 	if (ret < 0)
170 		dev_err(dev, "failed to set display off: %d\n", ret);
171 
172 	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
173 	if (ret < 0)
174 		dev_err(dev, "failed to enter sleep mode: %d\n", ret);
175 
176 	msleep(100);
177 }
178 
jdi_panel_disable(struct drm_panel * panel)179 static int jdi_panel_disable(struct drm_panel *panel)
180 {
181 	struct jdi_panel *jdi = to_jdi_panel(panel);
182 
183 	if (!jdi->enabled)
184 		return 0;
185 
186 	backlight_disable(jdi->backlight);
187 
188 	jdi->enabled = false;
189 
190 	return 0;
191 }
192 
jdi_panel_unprepare(struct drm_panel * panel)193 static int jdi_panel_unprepare(struct drm_panel *panel)
194 {
195 	struct jdi_panel *jdi = to_jdi_panel(panel);
196 	struct device *dev = &jdi->dsi->dev;
197 	int ret;
198 
199 	if (!jdi->prepared)
200 		return 0;
201 
202 	jdi_panel_off(jdi);
203 
204 	ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
205 	if (ret < 0)
206 		dev_err(dev, "regulator disable failed, %d\n", ret);
207 
208 	gpiod_set_value(jdi->enable_gpio, 0);
209 
210 	gpiod_set_value(jdi->reset_gpio, 1);
211 
212 	gpiod_set_value(jdi->dcdc_en_gpio, 0);
213 
214 	jdi->prepared = false;
215 
216 	return 0;
217 }
218 
jdi_panel_prepare(struct drm_panel * panel)219 static int jdi_panel_prepare(struct drm_panel *panel)
220 {
221 	struct jdi_panel *jdi = to_jdi_panel(panel);
222 	struct device *dev = &jdi->dsi->dev;
223 	int ret;
224 
225 	if (jdi->prepared)
226 		return 0;
227 
228 	ret = regulator_bulk_enable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
229 	if (ret < 0) {
230 		dev_err(dev, "regulator enable failed, %d\n", ret);
231 		return ret;
232 	}
233 
234 	msleep(20);
235 
236 	gpiod_set_value(jdi->dcdc_en_gpio, 1);
237 	usleep_range(10, 20);
238 
239 	gpiod_set_value(jdi->reset_gpio, 0);
240 	usleep_range(10, 20);
241 
242 	gpiod_set_value(jdi->enable_gpio, 1);
243 	usleep_range(10, 20);
244 
245 	ret = jdi_panel_init(jdi);
246 	if (ret < 0) {
247 		dev_err(dev, "failed to init panel: %d\n", ret);
248 		goto poweroff;
249 	}
250 
251 	ret = jdi_panel_on(jdi);
252 	if (ret < 0) {
253 		dev_err(dev, "failed to set panel on: %d\n", ret);
254 		goto poweroff;
255 	}
256 
257 	jdi->prepared = true;
258 
259 	return 0;
260 
261 poweroff:
262 	ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
263 	if (ret < 0)
264 		dev_err(dev, "regulator disable failed, %d\n", ret);
265 
266 	gpiod_set_value(jdi->enable_gpio, 0);
267 
268 	gpiod_set_value(jdi->reset_gpio, 1);
269 
270 	gpiod_set_value(jdi->dcdc_en_gpio, 0);
271 
272 	return ret;
273 }
274 
jdi_panel_enable(struct drm_panel * panel)275 static int jdi_panel_enable(struct drm_panel *panel)
276 {
277 	struct jdi_panel *jdi = to_jdi_panel(panel);
278 
279 	if (jdi->enabled)
280 		return 0;
281 
282 	backlight_enable(jdi->backlight);
283 
284 	jdi->enabled = true;
285 
286 	return 0;
287 }
288 
289 static const struct drm_display_mode default_mode = {
290 		.clock = 155493,
291 		.hdisplay = 1200,
292 		.hsync_start = 1200 + 48,
293 		.hsync_end = 1200 + 48 + 32,
294 		.htotal = 1200 + 48 + 32 + 60,
295 		.vdisplay = 1920,
296 		.vsync_start = 1920 + 3,
297 		.vsync_end = 1920 + 3 + 5,
298 		.vtotal = 1920 + 3 + 5 + 6,
299 		.flags = 0,
300 };
301 
jdi_panel_get_modes(struct drm_panel * panel,struct drm_connector * connector)302 static int jdi_panel_get_modes(struct drm_panel *panel,
303 			       struct drm_connector *connector)
304 {
305 	struct drm_display_mode *mode;
306 	struct jdi_panel *jdi = to_jdi_panel(panel);
307 	struct device *dev = &jdi->dsi->dev;
308 
309 	mode = drm_mode_duplicate(connector->dev, &default_mode);
310 	if (!mode) {
311 		dev_err(dev, "failed to add mode %ux%ux@%u\n",
312 			default_mode.hdisplay, default_mode.vdisplay,
313 			drm_mode_vrefresh(&default_mode));
314 		return -ENOMEM;
315 	}
316 
317 	drm_mode_set_name(mode);
318 
319 	drm_mode_probed_add(connector, mode);
320 
321 	connector->display_info.width_mm = 95;
322 	connector->display_info.height_mm = 151;
323 
324 	return 1;
325 }
326 
dsi_dcs_bl_get_brightness(struct backlight_device * bl)327 static int dsi_dcs_bl_get_brightness(struct backlight_device *bl)
328 {
329 	struct mipi_dsi_device *dsi = bl_get_data(bl);
330 	int ret;
331 	u16 brightness = bl->props.brightness;
332 
333 	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
334 
335 	ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);
336 	if (ret < 0)
337 		return ret;
338 
339 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
340 
341 	return brightness & 0xff;
342 }
343 
dsi_dcs_bl_update_status(struct backlight_device * bl)344 static int dsi_dcs_bl_update_status(struct backlight_device *bl)
345 {
346 	struct mipi_dsi_device *dsi = bl_get_data(bl);
347 	int ret;
348 
349 	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
350 
351 	ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness);
352 	if (ret < 0)
353 		return ret;
354 
355 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
356 
357 	return 0;
358 }
359 
360 static const struct backlight_ops dsi_bl_ops = {
361 	.update_status = dsi_dcs_bl_update_status,
362 	.get_brightness = dsi_dcs_bl_get_brightness,
363 };
364 
365 static struct backlight_device *
drm_panel_create_dsi_backlight(struct mipi_dsi_device * dsi)366 drm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi)
367 {
368 	struct device *dev = &dsi->dev;
369 	struct backlight_properties props;
370 
371 	memset(&props, 0, sizeof(props));
372 	props.type = BACKLIGHT_RAW;
373 	props.brightness = 255;
374 	props.max_brightness = 255;
375 
376 	return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
377 					      &dsi_bl_ops, &props);
378 }
379 
380 static const struct drm_panel_funcs jdi_panel_funcs = {
381 	.disable = jdi_panel_disable,
382 	.unprepare = jdi_panel_unprepare,
383 	.prepare = jdi_panel_prepare,
384 	.enable = jdi_panel_enable,
385 	.get_modes = jdi_panel_get_modes,
386 };
387 
388 static const struct of_device_id jdi_of_match[] = {
389 	{ .compatible = "jdi,lt070me05000", },
390 	{ }
391 };
392 MODULE_DEVICE_TABLE(of, jdi_of_match);
393 
jdi_panel_add(struct jdi_panel * jdi)394 static int jdi_panel_add(struct jdi_panel *jdi)
395 {
396 	struct device *dev = &jdi->dsi->dev;
397 	int ret;
398 	unsigned int i;
399 
400 	jdi->mode = &default_mode;
401 
402 	for (i = 0; i < ARRAY_SIZE(jdi->supplies); i++)
403 		jdi->supplies[i].supply = regulator_names[i];
404 
405 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(jdi->supplies),
406 				      jdi->supplies);
407 	if (ret < 0) {
408 		dev_err(dev, "failed to init regulator, ret=%d\n", ret);
409 		return ret;
410 	}
411 
412 	jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
413 	if (IS_ERR(jdi->enable_gpio)) {
414 		ret = PTR_ERR(jdi->enable_gpio);
415 		dev_err(dev, "cannot get enable-gpio %d\n", ret);
416 		return ret;
417 	}
418 
419 	jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
420 	if (IS_ERR(jdi->reset_gpio)) {
421 		ret = PTR_ERR(jdi->reset_gpio);
422 		dev_err(dev, "cannot get reset-gpios %d\n", ret);
423 		return ret;
424 	}
425 
426 	jdi->dcdc_en_gpio = devm_gpiod_get(dev, "dcdc-en", GPIOD_OUT_LOW);
427 	if (IS_ERR(jdi->dcdc_en_gpio)) {
428 		ret = PTR_ERR(jdi->dcdc_en_gpio);
429 		dev_err(dev, "cannot get dcdc-en-gpio %d\n", ret);
430 		return ret;
431 	}
432 
433 	jdi->backlight = drm_panel_create_dsi_backlight(jdi->dsi);
434 	if (IS_ERR(jdi->backlight)) {
435 		ret = PTR_ERR(jdi->backlight);
436 		dev_err(dev, "failed to register backlight %d\n", ret);
437 		return ret;
438 	}
439 
440 	drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs,
441 		       DRM_MODE_CONNECTOR_DSI);
442 
443 	drm_panel_add(&jdi->base);
444 
445 	return 0;
446 }
447 
jdi_panel_del(struct jdi_panel * jdi)448 static void jdi_panel_del(struct jdi_panel *jdi)
449 {
450 	if (jdi->base.dev)
451 		drm_panel_remove(&jdi->base);
452 }
453 
jdi_panel_probe(struct mipi_dsi_device * dsi)454 static int jdi_panel_probe(struct mipi_dsi_device *dsi)
455 {
456 	struct jdi_panel *jdi;
457 	int ret;
458 
459 	dsi->lanes = 4;
460 	dsi->format = MIPI_DSI_FMT_RGB888;
461 	dsi->mode_flags =  MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |
462 			   MIPI_DSI_CLOCK_NON_CONTINUOUS;
463 
464 	jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL);
465 	if (!jdi)
466 		return -ENOMEM;
467 
468 	mipi_dsi_set_drvdata(dsi, jdi);
469 
470 	jdi->dsi = dsi;
471 
472 	ret = jdi_panel_add(jdi);
473 	if (ret < 0)
474 		return ret;
475 
476 	ret = mipi_dsi_attach(dsi);
477 	if (ret < 0) {
478 		jdi_panel_del(jdi);
479 		return ret;
480 	}
481 
482 	return 0;
483 }
484 
jdi_panel_remove(struct mipi_dsi_device * dsi)485 static int jdi_panel_remove(struct mipi_dsi_device *dsi)
486 {
487 	struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
488 	int ret;
489 
490 	ret = jdi_panel_disable(&jdi->base);
491 	if (ret < 0)
492 		dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
493 
494 	ret = mipi_dsi_detach(dsi);
495 	if (ret < 0)
496 		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n",
497 			ret);
498 
499 	jdi_panel_del(jdi);
500 
501 	return 0;
502 }
503 
jdi_panel_shutdown(struct mipi_dsi_device * dsi)504 static void jdi_panel_shutdown(struct mipi_dsi_device *dsi)
505 {
506 	struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
507 
508 	jdi_panel_disable(&jdi->base);
509 }
510 
511 static struct mipi_dsi_driver jdi_panel_driver = {
512 	.driver = {
513 		.name = "panel-jdi-lt070me05000",
514 		.of_match_table = jdi_of_match,
515 	},
516 	.probe = jdi_panel_probe,
517 	.remove = jdi_panel_remove,
518 	.shutdown = jdi_panel_shutdown,
519 };
520 module_mipi_dsi_driver(jdi_panel_driver);
521 
522 MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>");
523 MODULE_AUTHOR("Vinay Simha BN <simhavcs@gmail.com>");
524 MODULE_DESCRIPTION("JDI LT070ME05000 WUXGA");
525 MODULE_LICENSE("GPL v2");
526