* [PATCH v2 0/2] drm/panel: add support for Ilitek ILI7807S DSI panels
@ 2026-06-18 10:24 Arpit Saini
2026-06-18 10:24 ` [PATCH v2 1/2] dt-bindings: display: panel: add Ilitek ILI7807S panel controller Arpit Saini
2026-06-18 10:24 ` [PATCH v2 2/2] drm/panel: add Ilitek ILI7807S panel driver Arpit Saini
0 siblings, 2 replies; 5+ messages in thread
From: Arpit Saini @ 2026-06-18 10:24 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: arpit.saini, linux-arm-msm, dri-devel, devicetree, linux-kernel,
ayushi.makhija, rajeevny
Add DT bindings and a DRM panel driver for panels based on the Ilitek
ILI7807S display controller. The first supported panel is the DLC
DLC0697 1080x1920@60Hz MIPI DSI panel.
Changes in v2:
- Drop MAINTAINERS entry (Dmitry Baryshkov)
- Use devm_drm_panel_add() instead of drm_panel_add() to avoid
manual drm_panel_remove() in the error path (Dmitry Baryshkov)
- Rework backlight: call drm_panel_of_backlight() first and fall back
to creating a DCS backlight device if panel->backlight is still NULL
(Dmitry Baryshkov)
- Remove backlight-en-gpios from the binding (Dmitry Baryshkov)
- Fix mode_flags LPM not restored on backlight update error path
- Link to v1 : https://lore.kernel.org/all/20260518-ili7807s-panel-v1-0-d7b048163b1c@oss.qualcomm.com/
---
Arpit Saini (2):
dt-bindings: display: panel: add Ilitek ILI7807S panel controller
drm/panel: add Ilitek ILI7807S panel driver
.../bindings/display/panel/ilitek,ili7807s.yaml | 71 +++++
drivers/gpu/drm/panel/Kconfig | 12 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-ilitek-ili7807s.c | 297 +++++++++++++++++++++
4 files changed, 381 insertions(+)
---
base-commit: abe651837cb394f76d738a7a747322fca3bf17ba
change-id: 20260615-ili7807s-panel
Best regards,
--
Arpit Saini <arpit.saini@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/2] dt-bindings: display: panel: add Ilitek ILI7807S panel controller
2026-06-18 10:24 [PATCH v2 0/2] drm/panel: add support for Ilitek ILI7807S DSI panels Arpit Saini
@ 2026-06-18 10:24 ` Arpit Saini
2026-06-18 10:24 ` [PATCH v2 2/2] drm/panel: add Ilitek ILI7807S panel driver Arpit Saini
1 sibling, 0 replies; 5+ messages in thread
From: Arpit Saini @ 2026-06-18 10:24 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: arpit.saini, linux-arm-msm, dri-devel, devicetree, linux-kernel,
ayushi.makhija, rajeevny
ILI7807S is a DSI display controller used to drive MIPI-DSI panels.
The DLC DLC0697 1080x1920 LCD panel is based on this controller.
The panel requires a reset GPIO, I/O voltage supply (vddi), positive
LCD bias supply (avdd) and negative LCD bias supply (avee). The panel
operates in video burst mode with four data lanes using RGB888 pixel
format.
Signed-off-by: Arpit Saini <arpit.saini@oss.qualcomm.com>
---
.../bindings/display/panel/ilitek,ili7807s.yaml | 71 ++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili7807s.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili7807s.yaml
new file mode 100644
index 000000000000..ba8c5bbf8ffc
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili7807s.yaml
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/ilitek,ili7807s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Ilitek ILI7807S-based DSI panels
+
+maintainers:
+ - Arpit Saini <arpit.saini@oss.qualcomm.com>
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - dlc,dlc0697
+ - const: ilitek,ili7807s
+
+ reg:
+ maxItems: 1
+ description: DSI virtual channel
+
+ vddi-supply:
+ description: I/O voltage supply (1.8V)
+
+ avdd-supply:
+ description: Positive LCD bias supply (AVDD), typically +5.5V
+ (range 4.5V to 6.3V)
+
+ avee-supply:
+ description: Negative LCD bias supply (AVEE), typically -5.5V
+ (range -6.3V to -4.5V)
+
+required:
+ - compatible
+ - reg
+ - reset-gpios
+ - vddi-supply
+ - avdd-supply
+ - avee-supply
+ - port
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel@0 {
+ compatible = "dlc,dlc0697", "ilitek,ili7807s";
+ reg = <0>;
+
+ reset-gpios = <&tlmm 3 GPIO_ACTIVE_LOW>;
+ vddi-supply = <&pm4125_l15>;
+ avdd-supply = <&avdd>;
+ avee-supply = <&avee>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dsi0_out>;
+ };
+ };
+ };
+ };
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 2/2] drm/panel: add Ilitek ILI7807S panel driver
2026-06-18 10:24 [PATCH v2 0/2] drm/panel: add support for Ilitek ILI7807S DSI panels Arpit Saini
2026-06-18 10:24 ` [PATCH v2 1/2] dt-bindings: display: panel: add Ilitek ILI7807S panel controller Arpit Saini
@ 2026-06-18 10:24 ` Arpit Saini
2026-06-18 10:32 ` sashiko-bot
2026-06-18 12:43 ` Neil Armstrong
1 sibling, 2 replies; 5+ messages in thread
From: Arpit Saini @ 2026-06-18 10:24 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: arpit.saini, linux-arm-msm, dri-devel, devicetree, linux-kernel,
ayushi.makhija, rajeevny
Add a DRM panel driver for the DLC DLC0697 1080x1920@60Hz MIPI DSI
panel based on the Ilitek ILI7807S display controller.
The panel operates in video burst mode with four data lanes using
RGB888 pixel format.
Signed-off-by: Arpit Saini <arpit.saini@oss.qualcomm.com>
---
drivers/gpu/drm/panel/Kconfig | 12 ++
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-ilitek-ili7807s.c | 297 ++++++++++++++++++++++++++
3 files changed, 310 insertions(+)
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 7450b27622a2..1cbaac1bf545 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -264,6 +264,18 @@ config DRM_PANEL_HYDIS_HV101HD1
If M is selected the module will be called panel-hydis-hv101hd1
+config DRM_PANEL_ILITEK_ILI7807S
+ tristate "Ilitek ILI7807S-based panels"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y if you want to enable support for panels based on the
+ Ilitek ILI7807S display controller, such as the DLC DLC0697
+ 1080x1920 MIPI DSI panel.
+
+ If M is selected the module will be called panel-ilitek-ili7807s.
+
config DRM_PANEL_ILITEK_IL9322
tristate "Ilitek ILI9322 320x240 QVGA panels"
depends on OF && SPI
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index c2c5cf817116..c3002b351cb8 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112B) += panel-himax-hx83112b.o
obj-$(CONFIG_DRM_PANEL_HIMAX_HX83121A) += panel-himax-hx83121a.o
obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
obj-$(CONFIG_DRM_PANEL_HYDIS_HV101HD1) += panel-hydis-hv101hd1.o
+obj-$(CONFIG_DRM_PANEL_ILITEK_ILI7807S) += panel-ilitek-ili7807s.o
obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9805) += panel-ilitek-ili9805.o
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili7807s.c b/drivers/gpu/drm/panel/panel-ilitek-ili7807s.c
new file mode 100644
index 000000000000..bfbb8e29a4aa
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili7807s.c
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.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 panel_desc {
+ const struct drm_display_mode *mode;
+ unsigned int lanes;
+ enum mipi_dsi_pixel_format format;
+ unsigned long mode_flags;
+ void (*init)(struct mipi_dsi_multi_context *dsi_ctx);
+};
+
+struct ili7807s {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+ const struct panel_desc *desc;
+
+ struct regulator_bulk_data *supplies;
+ struct gpio_desc *reset_gpio;
+};
+
+static const struct regulator_bulk_data ili7807s_supplies[] = {
+ { .supply = "vddi" },
+ { .supply = "avdd" },
+ { .supply = "avee" },
+};
+
+static inline struct ili7807s *to_ili7807s(struct drm_panel *panel)
+{
+ return container_of(panel, struct ili7807s, panel);
+}
+
+static void ili7807s_reset(struct ili7807s *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 void dlc0697_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
+{
+ mipi_dsi_dcs_soft_reset_multi(dsi_ctx);
+ mipi_dsi_msleep(dsi_ctx, 120);
+
+ mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0x78, 0x07, 0x00);
+ mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x35, 0x00);
+ mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x5e, 0x09, 0x99);
+ mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x53, 0x24);
+ mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x55, 0x01);
+ mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x51, 0x3f, 0xff);
+
+ mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
+ mipi_dsi_msleep(dsi_ctx, 120);
+
+ mipi_dsi_dcs_set_display_on_multi(dsi_ctx);
+ mipi_dsi_msleep(dsi_ctx, 20);
+}
+
+static int ili7807s_on(struct ili7807s *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ ctx->desc->init(&dsi_ctx);
+
+ ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ return dsi_ctx.accum_err;
+}
+
+static int ili7807s_off(struct ili7807s *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, 20);
+
+ mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 120);
+
+ ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ return dsi_ctx.accum_err;
+}
+
+static int ili7807s_prepare(struct drm_panel *panel)
+{
+ struct ili7807s *ctx = to_ili7807s(panel);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ili7807s_supplies), ctx->supplies);
+ if (ret < 0) {
+ dev_err(ctx->panel.dev, "failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ msleep(20);
+
+ ili7807s_reset(ctx);
+
+ ret = ili7807s_on(ctx);
+ if (ret < 0) {
+ dev_err(ctx->panel.dev, "failed to initialise panel: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+ regulator_bulk_disable(ARRAY_SIZE(ili7807s_supplies), ctx->supplies);
+ return ret;
+}
+
+static int ili7807s_unprepare(struct drm_panel *panel)
+{
+ struct ili7807s *ctx = to_ili7807s(panel);
+ int ret;
+
+ ret = ili7807s_off(ctx);
+ if (ret < 0)
+ dev_err(ctx->panel.dev, "failed to disable panel: %d\n", ret);
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+ regulator_bulk_disable(ARRAY_SIZE(ili7807s_supplies), ctx->supplies);
+
+ return 0;
+}
+
+static int ili7807s_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct ili7807s *ctx = to_ili7807s(panel);
+
+ return drm_connector_helper_get_modes_fixed(connector, ctx->desc->mode);
+}
+
+static const struct drm_panel_funcs ili7807s_panel_funcs = {
+ .prepare = ili7807s_prepare,
+ .unprepare = ili7807s_unprepare,
+ .get_modes = ili7807s_get_modes,
+};
+
+static int ili7807s_bl_update_status(struct backlight_device *bl)
+{
+ struct mipi_dsi_device *dsi = bl_get_data(bl);
+ u16 brightness = backlight_get_brightness(bl);
+ int ret;
+
+ dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ return ret;
+}
+
+static const struct backlight_ops ili7807s_bl_ops = {
+ .update_status = ili7807s_bl_update_status,
+};
+
+static struct backlight_device *ili7807s_create_backlight(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ const struct backlight_properties props = {
+ .type = BACKLIGHT_RAW,
+ .brightness = 0x3fff,
+ .max_brightness = 0x3fff,
+ };
+
+ return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
+ &ili7807s_bl_ops, &props);
+}
+
+static const struct drm_display_mode dlc0697_mode = {
+ .clock = 131911,
+
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 18,
+ .hsync_end = 1080 + 18 + 2,
+ .htotal = 1080 + 18 + 2 + 16,
+
+ .vdisplay = 1920,
+ .vsync_start = 1920 + 26,
+ .vsync_end = 1920 + 26 + 4,
+ .vtotal = 1920 + 26 + 4 + 20,
+
+ .width_mm = 0,
+ .height_mm = 0,
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static const struct panel_desc dlc0697_desc = {
+ .mode = &dlc0697_mode,
+ .lanes = 4,
+ .format = MIPI_DSI_FMT_RGB888,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,
+ .init = dlc0697_init_sequence,
+};
+
+static int ili7807s_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ const struct panel_desc *desc;
+ struct ili7807s *ctx;
+ int ret;
+
+ ctx = devm_drm_panel_alloc(dev, struct ili7807s, panel,
+ &ili7807s_panel_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ desc = of_device_get_match_data(dev);
+ ctx->desc = desc;
+
+ ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(ili7807s_supplies),
+ ili7807s_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_LOW);
+ if (IS_ERR(ctx->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+ "failed to get reset gpio\n");
+
+ ctx->dsi = dsi;
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ dsi->lanes = desc->lanes;
+ dsi->format = desc->format;
+ dsi->mode_flags = desc->mode_flags;
+
+ ctx->panel.prepare_prev_first = true;
+
+ ret = drm_panel_of_backlight(&ctx->panel);
+ if (ret)
+ return ret;
+
+ if (!ctx->panel.backlight) {
+ ctx->panel.backlight = ili7807s_create_backlight(dsi);
+ if (IS_ERR(ctx->panel.backlight))
+ return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
+ "failed to create backlight\n");
+ }
+
+ ret = devm_drm_panel_add(dev, &ctx->panel);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to add panel\n");
+
+ ret = devm_mipi_dsi_attach(dev, dsi);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to attach dsi\n");
+
+ return 0;
+}
+
+static const struct of_device_id ili7807s_of_match[] = {
+ { .compatible = "dlc,dlc0697", .data = &dlc0697_desc },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ili7807s_of_match);
+
+static struct mipi_dsi_driver ili7807s_dsi_driver = {
+ .probe = ili7807s_probe,
+ .driver = {
+ .name = "panel-ilitek-ili7807s",
+ .of_match_table = ili7807s_of_match,
+ },
+};
+module_mipi_dsi_driver(ili7807s_dsi_driver);
+
+MODULE_AUTHOR("Arpit Saini <arpit.saini@oss.qualcomm.com>");
+MODULE_DESCRIPTION("Panel driver for Ilitek ILI7807S LCD DSI panel");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 2/2] drm/panel: add Ilitek ILI7807S panel driver
2026-06-18 10:24 ` [PATCH v2 2/2] drm/panel: add Ilitek ILI7807S panel driver Arpit Saini
@ 2026-06-18 10:32 ` sashiko-bot
2026-06-18 12:43 ` Neil Armstrong
1 sibling, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-06-18 10:32 UTC (permalink / raw)
To: Arpit Saini; +Cc: robh, devicetree, dri-devel, conor+dt
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Inverted manipulation of MIPI_DSI_MODE_LPM in backlight update_status callback permanently corrupts DSI mode flags.
- [High] Concurrent read-modify-write operations on dsi->mode_flags can cause state corruption.
- [Medium] Backlight update_status callback sends DCS commands without checking if the panel is powered on.
- [Medium] Incorrect devm registration order causes the DSI device to be detached while the DRM panel and backlight sysfs are still active.
- [Medium] Missing NULL check for the return value of of_device_get_match_data() leads to a potential NULL pointer dereference.
--
commit 97a4deef0ca55e71f3420d40260130de4242cae3
Author: Arpit Saini <arpit.saini@oss.qualcomm.com>
drm/panel: add Ilitek ILI7807S panel driver
This commit adds a DRM panel driver for the DLC DLC0697 1080x1920@60Hz
MIPI DSI panel based on the Ilitek ILI7807S display controller.
> diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili7807s.c b/drivers/gpu/drm/panel/panel-ilitek-ili7807s.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-ilitek-ili7807s.c
[ ... ]
> +static int ili7807s_bl_update_status(struct backlight_device *bl)
> +{
> + struct mipi_dsi_device *dsi = bl_get_data(bl);
> + u16 brightness = backlight_get_brightness(bl);
> + int ret;
> +
[Severity: Medium]
Is it safe to send DCS commands here without checking if the panel is
currently powered on? If userspace writes to the sysfs brightness control
while the regulators are disabled and the panel is off, will this attempt
to send commands and cause DSI bus timeouts?
> + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> +
> + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
> +
> + dsi->mode_flags |= MIPI_DSI_MODE_LPM;
[Severity: High]
Does this sequence invert the intended mode flags? The default panel mode
flags do not include MIPI_DSI_MODE_LPM. Clearing it beforehand and setting it
afterward will permanently force the DSI host into Low Power Mode after the
first backlight update, which might break subsequent video transmissions.
[Severity: High]
Can concurrent calls to ili7807s_on(), ili7807s_off(), and this backlight
update callback cause a data race? These functions all modify dsi->mode_flags
using non-atomic bitwise operations, which might clobber each other's changes
if a backlight update is triggered from userspace simultaneously with a DRM
DPMS event.
[ ... ]
> +static int ili7807s_probe(struct mipi_dsi_device *dsi)
> +{
> + struct device *dev = &dsi->dev;
> + const struct panel_desc *desc;
> + struct ili7807s *ctx;
> + int ret;
> +
> + ctx = devm_drm_panel_alloc(dev, struct ili7807s, panel,
> + &ili7807s_panel_funcs,
> + DRM_MODE_CONNECTOR_DSI);
> + if (IS_ERR(ctx))
> + return PTR_ERR(ctx);
> +
> + desc = of_device_get_match_data(dev);
> + ctx->desc = desc;
[Severity: Medium]
Can of_device_get_match_data() return NULL if the driver is bound manually
via sysfs without an associated device tree node? If so, will dereferencing
desc->lanes later in this function cause a NULL pointer dereference?
[ ... ]
> + ret = devm_drm_panel_add(dev, &ctx->panel);
> + if (ret < 0)
> + return dev_err_probe(dev, ret, "failed to add panel\n");
> +
> + ret = devm_mipi_dsi_attach(dev, dsi);
> + if (ret < 0)
> + return dev_err_probe(dev, ret, "failed to attach dsi\n");
> +
> + return 0;
> +}
[Severity: Medium]
Does this devres registration order cause a teardown issue? Since devres
cleans up in reverse order of allocation, devm_mipi_dsi_detach() will run
before the DRM panel and backlight interfaces are removed. Could this leave
the sysfs interfaces exposed to userspace while the underlying DSI device is
already detached?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-ili7807s-v2-0-b3f0c109b102@oss.qualcomm.com?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 2/2] drm/panel: add Ilitek ILI7807S panel driver
2026-06-18 10:24 ` [PATCH v2 2/2] drm/panel: add Ilitek ILI7807S panel driver Arpit Saini
2026-06-18 10:32 ` sashiko-bot
@ 2026-06-18 12:43 ` Neil Armstrong
1 sibling, 0 replies; 5+ messages in thread
From: Neil Armstrong @ 2026-06-18 12:43 UTC (permalink / raw)
To: Arpit Saini, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-msm, dri-devel, devicetree, linux-kernel,
ayushi.makhija, rajeevny
On 6/18/26 12:24, Arpit Saini wrote:
> Add a DRM panel driver for the DLC DLC0697 1080x1920@60Hz MIPI DSI
> panel based on the Ilitek ILI7807S display controller.
>
> The panel operates in video burst mode with four data lanes using
> RGB888 pixel format.
>
> Signed-off-by: Arpit Saini <arpit.saini@oss.qualcomm.com>
> ---
> drivers/gpu/drm/panel/Kconfig | 12 ++
> drivers/gpu/drm/panel/Makefile | 1 +
> drivers/gpu/drm/panel/panel-ilitek-ili7807s.c | 297 ++++++++++++++++++++++++++
> 3 files changed, 310 insertions(+)
>
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index 7450b27622a2..1cbaac1bf545 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -264,6 +264,18 @@ config DRM_PANEL_HYDIS_HV101HD1
>
> If M is selected the module will be called panel-hydis-hv101hd1
>
> +config DRM_PANEL_ILITEK_ILI7807S
> + tristate "Ilitek ILI7807S-based panels"
> + depends on OF
> + depends on DRM_MIPI_DSI
> + depends on BACKLIGHT_CLASS_DEVICE
> + help
> + Say Y if you want to enable support for panels based on the
> + Ilitek ILI7807S display controller, such as the DLC DLC0697
> + 1080x1920 MIPI DSI panel.
> +
> + If M is selected the module will be called panel-ilitek-ili7807s.
> +
> config DRM_PANEL_ILITEK_IL9322
> tristate "Ilitek ILI9322 320x240 QVGA panels"
> depends on OF && SPI
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index c2c5cf817116..c3002b351cb8 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -26,6 +26,7 @@ obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112B) += panel-himax-hx83112b.o
> obj-$(CONFIG_DRM_PANEL_HIMAX_HX83121A) += panel-himax-hx83121a.o
> obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
> obj-$(CONFIG_DRM_PANEL_HYDIS_HV101HD1) += panel-hydis-hv101hd1.o
> +obj-$(CONFIG_DRM_PANEL_ILITEK_ILI7807S) += panel-ilitek-ili7807s.o
> obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
> obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
> obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9805) += panel-ilitek-ili9805.o
> diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili7807s.c b/drivers/gpu/drm/panel/panel-ilitek-ili7807s.c
> new file mode 100644
> index 000000000000..bfbb8e29a4aa
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-ilitek-ili7807s.c
> @@ -0,0 +1,297 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#include <linux/backlight.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/of.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 panel_desc {
> + const struct drm_display_mode *mode;
> + unsigned int lanes;
> + enum mipi_dsi_pixel_format format;
> + unsigned long mode_flags;
> + void (*init)(struct mipi_dsi_multi_context *dsi_ctx);
> +};
> +
> +struct ili7807s {
> + struct drm_panel panel;
> + struct mipi_dsi_device *dsi;
> + const struct panel_desc *desc;
> +
> + struct regulator_bulk_data *supplies;
> + struct gpio_desc *reset_gpio;
> +};
> +
> +static const struct regulator_bulk_data ili7807s_supplies[] = {
> + { .supply = "vddi" },
> + { .supply = "avdd" },
> + { .supply = "avee" },
> +};
> +
> +static inline struct ili7807s *to_ili7807s(struct drm_panel *panel)
> +{
> + return container_of(panel, struct ili7807s, panel);
> +}
> +
> +static void ili7807s_reset(struct ili7807s *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 void dlc0697_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
> +{
> + mipi_dsi_dcs_soft_reset_multi(dsi_ctx);
> + mipi_dsi_msleep(dsi_ctx, 120);
> +
> + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0x78, 0x07, 0x00);
> + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x35, 0x00);
> + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x5e, 0x09, 0x99);
> + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x53, 0x24);
> + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x55, 0x01);
> + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x51, 0x3f, 0xff);
> +
> + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
> + mipi_dsi_msleep(dsi_ctx, 120);
> +
> + mipi_dsi_dcs_set_display_on_multi(dsi_ctx);
> + mipi_dsi_msleep(dsi_ctx, 20);
> +}
> +
> +static int ili7807s_on(struct ili7807s *ctx)
> +{
> + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
> +
> + ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
> +
> + ctx->desc->init(&dsi_ctx);
> +
> + ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> +
> + return dsi_ctx.accum_err;
> +}
> +
> +static int ili7807s_off(struct ili7807s *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, 20);
> +
> + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
> + mipi_dsi_msleep(&dsi_ctx, 120);
> +
> + ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> +
> + return dsi_ctx.accum_err;
> +}
> +
> +static int ili7807s_prepare(struct drm_panel *panel)
> +{
> + struct ili7807s *ctx = to_ili7807s(panel);
> + int ret;
> +
> + ret = regulator_bulk_enable(ARRAY_SIZE(ili7807s_supplies), ctx->supplies);
> + if (ret < 0) {
> + dev_err(ctx->panel.dev, "failed to enable regulators: %d\n", ret);
> + return ret;
> + }
> +
> + msleep(20);
> +
> + ili7807s_reset(ctx);
> +
> + ret = ili7807s_on(ctx);
> + if (ret < 0) {
> + dev_err(ctx->panel.dev, "failed to initialise panel: %d\n", ret);
> + goto err;
> + }
> +
> + return 0;
> +
> +err:
> + gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> +
> + regulator_bulk_disable(ARRAY_SIZE(ili7807s_supplies), ctx->supplies);
> + return ret;
> +}
> +
> +static int ili7807s_unprepare(struct drm_panel *panel)
> +{
> + struct ili7807s *ctx = to_ili7807s(panel);
> + int ret;
> +
> + ret = ili7807s_off(ctx);
> + if (ret < 0)
> + dev_err(ctx->panel.dev, "failed to disable panel: %d\n", ret);
> +
> + gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> +
> + regulator_bulk_disable(ARRAY_SIZE(ili7807s_supplies), ctx->supplies);
> +
> + return 0;
> +}
> +
> +static int ili7807s_get_modes(struct drm_panel *panel,
> + struct drm_connector *connector)
> +{
> + struct ili7807s *ctx = to_ili7807s(panel);
> +
> + return drm_connector_helper_get_modes_fixed(connector, ctx->desc->mode);
> +}
> +
> +static const struct drm_panel_funcs ili7807s_panel_funcs = {
> + .prepare = ili7807s_prepare,
> + .unprepare = ili7807s_unprepare,
> + .get_modes = ili7807s_get_modes,
> +};
> +
> +static int ili7807s_bl_update_status(struct backlight_device *bl)
> +{
> + struct mipi_dsi_device *dsi = bl_get_data(bl);
> + u16 brightness = backlight_get_brightness(bl);
> + int ret;
> +
> + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
> +
> + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
> +
> + dsi->mode_flags |= MIPI_DSI_MODE_LPM;
> +
> + return ret;
> +}
> +
> +static const struct backlight_ops ili7807s_bl_ops = {
> + .update_status = ili7807s_bl_update_status,
> +};
> +
> +static struct backlight_device *ili7807s_create_backlight(struct mipi_dsi_device *dsi)
> +{
> + struct device *dev = &dsi->dev;
> + const struct backlight_properties props = {
> + .type = BACKLIGHT_RAW,
> + .brightness = 0x3fff,
> + .max_brightness = 0x3fff,
> + };
> +
> + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
> + &ili7807s_bl_ops, &props);
> +}
> +
> +static const struct drm_display_mode dlc0697_mode = {
> + .clock = 131911,
.clock = (1080 + 18 + 2 + 16) * (1920 + 26 + 4 + 20) * 60 / 1000,
> +
> + .hdisplay = 1080,
> + .hsync_start = 1080 + 18,
> + .hsync_end = 1080 + 18 + 2,
> + .htotal = 1080 + 18 + 2 + 16,
> +
> + .vdisplay = 1920,
> + .vsync_start = 1920 + 26,
> + .vsync_end = 1920 + 26 + 4,
> + .vtotal = 1920 + 26 + 4 + 20,
> +
> + .width_mm = 0,
> + .height_mm = 0,
> + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> +};
> +
> +static const struct panel_desc dlc0697_desc = {
> + .mode = &dlc0697_mode,
> + .lanes = 4,
> + .format = MIPI_DSI_FMT_RGB888,
> + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,
> + .init = dlc0697_init_sequence,
> +};
> +
> +static int ili7807s_probe(struct mipi_dsi_device *dsi)
> +{
> + struct device *dev = &dsi->dev;
> + const struct panel_desc *desc;
> + struct ili7807s *ctx;
> + int ret;
> +
> + ctx = devm_drm_panel_alloc(dev, struct ili7807s, panel,
> + &ili7807s_panel_funcs,
> + DRM_MODE_CONNECTOR_DSI);
> + if (IS_ERR(ctx))
> + return PTR_ERR(ctx);
> +
> + desc = of_device_get_match_data(dev);
> + ctx->desc = desc;
> +
> + ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(ili7807s_supplies),
> + ili7807s_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_LOW);
> + if (IS_ERR(ctx->reset_gpio))
> + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
> + "failed to get reset gpio\n");
> +
> + ctx->dsi = dsi;
> + mipi_dsi_set_drvdata(dsi, ctx);
> +
> + dsi->lanes = desc->lanes;
> + dsi->format = desc->format;
> + dsi->mode_flags = desc->mode_flags;
> +
> + ctx->panel.prepare_prev_first = true;
> +
> + ret = drm_panel_of_backlight(&ctx->panel);
> + if (ret)
> + return ret;
> +
> + if (!ctx->panel.backlight) {
> + ctx->panel.backlight = ili7807s_create_backlight(dsi);
> + if (IS_ERR(ctx->panel.backlight))
> + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
> + "failed to create backlight\n");
> + }
> +
> + ret = devm_drm_panel_add(dev, &ctx->panel);
> + if (ret < 0)
> + return dev_err_probe(dev, ret, "failed to add panel\n");
> +
> + ret = devm_mipi_dsi_attach(dev, dsi);
> + if (ret < 0)
> + return dev_err_probe(dev, ret, "failed to attach dsi\n");
> +
> + return 0;
Return devm_mipi_dsi_attach() directly
> +}
> +
> +static const struct of_device_id ili7807s_of_match[] = {
> + { .compatible = "dlc,dlc0697", .data = &dlc0697_desc },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, ili7807s_of_match);
> +
> +static struct mipi_dsi_driver ili7807s_dsi_driver = {
> + .probe = ili7807s_probe,
> + .driver = {
> + .name = "panel-ilitek-ili7807s",
> + .of_match_table = ili7807s_of_match,
> + },
> +};
> +module_mipi_dsi_driver(ili7807s_dsi_driver);
> +
> +MODULE_AUTHOR("Arpit Saini <arpit.saini@oss.qualcomm.com>");
> +MODULE_DESCRIPTION("Panel driver for Ilitek ILI7807S LCD DSI panel");
> +MODULE_LICENSE("GPL");
>
Thanks,
Neil
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-18 12:43 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-18 10:24 [PATCH v2 0/2] drm/panel: add support for Ilitek ILI7807S DSI panels Arpit Saini
2026-06-18 10:24 ` [PATCH v2 1/2] dt-bindings: display: panel: add Ilitek ILI7807S panel controller Arpit Saini
2026-06-18 10:24 ` [PATCH v2 2/2] drm/panel: add Ilitek ILI7807S panel driver Arpit Saini
2026-06-18 10:32 ` sashiko-bot
2026-06-18 12:43 ` Neil Armstrong
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.