[PATCH v2] video: add ChipWealth CH13726A AMOLED panel driver
Svyatoslav Ryhel
clamor95 at gmail.com
Tue Jul 7 10:14:03 CEST 2026
чт, 2 лип. 2026 р. о 18:14 Advait Dhamorikar <advaitd at mechasystems.com> пише:
>
> Add support for AMOLED panels based on the ChipWealth CH13726A
> MIPI DSI display driver IC.
>
> The driver configures the MIPI DSI interface for 4 data lanes in RGB888
> video mode, performs the panel reset sequence, sends the vendor-specific
> initialization commands required by the controller, and enables the
> panel using the standard MIPI DCS Sleep Out and Display On commands.
>
> This driver is based on an earlier implementation by Pratham Malaviya.
>
> Signed-off-by: Advait Dhamorikar <advaitd at mechasystems.com>
> ---
>
> v1->v2
> - Expand CC list based on get_maintainer.pl output.
>
> drivers/video/Kconfig | 8 ++
> drivers/video/Makefile | 1 +
> drivers/video/chipwealth-ch13726a.c | 193 ++++++++++++++++++++++++++++
> 3 files changed, 202 insertions(+)
> create mode 100644 drivers/video/chipwealth-ch13726a.c
>
Hey there! Thanks for your contribution, it is pretty solid but there
are a few places that can be improved.
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index c2acc13139c..7e82778e294 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -533,6 +533,14 @@ config VIDEO_BCM2835
> that same resolution (or as near as possible) and 32bpp depth, so
> that U-Boot can access it with full colour depth.
>
> +config VIDEO_AMOLED_CHIPWEALTH_CH13726A
May you please rename AMOLED > PANEL
> + bool "ChipWealth CH13726A AMOLED panel support"
> + depends on VIDEO
"depends on PANEL && BACKLIGHT"
> + select VIDEO_MIPI_DSI
> + help
> + Say Y here if you want to enable support for AMOLED panels
> + based on the ChipWealth CH13726A MIPI DSI display driver IC.
> +
> config VIDEO_LCD_ENDEAVORU
> tristate "Endeavoru 720x1280 DSI video mode panel"
> depends on PANEL && BACKLIGHT
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 082b8967982..56df5e1860d 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -55,6 +55,7 @@ obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o
> obj-$(CONFIG_VIDEO_DW_MIPI_DSI) += dw_mipi_dsi.o
> obj-$(CONFIG_VIDEO_EFI) += efi.o
> obj-y += imx/
> +obj-$(CONFIG_VIDEO_AMOLED_CHIPWEALTH_CH13726A) += chipwealth-ch13726a.o
> obj-$(CONFIG_VIDEO_IVYBRIDGE_IGD) += ivybridge_igd.o
> obj-$(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804) += anx9804.o
> obj-$(CONFIG_VIDEO_LCD_ENDEAVORU) += endeavoru-panel.o
> diff --git a/drivers/video/chipwealth-ch13726a.c b/drivers/video/chipwealth-ch13726a.c
> new file mode 100644
> index 00000000000..e6fef6c8e7f
> --- /dev/null
> +++ b/drivers/video/chipwealth-ch13726a.c
> @@ -0,0 +1,193 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * ChipWealth CH13726A DSI panel driver
> + *
> + * Copyright (C) 2026 Mecha Systems
> + * Author(s):
> + * Advait Dhamorikar <advaitd at mechasystems.com>
> + * Pratham Malaviya <prathamm at mechasystems.com>
> + */
> +
> +#include <backlight.h>
> +#include <dm.h>
> +#include <mipi_dsi.h>
> +#include <panel.h>
> +#include <asm/gpio.h>
> +#include <linux/delay.h>
> +#include <log.h>
> +
> +struct ch13726a_panel_priv {
> + struct udevice *reg;
> + struct udevice *backlight;
> + struct gpio_desc reset;
> +};
You are lacking supplies here: vdd1v2, vddio, vdd and avdd
U-Boot can handle them so you should include control over them.
> +
> +static const struct display_timing default_timing = {
> + .pixelclock.typ = 59832000,
> + .hactive.typ = 1080,
> + .hfront_porch.typ = 12,
> + .hback_porch.typ = 12,
> + .hsync_len.typ = 28,
> + .vactive.typ = 1240,
> + .vfront_porch.typ = 2,
> + .vback_porch.typ = 2,
> + .vsync_len.typ = 2,
> +};
> +
> +static int ch13726a_dcs_write_buf(struct udevice *dev, const void *data,
> + size_t len)
> +{
> + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
> + int ret;
> +
> + ret = mipi_dsi_dcs_write_buffer(plat->device, data, len);
> + if (ret < 0)
> + log_err("failed to write dcs sequence: %d\n", ret);
> +
> + return ret;
> +}
> +
> +#define dcs_write_seq(dev, cmd, seq...) \
> +({ \
> + const u8 d[] = { cmd, seq }; \
> + \
> + ch13726a_dcs_write_buf(dev, d, ARRAY_SIZE(d)); \
> +})
> +
You can fold this.
> +static void ch13726a_reset(struct udevice *dev)
> +{
> + struct ch13726a_panel_priv *priv = dev_get_priv(dev);
> +
> + dm_gpio_set_value(&priv->reset, true);
> + mdelay(10);
> + dm_gpio_set_value(&priv->reset, false);
> + mdelay(10);
> + dm_gpio_set_value(&priv->reset, true);
> + mdelay(5);
> +}
> +
> +static int ch13726a_set_backlight(struct udevice *dev, int percent)
> +{
> + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
> + struct mipi_dsi_device *device = plat->device;
> + u8 brightness;
> +
> + if (percent < 0)
> + percent = 0;
> + else if (percent > 100)
> + percent = 100;
> +
> + brightness = (percent * 255) / 100;
> +
> + return mipi_dsi_dcs_set_display_brightness(device, brightness);
> +}
> +
> +static int ch13726a_panel_enable_backlight(struct udevice *dev)
> +{
> + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
> + struct mipi_dsi_device *device = plat->device;
> + int ret;
> +
> + device->lanes = plat->lanes;
> + device->format = plat->format;
> + device->mode_flags = plat->mode_flags;
> +
You don't need this assignment.
> + ret = mipi_dsi_attach(device);
> + if (ret < 0)
> + return ret;
> +
> + ch13726a_reset(dev);
> +
> + device->mode_flags |= MIPI_DSI_MODE_LPM;
> +
LPM flag is removed by mipi_dsi_device_transfer so you don't need it here.
> + ret = dcs_write_seq(dev, 0x53, 0x00);
> + if (ret < 0) {
> + log_debug("%s: Init command failed(%d)\n",
> + __func__, ret);
> + return ret;
> + }
> +
> + ret = dcs_write_seq(dev, 0x17, 0x00);
> + if (ret < 0) {
> + log_debug("%s: Init command failed (%d)\n",
> + __func__, ret);
> + return ret;
> + }
> +
> + ret = dcs_write_seq(dev, 0x41, 0x00);
> + if (ret < 0) {
> + log_debug("%s: Init command failed (%d)\n",
> + __func__, ret);
> + return ret;
> + }
> +
> + ret = mipi_dsi_dcs_exit_sleep_mode(device);
> + if (ret)
> + return ret;
> +
> + mdelay(120);
> +
> + ret = mipi_dsi_dcs_set_display_on(device);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +static int ch13726a_panel_get_display_timing(struct udevice *dev,
> + struct display_timing *timings)
> +{
> + memcpy(timings, &default_timing, sizeof(*timings));
> + return 0;
> +}
> +
> +static int ch13726a_panel_of_to_plat(struct udevice *dev)
> +{
> + struct ch13726a_panel_priv *priv = dev_get_priv(dev);
> + int ret;
> +
> + ret = gpio_request_by_name(dev, "reset-gpios", 0,
> + &priv->reset,
> + GPIOD_IS_OUT);
> + if (ret) {
> + log_err("%s: cannot get reset GPIO (%d)\n",
> + __func__, ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int ch13726a_panel_probe(struct udevice *dev)
> +{
> + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
> +
> + plat->lanes = 4;
> + plat->format = MIPI_DSI_FMT_RGB888;
> + plat->mode_flags = MIPI_DSI_MODE_VIDEO |
> + MIPI_DSI_MODE_VIDEO_BURST;
> +
> + return 0;
> +}
> +
> +static const struct panel_ops ch13726a_panel_ops = {
> + .enable_backlight = ch13726a_panel_enable_backlight,
> + .set_backlight = ch13726a_set_backlight,
> + .get_display_timing = ch13726a_panel_get_display_timing,
> +};
> +
> +static const struct udevice_id ch13726a_panel_ids[] = {
> + { .compatible = "chipwealth,ch13726a" },
> + { }
> +};
> +
> +U_BOOT_DRIVER(ch13726a_panel) = {
> + .name = "ch13726a_panel",
> + .id = UCLASS_PANEL,
> + .of_match = ch13726a_panel_ids,
> + .ops = &ch13726a_panel_ops,
> + .of_to_plat = ch13726a_panel_of_to_plat,
> + .probe = ch13726a_panel_probe,
> + .plat_auto = sizeof(struct mipi_dsi_panel_plat),
> + .priv_auto = sizeof(struct ch13726a_panel_priv),
> +};
> --
> 2.43.0
>
More information about the U-Boot
mailing list