linux/drivers/gpu/drm/tinydrm/ili9341.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * DRM driver for Ilitek ILI9341 panels
   4 *
   5 * Copyright 2018 David Lechner <david@lechnology.com>
   6 *
   7 * Based on mi0283qt.c:
   8 * Copyright 2016 Noralf Trønnes
   9 */
  10
  11#include <linux/backlight.h>
  12#include <linux/delay.h>
  13#include <linux/gpio/consumer.h>
  14#include <linux/module.h>
  15#include <linux/property.h>
  16#include <linux/spi/spi.h>
  17
  18#include <drm/drm_atomic_helper.h>
  19#include <drm/drm_drv.h>
  20#include <drm/drm_fb_helper.h>
  21#include <drm/drm_gem_cma_helper.h>
  22#include <drm/drm_gem_framebuffer_helper.h>
  23#include <drm/drm_modeset_helper.h>
  24#include <drm/tinydrm/mipi-dbi.h>
  25#include <drm/tinydrm/tinydrm-helpers.h>
  26#include <video/mipi_display.h>
  27
  28#define ILI9341_FRMCTR1         0xb1
  29#define ILI9341_DISCTRL         0xb6
  30#define ILI9341_ETMOD           0xb7
  31
  32#define ILI9341_PWCTRL1         0xc0
  33#define ILI9341_PWCTRL2         0xc1
  34#define ILI9341_VMCTRL1         0xc5
  35#define ILI9341_VMCTRL2         0xc7
  36#define ILI9341_PWCTRLA         0xcb
  37#define ILI9341_PWCTRLB         0xcf
  38
  39#define ILI9341_PGAMCTRL        0xe0
  40#define ILI9341_NGAMCTRL        0xe1
  41#define ILI9341_DTCTRLA         0xe8
  42#define ILI9341_DTCTRLB         0xea
  43#define ILI9341_PWRSEQ          0xed
  44
  45#define ILI9341_EN3GAM          0xf2
  46#define ILI9341_PUMPCTRL        0xf7
  47
  48#define ILI9341_MADCTL_BGR      BIT(3)
  49#define ILI9341_MADCTL_MV       BIT(5)
  50#define ILI9341_MADCTL_MX       BIT(6)
  51#define ILI9341_MADCTL_MY       BIT(7)
  52
  53static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
  54                             struct drm_crtc_state *crtc_state,
  55                             struct drm_plane_state *plane_state)
  56{
  57        struct mipi_dbi *mipi = drm_to_mipi_dbi(pipe->crtc.dev);
  58        u8 addr_mode;
  59        int ret, idx;
  60
  61        if (!drm_dev_enter(pipe->crtc.dev, &idx))
  62                return;
  63
  64        DRM_DEBUG_KMS("\n");
  65
  66        ret = mipi_dbi_poweron_conditional_reset(mipi);
  67        if (ret < 0)
  68                goto out_exit;
  69        if (ret == 1)
  70                goto out_enable;
  71
  72        mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_OFF);
  73
  74        mipi_dbi_command(mipi, ILI9341_PWCTRLB, 0x00, 0xc1, 0x30);
  75        mipi_dbi_command(mipi, ILI9341_PWRSEQ, 0x64, 0x03, 0x12, 0x81);
  76        mipi_dbi_command(mipi, ILI9341_DTCTRLA, 0x85, 0x00, 0x78);
  77        mipi_dbi_command(mipi, ILI9341_PWCTRLA, 0x39, 0x2c, 0x00, 0x34, 0x02);
  78        mipi_dbi_command(mipi, ILI9341_PUMPCTRL, 0x20);
  79        mipi_dbi_command(mipi, ILI9341_DTCTRLB, 0x00, 0x00);
  80
  81        /* Power Control */
  82        mipi_dbi_command(mipi, ILI9341_PWCTRL1, 0x23);
  83        mipi_dbi_command(mipi, ILI9341_PWCTRL2, 0x10);
  84        /* VCOM */
  85        mipi_dbi_command(mipi, ILI9341_VMCTRL1, 0x3e, 0x28);
  86        mipi_dbi_command(mipi, ILI9341_VMCTRL2, 0x86);
  87
  88        /* Memory Access Control */
  89        mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
  90
  91        /* Frame Rate */
  92        mipi_dbi_command(mipi, ILI9341_FRMCTR1, 0x00, 0x1b);
  93
  94        /* Gamma */
  95        mipi_dbi_command(mipi, ILI9341_EN3GAM, 0x00);
  96        mipi_dbi_command(mipi, MIPI_DCS_SET_GAMMA_CURVE, 0x01);
  97        mipi_dbi_command(mipi, ILI9341_PGAMCTRL,
  98                         0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1,
  99                         0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00);
 100        mipi_dbi_command(mipi, ILI9341_NGAMCTRL,
 101                         0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1,
 102                         0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f);
 103
 104        /* DDRAM */
 105        mipi_dbi_command(mipi, ILI9341_ETMOD, 0x07);
 106
 107        /* Display */
 108        mipi_dbi_command(mipi, ILI9341_DISCTRL, 0x08, 0x82, 0x27, 0x00);
 109        mipi_dbi_command(mipi, MIPI_DCS_EXIT_SLEEP_MODE);
 110        msleep(100);
 111
 112        mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
 113        msleep(100);
 114
 115out_enable:
 116        switch (mipi->rotation) {
 117        default:
 118                addr_mode = ILI9341_MADCTL_MX;
 119                break;
 120        case 90:
 121                addr_mode = ILI9341_MADCTL_MV;
 122                break;
 123        case 180:
 124                addr_mode = ILI9341_MADCTL_MY;
 125                break;
 126        case 270:
 127                addr_mode = ILI9341_MADCTL_MV | ILI9341_MADCTL_MY |
 128                            ILI9341_MADCTL_MX;
 129                break;
 130        }
 131        addr_mode |= ILI9341_MADCTL_BGR;
 132        mipi_dbi_command(mipi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
 133        mipi_dbi_enable_flush(mipi, crtc_state, plane_state);
 134out_exit:
 135        drm_dev_exit(idx);
 136}
 137
 138static const struct drm_simple_display_pipe_funcs ili9341_pipe_funcs = {
 139        .enable = yx240qv29_enable,
 140        .disable = mipi_dbi_pipe_disable,
 141        .update = mipi_dbi_pipe_update,
 142        .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
 143};
 144
 145static const struct drm_display_mode yx240qv29_mode = {
 146        DRM_SIMPLE_MODE(240, 320, 37, 49),
 147};
 148
 149DEFINE_DRM_GEM_CMA_FOPS(ili9341_fops);
 150
 151static struct drm_driver ili9341_driver = {
 152        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
 153        .fops                   = &ili9341_fops,
 154        .release                = mipi_dbi_release,
 155        DRM_GEM_CMA_VMAP_DRIVER_OPS,
 156        .debugfs_init           = mipi_dbi_debugfs_init,
 157        .name                   = "ili9341",
 158        .desc                   = "Ilitek ILI9341",
 159        .date                   = "20180514",
 160        .major                  = 1,
 161        .minor                  = 0,
 162};
 163
 164static const struct of_device_id ili9341_of_match[] = {
 165        { .compatible = "adafruit,yx240qv29" },
 166        { }
 167};
 168MODULE_DEVICE_TABLE(of, ili9341_of_match);
 169
 170static const struct spi_device_id ili9341_id[] = {
 171        { "yx240qv29", 0 },
 172        { }
 173};
 174MODULE_DEVICE_TABLE(spi, ili9341_id);
 175
 176static int ili9341_probe(struct spi_device *spi)
 177{
 178        struct device *dev = &spi->dev;
 179        struct drm_device *drm;
 180        struct mipi_dbi *mipi;
 181        struct gpio_desc *dc;
 182        u32 rotation = 0;
 183        int ret;
 184
 185        mipi = kzalloc(sizeof(*mipi), GFP_KERNEL);
 186        if (!mipi)
 187                return -ENOMEM;
 188
 189        drm = &mipi->drm;
 190        ret = devm_drm_dev_init(dev, drm, &ili9341_driver);
 191        if (ret) {
 192                kfree(mipi);
 193                return ret;
 194        }
 195
 196        drm_mode_config_init(drm);
 197
 198        mipi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
 199        if (IS_ERR(mipi->reset)) {
 200                DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n");
 201                return PTR_ERR(mipi->reset);
 202        }
 203
 204        dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
 205        if (IS_ERR(dc)) {
 206                DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
 207                return PTR_ERR(dc);
 208        }
 209
 210        mipi->backlight = devm_of_find_backlight(dev);
 211        if (IS_ERR(mipi->backlight))
 212                return PTR_ERR(mipi->backlight);
 213
 214        device_property_read_u32(dev, "rotation", &rotation);
 215
 216        ret = mipi_dbi_spi_init(spi, mipi, dc);
 217        if (ret)
 218                return ret;
 219
 220        ret = mipi_dbi_init(mipi, &ili9341_pipe_funcs, &yx240qv29_mode, rotation);
 221        if (ret)
 222                return ret;
 223
 224        drm_mode_config_reset(drm);
 225
 226        ret = drm_dev_register(drm, 0);
 227        if (ret)
 228                return ret;
 229
 230        spi_set_drvdata(spi, drm);
 231
 232        drm_fbdev_generic_setup(drm, 0);
 233
 234        return 0;
 235}
 236
 237static int ili9341_remove(struct spi_device *spi)
 238{
 239        struct drm_device *drm = spi_get_drvdata(spi);
 240
 241        drm_dev_unplug(drm);
 242        drm_atomic_helper_shutdown(drm);
 243
 244        return 0;
 245}
 246
 247static void ili9341_shutdown(struct spi_device *spi)
 248{
 249        drm_atomic_helper_shutdown(spi_get_drvdata(spi));
 250}
 251
 252static struct spi_driver ili9341_spi_driver = {
 253        .driver = {
 254                .name = "ili9341",
 255                .of_match_table = ili9341_of_match,
 256        },
 257        .id_table = ili9341_id,
 258        .probe = ili9341_probe,
 259        .remove = ili9341_remove,
 260        .shutdown = ili9341_shutdown,
 261};
 262module_spi_driver(ili9341_spi_driver);
 263
 264MODULE_DESCRIPTION("Ilitek ILI9341 DRM driver");
 265MODULE_AUTHOR("David Lechner <david@lechnology.com>");
 266MODULE_LICENSE("GPL");
 267