linux/drivers/video/backlight/vgg2432a4.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* drivers/video/backlight/vgg2432a4.c
   3 *
   4 * VGG2432A4 (ILI9320) LCD controller driver.
   5 *
   6 * Copyright 2007 Simtec Electronics
   7 *      http://armlinux.simtec.co.uk/
   8 *      Ben Dooks <ben@simtec.co.uk>
   9*/
  10
  11#include <linux/delay.h>
  12#include <linux/err.h>
  13#include <linux/fb.h>
  14#include <linux/init.h>
  15#include <linux/lcd.h>
  16#include <linux/module.h>
  17
  18#include <linux/spi/spi.h>
  19
  20#include <video/ili9320.h>
  21
  22#include "ili9320.h"
  23
  24/* Device initialisation sequences */
  25
  26static const struct ili9320_reg vgg_init1[] = {
  27        {
  28                .address = ILI9320_POWER1,
  29                .value   = ILI9320_POWER1_AP(0) | ILI9320_POWER1_BT(0),
  30        }, {
  31                .address = ILI9320_POWER2,
  32                .value   = (ILI9320_POWER2_VC(7) |
  33                            ILI9320_POWER2_DC0(0) | ILI9320_POWER2_DC1(0)),
  34        }, {
  35                .address = ILI9320_POWER3,
  36                .value   = ILI9320_POWER3_VRH(0),
  37        }, {
  38                .address = ILI9320_POWER4,
  39                .value   = ILI9320_POWER4_VREOUT(0),
  40        },
  41};
  42
  43static const struct ili9320_reg vgg_init2[] = {
  44        {
  45                .address = ILI9320_POWER1,
  46                .value   = (ILI9320_POWER1_AP(3) | ILI9320_POWER1_APE |
  47                            ILI9320_POWER1_BT(7) | ILI9320_POWER1_SAP),
  48        }, {
  49                .address = ILI9320_POWER2,
  50                .value   = ILI9320_POWER2_VC(7) | ILI9320_POWER2_DC0(3),
  51        }
  52};
  53
  54static const struct ili9320_reg vgg_gamma[] = {
  55        {
  56                .address = ILI9320_GAMMA1,
  57                .value   = 0x0000,
  58        }, {
  59                .address = ILI9320_GAMMA2,
  60                .value   = 0x0505,
  61        }, {
  62                .address = ILI9320_GAMMA3,
  63                .value   = 0x0004,
  64        }, {
  65                .address = ILI9320_GAMMA4,
  66                .value   = 0x0006,
  67        }, {
  68                .address = ILI9320_GAMMA5,
  69                .value   = 0x0707,
  70        }, {
  71                .address = ILI9320_GAMMA6,
  72                .value   = 0x0105,
  73        }, {
  74                .address = ILI9320_GAMMA7,
  75                .value   = 0x0002,
  76        }, {
  77                .address = ILI9320_GAMMA8,
  78                .value   = 0x0707,
  79        }, {
  80                .address = ILI9320_GAMMA9,
  81                .value   = 0x0704,
  82        }, {
  83                .address = ILI9320_GAMMA10,
  84                .value   = 0x807,
  85        }
  86
  87};
  88
  89static const struct ili9320_reg vgg_init0[] = {
  90        [0]     = {
  91                /* set direction and scan mode gate */
  92                .address = ILI9320_DRIVER,
  93                .value   = ILI9320_DRIVER_SS,
  94        }, {
  95                .address = ILI9320_DRIVEWAVE,
  96                .value   = (ILI9320_DRIVEWAVE_MUSTSET |
  97                            ILI9320_DRIVEWAVE_EOR | ILI9320_DRIVEWAVE_BC),
  98        }, {
  99                .address = ILI9320_ENTRYMODE,
 100                .value   = ILI9320_ENTRYMODE_ID(3) | ILI9320_ENTRYMODE_BGR,
 101        }, {
 102                .address = ILI9320_RESIZING,
 103                .value   = 0x0,
 104        },
 105};
 106
 107
 108static int vgg2432a4_lcd_init(struct ili9320 *lcd,
 109                              struct ili9320_platdata *cfg)
 110{
 111        unsigned int addr;
 112        int ret;
 113
 114        /* Set VCore before anything else (VGG243237-6UFLWA) */
 115        ret = ili9320_write(lcd, 0x00e5, 0x8000);
 116        if (ret)
 117                goto err_initial;
 118
 119        /* Start the oscillator up before we can do anything else. */
 120        ret = ili9320_write(lcd, ILI9320_OSCILATION, ILI9320_OSCILATION_OSC);
 121        if (ret)
 122                goto err_initial;
 123
 124        /* must wait at-lesat 10ms after starting */
 125        mdelay(15);
 126
 127        ret = ili9320_write_regs(lcd, vgg_init0, ARRAY_SIZE(vgg_init0));
 128        if (ret != 0)
 129                goto err_initial;
 130
 131        ili9320_write(lcd, ILI9320_DISPLAY2, cfg->display2);
 132        ili9320_write(lcd, ILI9320_DISPLAY3, cfg->display3);
 133        ili9320_write(lcd, ILI9320_DISPLAY4, cfg->display4);
 134
 135        ili9320_write(lcd, ILI9320_RGB_IF1, cfg->rgb_if1);
 136        ili9320_write(lcd, ILI9320_FRAMEMAKER, 0x0);
 137        ili9320_write(lcd, ILI9320_RGB_IF2, cfg->rgb_if2);
 138
 139        ret = ili9320_write_regs(lcd, vgg_init1, ARRAY_SIZE(vgg_init1));
 140        if (ret != 0)
 141                goto err_vgg;
 142
 143        mdelay(300);
 144
 145        ret = ili9320_write_regs(lcd, vgg_init2, ARRAY_SIZE(vgg_init2));
 146        if (ret != 0)
 147                goto err_vgg2;
 148
 149        mdelay(100);
 150
 151        ili9320_write(lcd, ILI9320_POWER3, 0x13c);
 152
 153        mdelay(100);
 154
 155        ili9320_write(lcd, ILI9320_POWER4, 0x1c00);
 156        ili9320_write(lcd, ILI9320_POWER7, 0x000e);
 157
 158        mdelay(100);
 159
 160        ili9320_write(lcd, ILI9320_GRAM_HORIZ_ADDR, 0x00);
 161        ili9320_write(lcd, ILI9320_GRAM_VERT_ADD, 0x00);
 162
 163        ret = ili9320_write_regs(lcd, vgg_gamma, ARRAY_SIZE(vgg_gamma));
 164        if (ret != 0)
 165                goto err_vgg3;
 166
 167        ili9320_write(lcd, ILI9320_HORIZ_START, 0x0);
 168        ili9320_write(lcd, ILI9320_HORIZ_END, cfg->hsize - 1);
 169        ili9320_write(lcd, ILI9320_VERT_START, 0x0);
 170        ili9320_write(lcd, ILI9320_VERT_END, cfg->vsize - 1);
 171
 172        ili9320_write(lcd, ILI9320_DRIVER2,
 173                      ILI9320_DRIVER2_NL(((cfg->vsize - 240) / 8) + 0x1D));
 174
 175        ili9320_write(lcd, ILI9320_BASE_IMAGE, 0x1);
 176        ili9320_write(lcd, ILI9320_VERT_SCROLL, 0x00);
 177
 178        for (addr = ILI9320_PARTIAL1_POSITION; addr <= ILI9320_PARTIAL2_END;
 179             addr++) {
 180                ili9320_write(lcd, addr, 0x0);
 181        }
 182
 183        ili9320_write(lcd, ILI9320_INTERFACE1, 0x10);
 184        ili9320_write(lcd, ILI9320_INTERFACE2, cfg->interface2);
 185        ili9320_write(lcd, ILI9320_INTERFACE3, cfg->interface3);
 186        ili9320_write(lcd, ILI9320_INTERFACE4, cfg->interface4);
 187        ili9320_write(lcd, ILI9320_INTERFACE5, cfg->interface5);
 188        ili9320_write(lcd, ILI9320_INTERFACE6, cfg->interface6);
 189
 190        lcd->display1 = (ILI9320_DISPLAY1_D(3) | ILI9320_DISPLAY1_DTE |
 191                         ILI9320_DISPLAY1_GON | ILI9320_DISPLAY1_BASEE |
 192                         0x40);
 193
 194        ili9320_write(lcd, ILI9320_DISPLAY1, lcd->display1);
 195
 196        return 0;
 197
 198 err_vgg3:
 199 err_vgg2:
 200 err_vgg:
 201 err_initial:
 202        return ret;
 203}
 204
 205#ifdef CONFIG_PM_SLEEP
 206static int vgg2432a4_suspend(struct device *dev)
 207{
 208        return ili9320_suspend(dev_get_drvdata(dev));
 209}
 210static int vgg2432a4_resume(struct device *dev)
 211{
 212        return ili9320_resume(dev_get_drvdata(dev));
 213}
 214#endif
 215
 216static struct ili9320_client vgg2432a4_client = {
 217        .name   = "VGG2432A4",
 218        .init   = vgg2432a4_lcd_init,
 219};
 220
 221/* Device probe */
 222
 223static int vgg2432a4_probe(struct spi_device *spi)
 224{
 225        int ret;
 226
 227        ret = ili9320_probe_spi(spi, &vgg2432a4_client);
 228        if (ret != 0) {
 229                dev_err(&spi->dev, "failed to initialise ili9320\n");
 230                return ret;
 231        }
 232
 233        return 0;
 234}
 235
 236static int vgg2432a4_remove(struct spi_device *spi)
 237{
 238        return ili9320_remove(spi_get_drvdata(spi));
 239}
 240
 241static void vgg2432a4_shutdown(struct spi_device *spi)
 242{
 243        ili9320_shutdown(spi_get_drvdata(spi));
 244}
 245
 246static SIMPLE_DEV_PM_OPS(vgg2432a4_pm_ops, vgg2432a4_suspend, vgg2432a4_resume);
 247
 248static struct spi_driver vgg2432a4_driver = {
 249        .driver = {
 250                .name           = "VGG2432A4",
 251                .pm             = &vgg2432a4_pm_ops,
 252        },
 253        .probe          = vgg2432a4_probe,
 254        .remove         = vgg2432a4_remove,
 255        .shutdown       = vgg2432a4_shutdown,
 256};
 257
 258module_spi_driver(vgg2432a4_driver);
 259
 260MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
 261MODULE_DESCRIPTION("VGG2432A4 LCD Driver");
 262MODULE_LICENSE("GPL v2");
 263MODULE_ALIAS("spi:VGG2432A4");
 264