Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * DRM driver for Ilitek ILI9341 panels
0004  *
0005  * Copyright 2018 David Lechner <david@lechnology.com>
0006  *
0007  * Based on mi0283qt.c:
0008  * Copyright 2016 Noralf Trønnes
0009  */
0010 
0011 #include <linux/backlight.h>
0012 #include <linux/delay.h>
0013 #include <linux/gpio/consumer.h>
0014 #include <linux/module.h>
0015 #include <linux/property.h>
0016 #include <linux/spi/spi.h>
0017 
0018 #include <drm/drm_atomic_helper.h>
0019 #include <drm/drm_drv.h>
0020 #include <drm/drm_fb_helper.h>
0021 #include <drm/drm_gem_atomic_helper.h>
0022 #include <drm/drm_gem_cma_helper.h>
0023 #include <drm/drm_managed.h>
0024 #include <drm/drm_mipi_dbi.h>
0025 #include <drm/drm_modeset_helper.h>
0026 #include <video/mipi_display.h>
0027 
0028 #define ILI9341_FRMCTR1     0xb1
0029 #define ILI9341_DISCTRL     0xb6
0030 #define ILI9341_ETMOD       0xb7
0031 
0032 #define ILI9341_PWCTRL1     0xc0
0033 #define ILI9341_PWCTRL2     0xc1
0034 #define ILI9341_VMCTRL1     0xc5
0035 #define ILI9341_VMCTRL2     0xc7
0036 #define ILI9341_PWCTRLA     0xcb
0037 #define ILI9341_PWCTRLB     0xcf
0038 
0039 #define ILI9341_PGAMCTRL    0xe0
0040 #define ILI9341_NGAMCTRL    0xe1
0041 #define ILI9341_DTCTRLA     0xe8
0042 #define ILI9341_DTCTRLB     0xea
0043 #define ILI9341_PWRSEQ      0xed
0044 
0045 #define ILI9341_EN3GAM      0xf2
0046 #define ILI9341_PUMPCTRL    0xf7
0047 
0048 #define ILI9341_MADCTL_BGR  BIT(3)
0049 #define ILI9341_MADCTL_MV   BIT(5)
0050 #define ILI9341_MADCTL_MX   BIT(6)
0051 #define ILI9341_MADCTL_MY   BIT(7)
0052 
0053 static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
0054                  struct drm_crtc_state *crtc_state,
0055                  struct drm_plane_state *plane_state)
0056 {
0057     struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
0058     struct mipi_dbi *dbi = &dbidev->dbi;
0059     u8 addr_mode;
0060     int ret, idx;
0061 
0062     if (!drm_dev_enter(pipe->crtc.dev, &idx))
0063         return;
0064 
0065     DRM_DEBUG_KMS("\n");
0066 
0067     ret = mipi_dbi_poweron_conditional_reset(dbidev);
0068     if (ret < 0)
0069         goto out_exit;
0070     if (ret == 1)
0071         goto out_enable;
0072 
0073     mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
0074 
0075     mipi_dbi_command(dbi, ILI9341_PWCTRLB, 0x00, 0xc1, 0x30);
0076     mipi_dbi_command(dbi, ILI9341_PWRSEQ, 0x64, 0x03, 0x12, 0x81);
0077     mipi_dbi_command(dbi, ILI9341_DTCTRLA, 0x85, 0x00, 0x78);
0078     mipi_dbi_command(dbi, ILI9341_PWCTRLA, 0x39, 0x2c, 0x00, 0x34, 0x02);
0079     mipi_dbi_command(dbi, ILI9341_PUMPCTRL, 0x20);
0080     mipi_dbi_command(dbi, ILI9341_DTCTRLB, 0x00, 0x00);
0081 
0082     /* Power Control */
0083     mipi_dbi_command(dbi, ILI9341_PWCTRL1, 0x23);
0084     mipi_dbi_command(dbi, ILI9341_PWCTRL2, 0x10);
0085     /* VCOM */
0086     mipi_dbi_command(dbi, ILI9341_VMCTRL1, 0x3e, 0x28);
0087     mipi_dbi_command(dbi, ILI9341_VMCTRL2, 0x86);
0088 
0089     /* Memory Access Control */
0090     mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
0091 
0092     /* Frame Rate */
0093     mipi_dbi_command(dbi, ILI9341_FRMCTR1, 0x00, 0x1b);
0094 
0095     /* Gamma */
0096     mipi_dbi_command(dbi, ILI9341_EN3GAM, 0x00);
0097     mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, 0x01);
0098     mipi_dbi_command(dbi, ILI9341_PGAMCTRL,
0099              0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1,
0100              0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00);
0101     mipi_dbi_command(dbi, ILI9341_NGAMCTRL,
0102              0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1,
0103              0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f);
0104 
0105     /* DDRAM */
0106     mipi_dbi_command(dbi, ILI9341_ETMOD, 0x07);
0107 
0108     /* Display */
0109     mipi_dbi_command(dbi, ILI9341_DISCTRL, 0x08, 0x82, 0x27, 0x00);
0110     mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
0111     msleep(100);
0112 
0113     mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
0114     msleep(100);
0115 
0116 out_enable:
0117     switch (dbidev->rotation) {
0118     default:
0119         addr_mode = ILI9341_MADCTL_MX;
0120         break;
0121     case 90:
0122         addr_mode = ILI9341_MADCTL_MV;
0123         break;
0124     case 180:
0125         addr_mode = ILI9341_MADCTL_MY;
0126         break;
0127     case 270:
0128         addr_mode = ILI9341_MADCTL_MV | ILI9341_MADCTL_MY |
0129                 ILI9341_MADCTL_MX;
0130         break;
0131     }
0132     addr_mode |= ILI9341_MADCTL_BGR;
0133     mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
0134     mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
0135 out_exit:
0136     drm_dev_exit(idx);
0137 }
0138 
0139 static const struct drm_simple_display_pipe_funcs ili9341_pipe_funcs = {
0140     .enable = yx240qv29_enable,
0141     .disable = mipi_dbi_pipe_disable,
0142     .update = mipi_dbi_pipe_update,
0143 };
0144 
0145 static const struct drm_display_mode yx240qv29_mode = {
0146     DRM_SIMPLE_MODE(240, 320, 37, 49),
0147 };
0148 
0149 DEFINE_DRM_GEM_CMA_FOPS(ili9341_fops);
0150 
0151 static const struct drm_driver ili9341_driver = {
0152     .driver_features    = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
0153     .fops           = &ili9341_fops,
0154     DRM_GEM_CMA_DRIVER_OPS_VMAP,
0155     .debugfs_init       = mipi_dbi_debugfs_init,
0156     .name           = "ili9341",
0157     .desc           = "Ilitek ILI9341",
0158     .date           = "20180514",
0159     .major          = 1,
0160     .minor          = 0,
0161 };
0162 
0163 static const struct of_device_id ili9341_of_match[] = {
0164     { .compatible = "adafruit,yx240qv29" },
0165     { }
0166 };
0167 MODULE_DEVICE_TABLE(of, ili9341_of_match);
0168 
0169 static const struct spi_device_id ili9341_id[] = {
0170     { "yx240qv29", 0 },
0171     { }
0172 };
0173 MODULE_DEVICE_TABLE(spi, ili9341_id);
0174 
0175 static int ili9341_probe(struct spi_device *spi)
0176 {
0177     struct device *dev = &spi->dev;
0178     struct mipi_dbi_dev *dbidev;
0179     struct drm_device *drm;
0180     struct mipi_dbi *dbi;
0181     struct gpio_desc *dc;
0182     u32 rotation = 0;
0183     int ret;
0184 
0185     dbidev = devm_drm_dev_alloc(dev, &ili9341_driver,
0186                     struct mipi_dbi_dev, drm);
0187     if (IS_ERR(dbidev))
0188         return PTR_ERR(dbidev);
0189 
0190     dbi = &dbidev->dbi;
0191     drm = &dbidev->drm;
0192 
0193     dbi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
0194     if (IS_ERR(dbi->reset))
0195         return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n");
0196 
0197     dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
0198     if (IS_ERR(dc))
0199         return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n");
0200 
0201     dbidev->backlight = devm_of_find_backlight(dev);
0202     if (IS_ERR(dbidev->backlight))
0203         return PTR_ERR(dbidev->backlight);
0204 
0205     device_property_read_u32(dev, "rotation", &rotation);
0206 
0207     ret = mipi_dbi_spi_init(spi, dbi, dc);
0208     if (ret)
0209         return ret;
0210 
0211     ret = mipi_dbi_dev_init(dbidev, &ili9341_pipe_funcs, &yx240qv29_mode, rotation);
0212     if (ret)
0213         return ret;
0214 
0215     drm_mode_config_reset(drm);
0216 
0217     ret = drm_dev_register(drm, 0);
0218     if (ret)
0219         return ret;
0220 
0221     spi_set_drvdata(spi, drm);
0222 
0223     drm_fbdev_generic_setup(drm, 0);
0224 
0225     return 0;
0226 }
0227 
0228 static void ili9341_remove(struct spi_device *spi)
0229 {
0230     struct drm_device *drm = spi_get_drvdata(spi);
0231 
0232     drm_dev_unplug(drm);
0233     drm_atomic_helper_shutdown(drm);
0234 }
0235 
0236 static void ili9341_shutdown(struct spi_device *spi)
0237 {
0238     drm_atomic_helper_shutdown(spi_get_drvdata(spi));
0239 }
0240 
0241 static struct spi_driver ili9341_spi_driver = {
0242     .driver = {
0243         .name = "ili9341",
0244         .of_match_table = ili9341_of_match,
0245     },
0246     .id_table = ili9341_id,
0247     .probe = ili9341_probe,
0248     .remove = ili9341_remove,
0249     .shutdown = ili9341_shutdown,
0250 };
0251 module_spi_driver(ili9341_spi_driver);
0252 
0253 MODULE_DESCRIPTION("Ilitek ILI9341 DRM driver");
0254 MODULE_AUTHOR("David Lechner <david@lechnology.com>");
0255 MODULE_LICENSE("GPL");