linux/drivers/gpu/drm/tiny/hx8357d.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * DRM driver for the HX8357D LCD controller
   4 *
   5 * Copyright 2018 Broadcom
   6 * Copyright 2018 David Lechner <david@lechnology.com>
   7 * Copyright 2016 Noralf Trønnes
   8 * Copyright (C) 2015 Adafruit Industries
   9 * Copyright (C) 2013 Christian Vogelgsang
  10 */
  11
  12#include <linux/backlight.h>
  13#include <linux/delay.h>
  14#include <linux/gpio/consumer.h>
  15#include <linux/module.h>
  16#include <linux/property.h>
  17#include <linux/spi/spi.h>
  18
  19#include <drm/drm_atomic_helper.h>
  20#include <drm/drm_drv.h>
  21#include <drm/drm_fb_helper.h>
  22#include <drm/drm_gem_cma_helper.h>
  23#include <drm/drm_gem_framebuffer_helper.h>
  24#include <drm/drm_managed.h>
  25#include <drm/drm_mipi_dbi.h>
  26#include <drm/drm_modeset_helper.h>
  27#include <video/mipi_display.h>
  28
  29#define HX8357D_SETOSC 0xb0
  30#define HX8357D_SETPOWER 0xb1
  31#define HX8357D_SETRGB 0xb3
  32#define HX8357D_SETCYC 0xb3
  33#define HX8357D_SETCOM 0xb6
  34#define HX8357D_SETEXTC 0xb9
  35#define HX8357D_SETSTBA 0xc0
  36#define HX8357D_SETPANEL 0xcc
  37#define HX8357D_SETGAMMA 0xe0
  38
  39#define HX8357D_MADCTL_MY  0x80
  40#define HX8357D_MADCTL_MX  0x40
  41#define HX8357D_MADCTL_MV  0x20
  42#define HX8357D_MADCTL_ML  0x10
  43#define HX8357D_MADCTL_RGB 0x00
  44#define HX8357D_MADCTL_BGR 0x08
  45#define HX8357D_MADCTL_MH  0x04
  46
  47static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
  48                             struct drm_crtc_state *crtc_state,
  49                             struct drm_plane_state *plane_state)
  50{
  51        struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
  52        struct mipi_dbi *dbi = &dbidev->dbi;
  53        u8 addr_mode;
  54        int ret, idx;
  55
  56        if (!drm_dev_enter(pipe->crtc.dev, &idx))
  57                return;
  58
  59        DRM_DEBUG_KMS("\n");
  60
  61        ret = mipi_dbi_poweron_conditional_reset(dbidev);
  62        if (ret < 0)
  63                goto out_exit;
  64        if (ret == 1)
  65                goto out_enable;
  66
  67        /* setextc */
  68        mipi_dbi_command(dbi, HX8357D_SETEXTC, 0xFF, 0x83, 0x57);
  69        msleep(150);
  70
  71        /* setRGB which also enables SDO */
  72        mipi_dbi_command(dbi, HX8357D_SETRGB, 0x00, 0x00, 0x06, 0x06);
  73
  74        /* -1.52V */
  75        mipi_dbi_command(dbi, HX8357D_SETCOM, 0x25);
  76
  77        /* Normal mode 70Hz, Idle mode 55 Hz */
  78        mipi_dbi_command(dbi, HX8357D_SETOSC, 0x68);
  79
  80        /* Set Panel - BGR, Gate direction swapped */
  81        mipi_dbi_command(dbi, HX8357D_SETPANEL, 0x05);
  82
  83        mipi_dbi_command(dbi, HX8357D_SETPOWER,
  84                         0x00,  /* Not deep standby */
  85                         0x15,  /* BT */
  86                         0x1C,  /* VSPR */
  87                         0x1C,  /* VSNR */
  88                         0x83,  /* AP */
  89                         0xAA);  /* FS */
  90
  91        mipi_dbi_command(dbi, HX8357D_SETSTBA,
  92                         0x50,  /* OPON normal */
  93                         0x50,  /* OPON idle */
  94                         0x01,  /* STBA */
  95                         0x3C,  /* STBA */
  96                         0x1E,  /* STBA */
  97                         0x08);  /* GEN */
  98
  99        mipi_dbi_command(dbi, HX8357D_SETCYC,
 100                         0x02,  /* NW 0x02 */
 101                         0x40,  /* RTN */
 102                         0x00,  /* DIV */
 103                         0x2A,  /* DUM */
 104                         0x2A,  /* DUM */
 105                         0x0D,  /* GDON */
 106                         0x78);  /* GDOFF */
 107
 108        mipi_dbi_command(dbi, HX8357D_SETGAMMA,
 109                         0x02,
 110                         0x0A,
 111                         0x11,
 112                         0x1d,
 113                         0x23,
 114                         0x35,
 115                         0x41,
 116                         0x4b,
 117                         0x4b,
 118                         0x42,
 119                         0x3A,
 120                         0x27,
 121                         0x1B,
 122                         0x08,
 123                         0x09,
 124                         0x03,
 125                         0x02,
 126                         0x0A,
 127                         0x11,
 128                         0x1d,
 129                         0x23,
 130                         0x35,
 131                         0x41,
 132                         0x4b,
 133                         0x4b,
 134                         0x42,
 135                         0x3A,
 136                         0x27,
 137                         0x1B,
 138                         0x08,
 139                         0x09,
 140                         0x03,
 141                         0x00,
 142                         0x01);
 143
 144        /* 16 bit */
 145        mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT,
 146                         MIPI_DCS_PIXEL_FMT_16BIT);
 147
 148        /* TE off */
 149        mipi_dbi_command(dbi, MIPI_DCS_SET_TEAR_ON, 0x00);
 150
 151        /* tear line */
 152        mipi_dbi_command(dbi, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02);
 153
 154        /* Exit Sleep */
 155        mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
 156        msleep(150);
 157
 158        /* display on */
 159        mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
 160        usleep_range(5000, 7000);
 161
 162out_enable:
 163        switch (dbidev->rotation) {
 164        default:
 165                addr_mode = HX8357D_MADCTL_MX | HX8357D_MADCTL_MY;
 166                break;
 167        case 90:
 168                addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MY;
 169                break;
 170        case 180:
 171                addr_mode = 0;
 172                break;
 173        case 270:
 174                addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MX;
 175                break;
 176        }
 177        mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
 178        mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
 179out_exit:
 180        drm_dev_exit(idx);
 181}
 182
 183static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
 184        .enable = yx240qv29_enable,
 185        .disable = mipi_dbi_pipe_disable,
 186        .update = mipi_dbi_pipe_update,
 187        .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
 188};
 189
 190static const struct drm_display_mode yx350hv15_mode = {
 191        DRM_SIMPLE_MODE(320, 480, 60, 75),
 192};
 193
 194DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops);
 195
 196static struct drm_driver hx8357d_driver = {
 197        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
 198        .fops                   = &hx8357d_fops,
 199        DRM_GEM_CMA_DRIVER_OPS_VMAP,
 200        .debugfs_init           = mipi_dbi_debugfs_init,
 201        .name                   = "hx8357d",
 202        .desc                   = "HX8357D",
 203        .date                   = "20181023",
 204        .major                  = 1,
 205        .minor                  = 0,
 206};
 207
 208static const struct of_device_id hx8357d_of_match[] = {
 209        { .compatible = "adafruit,yx350hv15" },
 210        { }
 211};
 212MODULE_DEVICE_TABLE(of, hx8357d_of_match);
 213
 214static const struct spi_device_id hx8357d_id[] = {
 215        { "yx350hv15", 0 },
 216        { }
 217};
 218MODULE_DEVICE_TABLE(spi, hx8357d_id);
 219
 220static int hx8357d_probe(struct spi_device *spi)
 221{
 222        struct device *dev = &spi->dev;
 223        struct mipi_dbi_dev *dbidev;
 224        struct drm_device *drm;
 225        struct gpio_desc *dc;
 226        u32 rotation = 0;
 227        int ret;
 228
 229        dbidev = devm_drm_dev_alloc(dev, &hx8357d_driver,
 230                                    struct mipi_dbi_dev, drm);
 231        if (IS_ERR(dbidev))
 232                return PTR_ERR(dbidev);
 233
 234        drm = &dbidev->drm;
 235
 236        dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
 237        if (IS_ERR(dc)) {
 238                DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
 239                return PTR_ERR(dc);
 240        }
 241
 242        dbidev->backlight = devm_of_find_backlight(dev);
 243        if (IS_ERR(dbidev->backlight))
 244                return PTR_ERR(dbidev->backlight);
 245
 246        device_property_read_u32(dev, "rotation", &rotation);
 247
 248        ret = mipi_dbi_spi_init(spi, &dbidev->dbi, dc);
 249        if (ret)
 250                return ret;
 251
 252        ret = mipi_dbi_dev_init(dbidev, &hx8357d_pipe_funcs, &yx350hv15_mode, rotation);
 253        if (ret)
 254                return ret;
 255
 256        drm_mode_config_reset(drm);
 257
 258        ret = drm_dev_register(drm, 0);
 259        if (ret)
 260                return ret;
 261
 262        spi_set_drvdata(spi, drm);
 263
 264        drm_fbdev_generic_setup(drm, 0);
 265
 266        return 0;
 267}
 268
 269static int hx8357d_remove(struct spi_device *spi)
 270{
 271        struct drm_device *drm = spi_get_drvdata(spi);
 272
 273        drm_dev_unplug(drm);
 274        drm_atomic_helper_shutdown(drm);
 275
 276        return 0;
 277}
 278
 279static void hx8357d_shutdown(struct spi_device *spi)
 280{
 281        drm_atomic_helper_shutdown(spi_get_drvdata(spi));
 282}
 283
 284static struct spi_driver hx8357d_spi_driver = {
 285        .driver = {
 286                .name = "hx8357d",
 287                .of_match_table = hx8357d_of_match,
 288        },
 289        .id_table = hx8357d_id,
 290        .probe = hx8357d_probe,
 291        .remove = hx8357d_remove,
 292        .shutdown = hx8357d_shutdown,
 293};
 294module_spi_driver(hx8357d_spi_driver);
 295
 296MODULE_DESCRIPTION("HX8357D DRM driver");
 297MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
 298MODULE_LICENSE("GPL");
 299