Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Ilitek ILI9322 TFT LCD drm_panel driver.
0004  *
0005  * This panel can be configured to support:
0006  * - 8-bit serial RGB interface
0007  * - 24-bit parallel RGB interface
0008  * - 8-bit ITU-R BT.601 interface
0009  * - 8-bit ITU-R BT.656 interface
0010  * - Up to 320RGBx240 dots resolution TFT LCD displays
0011  * - Scaling, brightness and contrast
0012  *
0013  * The scaling means that the display accepts a 640x480 or 720x480
0014  * input and rescales it to fit to the 320x240 display. So what we
0015  * present to the system is something else than what comes out on the
0016  * actual display.
0017  *
0018  * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
0019  * Derived from drivers/drm/gpu/panel/panel-samsung-ld9040.c
0020  */
0021 
0022 #include <linux/bitops.h>
0023 #include <linux/gpio/consumer.h>
0024 #include <linux/module.h>
0025 #include <linux/of_device.h>
0026 #include <linux/regmap.h>
0027 #include <linux/regulator/consumer.h>
0028 #include <linux/spi/spi.h>
0029 
0030 #include <video/mipi_display.h>
0031 #include <video/of_videomode.h>
0032 #include <video/videomode.h>
0033 
0034 #include <drm/drm_modes.h>
0035 #include <drm/drm_panel.h>
0036 
0037 #define ILI9322_CHIP_ID         0x00
0038 #define ILI9322_CHIP_ID_MAGIC       0x96
0039 
0040 /*
0041  * Voltage on the communication interface, from 0.7 (0x00)
0042  * to 1.32 (0x1f) times the VREG1OUT voltage in 2% increments.
0043  * 1.00 (0x0f) is the default.
0044  */
0045 #define ILI9322_VCOM_AMP        0x01
0046 
0047 /*
0048  * High voltage on the communication signals, from 0.37 (0x00) to
0049  * 1.0 (0x3f) times the VREGOUT1 voltage in 1% increments.
0050  * 0.83 (0x2e) is the default.
0051  */
0052 #define ILI9322_VCOM_HIGH       0x02
0053 
0054 /*
0055  * VREG1 voltage regulator from 3.6V (0x00) to 6.0V (0x18) in 0.1V
0056  * increments. 5.4V (0x12) is the default. This is the reference
0057  * voltage for the VCOM levels and the greyscale level.
0058  */
0059 #define ILI9322_VREG1_VOLTAGE       0x03
0060 
0061 /* Describes the incoming signal */
0062 #define ILI9322_ENTRY           0x06
0063 /* 0 = right-to-left, 1 = left-to-right (default), horizontal flip */
0064 #define ILI9322_ENTRY_HDIR      BIT(0)
0065 /* 0 = down-to-up, 1 = up-to-down (default), vertical flip  */
0066 #define ILI9322_ENTRY_VDIR      BIT(1)
0067 /* NTSC, PAL or autodetect */
0068 #define ILI9322_ENTRY_NTSC      (0 << 2)
0069 #define ILI9322_ENTRY_PAL       (1 << 2)
0070 #define ILI9322_ENTRY_AUTODETECT    (3 << 2)
0071 /* Input format */
0072 #define ILI9322_ENTRY_SERIAL_RGB_THROUGH (0 << 4)
0073 #define ILI9322_ENTRY_SERIAL_RGB_ALIGNED (1 << 4)
0074 #define ILI9322_ENTRY_SERIAL_RGB_DUMMY_320X240 (2 << 4)
0075 #define ILI9322_ENTRY_SERIAL_RGB_DUMMY_360X240 (3 << 4)
0076 #define ILI9322_ENTRY_DISABLE_1     (4 << 4)
0077 #define ILI9322_ENTRY_PARALLEL_RGB_THROUGH (5 << 4)
0078 #define ILI9322_ENTRY_PARALLEL_RGB_ALIGNED (6 << 4)
0079 #define ILI9322_ENTRY_YUV_640Y_320CBCR_25_54_MHZ (7 << 4)
0080 #define ILI9322_ENTRY_YUV_720Y_360CBCR_27_MHZ (8 << 4)
0081 #define ILI9322_ENTRY_DISABLE_2     (9 << 4)
0082 #define ILI9322_ENTRY_ITU_R_BT_656_720X360 (10 << 4)
0083 #define ILI9322_ENTRY_ITU_R_BT_656_640X320 (11 << 4)
0084 
0085 /* Power control */
0086 #define ILI9322_POW_CTRL        0x07
0087 #define ILI9322_POW_CTRL_STB        BIT(0) /* 0 = standby, 1 = normal */
0088 #define ILI9322_POW_CTRL_VGL        BIT(1) /* 0 = off, 1 = on  */
0089 #define ILI9322_POW_CTRL_VGH        BIT(2) /* 0 = off, 1 = on  */
0090 #define ILI9322_POW_CTRL_DDVDH      BIT(3) /* 0 = off, 1 = on  */
0091 #define ILI9322_POW_CTRL_VCOM       BIT(4) /* 0 = off, 1 = on  */
0092 #define ILI9322_POW_CTRL_VCL        BIT(5) /* 0 = off, 1 = on  */
0093 #define ILI9322_POW_CTRL_AUTO       BIT(6) /* 0 = interactive, 1 = auto */
0094 #define ILI9322_POW_CTRL_STANDBY    (ILI9322_POW_CTRL_VGL | \
0095                      ILI9322_POW_CTRL_VGH | \
0096                      ILI9322_POW_CTRL_DDVDH | \
0097                      ILI9322_POW_CTRL_VCL | \
0098                      ILI9322_POW_CTRL_AUTO | \
0099                      BIT(7))
0100 #define ILI9322_POW_CTRL_DEFAULT    (ILI9322_POW_CTRL_STANDBY | \
0101                      ILI9322_POW_CTRL_STB)
0102 
0103 /* Vertical back porch bits 0..5 */
0104 #define ILI9322_VBP         0x08
0105 
0106 /* Horizontal back porch, 8 bits */
0107 #define ILI9322_HBP         0x09
0108 
0109 /*
0110  * Polarity settings:
0111  * 1 = positive polarity
0112  * 0 = negative polarity
0113  */
0114 #define ILI9322_POL         0x0a
0115 #define ILI9322_POL_DCLK        BIT(0) /* 1 default */
0116 #define ILI9322_POL_HSYNC       BIT(1) /* 0 default */
0117 #define ILI9322_POL_VSYNC       BIT(2) /* 0 default */
0118 #define ILI9322_POL_DE          BIT(3) /* 1 default */
0119 /*
0120  * 0 means YCBCR are ordered Cb0,Y0,Cr0,Y1,Cb2,Y2,Cr2,Y3 (default)
0121  *   in RGB mode this means RGB comes in RGBRGB
0122  * 1 means YCBCR are ordered Cr0,Y0,Cb0,Y1,Cr2,Y2,Cb2,Y3
0123  *   in RGB mode this means RGB comes in BGRBGR
0124  */
0125 #define ILI9322_POL_YCBCR_MODE      BIT(4)
0126 /* Formula A for YCbCR->RGB = 0, Formula B = 1 */
0127 #define ILI9322_POL_FORMULA     BIT(5)
0128 /* Reverse polarity: 0 = 0..255, 1 = 255..0 */
0129 #define ILI9322_POL_REV         BIT(6)
0130 
0131 #define ILI9322_IF_CTRL         0x0b
0132 #define ILI9322_IF_CTRL_HSYNC_VSYNC 0x00
0133 #define ILI9322_IF_CTRL_HSYNC_VSYNC_DE  BIT(2)
0134 #define ILI9322_IF_CTRL_DE_ONLY     BIT(3)
0135 #define ILI9322_IF_CTRL_SYNC_DISABLED   (BIT(2) | BIT(3))
0136 #define ILI9322_IF_CTRL_LINE_INVERSION  BIT(0) /* Not set means frame inv */
0137 
0138 #define ILI9322_GLOBAL_RESET        0x04
0139 #define ILI9322_GLOBAL_RESET_ASSERT 0x00 /* bit 0 = 0 -> reset */
0140 
0141 /*
0142  * 4+4 bits of negative and positive gamma correction
0143  * Upper nybble, bits 4-7 are negative gamma
0144  * Lower nybble, bits 0-3 are positive gamma
0145  */
0146 #define ILI9322_GAMMA_1         0x10
0147 #define ILI9322_GAMMA_2         0x11
0148 #define ILI9322_GAMMA_3         0x12
0149 #define ILI9322_GAMMA_4         0x13
0150 #define ILI9322_GAMMA_5         0x14
0151 #define ILI9322_GAMMA_6         0x15
0152 #define ILI9322_GAMMA_7         0x16
0153 #define ILI9322_GAMMA_8         0x17
0154 
0155 /*
0156  * enum ili9322_input - the format of the incoming signal to the panel
0157  *
0158  * The panel can be connected to various input streams and four of them can
0159  * be selected by electronic straps on the display. However it is possible
0160  * to select another mode or override the electronic default with this
0161  * setting.
0162  */
0163 enum ili9322_input {
0164     ILI9322_INPUT_SRGB_THROUGH = 0x0,
0165     ILI9322_INPUT_SRGB_ALIGNED = 0x1,
0166     ILI9322_INPUT_SRGB_DUMMY_320X240 = 0x2,
0167     ILI9322_INPUT_SRGB_DUMMY_360X240 = 0x3,
0168     ILI9322_INPUT_DISABLED_1 = 0x4,
0169     ILI9322_INPUT_PRGB_THROUGH = 0x5,
0170     ILI9322_INPUT_PRGB_ALIGNED = 0x6,
0171     ILI9322_INPUT_YUV_640X320_YCBCR = 0x7,
0172     ILI9322_INPUT_YUV_720X360_YCBCR = 0x8,
0173     ILI9322_INPUT_DISABLED_2 = 0x9,
0174     ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR = 0xa,
0175     ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR = 0xb,
0176     ILI9322_INPUT_UNKNOWN = 0xc,
0177 };
0178 
0179 static const char * const ili9322_inputs[] = {
0180     "8 bit serial RGB through",
0181     "8 bit serial RGB aligned",
0182     "8 bit serial RGB dummy 320x240",
0183     "8 bit serial RGB dummy 360x240",
0184     "disabled 1",
0185     "24 bit parallel RGB through",
0186     "24 bit parallel RGB aligned",
0187     "24 bit YUV 640Y 320CbCr",
0188     "24 bit YUV 720Y 360CbCr",
0189     "disabled 2",
0190     "8 bit ITU-R BT.656 720Y 360CbCr",
0191     "8 bit ITU-R BT.656 640Y 320CbCr",
0192 };
0193 
0194 /**
0195  * struct ili9322_config - the system specific ILI9322 configuration
0196  * @width_mm: physical panel width [mm]
0197  * @height_mm: physical panel height [mm]
0198  * @flip_horizontal: flip the image horizontally (right-to-left scan)
0199  * (only in RGB and YUV modes)
0200  * @flip_vertical: flip the image vertically (down-to-up scan)
0201  * (only in RGB and YUV modes)
0202  * @input: the input/entry type used in this system, if this is set to
0203  * ILI9322_INPUT_UNKNOWN the driver will try to figure it out by probing
0204  * the hardware
0205  * @vreg1out_mv: the output in microvolts for the VREGOUT1 regulator used
0206  * to drive the physical display. Valid ranges are 3600 thru 6000 in 100
0207  * microvolt increments. If not specified, hardware defaults will be
0208  * used (4.5V).
0209  * @vcom_high_percent: the percentage of VREGOUT1 used for the peak
0210  * voltage on the communications link. Valid ranges are 37 thru 100
0211  * percent. If not specified, hardware defaults will be used (91%).
0212  * @vcom_amplitude_percent: the percentage of VREGOUT1 used for the
0213  * peak-to-peak amplitude of the communcation signals to the physical
0214  * display. Valid ranges are 70 thru 132 percent in increments if two
0215  * percent. Odd percentages will be truncated. If not specified, hardware
0216  * defaults will be used (114%).
0217  * @dclk_active_high: data/pixel clock active high, data will be clocked
0218  * in on the rising edge of the DCLK (this is usually the case).
0219  * @syncmode: The synchronization mode, what sync signals are emitted.
0220  * See the enum for details.
0221  * @de_active_high: DE (data entry) is active high
0222  * @hsync_active_high: HSYNC is active high
0223  * @vsync_active_high: VSYNC is active high
0224  * @gamma_corr_pos: a set of 8 nybbles describing positive
0225  * gamma correction for voltages V1 thru V8. Valid range 0..15
0226  * @gamma_corr_neg: a set of 8 nybbles describing negative
0227  * gamma correction for voltages V1 thru V8. Valid range 0..15
0228  *
0229  * These adjust what grayscale voltage will be output for input data V1 = 0,
0230  * V2 = 16, V3 = 48, V4 = 96, V5 = 160, V6 = 208, V7 = 240 and V8 = 255.
0231  * The curve is shaped like this:
0232  *
0233  *  ^
0234  *  |                                                        V8
0235  *  |                                                   V7
0236  *  |                                          V6
0237  *  |                               V5
0238  *  |                    V4
0239  *  |            V3
0240  *  |     V2
0241  *  | V1
0242  *  +----------------------------------------------------------->
0243  *    0   16     48      96         160        208      240  255
0244  *
0245  * The negative and postive gamma values adjust the V1 thru V8 up/down
0246  * according to the datasheet specifications. This is a property of the
0247  * physical display connected to the display controller and may vary.
0248  * If defined, both arrays must be supplied in full. If the properties
0249  * are not supplied, hardware defaults will be used.
0250  */
0251 struct ili9322_config {
0252     u32 width_mm;
0253     u32 height_mm;
0254     bool flip_horizontal;
0255     bool flip_vertical;
0256     enum ili9322_input input;
0257     u32 vreg1out_mv;
0258     u32 vcom_high_percent;
0259     u32 vcom_amplitude_percent;
0260     bool dclk_active_high;
0261     bool de_active_high;
0262     bool hsync_active_high;
0263     bool vsync_active_high;
0264     u8 syncmode;
0265     u8 gamma_corr_pos[8];
0266     u8 gamma_corr_neg[8];
0267 };
0268 
0269 struct ili9322 {
0270     struct device *dev;
0271     const struct ili9322_config *conf;
0272     struct drm_panel panel;
0273     struct regmap *regmap;
0274     struct regulator_bulk_data supplies[3];
0275     struct gpio_desc *reset_gpio;
0276     enum ili9322_input input;
0277     struct videomode vm;
0278     u8 gamma[8];
0279     u8 vreg1out;
0280     u8 vcom_high;
0281     u8 vcom_amplitude;
0282 };
0283 
0284 static inline struct ili9322 *panel_to_ili9322(struct drm_panel *panel)
0285 {
0286     return container_of(panel, struct ili9322, panel);
0287 }
0288 
0289 static int ili9322_regmap_spi_write(void *context, const void *data,
0290                     size_t count)
0291 {
0292     struct device *dev = context;
0293     struct spi_device *spi = to_spi_device(dev);
0294     u8 buf[2];
0295 
0296     /* Clear bit 7 to write */
0297     memcpy(buf, data, 2);
0298     buf[0] &= ~0x80;
0299 
0300     dev_dbg(dev, "WRITE: %02x %02x\n", buf[0], buf[1]);
0301     return spi_write_then_read(spi, buf, 2, NULL, 0);
0302 }
0303 
0304 static int ili9322_regmap_spi_read(void *context, const void *reg,
0305                    size_t reg_size, void *val, size_t val_size)
0306 {
0307     struct device *dev = context;
0308     struct spi_device *spi = to_spi_device(dev);
0309     u8 buf[1];
0310 
0311     /* Set bit 7 to 1 to read */
0312     memcpy(buf, reg, 1);
0313     dev_dbg(dev, "READ: %02x reg size = %zu, val size = %zu\n",
0314         buf[0], reg_size, val_size);
0315     buf[0] |= 0x80;
0316 
0317     return spi_write_then_read(spi, buf, 1, val, 1);
0318 }
0319 
0320 static struct regmap_bus ili9322_regmap_bus = {
0321     .write = ili9322_regmap_spi_write,
0322     .read = ili9322_regmap_spi_read,
0323     .reg_format_endian_default = REGMAP_ENDIAN_BIG,
0324     .val_format_endian_default = REGMAP_ENDIAN_BIG,
0325 };
0326 
0327 static bool ili9322_volatile_reg(struct device *dev, unsigned int reg)
0328 {
0329     return false;
0330 }
0331 
0332 static bool ili9322_writeable_reg(struct device *dev, unsigned int reg)
0333 {
0334     /* Just register 0 is read-only */
0335     if (reg == 0x00)
0336         return false;
0337     return true;
0338 }
0339 
0340 static const struct regmap_config ili9322_regmap_config = {
0341     .reg_bits = 8,
0342     .val_bits = 8,
0343     .max_register = 0x44,
0344     .cache_type = REGCACHE_RBTREE,
0345     .volatile_reg = ili9322_volatile_reg,
0346     .writeable_reg = ili9322_writeable_reg,
0347 };
0348 
0349 static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili)
0350 {
0351     u8 reg;
0352     int ret;
0353     int i;
0354 
0355     /* Reset display */
0356     ret = regmap_write(ili->regmap, ILI9322_GLOBAL_RESET,
0357                ILI9322_GLOBAL_RESET_ASSERT);
0358     if (ret) {
0359         dev_err(ili->dev, "can't issue GRESET (%d)\n", ret);
0360         return ret;
0361     }
0362 
0363     /* Set up the main voltage regulator */
0364     if (ili->vreg1out != U8_MAX) {
0365         ret = regmap_write(ili->regmap, ILI9322_VREG1_VOLTAGE,
0366                    ili->vreg1out);
0367         if (ret) {
0368             dev_err(ili->dev, "can't set up VREG1OUT (%d)\n", ret);
0369             return ret;
0370         }
0371     }
0372 
0373     if (ili->vcom_amplitude != U8_MAX) {
0374         ret = regmap_write(ili->regmap, ILI9322_VCOM_AMP,
0375                    ili->vcom_amplitude);
0376         if (ret) {
0377             dev_err(ili->dev,
0378                 "can't set up VCOM amplitude (%d)\n", ret);
0379             return ret;
0380         }
0381     }
0382 
0383     if (ili->vcom_high != U8_MAX) {
0384         ret = regmap_write(ili->regmap, ILI9322_VCOM_HIGH,
0385                    ili->vcom_high);
0386         if (ret) {
0387             dev_err(ili->dev, "can't set up VCOM high (%d)\n", ret);
0388             return ret;
0389         }
0390     }
0391 
0392     /* Set up gamma correction */
0393     for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {
0394         ret = regmap_write(ili->regmap, ILI9322_GAMMA_1 + i,
0395                    ili->gamma[i]);
0396         if (ret) {
0397             dev_err(ili->dev,
0398                 "can't write gamma V%d to 0x%02x (%d)\n",
0399                 i + 1, ILI9322_GAMMA_1 + i, ret);
0400             return ret;
0401         }
0402     }
0403 
0404     /*
0405      * Polarity and inverted color order for RGB input.
0406      * None of this applies in the BT.656 mode.
0407      */
0408     reg = 0;
0409     if (ili->conf->dclk_active_high)
0410         reg = ILI9322_POL_DCLK;
0411     if (ili->conf->de_active_high)
0412         reg |= ILI9322_POL_DE;
0413     if (ili->conf->hsync_active_high)
0414         reg |= ILI9322_POL_HSYNC;
0415     if (ili->conf->vsync_active_high)
0416         reg |= ILI9322_POL_VSYNC;
0417     ret = regmap_write(ili->regmap, ILI9322_POL, reg);
0418     if (ret) {
0419         dev_err(ili->dev, "can't write POL register (%d)\n", ret);
0420         return ret;
0421     }
0422 
0423     /*
0424      * Set up interface control.
0425      * This is not used in the BT.656 mode (no H/Vsync or DE signals).
0426      */
0427     reg = ili->conf->syncmode;
0428     reg |= ILI9322_IF_CTRL_LINE_INVERSION;
0429     ret = regmap_write(ili->regmap, ILI9322_IF_CTRL, reg);
0430     if (ret) {
0431         dev_err(ili->dev, "can't write IF CTRL register (%d)\n", ret);
0432         return ret;
0433     }
0434 
0435     /* Set up the input mode */
0436     reg = (ili->input << 4);
0437     /* These are inverted, setting to 1 is the default, clearing flips */
0438     if (!ili->conf->flip_horizontal)
0439         reg |= ILI9322_ENTRY_HDIR;
0440     if (!ili->conf->flip_vertical)
0441         reg |= ILI9322_ENTRY_VDIR;
0442     reg |= ILI9322_ENTRY_AUTODETECT;
0443     ret = regmap_write(ili->regmap, ILI9322_ENTRY, reg);
0444     if (ret) {
0445         dev_err(ili->dev, "can't write ENTRY reg (%d)\n", ret);
0446         return ret;
0447     }
0448     dev_info(ili->dev, "display is in %s mode, syncmode %02x\n",
0449          ili9322_inputs[ili->input],
0450          ili->conf->syncmode);
0451 
0452     dev_info(ili->dev, "initialized display\n");
0453 
0454     return 0;
0455 }
0456 
0457 /*
0458  * This power-on sequence if from the datasheet, page 57.
0459  */
0460 static int ili9322_power_on(struct ili9322 *ili)
0461 {
0462     int ret;
0463 
0464     /* Assert RESET */
0465     gpiod_set_value(ili->reset_gpio, 1);
0466 
0467     ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies), ili->supplies);
0468     if (ret < 0) {
0469         dev_err(ili->dev, "unable to enable regulators\n");
0470         return ret;
0471     }
0472     msleep(20);
0473 
0474     /* De-assert RESET */
0475     gpiod_set_value(ili->reset_gpio, 0);
0476 
0477     msleep(10);
0478 
0479     return 0;
0480 }
0481 
0482 static int ili9322_power_off(struct ili9322 *ili)
0483 {
0484     return regulator_bulk_disable(ARRAY_SIZE(ili->supplies), ili->supplies);
0485 }
0486 
0487 static int ili9322_disable(struct drm_panel *panel)
0488 {
0489     struct ili9322 *ili = panel_to_ili9322(panel);
0490     int ret;
0491 
0492     ret = regmap_write(ili->regmap, ILI9322_POW_CTRL,
0493                ILI9322_POW_CTRL_STANDBY);
0494     if (ret) {
0495         dev_err(ili->dev, "unable to go to standby mode\n");
0496         return ret;
0497     }
0498 
0499     return 0;
0500 }
0501 
0502 static int ili9322_unprepare(struct drm_panel *panel)
0503 {
0504     struct ili9322 *ili = panel_to_ili9322(panel);
0505 
0506     return ili9322_power_off(ili);
0507 }
0508 
0509 static int ili9322_prepare(struct drm_panel *panel)
0510 {
0511     struct ili9322 *ili = panel_to_ili9322(panel);
0512     int ret;
0513 
0514     ret = ili9322_power_on(ili);
0515     if (ret < 0)
0516         return ret;
0517 
0518     ret = ili9322_init(panel, ili);
0519     if (ret < 0)
0520         ili9322_unprepare(panel);
0521 
0522     return ret;
0523 }
0524 
0525 static int ili9322_enable(struct drm_panel *panel)
0526 {
0527     struct ili9322 *ili = panel_to_ili9322(panel);
0528     int ret;
0529 
0530     ret = regmap_write(ili->regmap, ILI9322_POW_CTRL,
0531                ILI9322_POW_CTRL_DEFAULT);
0532     if (ret) {
0533         dev_err(ili->dev, "unable to enable panel\n");
0534         return ret;
0535     }
0536 
0537     return 0;
0538 }
0539 
0540 /* Serial RGB modes */
0541 static const struct drm_display_mode srgb_320x240_mode = {
0542     .clock = 24535,
0543     .hdisplay = 320,
0544     .hsync_start = 320 + 359,
0545     .hsync_end = 320 + 359 + 1,
0546     .htotal = 320 + 359 + 1 + 241,
0547     .vdisplay = 240,
0548     .vsync_start = 240 + 4,
0549     .vsync_end = 240 + 4 + 1,
0550     .vtotal = 262,
0551     .flags = 0,
0552 };
0553 
0554 static const struct drm_display_mode srgb_360x240_mode = {
0555     .clock = 27000,
0556     .hdisplay = 360,
0557     .hsync_start = 360 + 35,
0558     .hsync_end = 360 + 35 + 1,
0559     .htotal = 360 + 35 + 1 + 241,
0560     .vdisplay = 240,
0561     .vsync_start = 240 + 21,
0562     .vsync_end = 240 + 21 + 1,
0563     .vtotal = 262,
0564     .flags = 0,
0565 };
0566 
0567 /* This is the only mode listed for parallel RGB in the datasheet */
0568 static const struct drm_display_mode prgb_320x240_mode = {
0569     .clock = 64000,
0570     .hdisplay = 320,
0571     .hsync_start = 320 + 38,
0572     .hsync_end = 320 + 38 + 1,
0573     .htotal = 320 + 38 + 1 + 50,
0574     .vdisplay = 240,
0575     .vsync_start = 240 + 4,
0576     .vsync_end = 240 + 4 + 1,
0577     .vtotal = 262,
0578     .flags = 0,
0579 };
0580 
0581 /* YUV modes */
0582 static const struct drm_display_mode yuv_640x320_mode = {
0583     .clock = 24540,
0584     .hdisplay = 640,
0585     .hsync_start = 640 + 252,
0586     .hsync_end = 640 + 252 + 1,
0587     .htotal = 640 + 252 + 1 + 28,
0588     .vdisplay = 320,
0589     .vsync_start = 320 + 4,
0590     .vsync_end = 320 + 4 + 1,
0591     .vtotal = 320 + 4 + 1 + 18,
0592     .flags = 0,
0593 };
0594 
0595 static const struct drm_display_mode yuv_720x360_mode = {
0596     .clock = 27000,
0597     .hdisplay = 720,
0598     .hsync_start = 720 + 252,
0599     .hsync_end = 720 + 252 + 1,
0600     .htotal = 720 + 252 + 1 + 24,
0601     .vdisplay = 360,
0602     .vsync_start = 360 + 4,
0603     .vsync_end = 360 + 4 + 1,
0604     .vtotal = 360 + 4 + 1 + 18,
0605     .flags = 0,
0606 };
0607 
0608 /* BT.656 VGA mode, 640x480 */
0609 static const struct drm_display_mode itu_r_bt_656_640_mode = {
0610     .clock = 24540,
0611     .hdisplay = 640,
0612     .hsync_start = 640 + 3,
0613     .hsync_end = 640 + 3 + 1,
0614     .htotal = 640 + 3 + 1 + 272,
0615     .vdisplay = 480,
0616     .vsync_start = 480 + 4,
0617     .vsync_end = 480 + 4 + 1,
0618     .vtotal = 500,
0619     .flags = 0,
0620 };
0621 
0622 /* BT.656 D1 mode 720x480 */
0623 static const struct drm_display_mode itu_r_bt_656_720_mode = {
0624     .clock = 27000,
0625     .hdisplay = 720,
0626     .hsync_start = 720 + 3,
0627     .hsync_end = 720 + 3 + 1,
0628     .htotal = 720 + 3 + 1 + 272,
0629     .vdisplay = 480,
0630     .vsync_start = 480 + 4,
0631     .vsync_end = 480 + 4 + 1,
0632     .vtotal = 500,
0633     .flags = 0,
0634 };
0635 
0636 static int ili9322_get_modes(struct drm_panel *panel,
0637                  struct drm_connector *connector)
0638 {
0639     struct ili9322 *ili = panel_to_ili9322(panel);
0640     struct drm_device *drm = connector->dev;
0641     struct drm_display_mode *mode;
0642     struct drm_display_info *info;
0643 
0644     info = &connector->display_info;
0645     info->width_mm = ili->conf->width_mm;
0646     info->height_mm = ili->conf->height_mm;
0647     if (ili->conf->dclk_active_high)
0648         info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
0649     else
0650         info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
0651 
0652     if (ili->conf->de_active_high)
0653         info->bus_flags |= DRM_BUS_FLAG_DE_HIGH;
0654     else
0655         info->bus_flags |= DRM_BUS_FLAG_DE_LOW;
0656 
0657     switch (ili->input) {
0658     case ILI9322_INPUT_SRGB_DUMMY_320X240:
0659         mode = drm_mode_duplicate(drm, &srgb_320x240_mode);
0660         break;
0661     case ILI9322_INPUT_SRGB_DUMMY_360X240:
0662         mode = drm_mode_duplicate(drm, &srgb_360x240_mode);
0663         break;
0664     case ILI9322_INPUT_PRGB_THROUGH:
0665     case ILI9322_INPUT_PRGB_ALIGNED:
0666         mode = drm_mode_duplicate(drm, &prgb_320x240_mode);
0667         break;
0668     case ILI9322_INPUT_YUV_640X320_YCBCR:
0669         mode = drm_mode_duplicate(drm, &yuv_640x320_mode);
0670         break;
0671     case ILI9322_INPUT_YUV_720X360_YCBCR:
0672         mode = drm_mode_duplicate(drm, &yuv_720x360_mode);
0673         break;
0674     case ILI9322_INPUT_ITU_R_BT656_720X360_YCBCR:
0675         mode = drm_mode_duplicate(drm, &itu_r_bt_656_720_mode);
0676         break;
0677     case ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR:
0678         mode = drm_mode_duplicate(drm, &itu_r_bt_656_640_mode);
0679         break;
0680     default:
0681         mode = NULL;
0682         break;
0683     }
0684     if (!mode) {
0685         dev_err(panel->dev, "bad mode or failed to add mode\n");
0686         return -EINVAL;
0687     }
0688     drm_mode_set_name(mode);
0689     /*
0690      * This is the preferred mode because most people are going
0691      * to want to use the display with VGA type graphics.
0692      */
0693     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0694 
0695     /* Set up the polarity */
0696     if (ili->conf->hsync_active_high)
0697         mode->flags |= DRM_MODE_FLAG_PHSYNC;
0698     else
0699         mode->flags |= DRM_MODE_FLAG_NHSYNC;
0700     if (ili->conf->vsync_active_high)
0701         mode->flags |= DRM_MODE_FLAG_PVSYNC;
0702     else
0703         mode->flags |= DRM_MODE_FLAG_NVSYNC;
0704 
0705     mode->width_mm = ili->conf->width_mm;
0706     mode->height_mm = ili->conf->height_mm;
0707     drm_mode_probed_add(connector, mode);
0708 
0709     return 1; /* Number of modes */
0710 }
0711 
0712 static const struct drm_panel_funcs ili9322_drm_funcs = {
0713     .disable = ili9322_disable,
0714     .unprepare = ili9322_unprepare,
0715     .prepare = ili9322_prepare,
0716     .enable = ili9322_enable,
0717     .get_modes = ili9322_get_modes,
0718 };
0719 
0720 static int ili9322_probe(struct spi_device *spi)
0721 {
0722     struct device *dev = &spi->dev;
0723     struct ili9322 *ili;
0724     const struct regmap_config *regmap_config;
0725     u8 gamma;
0726     u32 val;
0727     int ret;
0728     int i;
0729 
0730     ili = devm_kzalloc(dev, sizeof(struct ili9322), GFP_KERNEL);
0731     if (!ili)
0732         return -ENOMEM;
0733 
0734     spi_set_drvdata(spi, ili);
0735 
0736     ili->dev = dev;
0737 
0738     /*
0739      * Every new incarnation of this display must have a unique
0740      * data entry for the system in this driver.
0741      */
0742     ili->conf = of_device_get_match_data(dev);
0743     if (!ili->conf) {
0744         dev_err(dev, "missing device configuration\n");
0745         return -ENODEV;
0746     }
0747 
0748     val = ili->conf->vreg1out_mv;
0749     if (!val) {
0750         /* Default HW value, do not touch (should be 4.5V) */
0751         ili->vreg1out = U8_MAX;
0752     } else {
0753         if (val < 3600) {
0754             dev_err(dev, "too low VREG1OUT\n");
0755             return -EINVAL;
0756         }
0757         if (val > 6000) {
0758             dev_err(dev, "too high VREG1OUT\n");
0759             return -EINVAL;
0760         }
0761         if ((val % 100) != 0) {
0762             dev_err(dev, "VREG1OUT is no even 100 microvolt\n");
0763             return -EINVAL;
0764         }
0765         val -= 3600;
0766         val /= 100;
0767         dev_dbg(dev, "VREG1OUT = 0x%02x\n", val);
0768         ili->vreg1out = val;
0769     }
0770 
0771     val = ili->conf->vcom_high_percent;
0772     if (!val) {
0773         /* Default HW value, do not touch (should be 91%) */
0774         ili->vcom_high = U8_MAX;
0775     } else {
0776         if (val < 37) {
0777             dev_err(dev, "too low VCOM high\n");
0778             return -EINVAL;
0779         }
0780         if (val > 100) {
0781             dev_err(dev, "too high VCOM high\n");
0782             return -EINVAL;
0783         }
0784         val -= 37;
0785         dev_dbg(dev, "VCOM high = 0x%02x\n", val);
0786         ili->vcom_high = val;
0787     }
0788 
0789     val = ili->conf->vcom_amplitude_percent;
0790     if (!val) {
0791         /* Default HW value, do not touch (should be 114%) */
0792         ili->vcom_high = U8_MAX;
0793     } else {
0794         if (val < 70) {
0795             dev_err(dev, "too low VCOM amplitude\n");
0796             return -EINVAL;
0797         }
0798         if (val > 132) {
0799             dev_err(dev, "too high VCOM amplitude\n");
0800             return -EINVAL;
0801         }
0802         val -= 70;
0803         val >>= 1; /* Increments of 2% */
0804         dev_dbg(dev, "VCOM amplitude = 0x%02x\n", val);
0805         ili->vcom_amplitude = val;
0806     }
0807 
0808     for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {
0809         val = ili->conf->gamma_corr_neg[i];
0810         if (val > 15) {
0811             dev_err(dev, "negative gamma %u > 15, capping\n", val);
0812             val = 15;
0813         }
0814         gamma = val << 4;
0815         val = ili->conf->gamma_corr_pos[i];
0816         if (val > 15) {
0817             dev_err(dev, "positive gamma %u > 15, capping\n", val);
0818             val = 15;
0819         }
0820         gamma |= val;
0821         ili->gamma[i] = gamma;
0822         dev_dbg(dev, "gamma V%d: 0x%02x\n", i + 1, gamma);
0823     }
0824 
0825     ili->supplies[0].supply = "vcc"; /* 2.7-3.6 V */
0826     ili->supplies[1].supply = "iovcc"; /* 1.65-3.6V */
0827     ili->supplies[2].supply = "vci"; /* 2.7-3.6V */
0828     ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies),
0829                       ili->supplies);
0830     if (ret < 0)
0831         return ret;
0832     ret = regulator_set_voltage(ili->supplies[0].consumer,
0833                     2700000, 3600000);
0834     if (ret)
0835         return ret;
0836     ret = regulator_set_voltage(ili->supplies[1].consumer,
0837                     1650000, 3600000);
0838     if (ret)
0839         return ret;
0840     ret = regulator_set_voltage(ili->supplies[2].consumer,
0841                     2700000, 3600000);
0842     if (ret)
0843         return ret;
0844 
0845     ili->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
0846     if (IS_ERR(ili->reset_gpio)) {
0847         dev_err(dev, "failed to get RESET GPIO\n");
0848         return PTR_ERR(ili->reset_gpio);
0849     }
0850 
0851     spi->bits_per_word = 8;
0852     ret = spi_setup(spi);
0853     if (ret < 0) {
0854         dev_err(dev, "spi setup failed.\n");
0855         return ret;
0856     }
0857     regmap_config = &ili9322_regmap_config;
0858     ili->regmap = devm_regmap_init(dev, &ili9322_regmap_bus, dev,
0859                        regmap_config);
0860     if (IS_ERR(ili->regmap)) {
0861         dev_err(dev, "failed to allocate register map\n");
0862         return PTR_ERR(ili->regmap);
0863     }
0864 
0865     ret = regmap_read(ili->regmap, ILI9322_CHIP_ID, &val);
0866     if (ret) {
0867         dev_err(dev, "can't get chip ID (%d)\n", ret);
0868         return ret;
0869     }
0870     if (val != ILI9322_CHIP_ID_MAGIC) {
0871         dev_err(dev, "chip ID 0x%0x2, expected 0x%02x\n", val,
0872             ILI9322_CHIP_ID_MAGIC);
0873         return -ENODEV;
0874     }
0875 
0876     /* Probe the system to find the display setting */
0877     if (ili->conf->input == ILI9322_INPUT_UNKNOWN) {
0878         ret = regmap_read(ili->regmap, ILI9322_ENTRY, &val);
0879         if (ret) {
0880             dev_err(dev, "can't get entry setting (%d)\n", ret);
0881             return ret;
0882         }
0883         /* Input enum corresponds to HW setting */
0884         ili->input = (val >> 4) & 0x0f;
0885         if (ili->input >= ILI9322_INPUT_UNKNOWN)
0886             ili->input = ILI9322_INPUT_UNKNOWN;
0887     } else {
0888         ili->input = ili->conf->input;
0889     }
0890 
0891     drm_panel_init(&ili->panel, dev, &ili9322_drm_funcs,
0892                DRM_MODE_CONNECTOR_DPI);
0893 
0894     drm_panel_add(&ili->panel);
0895 
0896     return 0;
0897 }
0898 
0899 static void ili9322_remove(struct spi_device *spi)
0900 {
0901     struct ili9322 *ili = spi_get_drvdata(spi);
0902 
0903     ili9322_power_off(ili);
0904     drm_panel_remove(&ili->panel);
0905 }
0906 
0907 /*
0908  * The D-Link DIR-685 panel is marked LM918A01-1A SY-B4-091116-E0199
0909  */
0910 static const struct ili9322_config ili9322_dir_685 = {
0911     .width_mm = 65,
0912     .height_mm = 50,
0913     .input = ILI9322_INPUT_ITU_R_BT656_640X320_YCBCR,
0914     .vreg1out_mv = 4600,
0915     .vcom_high_percent = 91,
0916     .vcom_amplitude_percent = 114,
0917     .syncmode = ILI9322_IF_CTRL_SYNC_DISABLED,
0918     .dclk_active_high = true,
0919     .gamma_corr_neg = { 0xa, 0x5, 0x7, 0x7, 0x7, 0x5, 0x1, 0x6 },
0920     .gamma_corr_pos = { 0x7, 0x7, 0x3, 0x2, 0x3, 0x5, 0x7, 0x2 },
0921 };
0922 
0923 static const struct of_device_id ili9322_of_match[] = {
0924     {
0925         .compatible = "dlink,dir-685-panel",
0926         .data = &ili9322_dir_685,
0927     },
0928     {
0929         .compatible = "ilitek,ili9322",
0930         .data = NULL,
0931     },
0932     { }
0933 };
0934 MODULE_DEVICE_TABLE(of, ili9322_of_match);
0935 
0936 static struct spi_driver ili9322_driver = {
0937     .probe = ili9322_probe,
0938     .remove = ili9322_remove,
0939     .driver = {
0940         .name = "panel-ilitek-ili9322",
0941         .of_match_table = ili9322_of_match,
0942     },
0943 };
0944 module_spi_driver(ili9322_driver);
0945 
0946 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
0947 MODULE_DESCRIPTION("ILI9322 LCD panel driver");
0948 MODULE_LICENSE("GPL v2");