vgg2432a4.c 6.0 KB

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