vgg2432a4.c 6.0 KB

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