linux/drivers/gpu/drm/tiny/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_atomic_helper.h>
  22#include <drm/drm_gem_cma_helper.h>
  23#include <drm/drm_managed.h>
  24#include <drm/drm_mipi_dbi.h>
  25#include <drm/drm_modeset_helper.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_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
  58        struct mipi_dbi *dbi = &dbidev->dbi;
  59        u8 addr_mode;
  60        int ret, idx;
  61
  62        if (!drm_dev_enter(pipe->crtc.dev, &idx))
  63                return;
  64
  65        DRM_DEBUG_KMS("\n");
  66
  67        ret = mipi_dbi_poweron_conditional_reset(dbidev);
  68        if (ret < 0)
  69                goto out_exit;
  70        if (ret == 1)
  71                goto out_enable;
  72
  73        mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
  74
  75        mipi_dbi_command(dbi, ILI9341_PWCTRLB, 0x00, 0xc1, 0x30);
  76        mipi_dbi_command(dbi, ILI9341_PWRSEQ, 0x64, 0x03, 0x12, 0x81);
  77        mipi_dbi_command(dbi, ILI9341_DTCTRLA, 0x85, 0x00, 0x78);
  78        mipi_dbi_command(dbi, ILI9341_PWCTRLA, 0x39, 0x2c, 0x00, 0x34, 0x02);
  79        mipi_dbi_command(dbi, ILI9341_PUMPCTRL, 0x20);
  80        mipi_dbi_command(dbi, ILI9341_DTCTRLB, 0x00, 0x00);
  81
  82        /* Power Control */
  83        mipi_dbi_command(dbi, ILI9341_PWCTRL1, 0x23);
  84        mipi_dbi_command(dbi, ILI9341_PWCTRL2, 0x10);
  85        /* VCOM */
  86        mipi_dbi_command(dbi, ILI9341_VMCTRL1, 0x3e, 0x28);
  87        mipi_dbi_command(dbi, ILI9341_VMCTRL2, 0x86);
  88
  89        /* Memory Access Control */
  90        mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
  91
  92        /* Frame Rate */
  93        mipi_dbi_command(dbi, ILI9341_FRMCTR1, 0x00, 0x1b);
  94
  95        /* Gamma */
  96        mipi_dbi_command(dbi, ILI9341_EN3GAM, 0x00);
  97        mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, 0x01);
  98        mipi_dbi_command(dbi, ILI9341_PGAMCTRL,
  99                         0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1,
 100                         0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00);
 101        mipi_dbi_command(dbi, ILI9341_NGAMCTRL,
 102                         0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1,
 103                         0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f);
 104
 105        /* DDRAM */
 106        mipi_dbi_command(dbi, ILI9341_ETMOD, 0x07);
 107
 108        /* Display */
 109        mipi_dbi_command(dbi, ILI9341_DISCTRL, 0x08, 0x82, 0x27, 0x00);
 110        mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
 111        msleep(100);
 112
 113        mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
 114        msleep(100);
 115
 116out_enable:
 117        switch (dbidev->rotation) {
 118        default:
 119                addr_mode = ILI9341_MADCTL_MX;
 120                break;
 121        case 90:
 122                addr_mode = ILI9341_MADCTL_MV;
 123                break;
 124        case 180:
 125                addr_mode = ILI9341_MADCTL_MY;
 126                break;
 127        case 270:
 128                addr_mode = ILI9341_MADCTL_MV | ILI9341_MADCTL_MY |
 129                            ILI9341_MADCTL_MX;
 130                break;
 131        }
 132        addr_mode |= ILI9341_MADCTL_BGR;
 133        mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
 134        mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
 135out_exit:
 136        drm_dev_exit(idx);
 137}
 138
 139static const struct drm_simple_display_pipe_funcs ili9341_pipe_funcs = {
 140        .enable = yx240qv29_enable,
 141        .disable = mipi_dbi_pipe_disable,
 142        .update = mipi_dbi_pipe_update,
 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 const struct drm_driver ili9341_driver = {
 152        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
 153        .fops                   = &ili9341_fops,
 154        DRM_GEM_CMA_DRIVER_OPS_VMAP,
 155        .debugfs_init           = mipi_dbi_debugfs_init,
 156        .name                   = "ili9341",
 157        .desc                   = "Ilitek ILI9341",
 158        .date                   = "20180514",
 159        .major                  = 1,
 160        .minor                  = 0,
 161};
 162
 163static const struct of_device_id ili9341_of_match[] = {
 164        { .compatible = "adafruit,yx240qv29" },
 165        { }
 166};
 167MODULE_DEVICE_TABLE(of, ili9341_of_match);
 168
 169static const struct spi_device_id ili9341_id[] = {
 170        { "yx240qv29", 0 },
 171        { }
 172};
 173MODULE_DEVICE_TABLE(spi, ili9341_id);
 174
 175static int ili9341_probe(struct spi_device *spi)
 176{
 177        struct device *dev = &spi->dev;
 178        struct mipi_dbi_dev *dbidev;
 179        struct drm_device *drm;
 180        struct mipi_dbi *dbi;
 181        struct gpio_desc *dc;
 182        u32 rotation = 0;
 183        int ret;
 184
 185        dbidev = devm_drm_dev_alloc(dev, &ili9341_driver,
 186                                    struct mipi_dbi_dev, drm);
 187        if (IS_ERR(dbidev))
 188                return PTR_ERR(dbidev);
 189
 190        dbi = &dbidev->dbi;
 191        drm = &dbidev->drm;
 192
 193        dbi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
 194        if (IS_ERR(dbi->reset))
 195                return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n");
 196
 197        dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
 198        if (IS_ERR(dc))
 199                return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n");
 200
 201        dbidev->backlight = devm_of_find_backlight(dev);
 202        if (IS_ERR(dbidev->backlight))
 203                return PTR_ERR(dbidev->backlight);
 204
 205        device_property_read_u32(dev, "rotation", &rotation);
 206
 207        ret = mipi_dbi_spi_init(spi, dbi, dc);
 208        if (ret)
 209                return ret;
 210
 211        ret = mipi_dbi_dev_init(dbidev, &ili9341_pipe_funcs, &yx240qv29_mode, rotation);
 212        if (ret)
 213                return ret;
 214
 215        drm_mode_config_reset(drm);
 216
 217        ret = drm_dev_register(drm, 0);
 218        if (ret)
 219                return ret;
 220
 221        spi_set_drvdata(spi, drm);
 222
 223        drm_fbdev_generic_setup(drm, 0);
 224
 225        return 0;
 226}
 227
 228static int ili9341_remove(struct spi_device *spi)
 229{
 230        struct drm_device *drm = spi_get_drvdata(spi);
 231
 232        drm_dev_unplug(drm);
 233        drm_atomic_helper_shutdown(drm);
 234
 235        return 0;
 236}
 237
 238static void ili9341_shutdown(struct spi_device *spi)
 239{
 240        drm_atomic_helper_shutdown(spi_get_drvdata(spi));
 241}
 242
 243static struct spi_driver ili9341_spi_driver = {
 244        .driver = {
 245                .name = "ili9341",
 246                .of_match_table = ili9341_of_match,
 247        },
 248        .id_table = ili9341_id,
 249        .probe = ili9341_probe,
 250        .remove = ili9341_remove,
 251        .shutdown = ili9341_shutdown,
 252};
 253module_spi_driver(ili9341_spi_driver);
 254
 255MODULE_DESCRIPTION("Ilitek ILI9341 DRM driver");
 256MODULE_AUTHOR("David Lechner <david@lechnology.com>");
 257MODULE_LICENSE("GPL");
 258