drm: panel: Add Orise Technology ota7290b dsi panel
authorHaaland Chen <haaland@milkv.io>
Fri, 1 Dec 2023 09:55:39 +0000 (17:55 +0800)
committerJaehoon Chung <jh80.chung@samsung.com>
Wed, 13 Mar 2024 06:59:04 +0000 (15:59 +0900)
Signed-off-by: Haaland Chen <haaland@milkv.io>
(cherry picked from commit 93bec7933ce8df4093ccb9e99070b25ddc68fa85)
Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/Makefile
drivers/gpu/drm/panel/panel-orisetech-ota7290b.c [new file with mode: 0644]

index 2ca5f4b6d81bf083f4c27b8c68f271905d1bd44b..152cc1ef836a6df3d9c70965da8f1d9a3ed09616 100644 (file)
@@ -241,6 +241,15 @@ config DRM_PANEL_OLIMEX_LCD_OLINUXINO
          Say Y here if you want to enable support for Olimex Ltd.
          LCD-OLinuXino panel.
 
+config DRM_PANEL_ORISETECH_OTA7290B
+       tristate "Orise Technology ota7290b dsi panel"
+       depends on OF
+       depends on DRM_MIPI_DSI
+       depends on BACKLIGHT_CLASS_DEVICE
+       help
+         Say Y here if you want to enable support for Orise Technology
+         ota7290b dsi panel.
+
 config DRM_PANEL_ORISETECH_OTM8009A
        tristate "Orise Technology otm8009a 480x800 dsi 2dl panel"
        depends on OF
index 1ca5576d6d70b12cbda2708d7c2f04ab9e83c7ca..9a2a75695e78c627f8f07d7c28696003d8dbdfb6 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o
 obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o
 obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o
 obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o
+obj-$(CONFIG_DRM_PANEL_ORISETECH_OTA7290B) += panel-orisetech-ota7290b.o
 obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o
 obj-$(CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS) += panel-osd-osd101t2587-53ts.o
 obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
