linux/drivers/gpu/drm/tiny/ili9486.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * DRM driver for Ilitek ILI9486 panels
   4 *
   5 * Copyright 2020 Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com>
   6 */
   7
   8#include <linux/backlight.h>
   9#include <linux/delay.h>
  10#include <linux/gpio/consumer.h>
  11#include <linux/module.h>
  12#include <linux/property.h>
  13#include <linux/spi/spi.h>
  14
  15#include <video/mipi_display.h>
  16
  17#include <drm/drm_atomic_helper.h>
  18#include <drm/drm_drv.h>
  19#include <drm/drm_fb_helper.h>
  20#include <drm/drm_gem_atomic_helper.h>
  21#include <drm/drm_gem_cma_helper.h>
  22#include <drm/drm_managed.h>
  23#include <drm/drm_mipi_dbi.h>
  24#include <drm/drm_modeset_helper.h>
  25
  26#define ILI9486_ITFCTR1         0xb0
  27#define ILI9486_PWCTRL1         0xc2
  28#define ILI9486_VMCTRL1         0xc5
  29#define ILI9486_PGAMCTRL        0xe0
  30#define ILI9486_NGAMCTRL        0xe1
  31#define ILI9486_DGAMCTRL        0xe2
  32#define ILI9486_MADCTL_BGR      BIT(3)
  33#define ILI9486_MADCTL_MV       BIT(5)
  34#define ILI9486_MADCTL_MX       BIT(6)
  35#define ILI9486_MADCTL_MY       BIT(7)
  36
  37/*
  38 * The PiScreen/waveshare rpi-lcd-35 has a SPI to 16-bit parallel bus converter
  39 * in front of the  display controller. This means that 8-bit values have to be
  40 * transferred as 16-bit.
  41 */
  42static int waveshare_command(struct mipi_dbi *mipi, u8 *cmd, u8 *par,
  43                             size_t num)
  44{
  45        struct spi_device *spi = mipi->spi;
  46        void *data = par;
  47        u32 speed_hz;
  48        int i, ret;
  49        __be16 *buf;
  50
  51        buf = kmalloc(32 * sizeof(u16), GFP_KERNEL);
  52        if (!buf)
  53                return -ENOMEM;
  54
  55        /*
  56         * The displays are Raspberry Pi HATs and connected to the 8-bit only
  57         * SPI controller, so 16-bit command and parameters need byte swapping
  58         * before being transferred as 8-bit on the big endian SPI bus.
  59         * Pixel data bytes have already been swapped before this function is
  60         * called.
  61         */
  62        buf[0] = cpu_to_be16(*cmd);
  63        gpiod_set_value_cansleep(mipi->dc, 0);
  64        speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 2);
  65        ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, buf, 2);
  66        if (ret || !num)
  67                goto free;
  68
  69        /* 8-bit configuration data, not 16-bit pixel data */
  70        if (num <= 32) {
  71                for (i = 0; i < num; i++)
  72                        buf[i] = cpu_to_be16(par[i]);
  73                num *= 2;
  74                speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num);
  75                data = buf;
  76        }
  77
  78        gpiod_set_value_cansleep(mipi->dc, 1);
  79        ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, data, num);
  80 free:
  81        kfree(buf);
  82
  83        return ret;
  84}
  85
  86static void waveshare_enable(struct drm_simple_display_pipe *pipe,
  87                             struct drm_crtc_state *crtc_state,
  88                             struct drm_plane_state *plane_state)
  89{
  90        struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
  91        struct mipi_dbi *dbi = &dbidev->dbi;
  92        u8 addr_mode;
  93        int ret, idx;
  94
  95        if (!drm_dev_enter(pipe->crtc.dev, &idx))
  96                return;
  97
  98        DRM_DEBUG_KMS("\n");
  99
 100        ret = mipi_dbi_poweron_conditional_reset(dbidev);
 101        if (ret < 0)
 102                goto out_exit;
 103        if (ret == 1)
 104                goto out_enable;
 105
 106        mipi_dbi_command(dbi, ILI9486_ITFCTR1);
 107        mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
 108        msleep(250);
 109
 110        mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55);
 111
 112        mipi_dbi_command(dbi, ILI9486_PWCTRL1, 0x44);
 113
 114        mipi_dbi_command(dbi, ILI9486_VMCTRL1, 0x00, 0x00, 0x00, 0x00);
 115
 116        mipi_dbi_command(dbi, ILI9486_PGAMCTRL,
 117                         0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98,
 118                         0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x0);
 119        mipi_dbi_command(dbi, ILI9486_NGAMCTRL,
 120                         0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75,
 121                         0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00);
 122        mipi_dbi_command(dbi, ILI9486_DGAMCTRL,
 123                         0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75,
 124                         0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00);
 125
 126        mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
 127        msleep(100);
 128
 129 out_enable:
 130        switch (dbidev->rotation) {
 131        case 90:
 132                addr_mode = ILI9486_MADCTL_MY;
 133                break;
 134        case 180:
 135                addr_mode = ILI9486_MADCTL_MV;
 136                break;
 137        case 270:
 138                addr_mode = ILI9486_MADCTL_MX;
 139                break;
 140        default:
 141                addr_mode = ILI9486_MADCTL_MV | ILI9486_MADCTL_MY |
 142                        ILI9486_MADCTL_MX;
 143                break;
 144        }
 145        addr_mode |= ILI9486_MADCTL_BGR;
 146        mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
 147        mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
 148 out_exit:
 149        drm_dev_exit(idx);
 150}
 151
 152static const struct drm_simple_display_pipe_funcs waveshare_pipe_funcs = {
 153        .enable = waveshare_enable,
 154        .disable = mipi_dbi_pipe_disable,
 155        .update = mipi_dbi_pipe_update,
 156};
 157
 158static const struct drm_display_mode waveshare_mode = {
 159        DRM_SIMPLE_MODE(480, 320, 73, 49),
 160};
 161
 162DEFINE_DRM_GEM_CMA_FOPS(ili9486_fops);
 163
 164static const struct drm_driver ili9486_driver = {
 165        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
 166        .fops                   = &ili9486_fops,
 167        DRM_GEM_CMA_DRIVER_OPS_VMAP,
 168        .debugfs_init           = mipi_dbi_debugfs_init,
 169        .name                   = "ili9486",
 170        .desc                   = "Ilitek ILI9486",
 171        .date                   = "20200118",
 172        .major                  = 1,
 173        .minor                  = 0,
 174};
 175
 176static const struct of_device_id ili9486_of_match[] = {
 177        { .compatible = "waveshare,rpi-lcd-35" },
 178        { .compatible = "ozzmaker,piscreen" },
 179        {},
 180};
 181MODULE_DEVICE_TABLE(of, ili9486_of_match);
 182
 183static const struct spi_device_id ili9486_id[] = {
 184        { "ili9486", 0 },
 185        { }
 186};
 187MODULE_DEVICE_TABLE(spi, ili9486_id);
 188
 189static int ili9486_probe(struct spi_device *spi)
 190{
 191        struct device *dev = &spi->dev;
 192        struct mipi_dbi_dev *dbidev;
 193        struct drm_device *drm;
 194        struct mipi_dbi *dbi;
 195        struct gpio_desc *dc;
 196        u32 rotation = 0;
 197        int ret;
 198
 199        dbidev = devm_drm_dev_alloc(dev, &ili9486_driver,
 200                                    struct mipi_dbi_dev, drm);
 201        if (IS_ERR(dbidev))
 202                return PTR_ERR(dbidev);
 203
 204        dbi = &dbidev->dbi;
 205        drm = &dbidev->drm;
 206
 207        dbi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
 208        if (IS_ERR(dbi->reset))
 209                return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n");
 210
 211        dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
 212        if (IS_ERR(dc))
 213                return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n");
 214
 215        dbidev->backlight = devm_of_find_backlight(dev);
 216        if (IS_ERR(dbidev->backlight))
 217                return PTR_ERR(dbidev->backlight);
 218
 219        device_property_read_u32(dev, "rotation", &rotation);
 220
 221        ret = mipi_dbi_spi_init(spi, dbi, dc);
 222        if (ret)
 223                return ret;
 224
 225        dbi->command = waveshare_command;
 226        dbi->read_commands = NULL;
 227
 228        ret = mipi_dbi_dev_init(dbidev, &waveshare_pipe_funcs,
 229                                &waveshare_mode, rotation);
 230        if (ret)
 231                return ret;
 232
 233        drm_mode_config_reset(drm);
 234
 235        ret = drm_dev_register(drm, 0);
 236        if (ret)
 237                return ret;
 238
 239        spi_set_drvdata(spi, drm);
 240
 241        drm_fbdev_generic_setup(drm, 0);
 242
 243        return 0;
 244}
 245
 246static int ili9486_remove(struct spi_device *spi)
 247{
 248        struct drm_device *drm = spi_get_drvdata(spi);
 249
 250        drm_dev_unplug(drm);
 251        drm_atomic_helper_shutdown(drm);
 252
 253        return 0;
 254}
 255
 256static void ili9486_shutdown(struct spi_device *spi)
 257{
 258        drm_atomic_helper_shutdown(spi_get_drvdata(spi));
 259}
 260
 261static struct spi_driver ili9486_spi_driver = {
 262        .driver = {
 263                .name = "ili9486",
 264                .of_match_table = ili9486_of_match,
 265        },
 266        .id_table = ili9486_id,
 267        .probe = ili9486_probe,
 268        .remove = ili9486_remove,
 269        .shutdown = ili9486_shutdown,
 270};
 271module_spi_driver(ili9486_spi_driver);
 272
 273MODULE_DESCRIPTION("Ilitek ILI9486 DRM driver");
 274MODULE_AUTHOR("Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com>");
 275MODULE_LICENSE("GPL");
 276