diff options
Diffstat (limited to 'drivers/gpu/drm/tiny')
-rw-r--r-- | drivers/gpu/drm/tiny/Kconfig | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/tiny/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/tiny/gm12u320.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/tiny/ili9225.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/tiny/ili9486.c | 286 | ||||
-rw-r--r-- | drivers/gpu/drm/tiny/repaper.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/tiny/st7586.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/tiny/st7735r.c | 76 |
8 files changed, 372 insertions, 61 deletions
diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig index a46ac284dd5e..4160e74e4751 100644 --- a/drivers/gpu/drm/tiny/Kconfig +++ b/drivers/gpu/drm/tiny/Kconfig @@ -47,6 +47,20 @@ config TINYDRM_ILI9341 If M is selected the module will be called ili9341. +config TINYDRM_ILI9486 + tristate "DRM support for ILI9486 display panels" + depends on DRM && SPI + select DRM_KMS_HELPER + select DRM_KMS_CMA_HELPER + select DRM_MIPI_DBI + select BACKLIGHT_CLASS_DEVICE + help + DRM driver for the following Ilitek ILI9486 panels: + * PISCREEN 3.5" 320x480 TFT (Ozzmaker 3.5") + * RPILCD 3.5" 320x480 TFT (Waveshare 3.5") + + If M is selected the module will be called ili9486. + config TINYDRM_MI0283QT tristate "DRM support for MI0283QT" depends on DRM && SPI @@ -85,14 +99,16 @@ config TINYDRM_ST7586 If M is selected the module will be called st7586. config TINYDRM_ST7735R - tristate "DRM support for Sitronix ST7735R display panels" + tristate "DRM support for Sitronix ST7715R/ST7735R display panels" depends on DRM && SPI select DRM_KMS_HELPER select DRM_KMS_CMA_HELPER select DRM_MIPI_DBI select BACKLIGHT_CLASS_DEVICE help - DRM driver Sitronix ST7735R with one of the following LCDs: - * JD-T18003-T01 1.8" 128x160 TFT + DRM driver for Sitronix ST7715R/ST7735R with one of the following + LCDs: + * Jianda JD-T18003-T01 1.8" 128x160 TFT + * Okaya RH128128T 1.44" 128x128 TFT If M is selected the module will be called st7735r. diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile index 896cf31132d3..c96ceee71453 100644 --- a/drivers/gpu/drm/tiny/Makefile +++ b/drivers/gpu/drm/tiny/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_GM12U320) += gm12u320.o obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o obj-$(CONFIG_TINYDRM_ILI9341) += ili9341.o +obj-$(CONFIG_TINYDRM_ILI9486) += ili9486.o obj-$(CONFIG_TINYDRM_MI0283QT) += mi0283qt.o obj-$(CONFIG_TINYDRM_REPAPER) += repaper.o obj-$(CONFIG_TINYDRM_ST7586) += st7586.o diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c index 94fb1f593564..a48173441ae0 100644 --- a/drivers/gpu/drm/tiny/gm12u320.c +++ b/drivers/gpu/drm/tiny/gm12u320.c @@ -22,7 +22,6 @@ #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> -#include <drm/drm_vblank.h> static bool eco_mode; module_param(eco_mode, bool, 0644); @@ -610,18 +609,10 @@ static void gm12u320_pipe_update(struct drm_simple_display_pipe *pipe, struct drm_plane_state *old_state) { struct drm_plane_state *state = pipe->plane.state; - struct drm_crtc *crtc = &pipe->crtc; struct drm_rect rect; if (drm_atomic_helper_damage_merged(old_state, state, &rect)) gm12u320_fb_mark_dirty(pipe->plane.state->fb, &rect); - - if (crtc->state->event) { - spin_lock_irq(&crtc->dev->event_lock); - drm_crtc_send_vblank_event(crtc, crtc->state->event); - crtc->state->event = NULL; - spin_unlock_irq(&crtc->dev->event_lock); - } } static const struct drm_simple_display_pipe_funcs gm12u320_pipe_funcs = { diff --git a/drivers/gpu/drm/tiny/ili9225.c b/drivers/gpu/drm/tiny/ili9225.c index c66acc566c2b..802fb8dde1b6 100644 --- a/drivers/gpu/drm/tiny/ili9225.c +++ b/drivers/gpu/drm/tiny/ili9225.c @@ -26,7 +26,6 @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_rect.h> -#include <drm/drm_vblank.h> #define ILI9225_DRIVER_READ_CODE 0x00 #define ILI9225_DRIVER_OUTPUT_CONTROL 0x01 @@ -165,18 +164,10 @@ static void ili9225_pipe_update(struct drm_simple_display_pipe *pipe, struct drm_plane_state *old_state) { struct drm_plane_state *state = pipe->plane.state; - struct drm_crtc *crtc = &pipe->crtc; struct drm_rect rect; if (drm_atomic_helper_damage_merged(old_state, state, &rect)) ili9225_fb_dirty(state->fb, &rect); - - if (crtc->state->event) { - spin_lock_irq(&crtc->dev->event_lock); - drm_crtc_send_vblank_event(crtc, crtc->state->event); - spin_unlock_irq(&crtc->dev->event_lock); - crtc->state->event = NULL; - } } static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe, diff --git a/drivers/gpu/drm/tiny/ili9486.c b/drivers/gpu/drm/tiny/ili9486.c new file mode 100644 index 000000000000..5084b38c1a71 --- /dev/null +++ b/drivers/gpu/drm/tiny/ili9486.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * DRM driver for Ilitek ILI9486 panels + * + * Copyright 2020 Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com> + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/spi/spi.h> + +#include <video/mipi_display.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_drv.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_mipi_dbi.h> +#include <drm/drm_modeset_helper.h> + +#define ILI9486_ITFCTR1 0xb0 +#define ILI9486_PWCTRL1 0xc2 +#define ILI9486_VMCTRL1 0xc5 +#define ILI9486_PGAMCTRL 0xe0 +#define ILI9486_NGAMCTRL 0xe1 +#define ILI9486_DGAMCTRL 0xe2 +#define ILI9486_MADCTL_BGR BIT(3) +#define ILI9486_MADCTL_MV BIT(5) +#define ILI9486_MADCTL_MX BIT(6) +#define ILI9486_MADCTL_MY BIT(7) + +/* + * The PiScreen/waveshare rpi-lcd-35 has a SPI to 16-bit parallel bus converter + * in front of the display controller. This means that 8-bit values have to be + * transferred as 16-bit. + */ +static int waveshare_command(struct mipi_dbi *mipi, u8 *cmd, u8 *par, + size_t num) +{ + struct spi_device *spi = mipi->spi; + void *data = par; + u32 speed_hz; + int i, ret; + u16 *buf; + + buf = kmalloc(32 * sizeof(u16), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* + * The displays are Raspberry Pi HATs and connected to the 8-bit only + * SPI controller, so 16-bit command and parameters need byte swapping + * before being transferred as 8-bit on the big endian SPI bus. + * Pixel data bytes have already been swapped before this function is + * called. + */ + buf[0] = cpu_to_be16(*cmd); + gpiod_set_value_cansleep(mipi->dc, 0); + speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 2); + ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, buf, 2); + if (ret || !num) + goto free; + + /* 8-bit configuration data, not 16-bit pixel data */ + if (num <= 32) { + for (i = 0; i < num; i++) + buf[i] = cpu_to_be16(par[i]); + num *= 2; + speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num); + data = buf; + } + + gpiod_set_value_cansleep(mipi->dc, 1); + ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, data, num); + free: + kfree(buf); + + return ret; +} + +static void waveshare_enable(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) +{ + struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); + struct mipi_dbi *dbi = &dbidev->dbi; + u8 addr_mode; + int ret, idx; + + if (!drm_dev_enter(pipe->crtc.dev, &idx)) + return; + + DRM_DEBUG_KMS("\n"); + + ret = mipi_dbi_poweron_conditional_reset(dbidev); + if (ret < 0) + goto out_exit; + if (ret == 1) + goto out_enable; + + mipi_dbi_command(dbi, ILI9486_ITFCTR1); + mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE); + msleep(250); + + mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55); + + mipi_dbi_command(dbi, ILI9486_PWCTRL1, 0x44); + + mipi_dbi_command(dbi, ILI9486_VMCTRL1, 0x00, 0x00, 0x00, 0x00); + + mipi_dbi_command(dbi, ILI9486_PGAMCTRL, + 0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98, + 0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x0); + mipi_dbi_command(dbi, ILI9486_NGAMCTRL, + 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, + 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00); + mipi_dbi_command(dbi, ILI9486_DGAMCTRL, + 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, + 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00); + + mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON); + msleep(100); + + out_enable: + switch (dbidev->rotation) { + case 90: + addr_mode = ILI9486_MADCTL_MY; + break; + case 180: + addr_mode = ILI9486_MADCTL_MV; + break; + case 270: + addr_mode = ILI9486_MADCTL_MX; + break; + default: + addr_mode = ILI9486_MADCTL_MV | ILI9486_MADCTL_MY | + ILI9486_MADCTL_MX; + break; + } + addr_mode |= ILI9486_MADCTL_BGR; + mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); + mipi_dbi_enable_flush(dbidev, crtc_state, plane_state); + out_exit: + drm_dev_exit(idx); +} + +static const struct drm_simple_display_pipe_funcs waveshare_pipe_funcs = { + .enable = waveshare_enable, + .disable = mipi_dbi_pipe_disable, + .update = mipi_dbi_pipe_update, + .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, +}; + +static const struct drm_display_mode waveshare_mode = { + DRM_SIMPLE_MODE(480, 320, 73, 49), +}; + +DEFINE_DRM_GEM_CMA_FOPS(ili9486_fops); + +static struct drm_driver ili9486_driver = { + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, + .fops = &ili9486_fops, + .release = mipi_dbi_release, + DRM_GEM_CMA_VMAP_DRIVER_OPS, + .debugfs_init = mipi_dbi_debugfs_init, + .name = "ili9486", + .desc = "Ilitek ILI9486", + .date = "20200118", + .major = 1, + .minor = 0, +}; + +static const struct of_device_id ili9486_of_match[] = { + { .compatible = "waveshare,rpi-lcd-35" }, + { .compatible = "ozzmaker,piscreen" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ili9486_of_match); + +static const struct spi_device_id ili9486_id[] = { + { "ili9486", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, ili9486_id); + +static int ili9486_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct mipi_dbi_dev *dbidev; + struct drm_device *drm; + struct mipi_dbi *dbi; + struct gpio_desc *dc; + u32 rotation = 0; + int ret; + + dbidev = kzalloc(sizeof(*dbidev), GFP_KERNEL); + if (!dbidev) + return -ENOMEM; + + dbi = &dbidev->dbi; + drm = &dbidev->drm; + ret = devm_drm_dev_init(dev, drm, &ili9486_driver); + if (ret) { + kfree(dbidev); + return ret; + } + + drm_mode_config_init(drm); + + dbi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(dbi->reset)) { + DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n"); + return PTR_ERR(dbi->reset); + } + + dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW); + if (IS_ERR(dc)) { + DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n"); + return PTR_ERR(dc); + } + + dbidev->backlight = devm_of_find_backlight(dev); + if (IS_ERR(dbidev->backlight)) + return PTR_ERR(dbidev->backlight); + + device_property_read_u32(dev, "rotation", &rotation); + + ret = mipi_dbi_spi_init(spi, dbi, dc); + if (ret) + return ret; + + dbi->command = waveshare_command; + dbi->read_commands = NULL; + + ret = mipi_dbi_dev_init(dbidev, &waveshare_pipe_funcs, + &waveshare_mode, rotation); + if (ret) + return ret; + + drm_mode_config_reset(drm); + + ret = drm_dev_register(drm, 0); + if (ret) + return ret; + + spi_set_drvdata(spi, drm); + + drm_fbdev_generic_setup(drm, 0); + + return 0; +} + +static int ili9486_remove(struct spi_device *spi) +{ + struct drm_device *drm = spi_get_drvdata(spi); + + drm_dev_unplug(drm); + drm_atomic_helper_shutdown(drm); + + return 0; +} + +static void ili9486_shutdown(struct spi_device *spi) +{ + drm_atomic_helper_shutdown(spi_get_drvdata(spi)); +} + +static struct spi_driver ili9486_spi_driver = { + .driver = { + .name = "ili9486", + .of_match_table = ili9486_of_match, + }, + .id_table = ili9486_id, + .probe = ili9486_probe, + .remove = ili9486_remove, + .shutdown = ili9486_shutdown, +}; +module_spi_driver(ili9486_spi_driver); + +MODULE_DESCRIPTION("Ilitek ILI9486 DRM driver"); +MODULE_AUTHOR("Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c index 76d179200775..f5ebcaf7ee3a 100644 --- a/drivers/gpu/drm/tiny/repaper.c +++ b/drivers/gpu/drm/tiny/repaper.c @@ -17,7 +17,7 @@ #include <linux/dma-buf.h> #include <linux/gpio/consumer.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/property.h> #include <linux/sched/clock.h> #include <linux/spi/spi.h> #include <linux/thermal.h> @@ -33,13 +33,13 @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_modes.h> #include <drm/drm_rect.h> -#include <drm/drm_vblank.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> #define REPAPER_RID_G2_COG_ID 0x12 enum repaper_model { + /* 0 is reserved to avoid clashing with NULL */ E1144CS021 = 1, E1190CS021, E2200CS021, @@ -856,18 +856,10 @@ static void repaper_pipe_update(struct drm_simple_display_pipe *pipe, struct drm_plane_state *old_state) { struct drm_plane_state *state = pipe->plane.state; - struct drm_crtc *crtc = &pipe->crtc; struct drm_rect rect; if (drm_atomic_helper_damage_merged(old_state, state, &rect)) repaper_fb_dirty(state->fb); - - if (crtc->state->event) { - spin_lock_irq(&crtc->dev->event_lock); - drm_crtc_send_vblank_event(crtc, crtc->state->event); - spin_unlock_irq(&crtc->dev->event_lock); - crtc->state->event = NULL; - } } static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = { @@ -995,21 +987,21 @@ static int repaper_probe(struct spi_device *spi) { const struct drm_display_mode *mode; const struct spi_device_id *spi_id; - const struct of_device_id *match; struct device *dev = &spi->dev; enum repaper_model model; const char *thermal_zone; struct repaper_epd *epd; size_t line_buffer_size; struct drm_device *drm; + const void *match; int ret; - match = of_match_device(repaper_of_match, dev); + match = device_get_match_data(dev); if (match) { - model = (enum repaper_model)match->data; + model = (enum repaper_model)match; } else { spi_id = spi_get_device_id(spi); - model = spi_id->driver_data; + model = (enum repaper_model)spi_id->driver_data; } /* The SPI device is used to allocate dma memory */ @@ -1197,7 +1189,6 @@ static void repaper_shutdown(struct spi_device *spi) static struct spi_driver repaper_spi_driver = { .driver = { .name = "repaper", - .owner = THIS_MODULE, .of_match_table = repaper_of_match, }, .id_table = repaper_id, diff --git a/drivers/gpu/drm/tiny/st7586.c b/drivers/gpu/drm/tiny/st7586.c index 060cc756194f..9ef559dd3191 100644 --- a/drivers/gpu/drm/tiny/st7586.c +++ b/drivers/gpu/drm/tiny/st7586.c @@ -23,7 +23,6 @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_rect.h> -#include <drm/drm_vblank.h> /* controller-specific commands */ #define ST7586_DISP_MODE_GRAY 0x38 @@ -159,18 +158,10 @@ static void st7586_pipe_update(struct drm_simple_display_pipe *pipe, struct drm_plane_state *old_state) { struct drm_plane_state *state = pipe->plane.state; - struct drm_crtc *crtc = &pipe->crtc; struct drm_rect rect; if (drm_atomic_helper_damage_merged(old_state, state, &rect)) st7586_fb_dirty(state->fb, &rect); - - if (crtc->state->event) { - spin_lock_irq(&crtc->dev->event_lock); - drm_crtc_send_vblank_event(crtc, crtc->state->event); - spin_unlock_irq(&crtc->dev->event_lock); - crtc->state->event = NULL; - } } static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe, diff --git a/drivers/gpu/drm/tiny/st7735r.c b/drivers/gpu/drm/tiny/st7735r.c index 3f4487c71684..3cd9b8d9888d 100644 --- a/drivers/gpu/drm/tiny/st7735r.c +++ b/drivers/gpu/drm/tiny/st7735r.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * DRM driver for Sitronix ST7735R panels + * DRM driver for display panels connected to a Sitronix ST7715R or ST7735R + * display controller in SPI mode. * * Copyright 2017 David Lechner <david@lechnology.com> + * Copyright (C) 2019 Glider bvba */ #include <linux/backlight.h> @@ -37,12 +39,28 @@ #define ST7735R_MY BIT(7) #define ST7735R_MX BIT(6) #define ST7735R_MV BIT(5) +#define ST7735R_RGB BIT(3) + +struct st7735r_cfg { + const struct drm_display_mode mode; + unsigned int left_offset; + unsigned int top_offset; + unsigned int write_only:1; + unsigned int rgb:1; /* RGB (vs. BGR) */ +}; + +struct st7735r_priv { + struct mipi_dbi_dev dbidev; /* Must be first for .release() */ + const struct st7735r_cfg *cfg; +}; -static void jd_t18003_t01_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void st7735r_pipe_enable(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) { struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); + struct st7735r_priv *priv = container_of(dbidev, struct st7735r_priv, + dbidev); struct mipi_dbi *dbi = &dbidev->dbi; int ret, idx; u8 addr_mode; @@ -87,6 +105,10 @@ static void jd_t18003_t01_pipe_enable(struct drm_simple_display_pipe *pipe, addr_mode = ST7735R_MY | ST7735R_MV; break; } + + if (priv->cfg->rgb) + addr_mode |= ST7735R_RGB; + mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT); @@ -109,15 +131,24 @@ out_exit: drm_dev_exit(idx); } -static const struct drm_simple_display_pipe_funcs jd_t18003_t01_pipe_funcs = { - .enable = jd_t18003_t01_pipe_enable, +static const struct drm_simple_display_pipe_funcs st7735r_pipe_funcs = { + .enable = st7735r_pipe_enable, .disable = mipi_dbi_pipe_disable, .update = mipi_dbi_pipe_update, .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, }; -static const struct drm_display_mode jd_t18003_t01_mode = { - DRM_SIMPLE_MODE(128, 160, 28, 35), +static const struct st7735r_cfg jd_t18003_t01_cfg = { + .mode = { DRM_SIMPLE_MODE(128, 160, 28, 35) }, + /* Cannot read from Adafruit 1.8" display via SPI */ + .write_only = true, +}; + +static const struct st7735r_cfg rh128128t_cfg = { + .mode = { DRM_SIMPLE_MODE(128, 128, 25, 26) }, + .left_offset = 2, + .top_offset = 3, + .rgb = true, }; DEFINE_DRM_GEM_CMA_FOPS(st7735r_fops); @@ -136,13 +167,14 @@ static struct drm_driver st7735r_driver = { }; static const struct of_device_id st7735r_of_match[] = { - { .compatible = "jianda,jd-t18003-t01" }, + { .compatible = "jianda,jd-t18003-t01", .data = &jd_t18003_t01_cfg }, + { .compatible = "okaya,rh128128t", .data = &rh128128t_cfg }, { }, }; MODULE_DEVICE_TABLE(of, st7735r_of_match); static const struct spi_device_id st7735r_id[] = { - { "jd-t18003-t01", 0 }, + { "jd-t18003-t01", (uintptr_t)&jd_t18003_t01_cfg }, { }, }; MODULE_DEVICE_TABLE(spi, st7735r_id); @@ -150,17 +182,26 @@ MODULE_DEVICE_TABLE(spi, st7735r_id); static int st7735r_probe(struct spi_device *spi) { struct device *dev = &spi->dev; + const struct st7735r_cfg *cfg; struct mipi_dbi_dev *dbidev; + struct st7735r_priv *priv; struct drm_device *drm; struct mipi_dbi *dbi; struct gpio_desc *dc; u32 rotation = 0; int ret; - dbidev = kzalloc(sizeof(*dbidev), GFP_KERNEL); - if (!dbidev) + cfg = device_get_match_data(&spi->dev); + if (!cfg) + cfg = (void *)spi_get_device_id(spi)->driver_data; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; + dbidev = &priv->dbidev; + priv->cfg = cfg; + dbi = &dbidev->dbi; drm = &dbidev->drm; ret = devm_drm_dev_init(dev, drm, &st7735r_driver); @@ -193,10 +234,14 @@ static int st7735r_probe(struct spi_device *spi) if (ret) return ret; - /* Cannot read from Adafruit 1.8" display via SPI */ - dbi->read_commands = NULL; + if (cfg->write_only) + dbi->read_commands = NULL; + + dbidev->left_offset = cfg->left_offset; + dbidev->top_offset = cfg->top_offset; - ret = mipi_dbi_dev_init(dbidev, &jd_t18003_t01_pipe_funcs, &jd_t18003_t01_mode, rotation); + ret = mipi_dbi_dev_init(dbidev, &st7735r_pipe_funcs, &cfg->mode, + rotation); if (ret) return ret; @@ -231,7 +276,6 @@ static void st7735r_shutdown(struct spi_device *spi) static struct spi_driver st7735r_spi_driver = { .driver = { .name = "st7735r", - .owner = THIS_MODULE, .of_match_table = st7735r_of_match, }, .id_table = st7735r_id, |