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 29 static 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 46 static 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 57 static 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 92 static 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 111 static 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 209 static int vgg2432a4_suspend(struct spi_device *spi, pm_message_t state) 210 { 211 return ili9320_suspend(dev_get_drvdata(&spi->dev), state); 212 } 213 214 static int vgg2432a4_resume(struct spi_device *spi) 215 { 216 return ili9320_resume(dev_get_drvdata(&spi->dev)); 217 } 218 #else 219 #define vgg2432a4_suspend NULL 220 #define vgg2432a4_resume NULL 221 #endif 222 223 static struct ili9320_client vgg2432a4_client = { 224 .name = "VGG2432A4", 225 .init = vgg2432a4_lcd_init, 226 }; 227 228 /* Device probe */ 229 230 static int __devinit vgg2432a4_probe(struct spi_device *spi) 231 { 232 int ret; 233 234 ret = ili9320_probe_spi(spi, &vgg2432a4_client); 235 if (ret != 0) { 236 dev_err(&spi->dev, "failed to initialise ili9320\n"); 237 return ret; 238 } 239 240 return 0; 241 } 242 243 static int __devexit vgg2432a4_remove(struct spi_device *spi) 244 { 245 return ili9320_remove(dev_get_drvdata(&spi->dev)); 246 } 247 248 static void vgg2432a4_shutdown(struct spi_device *spi) 249 { 250 ili9320_shutdown(dev_get_drvdata(&spi->dev)); 251 } 252 253 static struct spi_driver vgg2432a4_driver = { 254 .driver = { 255 .name = "VGG2432A4", 256 .owner = THIS_MODULE, 257 }, 258 .probe = vgg2432a4_probe, 259 .remove = __devexit_p(vgg2432a4_remove), 260 .shutdown = vgg2432a4_shutdown, 261 .suspend = vgg2432a4_suspend, 262 .resume = vgg2432a4_resume, 263 }; 264 265 /* Device driver initialisation */ 266 267 static int __init vgg2432a4_init(void) 268 { 269 return spi_register_driver(&vgg2432a4_driver); 270 } 271 272 static void __exit vgg2432a4_exit(void) 273 { 274 spi_unregister_driver(&vgg2432a4_driver); 275 } 276 277 module_init(vgg2432a4_init); 278 module_exit(vgg2432a4_exit); 279 280 MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>"); 281 MODULE_DESCRIPTION("VGG2432A4 LCD Driver"); 282 MODULE_LICENSE("GPL v2"); 283 284 285