linux/drivers/gpu/drm/panel/panel-ilitek-ili9322.c
<<
>>
Prefs
   1/*
   2 * Ilitek ILI9322 TFT LCD drm_panel driver.
   3 *
   4 * This panel can be configured to support:
   5 * - 8-bit serial RGB interface
   6 * - 24-bit parallel RGB interface
   7 * - 8-bit ITU-R BT.601 interface
   8 * - 8-bit ITU-R BT.656 interface
   9 * - Up to 320RGBx240 dots resolution TFT LCD displays
  10 * - Scaling, brightness and contrast
  11 *
  12 * The scaling means that the display accepts a 640x480 or 720x480
  13 * input and rescales it to fit to the 320x240 display. So what we
  14 * present to the system is something else than what comes out on the
  15 * actual display.
  16 *
  17 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
  18 * Derived from drivers/drm/gpu/panel/panel-samsung-ld9040.c
  19 *
  20 * This program is free software; you can redistribute it and/or modify
  21 * it under the terms of the GNU General Public License version 2 as
  22 * published by the Free Software Foundation.
  23 */
  24
  25#include <drm/drmP.h>
  26#include <drm/drm_panel.h>
  27
  28#include <linux/of_device.h>
  29#include <linux/bitops.h>
  30#include <linux/gpio/consumer.h>
  31#include <linux/module.h>
  32#include <linux/regmap.h>
  33#include <linux/regulator/consumer.h>
  34#include <linux/spi/spi.h>
  35
  36#include <video/mipi_display.h>
  37#include <video/of_videomode.h>
  38#include <video/videomode.h>
  39
  40#define ILI9322_CHIP_ID                 0x00
  41#define ILI9322_CHIP_ID_MAGIC           0x96
  42
  43/*
  44 * Voltage on the communication interface, from 0.7 (0x00)
  45 * to 1.32 (0x1f) times the VREG1OUT voltage in 2% increments.
  46 * 1.00 (0x0f) is the default.
  47 */
  48#define ILI9322_VCOM_AMP                0x01
  49
  50/*
  51 * High voltage on the communication signals, from 0.37 (0x00) to
  52 * 1.0 (0x3f) times the VREGOUT1 voltage in 1% increments.
  53 * 0.83 (0x2e) is the default.
  54 */
  55#define ILI9322_VCOM_HIGH               0x02
  56
  57/*
  58 * VREG1 voltage regulator from 3.6V (0x00) to 6.0V (0x18) in 0.1V
  59 * increments. 5.4V (0x12) is the default. This is the reference
  60 * voltage for the VCOM levels and the greyscale level.
  61 */
  62#define ILI9322_VREG1_VOLTAGE           0x03
  63
  64/* Describes the incoming signal */
  65#define ILI9322_ENTRY                   0x06
  66/* 0 = right-to-left, 1 = left-to-right (default), horizontal flip */
  67#define ILI9322_ENTRY_HDIR              BIT(0)
  68/* 0 = down-to-up, 1 = up-to-down (default), vertical flip  */
  69#define ILI9322_ENTRY_VDIR              BIT(1)
  70/* NTSC, PAL or autodetect */
  71#define ILI9322_ENTRY_NTSC              (0 << 2)
  72#define ILI9322_ENTRY_PAL               (1 << 2)
  73#define ILI9322_ENTRY_AUTODETECT        (3 << 2)
  74/* Input format */
  75#define ILI9322_ENTRY_SERIAL_RGB_THROUGH (0 << 4)
  76#define ILI9322_ENTRY_SERIAL_RGB_ALIGNED (1 << 4)
  77#define ILI9322_ENTRY_SERIAL_RGB_DUMMY_320X240 (2 << 4)
  78#define ILI9322_ENTRY_SERIAL_RGB_DUMMY_360X240 (3 << 4)
  79#define ILI9322_ENTRY_DISABLE_1         (4 << 4)
  80#define ILI9322_ENTRY_PARALLEL_RGB_THROUGH (5 << 4)
  81#define ILI9322_ENTRY_PARALLEL_RGB_ALIGNED (6 << 4)
  82#define ILI9322_ENTRY_YUV_640Y_320CBCR_25_54_MHZ (7 << 4)
  83#define ILI9322_ENTRY_YUV_720Y_360CBCR_27_MHZ (8 << 4)
  84#define ILI9322_ENTRY_DISABLE_2         (9 << 4)
  85#define ILI9322_ENTRY_ITU_R_BT_656_720X360 (10 << 4)
  86#define ILI9322_ENTRY_ITU_R_BT_656_640X320 (11 << 4)
  87
  88/* Power control */
  89#define ILI9322_POW_CTRL                0x07
  90#define ILI9322_POW_CTRL_STB            BIT(0) /* 0 = standby, 1 = normal */
  91#define ILI9322_POW_CTRL_VGL            BIT(1) /* 0 = off, 1 = on  */
  92#define ILI9322_POW_CTRL_VGH            BIT(2) /* 0 = off, 1 = on  */
  93#define ILI9322_POW_CTRL_DDVDH          BIT(3) /* 0 = off, 1 = on  */
  94#define ILI9322_POW_CTRL_VCOM           BIT(4) /* 0 = off, 1 = on  */
  95#define ILI9322_POW_CTRL_VCL            BIT(5) /* 0 = off, 1 = on  */
  96#define ILI9322_POW_CTRL_AUTO           BIT(6) /* 0 = interactive, 1 = auto */
  97#define ILI9322_POW_CTRL_STANDBY        (ILI9322_POW_CTRL_VGL | \
  98                                         ILI9322_POW_CTRL_VGH | \
  99                                         ILI9322_POW_CTRL_DDVDH | \
 100                                         ILI9322_POW_CTRL_VCL | \
 101                                         ILI9322_POW_CTRL_AUTO | \
 102                                         BIT(7))
 103#define ILI9322_POW_CTRL_DEFAULT        (ILI9322_POW_CTRL_STANDBY | \
 104                                         ILI9322_POW_CTRL_STB)
 105
 106/* Vertical back porch bits 0..5 */
 107#define ILI9322_VBP                     0x08
 108
 109/* Horizontal back porch, 8 bits */
 110#define ILI9322_HBP                     0x09
 111
 112/*
 113 * Polarity settings:
 114 * 1 = positive polarity
 115 * 0 = negative polarity
 116 */
 117#define ILI9322_POL                     0x0a
 118#define ILI9322_POL_DCLK                BIT(0) /* 1 default */
 119#define ILI9322_POL_HSYNC               BIT(1) /* 0 default */
 120#define ILI9322_POL_VSYNC               BIT(2) /* 0 default */
 121#define ILI9322_POL_DE                  BIT(3) /* 1 default */
 122/*
 123 * 0 means YCBCR are ordered Cb0,Y0,Cr0,Y1,Cb2,Y2,Cr2,Y3 (default)
 124 *   in RGB mode this means RGB comes in RGBRGB
 125 * 1 means YCBCR are ordered Cr0,Y0,Cb0,Y1,Cr2,Y2,Cb2,Y3
 126 *   in RGB mode this means RGB comes in BGRBGR
 127 */
 128#define ILI9322_POL_YCBCR_MODE          BIT(4)
 129/* Formula A for YCbCR->RGB = 0, Formula B = 1 */
 130#define ILI9322_POL_FORMULA             BIT(5)
 131/* Reverse polarity: 0 = 0..255, 1 = 255..0 */
 132#define ILI9322_POL_REV                 BIT(6)
 133
 134#define ILI9322_IF_CTRL                 0x0b
 135#define ILI9322_IF_CTRL_HSYNC_VSYNC     0x00
 136#define ILI9322_IF_CTRL_HSYNC_VSYNC_DE  BIT(2)
 137#define ILI9322_IF_CTRL_DE_ONLY         BIT(3)
 138#define ILI9322_IF_CTRL_SYNC_DISABLED   (BIT(2) | BIT(3))
 139#define ILI9322_IF_CTRL_LINE_INVERSION  BIT(0) /* Not set means frame inv */
 140
 141#define ILI9322_GLOBAL_RESET            0x04
 142#define ILI9322_GLOBAL_RESET_ASSERT     0x00 /* bit 0 = 0 -> reset */
 143
 144/*
 145 * 4+4 bits of negative and positive gamma correction
 146 * Upper nybble, bits 4-7 are negative gamma
 147 * Lower nybble, bits 0-3 are positive gamma
 148 */
 149#define ILI9322_GAMMA_1                 0x10
 150#define ILI9322_GAMMA_2                 0x11
 151#define ILI9322_GAMMA_3                 0x12
 152#define ILI9322_GAMMA_4                 0x13
 153#define ILI9322_GAMMA_5                 0x14
 154#define ILI9322_GAMMA_6                 0x15
 155#define ILI9322_GAMMA_7                 0x16
 156#define ILI9322_GAMMA_8                 0x17
 157
 158/**
 159 * enum ili9322_input - the format of the incoming signal to the panel
 160 *
 161 * The panel can be connected to various input streams and four of them can
 162 * be selected by electronic straps on the display. However it is possible
 163 * to select another mode or override the electronic default with this
 164 * setting.
 165 */
 166enum ili9322_input {
 167        ILI9322_INPUT_SRGB_THROUGH = 0x0,
 168        ILI9322_INPUT_SRGB_ALIGNED = 0x1,
 169        ILI9322_INPUT_SRGB_DUMMY_320X240 = 0x2,
 170        ILI9322_INPUT_SRGB_DUMMY_360X240 = 0x3,
 171        ILI9322_INPUT_DISABLED_1 = 0x4,
 172        ILI9322_INPUT_PRGB_THROUGH = 0x5,
 173        ILI9322_INPUT_PRGB_ALIGNED = 0x6,
 174        ILI9322_INPUT_YUV_640X320_YCBCR = 0x7,
 175        ILI9322_INPUT_YUV_720X360_YCBCR = 0x8,
 176        ILI9322_INPUT_DISABLED_2 = 0x9,
 177        ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR = 0xa,
 178        ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR = 0xb,
 179        ILI9322_INPUT_UNKNOWN = 0xc,
 180};
 181
 182static const char * const ili9322_inputs[] = {
 183        "8 bit serial RGB through",
 184        "8 bit serial RGB aligned",
 185        "8 bit serial RGB dummy 320x240",
 186        "8 bit serial RGB dummy 360x240",
 187        "disabled 1",
 188        "24 bit parallel RGB through",
 189        "24 bit parallel RGB aligned",
 190        "24 bit YUV 640Y 320CbCr",
 191        "24 bit YUV 720Y 360CbCr",
 192        "disabled 2",
 193        "8 bit ITU-R BT.656 720Y 360CbCr",
 194        "8 bit ITU-R BT.656 640Y 320CbCr",
 195};
 196
 197/**
 198 * struct ili9322_config - the system specific ILI9322 configuration
 199 * @width_mm: physical panel width [mm]
 200 * @height_mm: physical panel height [mm]
 201 * @flip_horizontal: flip the image horizontally (right-to-left scan)
 202 * (only in RGB and YUV modes)
 203 * @flip_vertical: flip the image vertically (down-to-up scan)
 204 * (only in RGB and YUV modes)
 205 * @input: the input/entry type used in this system, if this is set to
 206 * ILI9322_INPUT_UNKNOWN the driver will try to figure it out by probing
 207 * the hardware
 208 * @vreg1out_mv: the output in microvolts for the VREGOUT1 regulator used
 209 * to drive the physical display. Valid ranges are 3600 thru 6000 in 100
 210 * microvolt increments. If not specified, hardware defaults will be
 211 * used (4.5V).
 212 * @vcom_high_percent: the percentage of VREGOUT1 used for the peak
 213 * voltage on the communications link. Valid ranges are 37 thru 100
 214 * percent. If not specified, hardware defaults will be used (91%).
 215 * @vcom_amplitude_percent: the percentage of VREGOUT1 used for the
 216 * peak-to-peak amplitude of the communcation signals to the physical
 217 * display. Valid ranges are 70 thru 132 percent in increments if two
 218 * percent. Odd percentages will be truncated. If not specified, hardware
 219 * defaults will be used (114%).
 220 * @dclk_active_high: data/pixel clock active high, data will be clocked
 221 * in on the rising edge of the DCLK (this is usually the case).
 222 * @syncmode: The synchronization mode, what sync signals are emitted.
 223 * See the enum for details.
 224 * @de_active_high: DE (data entry) is active high
 225 * @hsync_active_high: HSYNC is active high
 226 * @vsync_active_high: VSYNC is active high
 227 * @gamma_corr_pos: a set of 8 nybbles describing positive
 228 * gamma correction for voltages V1 thru V8. Valid range 0..15
 229 * @gamma_corr_neg: a set of 8 nybbles describing negative
 230 * gamma correction for voltages V1 thru V8. Valid range 0..15
 231 *
 232 * These adjust what grayscale voltage will be output for input data V1 = 0,
 233 * V2 = 16, V3 = 48, V4 = 96, V5 = 160, V6 = 208, V7 = 240 and V8 = 255.
 234 * The curve is shaped like this:
 235 *
 236 *  ^
 237 *  |                                                        V8
 238 *  |                                                   V7
 239 *  |                                          V6
 240 *  |                               V5
 241 *  |                    V4
 242 *  |            V3
 243 *  |     V2
 244 *  | V1
 245 *  +----------------------------------------------------------->
 246 *    0   16     48      96         160        208      240  255
 247 *
 248 * The negative and postive gamma values adjust the V1 thru V8 up/down
 249 * according to the datasheet specifications. This is a property of the
 250 * physical display connected to the display controller and may vary.
 251 * If defined, both arrays must be supplied in full. If the properties
 252 * are not supplied, hardware defaults will be used.
 253 */
 254struct ili9322_config {
 255        u32 width_mm;
 256        u32 height_mm;
 257        bool flip_horizontal;
 258        bool flip_vertical;
 259        enum ili9322_input input;
 260        u32 vreg1out_mv;
 261        u32 vcom_high_percent;
 262        u32 vcom_amplitude_percent;
 263        bool dclk_active_high;
 264        bool de_active_high;
 265        bool hsync_active_high;
 266        bool vsync_active_high;
 267        u8 syncmode;
 268        u8 gamma_corr_pos[8];
 269        u8 gamma_corr_neg[8];
 270};
 271
 272struct ili9322 {
 273        struct device *dev;
 274        const struct ili9322_config *conf;
 275        struct drm_panel panel;
 276        struct regmap *regmap;
 277        struct regulator_bulk_data supplies[3];
 278        struct gpio_desc *reset_gpio;
 279        enum ili9322_input input;
 280        struct videomode vm;
 281        u8 gamma[8];
 282        u8 vreg1out;
 283        u8 vcom_high;
 284        u8 vcom_amplitude;
 285};
 286
 287static inline struct ili9322 *panel_to_ili9322(struct drm_panel *panel)
 288{
 289        return container_of(panel, struct ili9322, panel);
 290}
 291
 292static int ili9322_regmap_spi_write(void *context, const void *data,
 293                                    size_t count)
 294{
 295        struct device *dev = context;
 296        struct spi_device *spi = to_spi_device(dev);
 297        u8 buf[2];
 298
 299        /* Clear bit 7 to write */
 300        memcpy(buf, data, 2);
 301        buf[0] &= ~0x80;
 302
 303        dev_dbg(dev, "WRITE: %02x %02x\n", buf[0], buf[1]);
 304        return spi_write_then_read(spi, buf, 2, NULL, 0);
 305}
 306
 307static int ili9322_regmap_spi_read(void *context, const void *reg,
 308                                   size_t reg_size, void *val, size_t val_size)
 309{
 310        struct device *dev = context;
 311        struct spi_device *spi = to_spi_device(dev);
 312        u8 buf[1];
 313
 314        /* Set bit 7 to 1 to read */
 315        memcpy(buf, reg, 1);
 316        dev_dbg(dev, "READ: %02x reg size = %zu, val size = %zu\n",
 317                buf[0], reg_size, val_size);
 318        buf[0] |= 0x80;
 319
 320        return spi_write_then_read(spi, buf, 1, val, 1);
 321}
 322
 323static struct regmap_bus ili9322_regmap_bus = {
 324        .write = ili9322_regmap_spi_write,
 325        .read = ili9322_regmap_spi_read,
 326        .reg_format_endian_default = REGMAP_ENDIAN_BIG,
 327        .val_format_endian_default = REGMAP_ENDIAN_BIG,
 328};
 329
 330static bool ili9322_volatile_reg(struct device *dev, unsigned int reg)
 331{
 332        return false;
 333}
 334
 335static bool ili9322_writeable_reg(struct device *dev, unsigned int reg)
 336{
 337        /* Just register 0 is read-only */
 338        if (reg == 0x00)
 339                return false;
 340        return true;
 341}
 342
 343static const struct regmap_config ili9322_regmap_config = {
 344        .reg_bits = 8,
 345        .val_bits = 8,
 346        .max_register = 0x44,
 347        .cache_type = REGCACHE_RBTREE,
 348        .volatile_reg = ili9322_volatile_reg,
 349        .writeable_reg = ili9322_writeable_reg,
 350};
 351
 352static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili)
 353{
 354        struct drm_connector *connector = panel->connector;
 355        u8 reg;
 356        int ret;
 357        int i;
 358
 359        /* Reset display */
 360        ret = regmap_write(ili->regmap, ILI9322_GLOBAL_RESET,
 361                           ILI9322_GLOBAL_RESET_ASSERT);
 362        if (ret) {
 363                dev_err(ili->dev, "can't issue GRESET (%d)\n", ret);
 364                return ret;
 365        }
 366
 367        /* Set up the main voltage regulator */
 368        if (ili->vreg1out != U8_MAX) {
 369                ret = regmap_write(ili->regmap, ILI9322_VREG1_VOLTAGE,
 370                                   ili->vreg1out);
 371                if (ret) {
 372                        dev_err(ili->dev, "can't set up VREG1OUT (%d)\n", ret);
 373                        return ret;
 374                }
 375        }
 376
 377        if (ili->vcom_amplitude != U8_MAX) {
 378                ret = regmap_write(ili->regmap, ILI9322_VCOM_AMP,
 379                                   ili->vcom_amplitude);
 380                if (ret) {
 381                        dev_err(ili->dev,
 382                                "can't set up VCOM amplitude (%d)\n", ret);
 383                        return ret;
 384                }
 385        };
 386
 387        if (ili->vcom_high != U8_MAX) {
 388                ret = regmap_write(ili->regmap, ILI9322_VCOM_HIGH,
 389                                   ili->vcom_high);
 390                if (ret) {
 391                        dev_err(ili->dev, "can't set up VCOM high (%d)\n", ret);
 392                        return ret;
 393                }
 394        };
 395
 396        /* Set up gamma correction */
 397        for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {
 398                ret = regmap_write(ili->regmap, ILI9322_GAMMA_1 + i,
 399                                   ili->gamma[i]);
 400                if (ret) {
 401                        dev_err(ili->dev,
 402                                "can't write gamma V%d to 0x%02x (%d)\n",
 403                                i + 1, ILI9322_GAMMA_1 + i, ret);
 404                        return ret;
 405                }
 406        }
 407
 408        /*
 409         * Polarity and inverted color order for RGB input.
 410         * None of this applies in the BT.656 mode.
 411         */
 412        if (ili->conf->dclk_active_high) {
 413                reg = ILI9322_POL_DCLK;
 414                connector->display_info.bus_flags |=
 415                        DRM_BUS_FLAG_PIXDATA_POSEDGE;
 416        } else {
 417                reg = 0;
 418                connector->display_info.bus_flags |=
 419                        DRM_BUS_FLAG_PIXDATA_NEGEDGE;
 420        }
 421        if (ili->conf->de_active_high) {
 422                reg |= ILI9322_POL_DE;
 423                connector->display_info.bus_flags |=
 424                        DRM_BUS_FLAG_DE_HIGH;
 425        } else {
 426                connector->display_info.bus_flags |=
 427                        DRM_BUS_FLAG_DE_LOW;
 428        }
 429        if (ili->conf->hsync_active_high)
 430                reg |= ILI9322_POL_HSYNC;
 431        if (ili->conf->vsync_active_high)
 432                reg |= ILI9322_POL_VSYNC;
 433        ret = regmap_write(ili->regmap, ILI9322_POL, reg);
 434        if (ret) {
 435                dev_err(ili->dev, "can't write POL register (%d)\n", ret);
 436                return ret;
 437        }
 438
 439        /*
 440         * Set up interface control.
 441         * This is not used in the BT.656 mode (no H/Vsync or DE signals).
 442         */
 443        reg = ili->conf->syncmode;
 444        reg |= ILI9322_IF_CTRL_LINE_INVERSION;
 445        ret = regmap_write(ili->regmap, ILI9322_IF_CTRL, reg);
 446        if (ret) {
 447                dev_err(ili->dev, "can't write IF CTRL register (%d)\n", ret);
 448                return ret;
 449        }
 450
 451        /* Set up the input mode */
 452        reg = (ili->input << 4);
 453        /* These are inverted, setting to 1 is the default, clearing flips */
 454        if (!ili->conf->flip_horizontal)
 455                reg |= ILI9322_ENTRY_HDIR;
 456        if (!ili->conf->flip_vertical)
 457                reg |= ILI9322_ENTRY_VDIR;
 458        reg |= ILI9322_ENTRY_AUTODETECT;
 459        ret = regmap_write(ili->regmap, ILI9322_ENTRY, reg);
 460        if (ret) {
 461                dev_err(ili->dev, "can't write ENTRY reg (%d)\n", ret);
 462                return ret;
 463        }
 464        dev_info(ili->dev, "display is in %s mode, syncmode %02x\n",
 465                 ili9322_inputs[ili->input],
 466                 ili->conf->syncmode);
 467
 468        dev_info(ili->dev, "initialized display\n");
 469
 470        return 0;
 471}
 472
 473/*
 474 * This power-on sequence if from the datasheet, page 57.
 475 */
 476static int ili9322_power_on(struct ili9322 *ili)
 477{
 478        int ret;
 479
 480        /* Assert RESET */
 481        gpiod_set_value(ili->reset_gpio, 1);
 482
 483        ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies), ili->supplies);
 484        if (ret < 0) {
 485                dev_err(ili->dev, "unable to enable regulators\n");
 486                return ret;
 487        }
 488        msleep(20);
 489
 490        /* De-assert RESET */
 491        gpiod_set_value(ili->reset_gpio, 0);
 492
 493        msleep(10);
 494
 495        return 0;
 496}
 497
 498static int ili9322_power_off(struct ili9322 *ili)
 499{
 500        return regulator_bulk_disable(ARRAY_SIZE(ili->supplies), ili->supplies);
 501}
 502
 503static int ili9322_disable(struct drm_panel *panel)
 504{
 505        struct ili9322 *ili = panel_to_ili9322(panel);
 506        int ret;
 507
 508        ret = regmap_write(ili->regmap, ILI9322_POW_CTRL,
 509                           ILI9322_POW_CTRL_STANDBY);
 510        if (ret) {
 511                dev_err(ili->dev, "unable to go to standby mode\n");
 512                return ret;
 513        }
 514
 515        return 0;
 516}
 517
 518static int ili9322_unprepare(struct drm_panel *panel)
 519{
 520        struct ili9322 *ili = panel_to_ili9322(panel);
 521
 522        return ili9322_power_off(ili);
 523}
 524
 525static int ili9322_prepare(struct drm_panel *panel)
 526{
 527        struct ili9322 *ili = panel_to_ili9322(panel);
 528        int ret;
 529
 530        ret = ili9322_power_on(ili);
 531        if (ret < 0)
 532                return ret;
 533
 534        ret = ili9322_init(panel, ili);
 535        if (ret < 0)
 536                ili9322_unprepare(panel);
 537
 538        return ret;
 539}
 540
 541static int ili9322_enable(struct drm_panel *panel)
 542{
 543        struct ili9322 *ili = panel_to_ili9322(panel);
 544        int ret;
 545
 546        ret = regmap_write(ili->regmap, ILI9322_POW_CTRL,
 547                           ILI9322_POW_CTRL_DEFAULT);
 548        if (ret) {
 549                dev_err(ili->dev, "unable to enable panel\n");
 550                return ret;
 551        }
 552
 553        return 0;
 554}
 555
 556/* Serial RGB modes */
 557static const struct drm_display_mode srgb_320x240_mode = {
 558        .clock = 2453500,
 559        .hdisplay = 320,
 560        .hsync_start = 320 + 359,
 561        .hsync_end = 320 + 359 + 1,
 562        .htotal = 320 + 359 + 1 + 241,
 563        .vdisplay = 240,
 564        .vsync_start = 240 + 4,
 565        .vsync_end = 240 + 4 + 1,
 566        .vtotal = 262,
 567        .vrefresh = 60,
 568        .flags = 0,
 569};
 570
 571static const struct drm_display_mode srgb_360x240_mode = {
 572        .clock = 2700000,
 573        .hdisplay = 360,
 574        .hsync_start = 360 + 35,
 575        .hsync_end = 360 + 35 + 1,
 576        .htotal = 360 + 35 + 1 + 241,
 577        .vdisplay = 240,
 578        .vsync_start = 240 + 21,
 579        .vsync_end = 240 + 21 + 1,
 580        .vtotal = 262,
 581        .vrefresh = 60,
 582        .flags = 0,
 583};
 584
 585/* This is the only mode listed for parallel RGB in the datasheet */
 586static const struct drm_display_mode prgb_320x240_mode = {
 587        .clock = 6400000,
 588        .hdisplay = 320,
 589        .hsync_start = 320 + 38,
 590        .hsync_end = 320 + 38 + 1,
 591        .htotal = 320 + 38 + 1 + 50,
 592        .vdisplay = 240,
 593        .vsync_start = 240 + 4,
 594        .vsync_end = 240 + 4 + 1,
 595        .vtotal = 262,
 596        .vrefresh = 60,
 597        .flags = 0,
 598};
 599
 600/* YUV modes */
 601static const struct drm_display_mode yuv_640x320_mode = {
 602        .clock = 2454000,
 603        .hdisplay = 640,
 604        .hsync_start = 640 + 252,
 605        .hsync_end = 640 + 252 + 1,
 606        .htotal = 640 + 252 + 1 + 28,
 607        .vdisplay = 320,
 608        .vsync_start = 320 + 4,
 609        .vsync_end = 320 + 4 + 1,
 610        .vtotal = 320 + 4 + 1 + 18,
 611        .vrefresh = 60,
 612        .flags = 0,
 613};
 614
 615static const struct drm_display_mode yuv_720x360_mode = {
 616        .clock = 2700000,
 617        .hdisplay = 720,
 618        .hsync_start = 720 + 252,
 619        .hsync_end = 720 + 252 + 1,
 620        .htotal = 720 + 252 + 1 + 24,
 621        .vdisplay = 360,
 622        .vsync_start = 360 + 4,
 623        .vsync_end = 360 + 4 + 1,
 624        .vtotal = 360 + 4 + 1 + 18,
 625        .vrefresh = 60,
 626        .flags = 0,
 627};
 628
 629/* BT.656 VGA mode, 640x480 */
 630static const struct drm_display_mode itu_r_bt_656_640_mode = {
 631        .clock = 2454000,
 632        .hdisplay = 640,
 633        .hsync_start = 640 + 3,
 634        .hsync_end = 640 + 3 + 1,
 635        .htotal = 640 + 3 + 1 + 272,
 636        .vdisplay = 480,
 637        .vsync_start = 480 + 4,
 638        .vsync_end = 480 + 4 + 1,
 639        .vtotal = 500,
 640        .vrefresh = 60,
 641        .flags = 0,
 642};
 643
 644/* BT.656 D1 mode 720x480 */
 645static const struct drm_display_mode itu_r_bt_656_720_mode = {
 646        .clock = 2700000,
 647        .hdisplay = 720,
 648        .hsync_start = 720 + 3,
 649        .hsync_end = 720 + 3 + 1,
 650        .htotal = 720 + 3 + 1 + 272,
 651        .vdisplay = 480,
 652        .vsync_start = 480 + 4,
 653        .vsync_end = 480 + 4 + 1,
 654        .vtotal = 500,
 655        .vrefresh = 60,
 656        .flags = 0,
 657};
 658
 659static int ili9322_get_modes(struct drm_panel *panel)
 660{
 661        struct drm_connector *connector = panel->connector;
 662        struct ili9322 *ili = panel_to_ili9322(panel);
 663        struct drm_display_mode *mode;
 664
 665        strncpy(connector->display_info.name, "ILI9322 TFT LCD driver\0",
 666                DRM_DISPLAY_INFO_LEN);
 667        connector->display_info.width_mm = ili->conf->width_mm;
 668        connector->display_info.height_mm = ili->conf->height_mm;
 669
 670        switch (ili->input) {
 671        case ILI9322_INPUT_SRGB_DUMMY_320X240:
 672                mode = drm_mode_duplicate(panel->drm, &srgb_320x240_mode);
 673                break;
 674        case ILI9322_INPUT_SRGB_DUMMY_360X240:
 675                mode = drm_mode_duplicate(panel->drm, &srgb_360x240_mode);
 676                break;
 677        case ILI9322_INPUT_PRGB_THROUGH:
 678        case ILI9322_INPUT_PRGB_ALIGNED:
 679                mode = drm_mode_duplicate(panel->drm, &prgb_320x240_mode);
 680                break;
 681        case ILI9322_INPUT_YUV_640X320_YCBCR:
 682                mode = drm_mode_duplicate(panel->drm, &yuv_640x320_mode);
 683                break;
 684        case ILI9322_INPUT_YUV_720X360_YCBCR:
 685                mode = drm_mode_duplicate(panel->drm, &yuv_720x360_mode);
 686                break;
 687        case ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR:
 688                mode = drm_mode_duplicate(panel->drm, &itu_r_bt_656_720_mode);
 689                break;
 690        case ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR:
 691                mode = drm_mode_duplicate(panel->drm, &itu_r_bt_656_640_mode);
 692                break;
 693        default:
 694                mode = NULL;
 695                break;
 696        }
 697        if (!mode) {
 698                DRM_ERROR("bad mode or failed to add mode\n");
 699                return -EINVAL;
 700        }
 701        drm_mode_set_name(mode);
 702        /*
 703         * This is the preferred mode because most people are going
 704         * to want to use the display with VGA type graphics.
 705         */
 706        mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 707
 708        /* Set up the polarity */
 709        if (ili->conf->hsync_active_high)
 710                mode->flags |= DRM_MODE_FLAG_PHSYNC;
 711        else
 712                mode->flags |= DRM_MODE_FLAG_NHSYNC;
 713        if (ili->conf->vsync_active_high)
 714                mode->flags |= DRM_MODE_FLAG_PVSYNC;
 715        else
 716                mode->flags |= DRM_MODE_FLAG_NVSYNC;
 717
 718        mode->width_mm = ili->conf->width_mm;
 719        mode->height_mm = ili->conf->height_mm;
 720        drm_mode_probed_add(connector, mode);
 721
 722        return 1; /* Number of modes */
 723}
 724
 725static const struct drm_panel_funcs ili9322_drm_funcs = {
 726        .disable = ili9322_disable,
 727        .unprepare = ili9322_unprepare,
 728        .prepare = ili9322_prepare,
 729        .enable = ili9322_enable,
 730        .get_modes = ili9322_get_modes,
 731};
 732
 733static int ili9322_probe(struct spi_device *spi)
 734{
 735        struct device *dev = &spi->dev;
 736        struct ili9322 *ili;
 737        const struct regmap_config *regmap_config;
 738        u8 gamma;
 739        u32 val;
 740        int ret;
 741        int i;
 742
 743        ili = devm_kzalloc(dev, sizeof(struct ili9322), GFP_KERNEL);
 744        if (!ili)
 745                return -ENOMEM;
 746
 747        spi_set_drvdata(spi, ili);
 748
 749        ili->dev = dev;
 750
 751        /*
 752         * Every new incarnation of this display must have a unique
 753         * data entry for the system in this driver.
 754         */
 755        ili->conf = of_device_get_match_data(dev);
 756        if (!ili->conf) {
 757                dev_err(dev, "missing device configuration\n");
 758                return -ENODEV;
 759        }
 760
 761        val = ili->conf->vreg1out_mv;
 762        if (!val) {
 763                /* Default HW value, do not touch (should be 4.5V) */
 764                ili->vreg1out = U8_MAX;
 765        } else {
 766                if (val < 3600) {
 767                        dev_err(dev, "too low VREG1OUT\n");
 768                        return -EINVAL;
 769                }
 770                if (val > 6000) {
 771                        dev_err(dev, "too high VREG1OUT\n");
 772                        return -EINVAL;
 773                }
 774                if ((val % 100) != 0) {
 775                        dev_err(dev, "VREG1OUT is no even 100 microvolt\n");
 776                        return -EINVAL;
 777                }
 778                val -= 3600;
 779                val /= 100;
 780                dev_dbg(dev, "VREG1OUT = 0x%02x\n", val);
 781                ili->vreg1out = val;
 782        }
 783
 784        val = ili->conf->vcom_high_percent;
 785        if (!val) {
 786                /* Default HW value, do not touch (should be 91%) */
 787                ili->vcom_high = U8_MAX;
 788        } else {
 789                if (val < 37) {
 790                        dev_err(dev, "too low VCOM high\n");
 791                        return -EINVAL;
 792                }
 793                if (val > 100) {
 794                        dev_err(dev, "too high VCOM high\n");
 795                        return -EINVAL;
 796                }
 797                val -= 37;
 798                dev_dbg(dev, "VCOM high = 0x%02x\n", val);
 799                ili->vcom_high = val;
 800        }
 801
 802        val = ili->conf->vcom_amplitude_percent;
 803        if (!val) {
 804                /* Default HW value, do not touch (should be 114%) */
 805                ili->vcom_high = U8_MAX;
 806        } else {
 807                if (val < 70) {
 808                        dev_err(dev, "too low VCOM amplitude\n");
 809                        return -EINVAL;
 810                }
 811                if (val > 132) {
 812                        dev_err(dev, "too high VCOM amplitude\n");
 813                        return -EINVAL;
 814                }
 815                val -= 70;
 816                val >>= 1; /* Increments of 2% */
 817                dev_dbg(dev, "VCOM amplitude = 0x%02x\n", val);
 818                ili->vcom_amplitude = val;
 819        }
 820
 821        for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {
 822                val = ili->conf->gamma_corr_neg[i];
 823                if (val > 15) {
 824                        dev_err(dev, "negative gamma %u > 15, capping\n", val);
 825                        val = 15;
 826                }
 827                gamma = val << 4;
 828                val = ili->conf->gamma_corr_pos[i];
 829                if (val > 15) {
 830                        dev_err(dev, "positive gamma %u > 15, capping\n", val);
 831                        val = 15;
 832                }
 833                gamma |= val;
 834                ili->gamma[i] = gamma;
 835                dev_dbg(dev, "gamma V%d: 0x%02x\n", i + 1, gamma);
 836        }
 837
 838        ili->supplies[0].supply = "vcc"; /* 2.7-3.6 V */
 839        ili->supplies[1].supply = "iovcc"; /* 1.65-3.6V */
 840        ili->supplies[2].supply = "vci"; /* 2.7-3.6V */
 841        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies),
 842                                      ili->supplies);
 843        if (ret < 0)
 844                return ret;
 845        ret = regulator_set_voltage(ili->supplies[0].consumer,
 846                                    2700000, 3600000);
 847        if (ret)
 848                return ret;
 849        ret = regulator_set_voltage(ili->supplies[1].consumer,
 850                                    1650000, 3600000);
 851        if (ret)
 852                return ret;
 853        ret = regulator_set_voltage(ili->supplies[2].consumer,
 854                                    2700000, 3600000);
 855        if (ret)
 856                return ret;
 857
 858        ili->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
 859        if (IS_ERR(ili->reset_gpio)) {
 860                dev_err(dev, "failed to get RESET GPIO\n");
 861                return PTR_ERR(ili->reset_gpio);
 862        }
 863
 864        spi->bits_per_word = 8;
 865        ret = spi_setup(spi);
 866        if (ret < 0) {
 867                dev_err(dev, "spi setup failed.\n");
 868                return ret;
 869        }
 870        regmap_config = &ili9322_regmap_config;
 871        ili->regmap = devm_regmap_init(dev, &ili9322_regmap_bus, dev,
 872                                       regmap_config);
 873        if (IS_ERR(ili->regmap)) {
 874                dev_err(dev, "failed to allocate register map\n");
 875                return PTR_ERR(ili->regmap);
 876        }
 877
 878        ret = regmap_read(ili->regmap, ILI9322_CHIP_ID, &val);
 879        if (ret) {
 880                dev_err(dev, "can't get chip ID (%d)\n", ret);
 881                return ret;
 882        }
 883        if (val != ILI9322_CHIP_ID_MAGIC) {
 884                dev_err(dev, "chip ID 0x%0x2, expected 0x%02x\n", val,
 885                        ILI9322_CHIP_ID_MAGIC);
 886                return -ENODEV;
 887        }
 888
 889        /* Probe the system to find the display setting */
 890        if (ili->conf->input == ILI9322_INPUT_UNKNOWN) {
 891                ret = regmap_read(ili->regmap, ILI9322_ENTRY, &val);
 892                if (ret) {
 893                        dev_err(dev, "can't get entry setting (%d)\n", ret);
 894                        return ret;
 895                }
 896                /* Input enum corresponds to HW setting */
 897                ili->input = (val >> 4) & 0x0f;
 898                if (ili->input >= ILI9322_INPUT_UNKNOWN)
 899                        ili->input = ILI9322_INPUT_UNKNOWN;
 900        } else {
 901                ili->input = ili->conf->input;
 902        }
 903
 904        drm_panel_init(&ili->panel);
 905        ili->panel.dev = dev;
 906        ili->panel.funcs = &ili9322_drm_funcs;
 907
 908        return drm_panel_add(&ili->panel);
 909}
 910
 911static int ili9322_remove(struct spi_device *spi)
 912{
 913        struct ili9322 *ili = spi_get_drvdata(spi);
 914
 915        ili9322_power_off(ili);
 916        drm_panel_remove(&ili->panel);
 917
 918        return 0;
 919}
 920
 921/*
 922 * The D-Link DIR-685 panel is marked LM918A01-1A SY-B4-091116-E0199
 923 */
 924static const struct ili9322_config ili9322_dir_685 = {
 925        .width_mm = 65,
 926        .height_mm = 50,
 927        .input = ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR,
 928        .vreg1out_mv = 4600,
 929        .vcom_high_percent = 91,
 930        .vcom_amplitude_percent = 114,
 931        .syncmode = ILI9322_IF_CTRL_SYNC_DISABLED,
 932        .dclk_active_high = true,
 933        .gamma_corr_neg = { 0xa, 0x5, 0x7, 0x7, 0x7, 0x5, 0x1, 0x6 },
 934        .gamma_corr_pos = { 0x7, 0x7, 0x3, 0x2, 0x3, 0x5, 0x7, 0x2 },
 935};
 936
 937static const struct of_device_id ili9322_of_match[] = {
 938        {
 939                .compatible = "dlink,dir-685-panel",
 940                .data = &ili9322_dir_685,
 941        },
 942        {
 943                .compatible = "ilitek,ili9322",
 944                .data = NULL,
 945        },
 946        { }
 947};
 948MODULE_DEVICE_TABLE(of, ili9322_of_match);
 949
 950static struct spi_driver ili9322_driver = {
 951        .probe = ili9322_probe,
 952        .remove = ili9322_remove,
 953        .driver = {
 954                .name = "panel-ilitek-ili9322",
 955                .of_match_table = ili9322_of_match,
 956        },
 957};
 958module_spi_driver(ili9322_driver);
 959
 960MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
 961MODULE_DESCRIPTION("ILI9322 LCD panel driver");
 962MODULE_LICENSE("GPL v2");
 963