Add a driver for the ILITEK ILI9806E 480x864 RGB LCD controller connected over SPI, and implement the ShenZhen New Display Co NDS040480800-V3 480x800 panel. Signed-off-by: Luca Ceresoli <luca.ceresoli@xxxxxxxxxxx> --- MAINTAINERS | 1 + drivers/gpu/drm/panel/Kconfig | 13 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-ilitek-ili9806e.c | 384 ++++++++++++++++++ 4 files changed, 399 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-ilitek-ili9806e.c diff --git a/MAINTAINERS b/MAINTAINERS index 3c38699ee821..4d657a049acc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6520,6 +6520,7 @@ M: Luca Ceresoli <luca.ceresoli@xxxxxxxxxxx> S: Maintained T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/panel/ilitek,ili9806e.yaml +F: drivers/gpu/drm/panel/panel-ilitek-ili9806e.c DRM DRIVER FOR JADARD JD9365DA-H3 MIPI-DSI LCD PANELS M: Jagan Teki <jagan@xxxxxxxxxx> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 203c0ef0bbfd..e3e89d86668a 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -194,6 +194,19 @@ config DRM_PANEL_ILITEK_ILI9341 QVGA (240x320) RGB panels. support serial & parallel rgb interface. +config DRM_PANEL_ILITEK_ILI9806E + tristate "Ilitek ILI9806E panel" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + select VIDEOMODE_HELPERS + select DRM_MIPI_DBI + help + Say Y here if you want to enable support for LCD panels connected + over SPI and based on the Ilitek ILI9806E controller. + + The ILI9806E is an LCD controller capable of driving 18-bit a-Si + TFT LCDs up to a resolution of 480x800. + config DRM_PANEL_ILITEK_ILI9881C tristate "Ilitek ILI9881C-based panels" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 30cf553c8d1d..f465140ae7df 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.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_ILI9806E) += panel-ilitek-ili9806e.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o obj-$(CONFIG_DRM_PANEL_INNOLUX_EJ030NA) += panel-innolux-ej030na.o obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c b/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c new file mode 100644 index 000000000000..57c12bff70f8 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the Ilitek ILI9806E a-Si TFT LCD controller. + * + * Copyright (c) 2023 Delcon SRL + * Luca Ceresoli <luca.ceresoli@xxxxxxxxxxx> + */ + +#include <drm/drm_mipi_dbi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/media-bus-format.h> +#include <linux/of.h> +#include <linux/spi/spi.h> + +#include <video/mipi_display.h> + +#define ILI9806E_BUS_FORMAT MEDIA_BUS_FMT_RGB666_1X18 + +// Page 1 registers +#define ILI9806E_P1_IFMODE1 0x08 // Interface Mode Control 1 +#define IFMODE1_SEPT_SDIO BIT(3) // 1 = two data pins +#define IFMODE1_SDO_STATUS BIT(4) // 0 = SDO has output enable +#define ILI9806E_P1_DISCTRL1 0x20 // Display Function Control 1 +#define ILI9806E_P1_DISCTRL2 0x21 // Display Function Control 2 +#define DISCTRL2_EPL BIT(0) // DE polarity (1 = active high) +#define DISCTRL2_DPL BIT(1) // PCLK polarity (1 = fetch on falling edge) +#define DISCTRL2_HSPL BIT(2) // HS polarity (1 = active high) +#define DISCTRL2_VSPL BIT(3) // VS polarity (1 = active high) +#define ILI9806E_P1_RESCTRL 0x30 // Resolution Control +#define RESCTRL_480x864 0x0 +#define RESCTRL_480x854 0x1 +#define RESCTRL_480x800 0x2 +#define RESCTRL_480x640 0x3 +#define RESCTRL_480x720 0x4 +#define ILI9806E_P1_INVTR 0x31 // Display Inversion Control +#define INVTR_NLA_COLUMN 0x0 +#define INVTR_NLA_1DOT 0x1 +#define INVTR_NLA_2DOT 0x2 +#define INVTR_NLA_3DOT 0x3 +#define INVTR_NLA_4DOT 0x4 +#define ILI9806E_P1_PWCTRL1 0x40 // Power Control 1 +#define ILI9806E_P1_PWCTRL2 0x41 // Power Control 2 +#define ILI9806E_P1_PWCTRL3 0x42 // Power Control 3 +#define ILI9806E_P1_PWCTRL4 0x43 // Power Control 4 +#define ILI9806E_P1_PWCTRL5 0x44 // Power Control 5 +#define ILI9806E_P1_PWCTRL6 0x45 // Power Control 6 +#define ILI9806E_P1_PWCTRL7 0x46 // Power Control 7 +#define ILI9806E_P1_PWCTRL8 0x47 // Power Control 8 +#define ILI9806E_P1_PWCTRL9 0x50 // Power Control 9 +#define ILI9806E_P1_PWCTRL10 0x51 // Power Control 10 +#define ILI9806E_P1_VMCTRL1 0x52 // VCOM Control 1 +#define ILI9806E_P1_VMCTRL2 0x53 // VCOM Control 1 +#define ILI9806E_P1_SRCTADJ1 0x60 // Source Timing Adjust 1 +#define ILI9806E_P1_SRCTADJ2 0x61 // Source Timing Adjust 2 +#define ILI9806E_P1_SRCTADJ3 0x62 // Source Timing Adjust 3 +#define ILI9806E_P1_SRCTADJ4 0x63 // Source Timing Adjust 4 +#define ILI9806E_P1_P_GAMMA(n) (0xa0 + (n) - 1) // Positive Gamma Control 1~16 +#define ILI9806E_P1_N_GAMMA(n) (0xc0 + (n) - 1) // Negative Gamma Correction 1~16 + +// Page 7 registers +#define ILI9806E_P7_VGLREGEN 0x17 // VGL_REG EN +#define ILI9806E_P7_0x02 0x02 // undocumented +#define ILI9806E_P7_0xe1 0xe1 // undocumented + +// The page-switching register (valid for all pages) +#define ILI9806E_Px_ENEXTC 0xff + +static const struct drm_display_mode nds040480800_v3_mode = { + .width_mm = 51, + .height_mm = 85, + .clock = 30000, + .hdisplay = 480, + .hsync_start = 480 + 25, + .hsync_end = 480 + 25 + 54, + .htotal = 480 + 25 + 54 + 25, + .vdisplay = 800, + .vsync_start = 800 + 25, + .vsync_end = 800 + 25 + 14, + .vtotal = 800 + 25 + 14 + 22, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER, +}; + +struct ili9806e { + struct mipi_dbi dbi; + struct drm_panel panel; +}; + +static inline struct ili9806e *panel_to_ili9806e(struct drm_panel *panel) +{ + return container_of(panel, struct ili9806e, panel); +} + +static int ili9806e_switch_page(struct ili9806e *ctx, unsigned int page) +{ + return mipi_dbi_command(&ctx->dbi, ILI9806E_Px_ENEXTC, 0xff, 0x98, 0x06, 0x04, page); +} + +static int ili9806e_unprepare(struct drm_panel *panel) +{ + struct ili9806e *ctx = panel_to_ili9806e(panel); + struct mipi_dbi *dbi = &ctx->dbi; + + mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF, 0x00); + mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE, 0x00); + + return 0; +} + +static int ili9806e_prepare(struct drm_panel *panel) +{ + struct ili9806e *ctx = panel_to_ili9806e(panel); + struct mipi_dbi *dbi = &ctx->dbi; + + /* Reset */ + + gpiod_set_value(ctx->dbi.reset, 1); + usleep_range(15, 50); // Min 10 us + gpiod_set_value(ctx->dbi.reset, 0); + msleep(125); // Min 5 ms in sleep in mode, 120 ms in sleep out mode + + /* Init sequence */ + + ili9806e_switch_page(ctx, 1); + + mipi_dbi_command(dbi, ILI9806E_P1_IFMODE1, IFMODE1_SDO_STATUS); + mipi_dbi_command(dbi, ILI9806E_P1_DISCTRL2, DISCTRL2_EPL); + mipi_dbi_command(dbi, ILI9806E_P1_RESCTRL, RESCTRL_480x800); + mipi_dbi_command(dbi, ILI9806E_P1_INVTR, INVTR_NLA_COLUMN); + + mipi_dbi_command(dbi, ILI9806E_P1_PWCTRL1, 0x10); + mipi_dbi_command(dbi, ILI9806E_P1_PWCTRL2, 0x55); + mipi_dbi_command(dbi, ILI9806E_P1_PWCTRL3, 0x02); + mipi_dbi_command(dbi, ILI9806E_P1_PWCTRL4, 0x09); + mipi_dbi_command(dbi, ILI9806E_P1_PWCTRL5, 0x07); + mipi_dbi_command(dbi, ILI9806E_P1_PWCTRL9, 0x78); + mipi_dbi_command(dbi, ILI9806E_P1_PWCTRL10, 0x78); + + mipi_dbi_command(dbi, ILI9806E_P1_VMCTRL1, 0x00); + mipi_dbi_command(dbi, ILI9806E_P1_VMCTRL2, 0x6d); + + mipi_dbi_command(dbi, ILI9806E_P1_SRCTADJ1, 0x07); + mipi_dbi_command(dbi, ILI9806E_P1_SRCTADJ2, 0x00); + mipi_dbi_command(dbi, ILI9806E_P1_SRCTADJ3, 0x08); + mipi_dbi_command(dbi, ILI9806E_P1_SRCTADJ4, 0x00); + + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(1), 0x00); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(2), 0x07); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(3), 0x0c); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(4), 0x0b); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(5), 0x03); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(6), 0x07); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(7), 0x06); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(8), 0x04); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(9), 0x08); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(10), 0x0c); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(11), 0x13); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(12), 0x06); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(13), 0x0d); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(14), 0x19); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(15), 0x10); + mipi_dbi_command(dbi, ILI9806E_P1_P_GAMMA(16), 0x00); + + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(1), 0x00); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(2), 0x07); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(3), 0x0c); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(4), 0x0b); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(5), 0x03); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(6), 0x07); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(7), 0x07); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(8), 0x04); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(9), 0x08); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(10), 0x0c); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(11), 0x13); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(12), 0x06); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(13), 0x0d); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(14), 0x18); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(15), 0x10); + mipi_dbi_command(dbi, ILI9806E_P1_N_GAMMA(16), 0x00); + + ili9806e_switch_page(ctx, 6); + + /* Registers in page 6 are not really documented except for the comments copied below */ + mipi_dbi_command(dbi, 0x00, 0x20); // STV_A_Rise[10:8] | GIP_0_SET0 + mipi_dbi_command(dbi, 0x01, 0x0a); // STV_A_Rise[7:0] + mipi_dbi_command(dbi, 0x02, 0x00); // GIP_0_SET1 + mipi_dbi_command(dbi, 0x03, 0x00); // GIP_0_SET2 + mipi_dbi_command(dbi, 0x04, 0x01); // GIP_0_SET3 + mipi_dbi_command(dbi, 0x05, 0x01); // GIP_0_SET4 + mipi_dbi_command(dbi, 0x06, 0x98); // CLK_A_Rise[10:8] | GIP_0_SET5 + mipi_dbi_command(dbi, 0x07, 0x06); // CLK_A_Rise[7:0] + mipi_dbi_command(dbi, 0x08, 0x01); // GIP_0_SET6 + mipi_dbi_command(dbi, 0x09, 0x80); // GIP_0_SET7 + mipi_dbi_command(dbi, 0x0a, 0x00); // GIP_0_SET8 + mipi_dbi_command(dbi, 0x0b, 0x00); // GIP_0_SET9 + mipi_dbi_command(dbi, 0x0c, 0x01); // GIP_0_SET10 + mipi_dbi_command(dbi, 0x0d, 0x01); // GIP_0_SET11 + mipi_dbi_command(dbi, 0x0e, 0x00); // GIP_0_SET12 + mipi_dbi_command(dbi, 0x0f, 0x00); // GIP_0_SET13 + mipi_dbi_command(dbi, 0x10, 0xf0); // GIP_0_SET14 + mipi_dbi_command(dbi, 0x11, 0xf4); // GIP_0_SET15 + mipi_dbi_command(dbi, 0x12, 0x01); // GIP_0_SET16 + mipi_dbi_command(dbi, 0x13, 0x00); // GIP_0_SET17 + mipi_dbi_command(dbi, 0x14, 0x00); // GIP_0_SET18 + mipi_dbi_command(dbi, 0x15, 0xc0); // GIP_0_SET19 + mipi_dbi_command(dbi, 0x16, 0x08); // GIP_0_SET20 + mipi_dbi_command(dbi, 0x17, 0x00); // GIP_0_SET21 + mipi_dbi_command(dbi, 0x18, 0x00); // GIP_0_SET22 + mipi_dbi_command(dbi, 0x19, 0x00); // GIP_0_SET23 + mipi_dbi_command(dbi, 0x1a, 0x00); // GIP_0_SET24 + mipi_dbi_command(dbi, 0x1b, 0x00); // GIP_0_SET25 + mipi_dbi_command(dbi, 0x1c, 0x00); // GIP_0_SET26 + mipi_dbi_command(dbi, 0x1d, 0x00); // GIP_0_SET27 + mipi_dbi_command(dbi, 0x20, 0x01); // GIP_1_SET0 + mipi_dbi_command(dbi, 0x21, 0x23); // GIP_1_SET1 + mipi_dbi_command(dbi, 0x22, 0x45); // GIP_1_SET2 + mipi_dbi_command(dbi, 0x23, 0x67); // GIP_1_SET3 + mipi_dbi_command(dbi, 0x24, 0x01); // GIP_1_SET4 + mipi_dbi_command(dbi, 0x25, 0x23); // GIP_1_SET5 + mipi_dbi_command(dbi, 0x26, 0x45); // GIP_1_SET6 + mipi_dbi_command(dbi, 0x27, 0x67); // GIP_1_SET7 + mipi_dbi_command(dbi, 0x30, 0x11); // GIP_2_SET8 + mipi_dbi_command(dbi, 0x31, 0x11); // GIP_2_SET9 + mipi_dbi_command(dbi, 0x32, 0x00); // GIP_2_SET10 + mipi_dbi_command(dbi, 0x33, 0xee); // GIP_2_SET11 + mipi_dbi_command(dbi, 0x34, 0xff); // GIP_2_SET12 + mipi_dbi_command(dbi, 0x35, 0xbb); // GIP_2_SET13 + mipi_dbi_command(dbi, 0x36, 0xaa); // GIP_2_SET14 + mipi_dbi_command(dbi, 0x37, 0xdd); // GIP_2_SET15 + mipi_dbi_command(dbi, 0x38, 0xcc); // GIP_2_SET16 + mipi_dbi_command(dbi, 0x39, 0x66); // GIP_2_SET17 + mipi_dbi_command(dbi, 0x3a, 0x77); // GIP_2_SET18 + mipi_dbi_command(dbi, 0x3b, 0x22); // GIP_2_SET19 + mipi_dbi_command(dbi, 0x3c, 0x22); // GIP_2_SET20 + mipi_dbi_command(dbi, 0x3d, 0x22); // GIP_2_SET21 + mipi_dbi_command(dbi, 0x3e, 0x22); // GIP_2_SET22 + mipi_dbi_command(dbi, 0x3f, 0x22); // GIP_2_SET23 + mipi_dbi_command(dbi, 0x40, 0x22); // GIP_2_SET24 + mipi_dbi_command(dbi, 0x52, 0x10); // undocumented + mipi_dbi_command(dbi, 0x53, 0x10); // GOUT_VGLO Control + + ili9806e_switch_page(ctx, 7); + + mipi_dbi_command(dbi, ILI9806E_P7_VGLREGEN, 0x22); + mipi_dbi_command(dbi, ILI9806E_P7_0x02, 0x77); + mipi_dbi_command(dbi, ILI9806E_P7_0xe1, 0x79); + + ili9806e_switch_page(ctx, 0); + + mipi_dbi_command(dbi, MIPI_DCS_SET_TEAR_ON); + mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE); + + msleep(120); + + mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON); + + return 0; +} + +static int ili9806e_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + const u32 bus_format = ILI9806E_BUS_FORMAT; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &nds040480800_v3_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + drm_display_info_set_bus_formats(&connector->display_info, &bus_format, 1); + + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs ili9806e_drm_funcs = { + .unprepare = ili9806e_unprepare, + .prepare = ili9806e_prepare, + .get_modes = ili9806e_get_modes, +}; + +static int ili9806e_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct ili9806e *ctx; + int err; + + ctx = devm_kzalloc(dev, sizeof(struct ili9806e), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + drm_panel_init(&ctx->panel, dev, &ili9806e_drm_funcs, DRM_MODE_CONNECTOR_DPI); + + spi_set_drvdata(spi, ctx); + + ctx->dbi.reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->dbi.reset)) + return dev_err_probe(dev, PTR_ERR(ctx->dbi.reset), "cannot get reset-gpios\n"); + + err = drm_panel_of_backlight(&ctx->panel); + if (err) + return dev_err_probe(dev, err, "Failed to get backlight\n"); + + err = mipi_dbi_spi_init(spi, &ctx->dbi, NULL); + if (err) + return dev_err_probe(dev, err, "MIPI DBI init failed\n"); + + drm_panel_add(&ctx->panel); + + return 0; +} + +static void ili9806e_remove(struct spi_device *spi) +{ + struct ili9806e *ctx = spi_get_drvdata(spi); + + drm_panel_remove(&ctx->panel); +} + +#ifdef CONFIG_PM_SLEEP +static int ili9806e_suspend(struct device *dev) +{ + struct ili9806e *ctx = dev_get_drvdata(dev); + struct mipi_dbi *dbi = &ctx->dbi; + + mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF, 0x00); + mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE, 0x00); + + return 0; +} + +static int ili9806e_resume(struct device *dev) +{ + struct ili9806e *ctx = dev_get_drvdata(dev); + struct mipi_dbi *dbi = &ctx->dbi; + + mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE, 0x00); + msleep(120); + mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON, 0x00); + + return 0; +} +#endif + +static const struct dev_pm_ops ili9806e_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ili9806e_suspend, ili9806e_resume) +}; + +static const struct of_device_id ili9806e_of_match[] = { + { .compatible = "newdisplay,nds040480800-v3" }, + { } +}; +MODULE_DEVICE_TABLE(of, ili9806e_of_match); + +static const struct spi_device_id ili9806e_ids[] = { + { "nds040480800-v3", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(spi, ili9806e_ids); + +static struct spi_driver ili9806e_driver = { + .probe = ili9806e_probe, + .remove = ili9806e_remove, + .id_table = ili9806e_ids, + .driver = { + .name = "panel-ilitek-ili9806e", + .of_match_table = ili9806e_of_match, + .pm = &ili9806e_pm_ops, + }, +}; +module_spi_driver(ili9806e_driver); + +MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@xxxxxxxxxxx>"); +MODULE_DESCRIPTION("Ilitek ILI9806E LCD Driver"); +MODULE_LICENSE("GPL"); -- 2.34.1