diff options
author | Álvaro Fernández Rojas <noltari@gmail.com> | 2022-05-16 23:40:32 +0200 |
---|---|---|
committer | Álvaro Fernández Rojas <noltari@gmail.com> | 2022-05-17 15:11:22 +0200 |
commit | 20ea6adbf199097c4f5f591ffee088340630dae4 (patch) | |
tree | d6719d95e136611a1c25bbf7789652d6d402779d /target/linux/bcm27xx/patches-5.15/950-0694-drm-panel-panel-sitronix-st7701-Support-SPI-config-a.patch | |
parent | bca05bd072180dc38ef740b37ded9572a6db1981 (diff) | |
download | upstream-20ea6adbf199097c4f5f591ffee088340630dae4.tar.gz upstream-20ea6adbf199097c4f5f591ffee088340630dae4.tar.bz2 upstream-20ea6adbf199097c4f5f591ffee088340630dae4.zip |
bcm27xx: add support for linux v5.15
Build system: x86_64
Build-tested: bcm2708, bcm2709, bcm2710, bcm2711
Run-tested: bcm2708/RPiB+, bcm2709/RPi3B, bcm2710/RPi3B, bcm2711/RPi4B
Signed-off-by: Marty Jones <mj8263788@gmail.com>
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Diffstat (limited to 'target/linux/bcm27xx/patches-5.15/950-0694-drm-panel-panel-sitronix-st7701-Support-SPI-config-a.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.15/950-0694-drm-panel-panel-sitronix-st7701-Support-SPI-config-a.patch | 564 |
1 files changed, 564 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.15/950-0694-drm-panel-panel-sitronix-st7701-Support-SPI-config-a.patch b/target/linux/bcm27xx/patches-5.15/950-0694-drm-panel-panel-sitronix-st7701-Support-SPI-config-a.patch new file mode 100644 index 0000000000..f4cc7a87e3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.15/950-0694-drm-panel-panel-sitronix-st7701-Support-SPI-config-a.patch @@ -0,0 +1,564 @@ +From 6e9d09063a883bd69c84a95f6e854a7dbe7720af Mon Sep 17 00:00:00 2001 +From: Dave Stevenson <dave.stevenson@raspberrypi.com> +Date: Tue, 1 Feb 2022 15:27:01 +0000 +Subject: [PATCH] drm/panel/panel-sitronix-st7701: Support SPI config + and RGB data + +The ST7701 supports numerous different interface mechanisms for +MIPI DSI, RGB, or SPI. The driver was only implementing DSI input, +so add RGB parallel input with SPI configuration. + +Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com> +--- + drivers/gpu/drm/panel/panel-sitronix-st7701.c | 382 ++++++++++++++++-- + 1 file changed, 359 insertions(+), 23 deletions(-) + +--- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c ++++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c +@@ -7,15 +7,20 @@ + #include <drm/drm_mipi_dsi.h> + #include <drm/drm_modes.h> + #include <drm/drm_panel.h> ++#include <drm/drm_print.h> + + #include <linux/gpio/consumer.h> + #include <linux/delay.h> ++#include <linux/media-bus-format.h> + #include <linux/module.h> + #include <linux/of_device.h> + #include <linux/regulator/consumer.h> ++#include <linux/spi/spi.h> + + #include <video/mipi_display.h> + ++#define SPI_DATA_FLAG 0x100 ++ + /* Command2 BKx selection command */ + #define DSI_CMD2BKX_SEL 0xFF + +@@ -46,9 +51,14 @@ + * 11 = CMD2BK1, Command2 BK1 + * 00 = Command2 disable + */ ++#define DSI_CMD2BK3_SEL 0x13 + #define DSI_CMD2BK1_SEL 0x11 + #define DSI_CMD2BK0_SEL 0x10 + #define DSI_CMD2BKX_SEL_NONE 0x00 ++#define SPI_CMD2BK3_SEL (SPI_DATA_FLAG | DSI_CMD2BK3_SEL) ++#define SPI_CMD2BK1_SEL (SPI_DATA_FLAG | DSI_CMD2BK1_SEL) ++#define SPI_CMD2BK0_SEL (SPI_DATA_FLAG | DSI_CMD2BK0_SEL) ++#define SPI_CMD2BKX_SEL_NONE (SPI_DATA_FLAG | DSI_CMD2BKX_SEL_NONE) + + /* Command2, BK0 bytes */ + #define DSI_LINESET_LINE 0x69 +@@ -86,19 +96,34 @@ + #define DSI_MIPISET1_EOT_EN BIT(3) + #define DSI_CMD2_BK1_MIPISET1_SET (BIT(7) | DSI_MIPISET1_EOT_EN) + ++struct st7701; ++ ++enum st7701_ctrl_if { ++ ST7701_CTRL_DSI, ++ ST7701_CTRL_SPI, ++}; ++ + struct st7701_panel_desc { + const struct drm_display_mode *mode; + unsigned int lanes; + unsigned long flags; + enum mipi_dsi_pixel_format format; ++ u32 mediabus_format; + const char *const *supply_names; + unsigned int num_supplies; + unsigned int panel_sleep_delay; ++ void (*init_sequence)(struct st7701 *st7701); ++ unsigned int conn_type; ++ enum st7701_ctrl_if interface; ++ u32 bus_flags; + }; + + struct st7701 { + struct drm_panel panel; + struct mipi_dsi_device *dsi; ++ struct spi_device *spi; ++ const struct device *dev; ++ + const struct st7701_panel_desc *desc; + + struct regulator_bulk_data *supplies; +@@ -123,7 +148,23 @@ static inline int st7701_dsi_write(struc + st7701_dsi_write(st7701, d, ARRAY_SIZE(d)); \ + } + +-static void st7701_init_sequence(struct st7701 *st7701) ++#define ST7701_SPI(st7701, seq...) \ ++ { \ ++ const u16 d[] = { seq }; \ ++ struct spi_transfer xfer = { }; \ ++ struct spi_message spi; \ ++ \ ++ spi_message_init(&spi); \ ++ \ ++ xfer.tx_buf = d; \ ++ xfer.bits_per_word = 9; \ ++ xfer.len = sizeof(u16) * ARRAY_SIZE(d); \ ++ \ ++ spi_message_add_tail(&xfer, &spi); \ ++ spi_sync((st7701)->spi, &spi); \ ++ } ++ ++static void ts8550b_init_sequence(struct st7701 *st7701) + { + const struct drm_display_mode *mode = st7701->desc->mode; + +@@ -194,6 +235,111 @@ static void st7701_init_sequence(struct + 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE); + } + ++static void txw210001b0_init_sequence(struct st7701 *st7701) ++{ ++ ST7701_SPI(st7701, MIPI_DCS_SOFT_RESET); ++ ++ usleep_range(5000, 7000); ++ ++ ST7701_SPI(st7701, DSI_CMD2BKX_SEL, ++ 0x177, 0x101, 0x100, 0x100, SPI_CMD2BK0_SEL); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK0_LNESET, 0x13B, 0x100); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK0_PORCTRL, 0x10B, 0x102); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK0_INVSEL, 0x100, 0x102); ++ ++ ST7701_SPI(st7701, 0xCC, 0x110); ++ ++ /* ++ * Gamma option B: ++ * Positive Voltage Gamma Control ++ */ ++ ST7701_SPI(st7701, DSI_CMD2_BK0_PVGAMCTRL, ++ 0x102, 0x113, 0x11B, 0x10D, 0x110, 0x105, 0x108, 0x107, ++ 0x107, 0x124, 0x104, 0x111, 0x10E, 0x12C, 0x133, 0x11D); ++ ++ /* Negative Voltage Gamma Control */ ++ ST7701_SPI(st7701, DSI_CMD2_BK0_NVGAMCTRL, ++ 0x105, 0x113, 0x11B, 0x10D, 0x111, 0x105, 0x108, 0x107, ++ 0x107, 0x124, 0x104, 0x111, 0x10E, 0x12C, 0x133, 0x11D); ++ ++ ST7701_SPI(st7701, DSI_CMD2BKX_SEL, ++ 0x177, 0x101, 0x100, 0x100, SPI_CMD2BK1_SEL); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_VRHS, 0x15D); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_VCOM, 0x143); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_VGHSS, 0x181); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_TESTCMD, 0x180); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_VGLS, 0x143); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_PWCTLR1, 0x185); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_PWCTLR2, 0x120); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_SPD1, 0x178); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_SPD2, 0x178); ++ ++ ST7701_SPI(st7701, DSI_CMD2_BK1_MIPISET1, 0x188); ++ ++ ST7701_SPI(st7701, 0xE0, 0x100, 0x100, 0x102); ++ ++ ST7701_SPI(st7701, 0xE1, ++ 0x103, 0x1A0, 0x100, 0x100, 0x104, 0x1A0, 0x100, 0x100, ++ 0x100, 0x120, 0x120); ++ ++ ST7701_SPI(st7701, 0xE2, ++ 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, ++ 0x100, 0x100, 0x100, 0x100, 0x100); ++ ++ ST7701_SPI(st7701, 0xE3, 0x100, 0x100, 0x111, 0x100); ++ ++ ST7701_SPI(st7701, 0xE4, 0x122, 0x100); ++ ++ ST7701_SPI(st7701, 0xE5, ++ 0x105, 0x1EC, 0x1A0, 0x1A0, 0x107, 0x1EE, 0x1A0, 0x1A0, ++ 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100); ++ ++ ST7701_SPI(st7701, 0xE6, 0x100, 0x100, 0x111, 0x100); ++ ++ ST7701_SPI(st7701, 0xE7, 0x122, 0x100); ++ ++ ST7701_SPI(st7701, 0xE8, ++ 0x106, 0x1ED, 0x1A0, 0x1A0, 0x108, 0x1EF, 0x1A0, 0x1A0, ++ 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100); ++ ++ ST7701_SPI(st7701, 0xEB, ++ 0x100, 0x100, 0x140, 0x140, 0x100, 0x100, 0x100); ++ ++ ST7701_SPI(st7701, 0xED, ++ 0x1FF, 0x1FF, 0x1FF, 0x1BA, 0x10A, 0x1BF, 0x145, 0x1FF, ++ 0x1FF, 0x154, 0x1FB, 0x1A0, 0x1AB, 0x1FF, 0x1FF, 0x1FF); ++ ++ ST7701_SPI(st7701, 0xEF, 0x110, 0x10D, 0x104, 0x108, 0x13F, 0x11F); ++ ++ ST7701_SPI(st7701, DSI_CMD2BKX_SEL, ++ 0x177, 0x101, 0x100, 0x100, SPI_CMD2BK3_SEL); ++ ++ ST7701_SPI(st7701, 0xEF, 0x108); ++ ++ ST7701_SPI(st7701, DSI_CMD2BKX_SEL, ++ 0x177, 0x101, 0x100, 0x100, SPI_CMD2BKX_SEL_NONE); ++ ++ ST7701_SPI(st7701, 0xCD, 0x108); /* RGB format COLCTRL */ ++ ++ ST7701_SPI(st7701, 0x36, 0x108); /* MadCtl */ ++ ++ ST7701_SPI(st7701, 0x3A, 0x166); /* Colmod */ ++ ++ ST7701_SPI(st7701, MIPI_DCS_EXIT_SLEEP_MODE); ++} ++ + static int st7701_prepare(struct drm_panel *panel) + { + struct st7701 *st7701 = panel_to_st7701(panel); +@@ -210,7 +356,7 @@ static int st7701_prepare(struct drm_pan + gpiod_set_value(st7701->reset, 1); + msleep(150); + +- st7701_init_sequence(st7701); ++ st7701->desc->init_sequence(st7701); + + return 0; + } +@@ -219,7 +365,15 @@ static int st7701_enable(struct drm_pane + { + struct st7701 *st7701 = panel_to_st7701(panel); + +- ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_ON, 0x00); ++ switch (st7701->desc->interface) { ++ case ST7701_CTRL_DSI: ++ ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_ON, 0x00); ++ break; ++ case ST7701_CTRL_SPI: ++ ST7701_SPI(st7701, MIPI_DCS_SET_DISPLAY_ON); ++ msleep(30); ++ break; ++ } + + return 0; + } +@@ -228,7 +382,14 @@ static int st7701_disable(struct drm_pan + { + struct st7701 *st7701 = panel_to_st7701(panel); + +- ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_OFF, 0x00); ++ switch (st7701->desc->interface) { ++ case ST7701_CTRL_DSI: ++ ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_OFF, 0x00); ++ break; ++ case ST7701_CTRL_SPI: ++ ST7701_SPI(st7701, MIPI_DCS_SET_DISPLAY_OFF); ++ break; ++ } + + return 0; + } +@@ -237,7 +398,14 @@ static int st7701_unprepare(struct drm_p + { + struct st7701 *st7701 = panel_to_st7701(panel); + +- ST7701_DSI(st7701, MIPI_DCS_ENTER_SLEEP_MODE, 0x00); ++ switch (st7701->desc->interface) { ++ case ST7701_CTRL_DSI: ++ ST7701_DSI(st7701, MIPI_DCS_ENTER_SLEEP_MODE, 0x00); ++ break; ++ case ST7701_CTRL_SPI: ++ ST7701_SPI(st7701, MIPI_DCS_ENTER_SLEEP_MODE); ++ break; ++ } + + msleep(st7701->sleep_delay); + +@@ -268,7 +436,7 @@ static int st7701_get_modes(struct drm_p + + mode = drm_mode_duplicate(connector->dev, desc_mode); + if (!mode) { +- dev_err(&st7701->dsi->dev, "failed to add mode %ux%u@%u\n", ++ dev_err(st7701->dev, "failed to add mode %ux%u@%u\n", + desc_mode->hdisplay, desc_mode->vdisplay, + drm_mode_vrefresh(desc_mode)); + return -ENOMEM; +@@ -277,9 +445,18 @@ static int st7701_get_modes(struct drm_p + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + ++ if (st7701->desc->mediabus_format) ++ drm_display_info_set_bus_formats(&connector->display_info, ++ &st7701->desc->mediabus_format, ++ 1); ++ connector->display_info.bus_flags = 0; ++ + connector->display_info.width_mm = desc_mode->width_mm; + connector->display_info.height_mm = desc_mode->height_mm; + ++ if (st7701->desc->bus_flags) ++ connector->display_info.bus_flags = st7701->desc->bus_flags; ++ + return 1; + } + +@@ -323,24 +500,68 @@ static const struct st7701_panel_desc ts + .supply_names = ts8550b_supply_names, + .num_supplies = ARRAY_SIZE(ts8550b_supply_names), + .panel_sleep_delay = 80, /* panel need extra 80ms for sleep out cmd */ ++ .init_sequence = ts8550b_init_sequence, ++ .conn_type = DRM_MODE_CONNECTOR_DSI, ++ .interface = ST7701_CTRL_DSI, + }; + +-static int st7701_dsi_probe(struct mipi_dsi_device *dsi) ++static const struct drm_display_mode txw210001b0_mode = { ++ .clock = 19200, ++ ++ .hdisplay = 480, ++ .hsync_start = 480 + 10, ++ .hsync_end = 480 + 10 + 16, ++ .htotal = 480 + 10 + 16 + 56, ++ ++ .vdisplay = 480, ++ .vsync_start = 480 + 15, ++ .vsync_end = 480 + 15 + 60, ++ .vtotal = 480 + 15 + 60 + 15, ++ ++ .width_mm = 53, ++ .height_mm = 53, ++ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, ++ ++ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, ++}; ++ ++static const struct st7701_panel_desc txw210001b0_desc = { ++ .mode = &txw210001b0_mode, ++ .mediabus_format = MEDIA_BUS_FMT_RGB888_1X24, ++ .supply_names = ts8550b_supply_names, ++ .num_supplies = ARRAY_SIZE(ts8550b_supply_names), ++ .init_sequence = txw210001b0_init_sequence, ++ .conn_type = DRM_MODE_CONNECTOR_DPI, ++ .interface = ST7701_CTRL_SPI, ++ .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, ++}; ++ ++static const struct st7701_panel_desc hyperpixel2r_desc = { ++ .mode = &txw210001b0_mode, ++ .mediabus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI, ++ .supply_names = ts8550b_supply_names, ++ .num_supplies = ARRAY_SIZE(ts8550b_supply_names), ++ .init_sequence = txw210001b0_init_sequence, ++ .conn_type = DRM_MODE_CONNECTOR_DPI, ++ .interface = ST7701_CTRL_SPI, ++ .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, ++}; ++ ++static int st7701_probe(struct device *dev, struct st7701 **ret_st7701) + { + const struct st7701_panel_desc *desc; + struct st7701 *st7701; + int ret, i; + +- st7701 = devm_kzalloc(&dsi->dev, sizeof(*st7701), GFP_KERNEL); ++ st7701 = devm_kzalloc(dev, sizeof(*st7701), GFP_KERNEL); + if (!st7701) + return -ENOMEM; + +- desc = of_device_get_match_data(&dsi->dev); +- dsi->mode_flags = desc->flags; +- dsi->format = desc->format; +- dsi->lanes = desc->lanes; ++ desc = of_device_get_match_data(dev); ++ if (!desc) ++ return -EINVAL; + +- st7701->supplies = devm_kcalloc(&dsi->dev, desc->num_supplies, ++ st7701->supplies = devm_kcalloc(dev, desc->num_supplies, + sizeof(*st7701->supplies), + GFP_KERNEL); + if (!st7701->supplies) +@@ -349,19 +570,19 @@ static int st7701_dsi_probe(struct mipi_ + for (i = 0; i < desc->num_supplies; i++) + st7701->supplies[i].supply = desc->supply_names[i]; + +- ret = devm_regulator_bulk_get(&dsi->dev, desc->num_supplies, ++ ret = devm_regulator_bulk_get(dev, desc->num_supplies, + st7701->supplies); + if (ret < 0) + return ret; + +- st7701->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); ++ st7701->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(st7701->reset)) { +- dev_err(&dsi->dev, "Couldn't get our reset GPIO\n"); ++ dev_err(dev, "Couldn't get our reset GPIO\n"); + return PTR_ERR(st7701->reset); + } + +- drm_panel_init(&st7701->panel, &dsi->dev, &st7701_funcs, +- DRM_MODE_CONNECTOR_DSI); ++ drm_panel_init(&st7701->panel, dev, &st7701_funcs, ++ desc->conn_type); + + /** + * Once sleep out has been issued, ST7701 IC required to wait 120ms +@@ -380,9 +601,30 @@ static int st7701_dsi_probe(struct mipi_ + + drm_panel_add(&st7701->panel); + ++ st7701->desc = desc; ++ st7701->dev = dev; ++ ++ *ret_st7701 = st7701; ++ ++ return 0; ++} ++ ++static int st7701_dsi_probe(struct mipi_dsi_device *dsi) ++{ ++ struct st7701 *st7701; ++ int ret; ++ ++ ret = st7701_probe(&dsi->dev, &st7701); ++ ++ if (ret) ++ return ret; ++ ++ dsi->mode_flags = st7701->desc->flags; ++ dsi->format = st7701->desc->format; ++ dsi->lanes = st7701->desc->lanes; ++ + mipi_dsi_set_drvdata(dsi, st7701); + st7701->dsi = dsi; +- st7701->desc = desc; + + return mipi_dsi_attach(dsi); + } +@@ -397,21 +639,115 @@ static int st7701_dsi_remove(struct mipi + return 0; + } + +-static const struct of_device_id st7701_of_match[] = { ++static const struct of_device_id st7701_dsi_of_match[] = { + { .compatible = "techstar,ts8550b", .data = &ts8550b_desc }, + { } + }; +-MODULE_DEVICE_TABLE(of, st7701_of_match); ++MODULE_DEVICE_TABLE(of, st7701_dsi_of_match); + + static struct mipi_dsi_driver st7701_dsi_driver = { + .probe = st7701_dsi_probe, + .remove = st7701_dsi_remove, + .driver = { + .name = "st7701", +- .of_match_table = st7701_of_match, ++ .of_match_table = st7701_dsi_of_match, + }, + }; +-module_mipi_dsi_driver(st7701_dsi_driver); ++ ++/* SPI display probe */ ++static const struct of_device_id st7701_spi_of_match[] = { ++ { .compatible = "txw,txw210001b0", ++ .data = &txw210001b0_desc, ++ }, { ++ .compatible = "pimoroni,hyperpixel2round", ++ .data = &hyperpixel2r_desc, ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(of, st7701_spi_of_match); ++ ++static int st7701_spi_probe(struct spi_device *spi) ++{ ++ struct st7701 *st7701; ++ int ret; ++ ++ spi->mode = SPI_MODE_3; ++ spi->bits_per_word = 9; ++ ret = spi_setup(spi); ++ if (ret < 0) { ++ dev_err(&spi->dev, "failed to setup SPI: %d\n", ret); ++ return ret; ++ } ++ ++ ret = st7701_probe(&spi->dev, &st7701); ++ ++ if (ret) ++ return ret; ++ ++ spi_set_drvdata(spi, st7701); ++ st7701->spi = spi; ++ ++ return 0; ++} ++ ++static int st7701_spi_remove(struct spi_device *spi) ++{ ++ struct st7701 *ctx = spi_get_drvdata(spi); ++ ++ drm_panel_remove(&ctx->panel); ++ ++ return 0; ++} ++ ++static const struct spi_device_id st7701_spi_ids[] = { ++ { "txw210001b0", 0 }, ++ { "hyperpixel2round", 0 }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(spi, st7701_spi_ids); ++ ++static struct spi_driver st7701_spi_driver = { ++ .probe = st7701_spi_probe, ++ .remove = st7701_spi_remove, ++ .driver = { ++ .name = "st7701", ++ .of_match_table = st7701_spi_of_match, ++ }, ++ .id_table = st7701_spi_ids, ++}; ++ ++static int __init panel_st7701_init(void) ++{ ++ int err; ++ ++ err = spi_register_driver(&st7701_spi_driver); ++ if (err < 0) ++ return err; ++ ++ if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) { ++ err = mipi_dsi_driver_register(&st7701_dsi_driver); ++ if (err < 0) ++ goto err_did_spi_register; ++ } ++ ++ return 0; ++ ++err_did_spi_register: ++ spi_unregister_driver(&st7701_spi_driver); ++ ++ return err; ++} ++module_init(panel_st7701_init); ++ ++static void __exit panel_st7701_exit(void) ++{ ++ if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) ++ mipi_dsi_driver_unregister(&st7701_dsi_driver); ++ ++ spi_unregister_driver(&st7701_spi_driver); ++} ++module_exit(panel_st7701_exit); + + MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>"); + MODULE_DESCRIPTION("Sitronix ST7701 LCD Panel Driver"); |