Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/panel: ilitek-ili9806e: split core and DSI logic

Split the driver to support multiple transport buses. The core logic
(power, GPIO, backlight) is moved to a dedicated core module, while
DSI-specific code is restricted to the DSI module.

Introduce DRM_PANEL_ILITEK_ILI9806E_CORE as a hidden Kconfig symbol
selected by the bus-specific configuration.

Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patch.msgid.link/20260318073346.18041-3-dario.binacchi@amarulasolutions.com

authored by

Dario Binacchi and committed by
Neil Armstrong
0efa7924 3bdd847a

+193 -109
+1 -1
MAINTAINERS
··· 8028 8028 DRM DRIVER FOR ILITEK ILI9806E PANELS 8029 8029 M: Michael Walle <mwalle@kernel.org> 8030 8030 S: Maintained 8031 - F: drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c 8031 + F: drivers/gpu/drm/panel/panel-ilitek-ili9806e-* 8032 8032 8033 8033 DRM DRIVER FOR JADARD JD9365DA-H3 MIPI-DSI LCD PANELS 8034 8034 M: Jagan Teki <jagan@edgeble.ai>
+4
drivers/gpu/drm/panel/Kconfig
··· 268 268 Say Y if you want to enable support for panels based on the 269 269 Ilitek ILI9805 controller. 270 270 271 + config DRM_PANEL_ILITEK_ILI9806E_CORE 272 + tristate 273 + 271 274 config DRM_PANEL_ILITEK_ILI9806E_DSI 272 275 tristate "Ilitek ILI9806E-based DSI panels" 273 276 depends on OF 274 277 depends on DRM_MIPI_DSI 275 278 depends on BACKLIGHT_CLASS_DEVICE 279 + select DRM_PANEL_ILITEK_ILI9806E_CORE 276 280 help 277 281 Say Y if you want to enable support for panels based on the 278 282 Ilitek ILI9806E controller using DSI.
+1
drivers/gpu/drm/panel/Makefile
··· 27 27 obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o 28 28 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o 29 29 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9805) += panel-ilitek-ili9805.o 30 + obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9806E_CORE) += panel-ilitek-ili9806e-core.o 30 31 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9806E_DSI) += panel-ilitek-ili9806e-dsi.o 31 32 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o 32 33 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9882T) += panel-ilitek-ili9882t.o
+129
drivers/gpu/drm/panel/panel-ilitek-ili9806e-core.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Ilitek ILI9806E core driver. 4 + * 5 + * Copyright (c) 2026 Amarula Solutions, Dario Binacchi <dario.binacchi@amarulasolutions.com> 6 + */ 7 + 8 + #include <drm/drm_panel.h> 9 + 10 + #include <linux/delay.h> 11 + #include <linux/export.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/module.h> 14 + #include <linux/property.h> 15 + #include <linux/regulator/consumer.h> 16 + 17 + #include "panel-ilitek-ili9806e-core.h" 18 + 19 + struct ili9806e { 20 + void *transport; 21 + struct drm_panel panel; 22 + 23 + struct regulator_bulk_data supplies[2]; 24 + struct gpio_desc *reset_gpio; 25 + }; 26 + 27 + static const char * const regulator_names[] = { 28 + "vdd", 29 + "vccio", 30 + }; 31 + 32 + void *ili9806e_get_transport(struct drm_panel *panel) 33 + { 34 + struct ili9806e *ctx = container_of(panel, struct ili9806e, panel); 35 + 36 + return ctx->transport; 37 + } 38 + EXPORT_SYMBOL_GPL(ili9806e_get_transport); 39 + 40 + int ili9806e_power_on(struct device *dev) 41 + { 42 + struct ili9806e *ctx = dev_get_drvdata(dev); 43 + int ret; 44 + 45 + gpiod_set_value(ctx->reset_gpio, 1); 46 + 47 + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 48 + if (ret) { 49 + dev_err(dev, "regulator bulk enable failed: %d\n", ret); 50 + return ret; 51 + } 52 + 53 + usleep_range(10000, 20000); 54 + gpiod_set_value(ctx->reset_gpio, 0); 55 + usleep_range(10000, 20000); 56 + 57 + return 0; 58 + } 59 + EXPORT_SYMBOL_GPL(ili9806e_power_on); 60 + 61 + int ili9806e_power_off(struct device *dev) 62 + { 63 + struct ili9806e *ctx = dev_get_drvdata(dev); 64 + int ret; 65 + 66 + gpiod_set_value(ctx->reset_gpio, 1); 67 + 68 + ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 69 + if (ret) 70 + dev_err(dev, "regulator bulk disable failed: %d\n", ret); 71 + 72 + return ret; 73 + } 74 + EXPORT_SYMBOL_GPL(ili9806e_power_off); 75 + 76 + int ili9806e_probe(struct device *dev, void *transport, 77 + const struct drm_panel_funcs *funcs, 78 + int connector_type) 79 + { 80 + struct ili9806e *ctx; 81 + int i, ret; 82 + 83 + ctx = devm_kzalloc(dev, sizeof(struct ili9806e), GFP_KERNEL); 84 + if (!ctx) 85 + return -ENOMEM; 86 + 87 + dev_set_drvdata(dev, ctx); 88 + ctx->transport = transport; 89 + 90 + for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) 91 + ctx->supplies[i].supply = regulator_names[i]; 92 + 93 + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), 94 + ctx->supplies); 95 + if (ret) 96 + return dev_err_probe(dev, ret, "failed to get regulators\n"); 97 + 98 + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 99 + if (IS_ERR(ctx->reset_gpio)) 100 + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 101 + "Failed to get reset-gpios\n"); 102 + 103 + drm_panel_init(&ctx->panel, dev, funcs, connector_type); 104 + 105 + ret = drm_panel_of_backlight(&ctx->panel); 106 + if (ret) 107 + return dev_err_probe(dev, ret, "Failed to get backlight\n"); 108 + 109 + ctx->panel.prepare_prev_first = true; 110 + drm_panel_add(&ctx->panel); 111 + 112 + return 0; 113 + 114 + } 115 + EXPORT_SYMBOL_GPL(ili9806e_probe); 116 + 117 + void ili9806e_remove(struct device *dev) 118 + { 119 + struct ili9806e *ctx = dev_get_drvdata(dev); 120 + 121 + drm_panel_remove(&ctx->panel); 122 + } 123 + EXPORT_SYMBOL_GPL(ili9806e_remove); 124 + 125 + MODULE_AUTHOR("Dario Binacchi <dario.binacchi@amarulasolutions.com>"); 126 + MODULE_AUTHOR("Gunnar Dibbern <gunnar.dibbern@lht.dlh.de>"); 127 + MODULE_AUTHOR("Michael Walle <mwalle@kernel.org>"); 128 + MODULE_DESCRIPTION("Ilitek ILI9806E Controller Driver"); 129 + MODULE_LICENSE("GPL");
+15
drivers/gpu/drm/panel/panel-ilitek-ili9806e-core.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef _PANEL_ILITEK_ILI9806E_CORE_H 4 + #define _PANEL_ILITEK_ILI9806E_CORE_H 5 + 6 + void *ili9806e_get_transport(struct drm_panel *panel); 7 + int ili9806e_power_off(struct device *dev); 8 + int ili9806e_power_on(struct device *dev); 9 + 10 + int ili9806e_probe(struct device *dev, void *transport, 11 + const struct drm_panel_funcs *funcs, 12 + int connector_type); 13 + void ili9806e_remove(struct device *dev); 14 + 15 + #endif /* _PANEL_ILITEK_ILI9806E_CORE_H */
+43 -108
drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 - #include <linux/delay.h> 4 3 #include <linux/device.h> 5 4 #include <linux/err.h> 6 5 #include <linux/errno.h> 7 - #include <linux/gpio/consumer.h> 8 6 #include <linux/kernel.h> 9 7 #include <linux/mod_devicetable.h> 10 8 #include <linux/module.h> 11 9 #include <linux/property.h> 12 - #include <linux/regulator/consumer.h> 13 10 14 11 #include <drm/drm_mipi_dsi.h> 15 12 #include <drm/drm_modes.h> ··· 15 18 16 19 #include <video/mipi_display.h> 17 20 18 - struct panel_desc { 21 + #include "panel-ilitek-ili9806e-core.h" 22 + 23 + struct ili9806e_dsi_panel_desc { 19 24 const struct drm_display_mode *display_mode; 20 25 unsigned long mode_flags; 21 26 enum mipi_dsi_pixel_format format; ··· 25 26 void (*init_sequence)(struct mipi_dsi_multi_context *ctx); 26 27 }; 27 28 28 - struct ili9806e_panel { 29 - struct drm_panel panel; 29 + struct ili9806e_dsi_panel { 30 30 struct mipi_dsi_device *dsi; 31 - struct gpio_desc *reset_gpio; 32 - struct regulator_bulk_data supplies[2]; 33 - const struct panel_desc *desc; 31 + const struct ili9806e_dsi_panel_desc *desc; 34 32 enum drm_panel_orientation orientation; 35 33 }; 36 34 37 - static const char * const regulator_names[] = { 38 - "vdd", 39 - "vccio", 40 - }; 41 - 42 - static inline struct ili9806e_panel *to_ili9806e_panel(struct drm_panel *panel) 43 - { 44 - return container_of(panel, struct ili9806e_panel, panel); 45 - } 46 - 47 - static int ili9806e_power_on(struct ili9806e_panel *ctx) 48 - { 49 - struct mipi_dsi_device *dsi = ctx->dsi; 50 - int ret; 51 - 52 - gpiod_set_value(ctx->reset_gpio, 1); 53 - 54 - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 55 - if (ret < 0) { 56 - dev_err(&dsi->dev, "regulator bulk enable failed: %d\n", ret); 57 - return ret; 58 - } 59 - 60 - usleep_range(10000, 20000); 61 - gpiod_set_value(ctx->reset_gpio, 0); 62 - usleep_range(10000, 20000); 63 - 64 - return 0; 65 - } 66 - 67 - static int ili9806e_power_off(struct ili9806e_panel *ctx) 68 - { 69 - struct mipi_dsi_device *dsi = ctx->dsi; 70 - int ret; 71 - 72 - gpiod_set_value(ctx->reset_gpio, 1); 73 - 74 - ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 75 - if (ret) 76 - dev_err(&dsi->dev, "regulator bulk disable failed: %d\n", ret); 77 - 78 - return ret; 79 - } 80 - 81 - static int ili9806e_on(struct ili9806e_panel *ili9806e) 35 + static int ili9806e_dsi_on(struct ili9806e_dsi_panel *ili9806e) 82 36 { 83 37 struct mipi_dsi_multi_context ctx = { .dsi = ili9806e->dsi }; 84 38 ··· 45 93 return ctx.accum_err; 46 94 } 47 95 48 - static int ili9806e_off(struct ili9806e_panel *panel) 96 + static int ili9806e_dsi_off(struct ili9806e_dsi_panel *panel) 49 97 { 50 98 struct mipi_dsi_multi_context ctx = { .dsi = panel->dsi }; 51 99 ··· 56 104 return ctx.accum_err; 57 105 } 58 106 59 - static int ili9806e_prepare(struct drm_panel *panel) 107 + static int ili9806e_dsi_prepare(struct drm_panel *panel) 60 108 { 61 - struct ili9806e_panel *ctx = to_ili9806e_panel(panel); 109 + struct ili9806e_dsi_panel *ctx = ili9806e_get_transport(panel); 110 + struct device *dev = &ctx->dsi->dev; 62 111 int ret; 63 112 64 - ret = ili9806e_power_on(ctx); 113 + ret = ili9806e_power_on(dev); 65 114 if (ret < 0) 66 115 return ret; 67 116 68 - ret = ili9806e_on(ctx); 117 + ret = ili9806e_dsi_on(ctx); 69 118 if (ret < 0) { 70 - ili9806e_power_off(ctx); 119 + ili9806e_power_off(dev); 71 120 return ret; 72 121 } 73 122 74 123 return 0; 75 124 } 76 125 77 - static int ili9806e_unprepare(struct drm_panel *panel) 126 + static int ili9806e_dsi_unprepare(struct drm_panel *panel) 78 127 { 79 - struct ili9806e_panel *ctx = to_ili9806e_panel(panel); 80 - struct mipi_dsi_device *dsi = ctx->dsi; 128 + struct ili9806e_dsi_panel *ctx = ili9806e_get_transport(panel); 129 + struct device *dev = &ctx->dsi->dev; 81 130 int ret; 82 131 83 - ili9806e_off(ctx); 132 + ili9806e_dsi_off(ctx); 84 133 85 - ret = ili9806e_power_off(ctx); 134 + ret = ili9806e_power_off(dev); 86 135 if (ret < 0) 87 - dev_err(&dsi->dev, "power off failed: %d\n", ret); 136 + dev_err(dev, "power off failed: %d\n", ret); 88 137 89 138 return ret; 90 139 } 91 140 92 - static int ili9806e_get_modes(struct drm_panel *panel, 141 + static int ili9806e_dsi_get_modes(struct drm_panel *panel, 93 142 struct drm_connector *connector) 94 143 { 95 - struct ili9806e_panel *ctx = to_ili9806e_panel(panel); 144 + struct ili9806e_dsi_panel *ctx = ili9806e_get_transport(panel); 96 145 const struct drm_display_mode *mode = ctx->desc->display_mode; 97 146 98 147 return drm_connector_helper_get_modes_fixed(connector, mode); 99 148 } 100 149 101 - static enum drm_panel_orientation ili9806e_get_orientation(struct drm_panel *panel) 150 + static enum drm_panel_orientation ili9806e_dsi_get_orientation(struct drm_panel *panel) 102 151 { 103 - struct ili9806e_panel *ctx = to_ili9806e_panel(panel); 152 + struct ili9806e_dsi_panel *ctx = ili9806e_get_transport(panel); 104 153 105 154 return ctx->orientation; 106 155 } 107 156 108 - static const struct drm_panel_funcs ili9806e_funcs = { 109 - .prepare = ili9806e_prepare, 110 - .unprepare = ili9806e_unprepare, 111 - .get_modes = ili9806e_get_modes, 112 - .get_orientation = ili9806e_get_orientation, 157 + static const struct drm_panel_funcs ili9806e_dsi_funcs = { 158 + .prepare = ili9806e_dsi_prepare, 159 + .unprepare = ili9806e_dsi_unprepare, 160 + .get_modes = ili9806e_dsi_get_modes, 161 + .get_orientation = ili9806e_dsi_get_orientation, 113 162 }; 114 163 115 164 static int ili9806e_dsi_probe(struct mipi_dsi_device *dsi) 116 165 { 117 166 struct device *dev = &dsi->dev; 118 - struct ili9806e_panel *ctx; 119 - int i, ret; 167 + struct ili9806e_dsi_panel *ctx; 168 + int ret; 120 169 121 - ctx = devm_drm_panel_alloc(dev, struct ili9806e_panel, panel, &ili9806e_funcs, 122 - DRM_MODE_CONNECTOR_DSI); 123 - if (IS_ERR(ctx)) 124 - return PTR_ERR(ctx); 170 + ctx = devm_kzalloc(dev, sizeof(struct ili9806e_dsi_panel), GFP_KERNEL); 171 + if (!ctx) 172 + return -ENOMEM; 125 173 126 174 ctx->desc = device_get_match_data(dev); 127 - 128 - for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) 129 - ctx->supplies[i].supply = regulator_names[i]; 130 - 131 - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), 132 - ctx->supplies); 133 - if (ret < 0) 134 - return ret; 135 - 136 - ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 137 - if (IS_ERR(ctx->reset_gpio)) 138 - return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 139 - "Failed to get reset-gpios\n"); 140 175 141 176 mipi_dsi_set_drvdata(dsi, ctx); 142 177 ctx->dsi = dsi; ··· 136 197 if (ret) 137 198 return dev_err_probe(dev, ret, "Failed to get orientation\n"); 138 199 139 - ret = drm_panel_of_backlight(&ctx->panel); 200 + ret = ili9806e_probe(dev, ctx, &ili9806e_dsi_funcs, 201 + DRM_MODE_CONNECTOR_DSI); 140 202 if (ret) 141 - return dev_err_probe(dev, ret, "Failed to get backlight\n"); 142 - 143 - ctx->panel.prepare_prev_first = true; 144 - drm_panel_add(&ctx->panel); 203 + return ret; 145 204 146 205 ret = mipi_dsi_attach(dsi); 147 206 if (ret < 0) { 148 207 dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); 149 - drm_panel_remove(&ctx->panel); 208 + ili9806e_remove(dev); 150 209 return ret; 151 210 } 152 211 ··· 153 216 154 217 static void ili9806e_dsi_remove(struct mipi_dsi_device *dsi) 155 218 { 156 - struct ili9806e_panel *ctx = mipi_dsi_get_drvdata(dsi); 157 - 158 219 mipi_dsi_detach(dsi); 159 - drm_panel_remove(&ctx->panel); 220 + ili9806e_remove(&dsi->dev); 160 221 } 161 222 162 223 static void com35h3p70ulc_init(struct mipi_dsi_multi_context *ctx) ··· 304 369 .height_mm = 71, 305 370 }; 306 371 307 - static const struct panel_desc com35h3p70ulc_desc = { 372 + static const struct ili9806e_dsi_panel_desc com35h3p70ulc_desc = { 308 373 .init_sequence = com35h3p70ulc_init, 309 374 .display_mode = &com35h3p70ulc_default_mode, 310 375 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | ··· 468 533 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, 469 534 }; 470 535 471 - static const struct panel_desc dmt028vghmcmi_1d_desc = { 536 + static const struct ili9806e_dsi_panel_desc dmt028vghmcmi_1d_desc = { 472 537 .init_sequence = dmt028vghmcmi_1d_init, 473 538 .display_mode = &dmt028vghmcmi_1d_default_mode, 474 539 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | ··· 477 542 .lanes = 2, 478 543 }; 479 544 480 - static const struct of_device_id ili9806e_of_match[] = { 545 + static const struct of_device_id ili9806e_dsi_of_match[] = { 481 546 { .compatible = "densitron,dmt028vghmcmi-1d", .data = &dmt028vghmcmi_1d_desc }, 482 547 { .compatible = "ortustech,com35h3p70ulc", .data = &com35h3p70ulc_desc }, 483 548 { } 484 549 }; 485 - MODULE_DEVICE_TABLE(of, ili9806e_of_match); 550 + MODULE_DEVICE_TABLE(of, ili9806e_dsi_of_match); 486 551 487 552 static struct mipi_dsi_driver ili9806e_dsi_driver = { 488 553 .driver = { 489 554 .name = "ili9806e-dsi", 490 - .of_match_table = ili9806e_of_match, 555 + .of_match_table = ili9806e_dsi_of_match, 491 556 }, 492 557 .probe = ili9806e_dsi_probe, 493 558 .remove = ili9806e_dsi_remove,