1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
6 #include <linux/backlight.h>
7 #include <linux/gpio/consumer.h>
8 #include <linux/module.h>
10 #include <linux/regulator/consumer.h>
13 #include <drm/drm_crtc.h>
14 #include <drm/drm_mipi_dsi.h>
15 #include <drm/drm_panel.h>
17 #include <video/mipi_display.h>
19 struct kingdisplay_panel
{
20 struct drm_panel base
;
21 struct mipi_dsi_device
*link
;
23 struct backlight_device
*backlight
;
24 struct regulator
*supply
;
25 struct gpio_desc
*enable_gpio
;
31 struct kingdisplay_panel_cmd
{
37 * According to the discussion on
38 * https://review.coreboot.org/#/c/coreboot/+/22472/
39 * the panel init array is not part of the panels datasheet but instead
40 * just came in this form from the panel vendor.
42 static const struct kingdisplay_panel_cmd init_code
[] = {
111 /* GOA MUX setting */
149 /* GOA timing setting */
178 struct kingdisplay_panel
*to_kingdisplay_panel(struct drm_panel
*panel
)
180 return container_of(panel
, struct kingdisplay_panel
, base
);
183 static int kingdisplay_panel_disable(struct drm_panel
*panel
)
185 struct kingdisplay_panel
*kingdisplay
= to_kingdisplay_panel(panel
);
188 if (!kingdisplay
->enabled
)
191 backlight_disable(kingdisplay
->backlight
);
193 err
= mipi_dsi_dcs_set_display_off(kingdisplay
->link
);
195 DRM_DEV_ERROR(panel
->dev
, "failed to set display off: %d\n",
198 kingdisplay
->enabled
= false;
203 static int kingdisplay_panel_unprepare(struct drm_panel
*panel
)
205 struct kingdisplay_panel
*kingdisplay
= to_kingdisplay_panel(panel
);
208 if (!kingdisplay
->prepared
)
211 err
= mipi_dsi_dcs_enter_sleep_mode(kingdisplay
->link
);
213 DRM_DEV_ERROR(panel
->dev
, "failed to enter sleep mode: %d\n",
221 gpiod_set_value_cansleep(kingdisplay
->enable_gpio
, 0);
223 err
= regulator_disable(kingdisplay
->supply
);
227 kingdisplay
->prepared
= false;
232 static int kingdisplay_panel_prepare(struct drm_panel
*panel
)
234 struct kingdisplay_panel
*kingdisplay
= to_kingdisplay_panel(panel
);
235 int err
, regulator_err
;
238 if (kingdisplay
->prepared
)
241 gpiod_set_value_cansleep(kingdisplay
->enable_gpio
, 0);
243 err
= regulator_enable(kingdisplay
->supply
);
248 usleep_range(15000, 16000);
250 gpiod_set_value_cansleep(kingdisplay
->enable_gpio
, 1);
253 usleep_range(15000, 16000);
255 for (i
= 0; i
< ARRAY_SIZE(init_code
); i
++) {
256 err
= mipi_dsi_generic_write(kingdisplay
->link
, &init_code
[i
],
257 sizeof(struct kingdisplay_panel_cmd
));
259 DRM_DEV_ERROR(panel
->dev
, "failed write init cmds: %d\n",
265 err
= mipi_dsi_dcs_exit_sleep_mode(kingdisplay
->link
);
267 DRM_DEV_ERROR(panel
->dev
, "failed to exit sleep mode: %d\n",
275 err
= mipi_dsi_dcs_set_display_on(kingdisplay
->link
);
277 DRM_DEV_ERROR(panel
->dev
, "failed to set display on: %d\n",
283 usleep_range(10000, 11000);
285 kingdisplay
->prepared
= true;
290 gpiod_set_value_cansleep(kingdisplay
->enable_gpio
, 0);
292 regulator_err
= regulator_disable(kingdisplay
->supply
);
294 DRM_DEV_ERROR(panel
->dev
, "failed to disable regulator: %d\n",
300 static int kingdisplay_panel_enable(struct drm_panel
*panel
)
302 struct kingdisplay_panel
*kingdisplay
= to_kingdisplay_panel(panel
);
305 if (kingdisplay
->enabled
)
308 ret
= backlight_enable(kingdisplay
->backlight
);
310 DRM_DEV_ERROR(panel
->drm
->dev
,
311 "Failed to enable backlight %d\n", ret
);
315 kingdisplay
->enabled
= true;
320 static const struct drm_display_mode default_mode
= {
323 .hsync_start
= 1536 + 100,
324 .hsync_end
= 1536 + 100 + 24,
325 .htotal
= 1536 + 100 + 24 + 100,
327 .vsync_start
= 2048 + 95,
328 .vsync_end
= 2048 + 95 + 2,
329 .vtotal
= 2048 + 95 + 2 + 23,
333 static int kingdisplay_panel_get_modes(struct drm_panel
*panel
)
335 struct drm_display_mode
*mode
;
337 mode
= drm_mode_duplicate(panel
->drm
, &default_mode
);
339 DRM_DEV_ERROR(panel
->drm
->dev
, "failed to add mode %ux%ux@%u\n",
340 default_mode
.hdisplay
, default_mode
.vdisplay
,
341 default_mode
.vrefresh
);
345 drm_mode_set_name(mode
);
347 drm_mode_probed_add(panel
->connector
, mode
);
349 panel
->connector
->display_info
.width_mm
= 147;
350 panel
->connector
->display_info
.height_mm
= 196;
351 panel
->connector
->display_info
.bpc
= 8;
356 static const struct drm_panel_funcs kingdisplay_panel_funcs
= {
357 .disable
= kingdisplay_panel_disable
,
358 .unprepare
= kingdisplay_panel_unprepare
,
359 .prepare
= kingdisplay_panel_prepare
,
360 .enable
= kingdisplay_panel_enable
,
361 .get_modes
= kingdisplay_panel_get_modes
,
364 static const struct of_device_id kingdisplay_of_match
[] = {
365 { .compatible
= "kingdisplay,kd097d04", },
368 MODULE_DEVICE_TABLE(of
, kingdisplay_of_match
);
370 static int kingdisplay_panel_add(struct kingdisplay_panel
*kingdisplay
)
372 struct device
*dev
= &kingdisplay
->link
->dev
;
375 kingdisplay
->supply
= devm_regulator_get(dev
, "power");
376 if (IS_ERR(kingdisplay
->supply
))
377 return PTR_ERR(kingdisplay
->supply
);
379 kingdisplay
->enable_gpio
= devm_gpiod_get_optional(dev
, "enable",
381 if (IS_ERR(kingdisplay
->enable_gpio
)) {
382 err
= PTR_ERR(kingdisplay
->enable_gpio
);
383 dev_dbg(dev
, "failed to get enable gpio: %d\n", err
);
384 kingdisplay
->enable_gpio
= NULL
;
387 kingdisplay
->backlight
= devm_of_find_backlight(dev
);
388 if (IS_ERR(kingdisplay
->backlight
))
389 return PTR_ERR(kingdisplay
->backlight
);
391 drm_panel_init(&kingdisplay
->base
);
392 kingdisplay
->base
.funcs
= &kingdisplay_panel_funcs
;
393 kingdisplay
->base
.dev
= &kingdisplay
->link
->dev
;
395 return drm_panel_add(&kingdisplay
->base
);
398 static void kingdisplay_panel_del(struct kingdisplay_panel
*kingdisplay
)
400 drm_panel_remove(&kingdisplay
->base
);
403 static int kingdisplay_panel_probe(struct mipi_dsi_device
*dsi
)
405 struct kingdisplay_panel
*kingdisplay
;
409 dsi
->format
= MIPI_DSI_FMT_RGB888
;
410 dsi
->mode_flags
= MIPI_DSI_MODE_VIDEO
| MIPI_DSI_MODE_VIDEO_BURST
|
413 kingdisplay
= devm_kzalloc(&dsi
->dev
, sizeof(*kingdisplay
), GFP_KERNEL
);
417 mipi_dsi_set_drvdata(dsi
, kingdisplay
);
418 kingdisplay
->link
= dsi
;
420 err
= kingdisplay_panel_add(kingdisplay
);
424 return mipi_dsi_attach(dsi
);
427 static int kingdisplay_panel_remove(struct mipi_dsi_device
*dsi
)
429 struct kingdisplay_panel
*kingdisplay
= mipi_dsi_get_drvdata(dsi
);
432 err
= kingdisplay_panel_unprepare(&kingdisplay
->base
);
434 DRM_DEV_ERROR(&dsi
->dev
, "failed to unprepare panel: %d\n",
437 err
= kingdisplay_panel_disable(&kingdisplay
->base
);
439 DRM_DEV_ERROR(&dsi
->dev
, "failed to disable panel: %d\n", err
);
441 err
= mipi_dsi_detach(dsi
);
443 DRM_DEV_ERROR(&dsi
->dev
, "failed to detach from DSI host: %d\n",
446 kingdisplay_panel_del(kingdisplay
);
451 static void kingdisplay_panel_shutdown(struct mipi_dsi_device
*dsi
)
453 struct kingdisplay_panel
*kingdisplay
= mipi_dsi_get_drvdata(dsi
);
455 kingdisplay_panel_unprepare(&kingdisplay
->base
);
456 kingdisplay_panel_disable(&kingdisplay
->base
);
459 static struct mipi_dsi_driver kingdisplay_panel_driver
= {
461 .name
= "panel-kingdisplay-kd097d04",
462 .of_match_table
= kingdisplay_of_match
,
464 .probe
= kingdisplay_panel_probe
,
465 .remove
= kingdisplay_panel_remove
,
466 .shutdown
= kingdisplay_panel_shutdown
,
468 module_mipi_dsi_driver(kingdisplay_panel_driver
);
470 MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
471 MODULE_AUTHOR("Nickey Yang <nickey.yang@rock-chips.com>");
472 MODULE_DESCRIPTION("kingdisplay KD097D04 panel driver");
473 MODULE_LICENSE("GPL v2");