Files

289 lines
8.3 KiB
Diff
Raw Permalink Normal View History

2026-08-25 10:02:36 +08:00
From c1a1f1d0c9d7c23992cf44e74669b5cd9c7d9afd Mon Sep 17 00:00:00 2001
From: Philippe Simons <simons.philippe@gmail.com>
Date: Sun, 6 Jul 2025 00:18:34 +0200
Subject: [PATCH] gpu: panel: add Pocket ACE panel driver
---
drivers/gpu/drm/panel/Kconfig | 10 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-ar06-4inch.c | 235 +++++++++++++++++++++++
3 files changed, 246 insertions(+)
create mode 100644 drivers/gpu/drm/panel/panel-ar06-4inch.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index e059b06e0239..11c3d7106d50 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -17,6 +17,16 @@ config DRM_PANEL_ABT_Y030XX067A
Y030XX067A 320x480 3.0" panel as found in the YLM RG-280M, RG-300
and RG-99 handheld gaming consoles.
+config DRM_PANEL_AR06_4INCH
+ tristate "Ayaneo Pocket ACE panel driver"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_DISPLAY_HELPER
+ help
+ Say Y here if you want to enable support for Ayaneo Pocket ACE
+ 1080x1620 60hz Panel.
+
config DRM_PANEL_ARM_VERSATILE
tristate "ARM Versatile panel driver"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 1bb8ae46b59b..fb145bc6a8df 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_DRM_PANEL_ABT_Y030XX067A) += panel-abt-y030xx067a.o
+obj-$(CONFIG_DRM_PANEL_AR06_4INCH) += panel-ar06-4inch.o
obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596.o
obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o
diff --git a/drivers/gpu/drm/panel/panel-ar06-4inch.c b/drivers/gpu/drm/panel/panel-ar06-4inch.c
new file mode 100644
index 000000000000..fe76ac9fab2c
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-ar06-4inch.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2025 FIXME
+// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
+// Copyright (c) 2013, The Linux Foundation. All rights reserved. (FIXME)
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+struct ar06_4inch {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data *supplies;
+ enum drm_panel_orientation orientation;
+};
+
+static const struct regulator_bulk_data panel_supplies[] = {
+ { .supply = "avdd" },
+ { .supply = "vci" },
+ { .supply = "vddio" },
+};
+
+static inline struct ar06_4inch *to_ar06_4inch(struct drm_panel *panel)
+{
+ return container_of(panel, struct ar06_4inch, panel);
+}
+
+static void ar06_4inch_reset(struct ar06_4inch *ctx)
+{
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(10000, 11000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ usleep_range(10000, 11000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(10000, 11000);
+}
+
+static int ar06_4inch_on(struct ar06_4inch *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 200);
+ mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 120);
+
+ return dsi_ctx.accum_err;
+}
+
+static int ar06_4inch_off(struct ar06_4inch *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 120);
+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_usleep_range(&dsi_ctx, 10000, 11000);
+
+ return dsi_ctx.accum_err;
+}
+
+static int ar06_4inch_prepare(struct drm_panel *panel)
+{
+ struct ar06_4inch *ctx = to_ar06_4inch(panel);
+ struct device *dev = &ctx->dsi->dev;
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(panel_supplies), ctx->supplies);
+ if (ret < 0) {
+ dev_err(panel->dev, "failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+ msleep(20);
+
+ ar06_4inch_reset(ctx);
+
+ ret = ar06_4inch_on(ctx);
+ if (ret < 0) {
+ dev_err(dev, "Failed to initialize panel: %d\n", ret);
+ regulator_bulk_disable(ARRAY_SIZE(panel_supplies), ctx->supplies);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ar06_4inch_unprepare(struct drm_panel *panel)
+{
+ struct ar06_4inch *ctx = to_ar06_4inch(panel);
+ struct device *dev = &ctx->dsi->dev;
+ int ret;
+
+ ret = ar06_4inch_off(ctx);
+ if (ret < 0)
+ dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
+
+ regulator_bulk_disable(ARRAY_SIZE(panel_supplies), ctx->supplies);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+ return 0;
+}
+
+static const struct drm_display_mode ar06_4inch_mode = {
+ .clock = (1080 + 152 + 20 + 180) * (1620 + 18 + 2 + 5) * 60 / 1000,
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 152,
+ .hsync_end = 1080 + 152 + 20,
+ .htotal = 1080 + 152 + 20 + 180,
+ .vdisplay = 1620,
+ .vsync_start = 1620 + 18,
+ .vsync_end = 1620 + 18 + 2,
+ .vtotal = 1620 + 18 + 2 + 5,
+ .width_mm = 63,
+ .height_mm = 95,
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static int ar06_4inch_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ return drm_connector_helper_get_modes_fixed(connector, &ar06_4inch_mode);
+}
+
+static enum drm_panel_orientation ar06_4inch_get_orientation(struct drm_panel *panel)
+{
+ struct ar06_4inch *ctx = to_ar06_4inch(panel);
+
+ return ctx->orientation;
+}
+
+static const struct drm_panel_funcs ar06_4inch_panel_funcs = {
+ .prepare = ar06_4inch_prepare,
+ .unprepare = ar06_4inch_unprepare,
+ .get_modes = ar06_4inch_get_modes,
+ .get_orientation = ar06_4inch_get_orientation,
+};
+
+static int ar06_4inch_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct ar06_4inch *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(panel_supplies),
+ panel_supplies, &ctx->supplies);
+ if (ret < 0){
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
+ }
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(ctx->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+ "Failed to get reset-gpios\n");
+
+ ctx->dsi = dsi;
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS;
+
+ /* Orientation */
+ ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+ if (ret < 0) {
+ dev_err(dev, "failed to get orientation %d\n", ret);
+ return ret;
+ }
+
+ drm_panel_init(&ctx->panel, dev, &ar06_4inch_panel_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ ctx->panel.prepare_prev_first = true;
+
+ ret = drm_panel_of_backlight(&ctx->panel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get backlight\n");
+
+ drm_panel_add(&ctx->panel);
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ drm_panel_remove(&ctx->panel);
+ return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
+ }
+
+ return 0;
+}
+
+static void ar06_4inch_remove(struct mipi_dsi_device *dsi)
+{
+ struct ar06_4inch *ctx = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_remove(&ctx->panel);
+}
+
+static const struct of_device_id ar06_4inch_of_match[] = {
+ { .compatible = "ayaneo,pocket-ace-panel" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ar06_4inch_of_match);
+
+static struct mipi_dsi_driver ar06_4inch_driver = {
+ .probe = ar06_4inch_probe,
+ .remove = ar06_4inch_remove,
+ .driver = {
+ .name = "panel-ar06-4inch",
+ .of_match_table = ar06_4inch_of_match,
+ },
+};
+module_mipi_dsi_driver(ar06_4inch_driver);
+
+MODULE_AUTHOR("linux-mdss-dsi-panel-driver-generator <fix@me>"); // FIXME
+MODULE_DESCRIPTION("DRM driver for ar06 4inch video mode dsi panel");
+MODULE_LICENSE("GPL");
--
2.50.0