1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020 BayLibre, SAS
7 #include <linux/delay.h>
8 #include <linux/gpio/consumer.h>
9 #include <linux/module.h>
11 #include <linux/regulator/consumer.h>
13 #include <video/mipi_display.h>
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>
21 struct khadas_ts050_panel {
22 struct drm_panel base;
23 struct mipi_dsi_device *link;
25 struct regulator *supply;
26 struct gpio_desc *reset_gpio;
27 struct gpio_desc *enable_gpio;
33 struct khadas_ts050_panel_cmd {
38 /* Only the CMD1 User Command set is documented */
39 static const struct khadas_ts050_panel_cmd init_code[] = {
40 /* Select Unknown CMD Page (Undocumented) */
42 /* Reload CMD1: Don't reload default value to register */
55 /* Select CMD2 Page0 (Undocumented) */
57 /* Reload CMD1: Don't reload default value to register */
101 /* Select CMD2 Page4 (Undocumented) */
103 /* Reload CMD1: Don't reload default value to register */
189 /* Select CMD2 Page0 (Undocumented) */
191 /* Reload CMD1: Don't reload default value to register */
325 /* Select CMD2 Page2 (Undocumented) */
327 /* Reload CMD1: Don't reload default value to register */
557 /* Select CMD2 Page0 (Undocumented) */
559 /* Reload CMD1: Don't reload default value to register */
561 /* Select CMD2 Page1 (Undocumented) */
563 /* Reload CMD1: Don't reload default value to register */
565 /* Select CMD2 Page3 (Undocumented) */
567 /* Reload CMD1: Don't reload default value to register */
571 {0xd3, 0x22}, /* RGBMIPICTRL: VSYNC back porch = 34 */
572 {0xd4, 0x04}, /* RGBMIPICTRL: VSYNC front porch = 4 */
576 struct khadas_ts050_panel *to_khadas_ts050_panel(struct drm_panel *panel)
578 return container_of(panel, struct khadas_ts050_panel, base);
581 static int khadas_ts050_panel_prepare(struct drm_panel *panel)
583 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel);
587 if (khadas_ts050->prepared)
590 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0);
592 err = regulator_enable(khadas_ts050->supply);
596 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 1);
600 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1);
602 usleep_range(10000, 11000);
604 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 0);
606 /* Select CMD2 page 4 (Undocumented) */
607 mipi_dsi_dcs_write(khadas_ts050->link, 0xff, (u8[]){ 0x05 }, 1);
609 /* Reload CMD1: Don't reload default value to register */
610 mipi_dsi_dcs_write(khadas_ts050->link, 0xfb, (u8[]){ 0x01 }, 1);
612 mipi_dsi_dcs_write(khadas_ts050->link, 0xc5, (u8[]){ 0x01 }, 1);
616 for (i = 0; i < ARRAY_SIZE(init_code); i++) {
617 err = mipi_dsi_dcs_write(khadas_ts050->link,
619 &init_code[i].data, 1);
621 dev_err(panel->dev, "failed write cmds: %d\n", err);
626 err = mipi_dsi_dcs_exit_sleep_mode(khadas_ts050->link);
628 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
635 mipi_dsi_dcs_write(khadas_ts050->link, 0xff, (u8[]){ 0x00 }, 1);
637 err = mipi_dsi_dcs_set_tear_on(khadas_ts050->link,
638 MIPI_DSI_DCS_TEAR_MODE_VBLANK);
640 dev_err(panel->dev, "failed to set tear on: %d\n", err);
644 err = mipi_dsi_dcs_set_display_on(khadas_ts050->link);
646 dev_err(panel->dev, "failed to set display on: %d\n", err);
650 usleep_range(10000, 11000);
652 khadas_ts050->prepared = true;
657 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0);
658 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1);
660 regulator_disable(khadas_ts050->supply);
665 static int khadas_ts050_panel_unprepare(struct drm_panel *panel)
667 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel);
670 if (!khadas_ts050->prepared)
673 khadas_ts050->prepared = false;
675 err = mipi_dsi_dcs_enter_sleep_mode(khadas_ts050->link);
677 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
681 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0);
682 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1);
684 err = regulator_disable(khadas_ts050->supply);
691 static int khadas_ts050_panel_enable(struct drm_panel *panel)
693 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel);
695 khadas_ts050->enabled = true;
700 static int khadas_ts050_panel_disable(struct drm_panel *panel)
702 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel);
705 if (!khadas_ts050->enabled)
708 err = mipi_dsi_dcs_set_display_off(khadas_ts050->link);
710 dev_err(panel->dev, "failed to set display off: %d\n", err);
712 usleep_range(10000, 11000);
714 khadas_ts050->enabled = false;
719 static const struct drm_display_mode default_mode = {
722 .hsync_start = 1080 + 117,
723 .hsync_end = 1080 + 117 + 5,
724 .htotal = 1080 + 117 + 5 + 160,
726 .vsync_start = 1920 + 4,
727 .vsync_end = 1920 + 4 + 3,
728 .vtotal = 1920 + 4 + 3 + 31,
729 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
732 static int khadas_ts050_panel_get_modes(struct drm_panel *panel,
733 struct drm_connector *connector)
735 struct drm_display_mode *mode;
737 mode = drm_mode_duplicate(connector->dev, &default_mode);
739 dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
740 default_mode.hdisplay, default_mode.vdisplay,
741 drm_mode_vrefresh(&default_mode));
745 drm_mode_set_name(mode);
747 drm_mode_probed_add(connector, mode);
749 connector->display_info.width_mm = 64;
750 connector->display_info.height_mm = 118;
751 connector->display_info.bpc = 8;
756 static const struct drm_panel_funcs khadas_ts050_panel_funcs = {
757 .prepare = khadas_ts050_panel_prepare,
758 .unprepare = khadas_ts050_panel_unprepare,
759 .enable = khadas_ts050_panel_enable,
760 .disable = khadas_ts050_panel_disable,
761 .get_modes = khadas_ts050_panel_get_modes,
764 static const struct of_device_id khadas_ts050_of_match[] = {
765 { .compatible = "khadas,ts050", },
768 MODULE_DEVICE_TABLE(of, khadas_ts050_of_match);
770 static int khadas_ts050_panel_add(struct khadas_ts050_panel *khadas_ts050)
772 struct device *dev = &khadas_ts050->link->dev;
775 khadas_ts050->supply = devm_regulator_get(dev, "power");
776 if (IS_ERR(khadas_ts050->supply))
777 return dev_err_probe(dev, PTR_ERR(khadas_ts050->supply),
778 "failed to get power supply");
780 khadas_ts050->reset_gpio = devm_gpiod_get(dev, "reset",
782 if (IS_ERR(khadas_ts050->reset_gpio))
783 return dev_err_probe(dev, PTR_ERR(khadas_ts050->reset_gpio),
784 "failed to get reset gpio");
786 khadas_ts050->enable_gpio = devm_gpiod_get(dev, "enable",
788 if (IS_ERR(khadas_ts050->enable_gpio))
789 return dev_err_probe(dev, PTR_ERR(khadas_ts050->enable_gpio),
790 "failed to get enable gpio");
792 drm_panel_init(&khadas_ts050->base, &khadas_ts050->link->dev,
793 &khadas_ts050_panel_funcs, DRM_MODE_CONNECTOR_DSI);
795 err = drm_panel_of_backlight(&khadas_ts050->base);
799 drm_panel_add(&khadas_ts050->base);
804 static int khadas_ts050_panel_probe(struct mipi_dsi_device *dsi)
806 struct khadas_ts050_panel *khadas_ts050;
810 dsi->format = MIPI_DSI_FMT_RGB888;
811 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
812 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
814 khadas_ts050 = devm_kzalloc(&dsi->dev, sizeof(*khadas_ts050),
819 mipi_dsi_set_drvdata(dsi, khadas_ts050);
820 khadas_ts050->link = dsi;
822 err = khadas_ts050_panel_add(khadas_ts050);
826 err = mipi_dsi_attach(dsi);
828 drm_panel_remove(&khadas_ts050->base);
833 static void khadas_ts050_panel_remove(struct mipi_dsi_device *dsi)
835 struct khadas_ts050_panel *khadas_ts050 = mipi_dsi_get_drvdata(dsi);
838 err = mipi_dsi_detach(dsi);
840 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
842 drm_panel_remove(&khadas_ts050->base);
843 drm_panel_disable(&khadas_ts050->base);
844 drm_panel_unprepare(&khadas_ts050->base);
847 static void khadas_ts050_panel_shutdown(struct mipi_dsi_device *dsi)
849 struct khadas_ts050_panel *khadas_ts050 = mipi_dsi_get_drvdata(dsi);
851 drm_panel_disable(&khadas_ts050->base);
852 drm_panel_unprepare(&khadas_ts050->base);
855 static struct mipi_dsi_driver khadas_ts050_panel_driver = {
857 .name = "panel-khadas-ts050",
858 .of_match_table = khadas_ts050_of_match,
860 .probe = khadas_ts050_panel_probe,
861 .remove = khadas_ts050_panel_remove,
862 .shutdown = khadas_ts050_panel_shutdown,
864 module_mipi_dsi_driver(khadas_ts050_panel_driver);
867 MODULE_DESCRIPTION("Khadas TS050 panel driver");
868 MODULE_LICENSE("GPL v2");