diff --git a/drivers/gpu/drm/panel/panel-orisetech-ota7290b.c b/drivers/gpu/drm/panel/panel-orisetech-ota7290b.c
new file mode 100644 (file)
index 0000000..78fb864
--- /dev/null
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019 Radxa Limited
+ * Copyright (c) 2022 Edgeble AI Technologies Pvt. Ltd.
+ *
+ * Author:
+ * - Jagan Teki <jagan@amarulasolutions.com>
+ * - Stephen Chen <stephen@radxa.com>
+ *
+ * This file based on panel-jadard-jd9365da-h3.c
+ */
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+
+struct orisetech_panel_desc {
+       const struct drm_display_mode mode;
+       unsigned int lanes;
+       enum mipi_dsi_pixel_format format;
+};
+
+struct orisetech {
+       struct drm_panel panel;
+       struct mipi_dsi_device *dsi;
+       const struct orisetech_panel_desc *desc;
+
+       struct regulator *vdd;
+       struct regulator *vccio;
+       struct gpio_desc *reset;
+};
+
+static inline struct orisetech *panel_to_orisetech(struct drm_panel *panel)
+{
+       return container_of(panel, struct orisetech, panel);
+}
+
+static int orisetech_enable(struct drm_panel *panel)
+{
+       struct device *dev = panel->dev;
+       struct orisetech *orisetech = panel_to_orisetech(panel);
+       struct mipi_dsi_device *dsi = orisetech->dsi;
+       int err;
+
+       msleep(10);
+
+       err = mipi_dsi_dcs_exit_sleep_mode(dsi);
+       if (err < 0)
+               DRM_DEV_ERROR(dev, "failed to exit sleep mode ret = %d\n", err);
+
+       err =  mipi_dsi_dcs_set_display_on(dsi);
+       if (err < 0)
+               DRM_DEV_ERROR(dev, "failed to set display on ret = %d\n", err);
+
+       return 0;
+}
+
+static int orisetech_disable(struct drm_panel *panel)
+{
+       struct device *dev = panel->dev;
+       struct orisetech *orisetech = panel_to_orisetech(panel);
+       int ret;
+
+       ret = mipi_dsi_dcs_set_display_off(orisetech->dsi);
+       if (ret < 0)
+               DRM_DEV_ERROR(dev, "failed to set display off: %d\n", ret);
+
+       ret = mipi_dsi_dcs_enter_sleep_mode(orisetech->dsi);
+       if (ret < 0)
+               DRM_DEV_ERROR(dev, "failed to enter sleep mode: %d\n", ret);
+
+       return 0;
+}
+
+static int orisetech_prepare(struct drm_panel *panel)
+{
+       struct orisetech *orisetech = panel_to_orisetech(panel);
+       int ret;
+
+       ret = regulator_enable(orisetech->vccio);
+       if (ret)
+               return ret;
+
+       ret = regulator_enable(orisetech->vdd);
+       if (ret)
+               return ret;
+
+       gpiod_set_value(orisetech->reset, 1);
+       msleep(5);
+
+       gpiod_set_value(orisetech->reset, 0);
+       msleep(120);
+
+       gpiod_set_value(orisetech->reset, 1);
+       msleep(120);
+
+       return 0;
+}
+
+static int orisetech_unprepare(struct drm_panel *panel)
+{
+       struct orisetech *orisetech = panel_to_orisetech(panel);
+
+       gpiod_set_value(orisetech->reset, 1);
+       msleep(120);
+
+       regulator_disable(orisetech->vdd);
+       regulator_disable(orisetech->vccio);
+
+       return 0;
+}
+
+static int orisetech_get_modes(struct drm_panel *panel,
+                           struct drm_connector *connector)
+{
+       struct orisetech *orisetech = panel_to_orisetech(panel);
+       const struct drm_display_mode *desc_mode = &orisetech->desc->mode;
+       struct drm_display_mode *mode;
+
+       mode = drm_mode_duplicate(connector->dev, desc_mode);
+       if (!mode) {
+               DRM_DEV_ERROR(&orisetech->dsi->dev, "failed to add mode %ux%ux@%u\n",
+                             desc_mode->hdisplay, desc_mode->vdisplay,
+                             drm_mode_vrefresh(desc_mode));
+               return -ENOMEM;
+       }
+
+       drm_mode_set_name(mode);
+       drm_mode_probed_add(connector, mode);
+
+       connector->display_info.width_mm = mode->width_mm;
+       connector->display_info.height_mm = mode->height_mm;
+
+       return 1;
+}
+
+static const struct drm_panel_funcs orisetech_funcs = {
+       .disable = orisetech_disable,
+       .unprepare = orisetech_unprepare,
+       .prepare = orisetech_prepare,
+       .enable = orisetech_enable,
+       .get_modes = orisetech_get_modes,
+};
+
+static const struct orisetech_panel_desc radxa_display_10fhd_ad003_desc = {
+       .mode = {
+               .clock        = 160000,
+
+               .hdisplay    = 1200,
+               .hsync_start    = 1200 + 80,
+               .hsync_end    = 1200 + 80 + 60,
+               .htotal        = 1200 + 80 + 60 + 4,
+
+               .vdisplay    = 1920,
+               .vsync_start    = 1920 + 35,
+               .vsync_end    = 1920 + 35 + 25,
+               .vtotal        = 1920 + 35 + 25 + 4,
+
+               .width_mm    = 135,
+               .height_mm    = 217,
+               .type        = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+               .flags          = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+       },
+       .lanes = 4,
+       .format = MIPI_DSI_FMT_RGB888,
+};
+
+static int orisetech_dsi_probe(struct mipi_dsi_device *dsi)
+{
+       struct device *dev = &dsi->dev;
+       const struct orisetech_panel_desc *desc;
+       struct orisetech *orisetech;
+       int ret;
+
+       orisetech = devm_kzalloc(&dsi->dev, sizeof(*orisetech), GFP_KERNEL);
+       if (!orisetech)
+               return -ENOMEM;
+
+       desc = of_device_get_match_data(dev);
+       dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+                         MIPI_DSI_MODE_EOT_PACKET;
+       dsi->format = desc->format;
+       dsi->lanes = desc->lanes;
+
+       orisetech->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(orisetech->reset)) {
+               DRM_DEV_ERROR(&dsi->dev, "failed to get our reset GPIO\n");
+               return PTR_ERR(orisetech->reset);
+       }
+
+       orisetech->vdd = devm_regulator_get(dev, "vdd");
+       if (IS_ERR(orisetech->vdd)) {
+               DRM_DEV_ERROR(&dsi->dev, "failed to get vdd regulator\n");
+               return PTR_ERR(orisetech->vdd);
+       }
+
+       orisetech->vccio = devm_regulator_get(dev, "vccio");
+       if (IS_ERR(orisetech->vccio)) {
+               DRM_DEV_ERROR(&dsi->dev, "failed to get vccio regulator\n");
+               return PTR_ERR(orisetech->vccio);
+       }
+
+       drm_panel_init(&orisetech->panel, dev, &orisetech_funcs,
+                      DRM_MODE_CONNECTOR_DSI);
+
+       ret = drm_panel_of_backlight(&orisetech->panel);
+       if (ret)
+               return ret;
+
+       drm_panel_add(&orisetech->panel);
+
+       mipi_dsi_set_drvdata(dsi, orisetech);
+       orisetech->dsi = dsi;
+       orisetech->desc = desc;
+
+       ret = mipi_dsi_attach(dsi);
+       if (ret < 0)
+               drm_panel_remove(&orisetech->panel);
+
+       return ret;
+}
+
+static int orisetech_dsi_remove(struct mipi_dsi_device *dsi)
+{
+       struct orisetech *orisetech = mipi_dsi_get_drvdata(dsi);
+
+       mipi_dsi_detach(dsi);
+       drm_panel_remove(&orisetech->panel);
+
+       return 0;
+}
+
+static const struct of_device_id orisetech_of_match[] = {
+       { .compatible = "radxa,display-10fhd-ad003", .data = &radxa_display_10fhd_ad003_desc },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, orisetech_of_match);
+
+static struct mipi_dsi_driver orisetech_driver = {
+       .probe = orisetech_dsi_probe,
+       .remove = orisetech_dsi_remove,
+       .driver = {
+               .name = "orisetech-ota7290b",
+               .of_match_table = orisetech_of_match,
+       },
+};
+module_mipi_dsi_driver(orisetech_driver);
+
+MODULE_AUTHOR("Haaland Chen <haaland@milkv.io>");
+MODULE_DESCRIPTION("Orise Tech OTA7290B TFT-LCD panel");
+MODULE_LICENSE("GPL");