lms283gf05.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * lms283gf05.c -- support for Samsung LMS283GF05 LCD
  3. *
  4. * Copyright (c) 2009 Marek Vasut <marek.vasut@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. */
  10. #include <linux/device.h>
  11. #include <linux/kernel.h>
  12. #include <linux/delay.h>
  13. #include <linux/gpio.h>
  14. #include <linux/lcd.h>
  15. #include <linux/spi/spi.h>
  16. #include <linux/spi/lms283gf05.h>
  17. struct lms283gf05_state {
  18. struct spi_device *spi;
  19. struct lcd_device *ld;
  20. };
  21. struct lms283gf05_seq {
  22. unsigned char reg;
  23. unsigned short value;
  24. unsigned char delay;
  25. };
  26. /* Magic sequences supplied by manufacturer, for details refer to datasheet */
  27. static struct lms283gf05_seq disp_initseq[] = {
  28. /* REG, VALUE, DELAY */
  29. { 0x07, 0x0000, 0 },
  30. { 0x13, 0x0000, 10 },
  31. { 0x11, 0x3004, 0 },
  32. { 0x14, 0x200F, 0 },
  33. { 0x10, 0x1a20, 0 },
  34. { 0x13, 0x0040, 50 },
  35. { 0x13, 0x0060, 0 },
  36. { 0x13, 0x0070, 200 },
  37. { 0x01, 0x0127, 0 },
  38. { 0x02, 0x0700, 0 },
  39. { 0x03, 0x1030, 0 },
  40. { 0x08, 0x0208, 0 },
  41. { 0x0B, 0x0620, 0 },
  42. { 0x0C, 0x0110, 0 },
  43. { 0x30, 0x0120, 0 },
  44. { 0x31, 0x0127, 0 },
  45. { 0x32, 0x0000, 0 },
  46. { 0x33, 0x0503, 0 },
  47. { 0x34, 0x0727, 0 },
  48. { 0x35, 0x0124, 0 },
  49. { 0x36, 0x0706, 0 },
  50. { 0x37, 0x0701, 0 },
  51. { 0x38, 0x0F00, 0 },
  52. { 0x39, 0x0F00, 0 },
  53. { 0x40, 0x0000, 0 },
  54. { 0x41, 0x0000, 0 },
  55. { 0x42, 0x013f, 0 },
  56. { 0x43, 0x0000, 0 },
  57. { 0x44, 0x013f, 0 },
  58. { 0x45, 0x0000, 0 },
  59. { 0x46, 0xef00, 0 },
  60. { 0x47, 0x013f, 0 },
  61. { 0x48, 0x0000, 0 },
  62. { 0x07, 0x0015, 30 },
  63. { 0x07, 0x0017, 0 },
  64. { 0x20, 0x0000, 0 },
  65. { 0x21, 0x0000, 0 },
  66. { 0x22, 0x0000, 0 }
  67. };
  68. static struct lms283gf05_seq disp_pdwnseq[] = {
  69. { 0x07, 0x0016, 30 },
  70. { 0x07, 0x0004, 0 },
  71. { 0x10, 0x0220, 20 },
  72. { 0x13, 0x0060, 50 },
  73. { 0x13, 0x0040, 50 },
  74. { 0x13, 0x0000, 0 },
  75. { 0x10, 0x0000, 0 }
  76. };
  77. static void lms283gf05_reset(unsigned long gpio, bool inverted)
  78. {
  79. gpio_set_value(gpio, !inverted);
  80. mdelay(100);
  81. gpio_set_value(gpio, inverted);
  82. mdelay(20);
  83. gpio_set_value(gpio, !inverted);
  84. mdelay(20);
  85. }
  86. static void lms283gf05_toggle(struct spi_device *spi,
  87. struct lms283gf05_seq *seq, int sz)
  88. {
  89. char buf[3];
  90. int i;
  91. for (i = 0; i < sz; i++) {
  92. buf[0] = 0x74;
  93. buf[1] = 0x00;
  94. buf[2] = seq[i].reg;
  95. spi_write(spi, buf, 3);
  96. buf[0] = 0x76;
  97. buf[1] = seq[i].value >> 8;
  98. buf[2] = seq[i].value & 0xff;
  99. spi_write(spi, buf, 3);
  100. mdelay(seq[i].delay);
  101. }
  102. }
  103. static int lms283gf05_power_set(struct lcd_device *ld, int power)
  104. {
  105. struct lms283gf05_state *st = lcd_get_data(ld);
  106. struct spi_device *spi = st->spi;
  107. struct lms283gf05_pdata *pdata = spi->dev.platform_data;
  108. if (power) {
  109. if (pdata)
  110. lms283gf05_reset(pdata->reset_gpio,
  111. pdata->reset_inverted);
  112. lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq));
  113. } else {
  114. lms283gf05_toggle(spi, disp_pdwnseq, ARRAY_SIZE(disp_pdwnseq));
  115. if (pdata)
  116. gpio_set_value(pdata->reset_gpio,
  117. pdata->reset_inverted);
  118. }
  119. return 0;
  120. }
  121. static struct lcd_ops lms_ops = {
  122. .set_power = lms283gf05_power_set,
  123. .get_power = NULL,
  124. };
  125. static int __devinit lms283gf05_probe(struct spi_device *spi)
  126. {
  127. struct lms283gf05_state *st;
  128. struct lms283gf05_pdata *pdata = spi->dev.platform_data;
  129. struct lcd_device *ld;
  130. int ret = 0;
  131. if (pdata != NULL) {
  132. ret = gpio_request(pdata->reset_gpio, "LMS285GF05 RESET");
  133. if (ret)
  134. return ret;
  135. ret = gpio_direction_output(pdata->reset_gpio,
  136. !pdata->reset_inverted);
  137. if (ret)
  138. goto err;
  139. }
  140. st = kzalloc(sizeof(struct lms283gf05_state), GFP_KERNEL);
  141. if (st == NULL) {
  142. dev_err(&spi->dev, "No memory for device state\n");
  143. ret = -ENOMEM;
  144. goto err;
  145. }
  146. ld = lcd_device_register("lms283gf05", &spi->dev, st, &lms_ops);
  147. if (IS_ERR(ld)) {
  148. ret = PTR_ERR(ld);
  149. goto err2;
  150. }
  151. st->spi = spi;
  152. st->ld = ld;
  153. dev_set_drvdata(&spi->dev, st);
  154. /* kick in the LCD */
  155. if (pdata)
  156. lms283gf05_reset(pdata->reset_gpio, pdata->reset_inverted);
  157. lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq));
  158. return 0;
  159. err2:
  160. kfree(st);
  161. err:
  162. if (pdata != NULL)
  163. gpio_free(pdata->reset_gpio);
  164. return ret;
  165. }
  166. static int __devexit lms283gf05_remove(struct spi_device *spi)
  167. {
  168. struct lms283gf05_state *st = dev_get_drvdata(&spi->dev);
  169. struct lms283gf05_pdata *pdata = st->spi->dev.platform_data;
  170. lcd_device_unregister(st->ld);
  171. if (pdata != NULL)
  172. gpio_free(pdata->reset_gpio);
  173. kfree(st);
  174. return 0;
  175. }
  176. static struct spi_driver lms283gf05_driver = {
  177. .driver = {
  178. .name = "lms283gf05",
  179. .owner = THIS_MODULE,
  180. },
  181. .probe = lms283gf05_probe,
  182. .remove = __devexit_p(lms283gf05_remove),
  183. };
  184. static __init int lms283gf05_init(void)
  185. {
  186. return spi_register_driver(&lms283gf05_driver);
  187. }
  188. static __exit void lms283gf05_exit(void)
  189. {
  190. spi_unregister_driver(&lms283gf05_driver);
  191. }
  192. module_init(lms283gf05_init);
  193. module_exit(lms283gf05_exit);
  194. MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
  195. MODULE_DESCRIPTION("LCD283GF05 LCD");
  196. MODULE_LICENSE("GPL v2");