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