Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * DRM driver for the HX8357D LCD controller
0004  *
0005  * Copyright 2018 Broadcom
0006  * Copyright 2018 David Lechner <david@lechnology.com>
0007  * Copyright 2016 Noralf Trønnes
0008  * Copyright (C) 2015 Adafruit Industries
0009  * Copyright (C) 2013 Christian Vogelgsang
0010  */
0011 
0012 #include <linux/backlight.h>
0013 #include <linux/delay.h>
0014 #include <linux/gpio/consumer.h>
0015 #include <linux/module.h>
0016 #include <linux/property.h>
0017 #include <linux/spi/spi.h>
0018 
0019 #include <drm/drm_atomic_helper.h>
0020 #include <drm/drm_drv.h>
0021 #include <drm/drm_fb_helper.h>
0022 #include <drm/drm_gem_atomic_helper.h>
0023 #include <drm/drm_gem_cma_helper.h>
0024 #include <drm/drm_managed.h>
0025 #include <drm/drm_mipi_dbi.h>
0026 #include <drm/drm_modeset_helper.h>
0027 #include <video/mipi_display.h>
0028 
0029 #define HX8357D_SETOSC 0xb0
0030 #define HX8357D_SETPOWER 0xb1
0031 #define HX8357D_SETRGB 0xb3
0032 #define HX8357D_SETCYC 0xb3
0033 #define HX8357D_SETCOM 0xb6
0034 #define HX8357D_SETEXTC 0xb9
0035 #define HX8357D_SETSTBA 0xc0
0036 #define HX8357D_SETPANEL 0xcc
0037 #define HX8357D_SETGAMMA 0xe0
0038 
0039 #define HX8357D_MADCTL_MY  0x80
0040 #define HX8357D_MADCTL_MX  0x40
0041 #define HX8357D_MADCTL_MV  0x20
0042 #define HX8357D_MADCTL_ML  0x10
0043 #define HX8357D_MADCTL_RGB 0x00
0044 #define HX8357D_MADCTL_BGR 0x08
0045 #define HX8357D_MADCTL_MH  0x04
0046 
0047 static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
0048                  struct drm_crtc_state *crtc_state,
0049                  struct drm_plane_state *plane_state)
0050 {
0051     struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
0052     struct mipi_dbi *dbi = &dbidev->dbi;
0053     u8 addr_mode;
0054     int ret, idx;
0055 
0056     if (!drm_dev_enter(pipe->crtc.dev, &idx))
0057         return;
0058 
0059     DRM_DEBUG_KMS("\n");
0060 
0061     ret = mipi_dbi_poweron_conditional_reset(dbidev);
0062     if (ret < 0)
0063         goto out_exit;
0064     if (ret == 1)
0065         goto out_enable;
0066 
0067     /* setextc */
0068     mipi_dbi_command(dbi, HX8357D_SETEXTC, 0xFF, 0x83, 0x57);
0069     msleep(150);
0070 
0071     /* setRGB which also enables SDO */
0072     mipi_dbi_command(dbi, HX8357D_SETRGB, 0x00, 0x00, 0x06, 0x06);
0073 
0074     /* -1.52V */
0075     mipi_dbi_command(dbi, HX8357D_SETCOM, 0x25);
0076 
0077     /* Normal mode 70Hz, Idle mode 55 Hz */
0078     mipi_dbi_command(dbi, HX8357D_SETOSC, 0x68);
0079 
0080     /* Set Panel - BGR, Gate direction swapped */
0081     mipi_dbi_command(dbi, HX8357D_SETPANEL, 0x05);
0082 
0083     mipi_dbi_command(dbi, HX8357D_SETPOWER,
0084              0x00,  /* Not deep standby */
0085              0x15,  /* BT */
0086              0x1C,  /* VSPR */
0087              0x1C,  /* VSNR */
0088              0x83,  /* AP */
0089              0xAA);  /* FS */
0090 
0091     mipi_dbi_command(dbi, HX8357D_SETSTBA,
0092              0x50,  /* OPON normal */
0093              0x50,  /* OPON idle */
0094              0x01,  /* STBA */
0095              0x3C,  /* STBA */
0096              0x1E,  /* STBA */
0097              0x08);  /* GEN */
0098 
0099     mipi_dbi_command(dbi, HX8357D_SETCYC,
0100              0x02,  /* NW 0x02 */
0101              0x40,  /* RTN */
0102              0x00,  /* DIV */
0103              0x2A,  /* DUM */
0104              0x2A,  /* DUM */
0105              0x0D,  /* GDON */
0106              0x78);  /* GDOFF */
0107 
0108     mipi_dbi_command(dbi, HX8357D_SETGAMMA,
0109              0x02,
0110              0x0A,
0111              0x11,
0112              0x1d,
0113              0x23,
0114              0x35,
0115              0x41,
0116              0x4b,
0117              0x4b,
0118              0x42,
0119              0x3A,
0120              0x27,
0121              0x1B,
0122              0x08,
0123              0x09,
0124              0x03,
0125              0x02,
0126              0x0A,
0127              0x11,
0128              0x1d,
0129              0x23,
0130              0x35,
0131              0x41,
0132              0x4b,
0133              0x4b,
0134              0x42,
0135              0x3A,
0136              0x27,
0137              0x1B,
0138              0x08,
0139              0x09,
0140              0x03,
0141              0x00,
0142              0x01);
0143 
0144     /* 16 bit */
0145     mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT,
0146              MIPI_DCS_PIXEL_FMT_16BIT);
0147 
0148     /* TE off */
0149     mipi_dbi_command(dbi, MIPI_DCS_SET_TEAR_ON, 0x00);
0150 
0151     /* tear line */
0152     mipi_dbi_command(dbi, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02);
0153 
0154     /* Exit Sleep */
0155     mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
0156     msleep(150);
0157 
0158     /* display on */
0159     mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
0160     usleep_range(5000, 7000);
0161 
0162 out_enable:
0163     switch (dbidev->rotation) {
0164     default:
0165         addr_mode = HX8357D_MADCTL_MX | HX8357D_MADCTL_MY;
0166         break;
0167     case 90:
0168         addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MY;
0169         break;
0170     case 180:
0171         addr_mode = 0;
0172         break;
0173     case 270:
0174         addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MX;
0175         break;
0176     }
0177     mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
0178     mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
0179 out_exit:
0180     drm_dev_exit(idx);
0181 }
0182 
0183 static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
0184     .enable = yx240qv29_enable,
0185     .disable = mipi_dbi_pipe_disable,
0186     .update = mipi_dbi_pipe_update,
0187 };
0188 
0189 static const struct drm_display_mode yx350hv15_mode = {
0190     DRM_SIMPLE_MODE(320, 480, 60, 75),
0191 };
0192 
0193 DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops);
0194 
0195 static const struct drm_driver hx8357d_driver = {
0196     .driver_features    = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
0197     .fops           = &hx8357d_fops,
0198     DRM_GEM_CMA_DRIVER_OPS_VMAP,
0199     .debugfs_init       = mipi_dbi_debugfs_init,
0200     .name           = "hx8357d",
0201     .desc           = "HX8357D",
0202     .date           = "20181023",
0203     .major          = 1,
0204     .minor          = 0,
0205 };
0206 
0207 static const struct of_device_id hx8357d_of_match[] = {
0208     { .compatible = "adafruit,yx350hv15" },
0209     { }
0210 };
0211 MODULE_DEVICE_TABLE(of, hx8357d_of_match);
0212 
0213 static const struct spi_device_id hx8357d_id[] = {
0214     { "yx350hv15", 0 },
0215     { }
0216 };
0217 MODULE_DEVICE_TABLE(spi, hx8357d_id);
0218 
0219 static int hx8357d_probe(struct spi_device *spi)
0220 {
0221     struct device *dev = &spi->dev;
0222     struct mipi_dbi_dev *dbidev;
0223     struct drm_device *drm;
0224     struct gpio_desc *dc;
0225     u32 rotation = 0;
0226     int ret;
0227 
0228     dbidev = devm_drm_dev_alloc(dev, &hx8357d_driver,
0229                     struct mipi_dbi_dev, drm);
0230     if (IS_ERR(dbidev))
0231         return PTR_ERR(dbidev);
0232 
0233     drm = &dbidev->drm;
0234 
0235     dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
0236     if (IS_ERR(dc))
0237         return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n");
0238 
0239     dbidev->backlight = devm_of_find_backlight(dev);
0240     if (IS_ERR(dbidev->backlight))
0241         return PTR_ERR(dbidev->backlight);
0242 
0243     device_property_read_u32(dev, "rotation", &rotation);
0244 
0245     ret = mipi_dbi_spi_init(spi, &dbidev->dbi, dc);
0246     if (ret)
0247         return ret;
0248 
0249     ret = mipi_dbi_dev_init(dbidev, &hx8357d_pipe_funcs, &yx350hv15_mode, rotation);
0250     if (ret)
0251         return ret;
0252 
0253     drm_mode_config_reset(drm);
0254 
0255     ret = drm_dev_register(drm, 0);
0256     if (ret)
0257         return ret;
0258 
0259     spi_set_drvdata(spi, drm);
0260 
0261     drm_fbdev_generic_setup(drm, 0);
0262 
0263     return 0;
0264 }
0265 
0266 static void hx8357d_remove(struct spi_device *spi)
0267 {
0268     struct drm_device *drm = spi_get_drvdata(spi);
0269 
0270     drm_dev_unplug(drm);
0271     drm_atomic_helper_shutdown(drm);
0272 }
0273 
0274 static void hx8357d_shutdown(struct spi_device *spi)
0275 {
0276     drm_atomic_helper_shutdown(spi_get_drvdata(spi));
0277 }
0278 
0279 static struct spi_driver hx8357d_spi_driver = {
0280     .driver = {
0281         .name = "hx8357d",
0282         .of_match_table = hx8357d_of_match,
0283     },
0284     .id_table = hx8357d_id,
0285     .probe = hx8357d_probe,
0286     .remove = hx8357d_remove,
0287     .shutdown = hx8357d_shutdown,
0288 };
0289 module_spi_driver(hx8357d_spi_driver);
0290 
0291 MODULE_DESCRIPTION("HX8357D DRM driver");
0292 MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
0293 MODULE_LICENSE("GPL");