root/drivers/gpu/drm/tiny/mi0283qt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mi0283qt_enable
  2. mi0283qt_probe
  3. mi0283qt_remove
  4. mi0283qt_shutdown
  5. mi0283qt_pm_suspend
  6. mi0283qt_pm_resume

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * DRM driver for Multi-Inno MI0283QT panels
   4  *
   5  * Copyright 2016 Noralf Trønnes
   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/regulator/consumer.h>
  14 #include <linux/spi/spi.h>
  15 
  16 #include <drm/drm_atomic_helper.h>
  17 #include <drm/drm_drv.h>
  18 #include <drm/drm_fb_helper.h>
  19 #include <drm/drm_gem_cma_helper.h>
  20 #include <drm/drm_gem_framebuffer_helper.h>
  21 #include <drm/drm_mipi_dbi.h>
  22 #include <drm/drm_modeset_helper.h>
  23 #include <video/mipi_display.h>
  24 
  25 #define ILI9341_FRMCTR1         0xb1
  26 #define ILI9341_DISCTRL         0xb6
  27 #define ILI9341_ETMOD           0xb7
  28 
  29 #define ILI9341_PWCTRL1         0xc0
  30 #define ILI9341_PWCTRL2         0xc1
  31 #define ILI9341_VMCTRL1         0xc5
  32 #define ILI9341_VMCTRL2         0xc7
  33 #define ILI9341_PWCTRLA         0xcb
  34 #define ILI9341_PWCTRLB         0xcf
  35 
  36 #define ILI9341_PGAMCTRL        0xe0
  37 #define ILI9341_NGAMCTRL        0xe1
  38 #define ILI9341_DTCTRLA         0xe8
  39 #define ILI9341_DTCTRLB         0xea
  40 #define ILI9341_PWRSEQ          0xed
  41 
  42 #define ILI9341_EN3GAM          0xf2
  43 #define ILI9341_PUMPCTRL        0xf7
  44 
  45 #define ILI9341_MADCTL_BGR      BIT(3)
  46 #define ILI9341_MADCTL_MV       BIT(5)
  47 #define ILI9341_MADCTL_MX       BIT(6)
  48 #define ILI9341_MADCTL_MY       BIT(7)
  49 
  50 static void mi0283qt_enable(struct drm_simple_display_pipe *pipe,
  51                             struct drm_crtc_state *crtc_state,
  52                             struct drm_plane_state *plane_state)
  53 {
  54         struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
  55         struct mipi_dbi *dbi = &dbidev->dbi;
  56         u8 addr_mode;
  57         int ret, idx;
  58 
  59         if (!drm_dev_enter(pipe->crtc.dev, &idx))
  60                 return;
  61 
  62         DRM_DEBUG_KMS("\n");
  63 
  64         ret = mipi_dbi_poweron_conditional_reset(dbidev);
  65         if (ret < 0)
  66                 goto out_exit;
  67         if (ret == 1)
  68                 goto out_enable;
  69 
  70         mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
  71 
  72         mipi_dbi_command(dbi, ILI9341_PWCTRLB, 0x00, 0x83, 0x30);
  73         mipi_dbi_command(dbi, ILI9341_PWRSEQ, 0x64, 0x03, 0x12, 0x81);
  74         mipi_dbi_command(dbi, ILI9341_DTCTRLA, 0x85, 0x01, 0x79);
  75         mipi_dbi_command(dbi, ILI9341_PWCTRLA, 0x39, 0x2c, 0x00, 0x34, 0x02);
  76         mipi_dbi_command(dbi, ILI9341_PUMPCTRL, 0x20);
  77         mipi_dbi_command(dbi, ILI9341_DTCTRLB, 0x00, 0x00);
  78 
  79         /* Power Control */
  80         mipi_dbi_command(dbi, ILI9341_PWCTRL1, 0x26);
  81         mipi_dbi_command(dbi, ILI9341_PWCTRL2, 0x11);
  82         /* VCOM */
  83         mipi_dbi_command(dbi, ILI9341_VMCTRL1, 0x35, 0x3e);
  84         mipi_dbi_command(dbi, ILI9341_VMCTRL2, 0xbe);
  85 
  86         /* Memory Access Control */
  87         mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
  88 
  89         /* Frame Rate */
  90         mipi_dbi_command(dbi, ILI9341_FRMCTR1, 0x00, 0x1b);
  91 
  92         /* Gamma */
  93         mipi_dbi_command(dbi, ILI9341_EN3GAM, 0x08);
  94         mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, 0x01);
  95         mipi_dbi_command(dbi, ILI9341_PGAMCTRL,
  96                        0x1f, 0x1a, 0x18, 0x0a, 0x0f, 0x06, 0x45, 0x87,
  97                        0x32, 0x0a, 0x07, 0x02, 0x07, 0x05, 0x00);
  98         mipi_dbi_command(dbi, ILI9341_NGAMCTRL,
  99                        0x00, 0x25, 0x27, 0x05, 0x10, 0x09, 0x3a, 0x78,
 100                        0x4d, 0x05, 0x18, 0x0d, 0x38, 0x3a, 0x1f);
 101 
 102         /* DDRAM */
 103         mipi_dbi_command(dbi, ILI9341_ETMOD, 0x07);
 104 
 105         /* Display */
 106         mipi_dbi_command(dbi, ILI9341_DISCTRL, 0x0a, 0x82, 0x27, 0x00);
 107         mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
 108         msleep(100);
 109 
 110         mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
 111         msleep(100);
 112 
 113 out_enable:
 114         /* The PiTFT (ili9340) has a hardware reset circuit that
 115          * resets only on power-on and not on each reboot through
 116          * a gpio like the rpi-display does.
 117          * As a result, we need to always apply the rotation value
 118          * regardless of the display "on/off" state.
 119          */
 120         switch (dbidev->rotation) {
 121         default:
 122                 addr_mode = ILI9341_MADCTL_MV | ILI9341_MADCTL_MY |
 123                             ILI9341_MADCTL_MX;
 124                 break;
 125         case 90:
 126                 addr_mode = ILI9341_MADCTL_MY;
 127                 break;
 128         case 180:
 129                 addr_mode = ILI9341_MADCTL_MV;
 130                 break;
 131         case 270:
 132                 addr_mode = ILI9341_MADCTL_MX;
 133                 break;
 134         }
 135         addr_mode |= ILI9341_MADCTL_BGR;
 136         mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
 137         mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
 138 out_exit:
 139         drm_dev_exit(idx);
 140 }
 141 
 142 static const struct drm_simple_display_pipe_funcs mi0283qt_pipe_funcs = {
 143         .enable = mi0283qt_enable,
 144         .disable = mipi_dbi_pipe_disable,
 145         .update = mipi_dbi_pipe_update,
 146         .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
 147 };
 148 
 149 static const struct drm_display_mode mi0283qt_mode = {
 150         DRM_SIMPLE_MODE(320, 240, 58, 43),
 151 };
 152 
 153 DEFINE_DRM_GEM_CMA_FOPS(mi0283qt_fops);
 154 
 155 static struct drm_driver mi0283qt_driver = {
 156         .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
 157         .fops                   = &mi0283qt_fops,
 158         .release                = mipi_dbi_release,
 159         DRM_GEM_CMA_VMAP_DRIVER_OPS,
 160         .debugfs_init           = mipi_dbi_debugfs_init,
 161         .name                   = "mi0283qt",
 162         .desc                   = "Multi-Inno MI0283QT",
 163         .date                   = "20160614",
 164         .major                  = 1,
 165         .minor                  = 0,
 166 };
 167 
 168 static const struct of_device_id mi0283qt_of_match[] = {
 169         { .compatible = "multi-inno,mi0283qt" },
 170         {},
 171 };
 172 MODULE_DEVICE_TABLE(of, mi0283qt_of_match);
 173 
 174 static const struct spi_device_id mi0283qt_id[] = {
 175         { "mi0283qt", 0 },
 176         { },
 177 };
 178 MODULE_DEVICE_TABLE(spi, mi0283qt_id);
 179 
 180 static int mi0283qt_probe(struct spi_device *spi)
 181 {
 182         struct device *dev = &spi->dev;
 183         struct mipi_dbi_dev *dbidev;
 184         struct drm_device *drm;
 185         struct mipi_dbi *dbi;
 186         struct gpio_desc *dc;
 187         u32 rotation = 0;
 188         int ret;
 189 
 190         dbidev = kzalloc(sizeof(*dbidev), GFP_KERNEL);
 191         if (!dbidev)
 192                 return -ENOMEM;
 193 
 194         dbi = &dbidev->dbi;
 195         drm = &dbidev->drm;
 196         ret = devm_drm_dev_init(dev, drm, &mi0283qt_driver);
 197         if (ret) {
 198                 kfree(dbidev);
 199                 return ret;
 200         }
 201 
 202         drm_mode_config_init(drm);
 203 
 204         dbi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
 205         if (IS_ERR(dbi->reset)) {
 206                 DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n");
 207                 return PTR_ERR(dbi->reset);
 208         }
 209 
 210         dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
 211         if (IS_ERR(dc)) {
 212                 DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
 213                 return PTR_ERR(dc);
 214         }
 215 
 216         dbidev->regulator = devm_regulator_get(dev, "power");
 217         if (IS_ERR(dbidev->regulator))
 218                 return PTR_ERR(dbidev->regulator);
 219 
 220         dbidev->backlight = devm_of_find_backlight(dev);
 221         if (IS_ERR(dbidev->backlight))
 222                 return PTR_ERR(dbidev->backlight);
 223 
 224         device_property_read_u32(dev, "rotation", &rotation);
 225 
 226         ret = mipi_dbi_spi_init(spi, dbi, dc);
 227         if (ret)
 228                 return ret;
 229 
 230         ret = mipi_dbi_dev_init(dbidev, &mi0283qt_pipe_funcs, &mi0283qt_mode, rotation);
 231         if (ret)
 232                 return ret;
 233 
 234         drm_mode_config_reset(drm);
 235 
 236         ret = drm_dev_register(drm, 0);
 237         if (ret)
 238                 return ret;
 239 
 240         spi_set_drvdata(spi, drm);
 241 
 242         drm_fbdev_generic_setup(drm, 0);
 243 
 244         return 0;
 245 }
 246 
 247 static int mi0283qt_remove(struct spi_device *spi)
 248 {
 249         struct drm_device *drm = spi_get_drvdata(spi);
 250 
 251         drm_dev_unplug(drm);
 252         drm_atomic_helper_shutdown(drm);
 253 
 254         return 0;
 255 }
 256 
 257 static void mi0283qt_shutdown(struct spi_device *spi)
 258 {
 259         drm_atomic_helper_shutdown(spi_get_drvdata(spi));
 260 }
 261 
 262 static int __maybe_unused mi0283qt_pm_suspend(struct device *dev)
 263 {
 264         return drm_mode_config_helper_suspend(dev_get_drvdata(dev));
 265 }
 266 
 267 static int __maybe_unused mi0283qt_pm_resume(struct device *dev)
 268 {
 269         drm_mode_config_helper_resume(dev_get_drvdata(dev));
 270 
 271         return 0;
 272 }
 273 
 274 static const struct dev_pm_ops mi0283qt_pm_ops = {
 275         SET_SYSTEM_SLEEP_PM_OPS(mi0283qt_pm_suspend, mi0283qt_pm_resume)
 276 };
 277 
 278 static struct spi_driver mi0283qt_spi_driver = {
 279         .driver = {
 280                 .name = "mi0283qt",
 281                 .owner = THIS_MODULE,
 282                 .of_match_table = mi0283qt_of_match,
 283                 .pm = &mi0283qt_pm_ops,
 284         },
 285         .id_table = mi0283qt_id,
 286         .probe = mi0283qt_probe,
 287         .remove = mi0283qt_remove,
 288         .shutdown = mi0283qt_shutdown,
 289 };
 290 module_spi_driver(mi0283qt_spi_driver);
 291 
 292 MODULE_DESCRIPTION("Multi-Inno MI0283QT DRM driver");
 293 MODULE_AUTHOR("Noralf Trønnes");
 294 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */