vgg2432a4.c 6.2 KB

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