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 26 static 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 43 static 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 54 static 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 89 static 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 108 static 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 206 static int vgg2432a4_suspend(struct device *dev) 207 { 208 return ili9320_suspend(dev_get_drvdata(dev)); 209 } 210 static int vgg2432a4_resume(struct device *dev) 211 { 212 return ili9320_resume(dev_get_drvdata(dev)); 213 } 214 #endif 215 216 static struct ili9320_client vgg2432a4_client = { 217 .name = "VGG2432A4", 218 .init = vgg2432a4_lcd_init, 219 }; 220 221 /* Device probe */ 222 223 static 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 236 static int vgg2432a4_remove(struct spi_device *spi) 237 { 238 ili9320_remove(spi_get_drvdata(spi)); 239 240 return 0; 241 } 242 243 static void vgg2432a4_shutdown(struct spi_device *spi) 244 { 245 ili9320_shutdown(spi_get_drvdata(spi)); 246 } 247 248 static SIMPLE_DEV_PM_OPS(vgg2432a4_pm_ops, vgg2432a4_suspend, vgg2432a4_resume); 249 250 static struct spi_driver vgg2432a4_driver = { 251 .driver = { 252 .name = "VGG2432A4", 253 .pm = &vgg2432a4_pm_ops, 254 }, 255 .probe = vgg2432a4_probe, 256 .remove = vgg2432a4_remove, 257 .shutdown = vgg2432a4_shutdown, 258 }; 259 260 module_spi_driver(vgg2432a4_driver); 261 262 MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>"); 263 MODULE_DESCRIPTION("VGG2432A4 LCD Driver"); 264 MODULE_LICENSE("GPL v2"); 265 MODULE_ALIAS("spi:VGG2432A4"); 266