lms501kf03.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * lms501kf03 TFT LCD panel driver.
  4. *
  5. * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  6. * Author: Jingoo Han <jg1.han@samsung.com>
  7. */
  8. #include <linux/delay.h>
  9. #include <linux/lcd.h>
  10. #include <linux/module.h>
  11. #include <linux/spi/spi.h>
  12. #include <linux/wait.h>
  13. #define COMMAND_ONLY 0x00
  14. #define DATA_ONLY 0x01
  15. struct lms501kf03 {
  16. struct device *dev;
  17. struct spi_device *spi;
  18. unsigned int power;
  19. struct lcd_device *ld;
  20. struct lcd_platform_data *lcd_pd;
  21. };
  22. static const unsigned char seq_password[] = {
  23. 0xb9, 0xff, 0x83, 0x69,
  24. };
  25. static const unsigned char seq_power[] = {
  26. 0xb1, 0x01, 0x00, 0x34, 0x06, 0x00, 0x14, 0x14, 0x20, 0x28,
  27. 0x12, 0x12, 0x17, 0x0a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
  28. };
  29. static const unsigned char seq_display[] = {
  30. 0xb2, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00, 0xff, 0x00, 0x00,
  31. 0x00, 0x00, 0x03, 0x03, 0x00, 0x01,
  32. };
  33. static const unsigned char seq_rgb_if[] = {
  34. 0xb3, 0x09,
  35. };
  36. static const unsigned char seq_display_inv[] = {
  37. 0xb4, 0x01, 0x08, 0x77, 0x0e, 0x06,
  38. };
  39. static const unsigned char seq_vcom[] = {
  40. 0xb6, 0x4c, 0x2e,
  41. };
  42. static const unsigned char seq_gate[] = {
  43. 0xd5, 0x00, 0x05, 0x03, 0x29, 0x01, 0x07, 0x17, 0x68, 0x13,
  44. 0x37, 0x20, 0x31, 0x8a, 0x46, 0x9b, 0x57, 0x13, 0x02, 0x75,
  45. 0xb9, 0x64, 0xa8, 0x07, 0x0f, 0x04, 0x07,
  46. };
  47. static const unsigned char seq_panel[] = {
  48. 0xcc, 0x02,
  49. };
  50. static const unsigned char seq_col_mod[] = {
  51. 0x3a, 0x77,
  52. };
  53. static const unsigned char seq_w_gamma[] = {
  54. 0xe0, 0x00, 0x04, 0x09, 0x0f, 0x1f, 0x3f, 0x1f, 0x2f, 0x0a,
  55. 0x0f, 0x10, 0x16, 0x18, 0x16, 0x17, 0x0d, 0x15, 0x00, 0x04,
  56. 0x09, 0x0f, 0x38, 0x3f, 0x20, 0x39, 0x0a, 0x0f, 0x10, 0x16,
  57. 0x18, 0x16, 0x17, 0x0d, 0x15,
  58. };
  59. static const unsigned char seq_rgb_gamma[] = {
  60. 0xc1, 0x01, 0x03, 0x07, 0x0f, 0x1a, 0x22, 0x2c, 0x33, 0x3c,
  61. 0x46, 0x4f, 0x58, 0x60, 0x69, 0x71, 0x79, 0x82, 0x89, 0x92,
  62. 0x9a, 0xa1, 0xa9, 0xb1, 0xb9, 0xc1, 0xc9, 0xcf, 0xd6, 0xde,
  63. 0xe5, 0xec, 0xf3, 0xf9, 0xff, 0xdd, 0x39, 0x07, 0x1c, 0xcb,
  64. 0xab, 0x5f, 0x49, 0x80, 0x03, 0x07, 0x0f, 0x19, 0x20, 0x2a,
  65. 0x31, 0x39, 0x42, 0x4b, 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b,
  66. 0x83, 0x8a, 0x92, 0x9b, 0xa2, 0xaa, 0xb2, 0xba, 0xc2, 0xca,
  67. 0xd0, 0xd8, 0xe1, 0xe8, 0xf0, 0xf8, 0xff, 0xf7, 0xd8, 0xbe,
  68. 0xa7, 0x39, 0x40, 0x85, 0x8c, 0xc0, 0x04, 0x07, 0x0c, 0x17,
  69. 0x1c, 0x23, 0x2b, 0x34, 0x3b, 0x43, 0x4c, 0x54, 0x5b, 0x63,
  70. 0x6a, 0x73, 0x7a, 0x82, 0x8a, 0x91, 0x98, 0xa1, 0xa8, 0xb0,
  71. 0xb7, 0xc1, 0xc9, 0xcf, 0xd9, 0xe3, 0xea, 0xf4, 0xff, 0x00,
  72. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  73. };
  74. static const unsigned char seq_sleep_out[] = {
  75. 0x11,
  76. };
  77. static const unsigned char seq_display_on[] = {
  78. 0x29,
  79. };
  80. static const unsigned char seq_display_off[] = {
  81. 0x10,
  82. };
  83. static int lms501kf03_spi_write_byte(struct lms501kf03 *lcd, int addr, int data)
  84. {
  85. u16 buf[1];
  86. struct spi_message msg;
  87. struct spi_transfer xfer = {
  88. .len = 2,
  89. .tx_buf = buf,
  90. };
  91. buf[0] = (addr << 8) | data;
  92. spi_message_init(&msg);
  93. spi_message_add_tail(&xfer, &msg);
  94. return spi_sync(lcd->spi, &msg);
  95. }
  96. static int lms501kf03_spi_write(struct lms501kf03 *lcd, unsigned char address,
  97. unsigned char command)
  98. {
  99. return lms501kf03_spi_write_byte(lcd, address, command);
  100. }
  101. static int lms501kf03_panel_send_sequence(struct lms501kf03 *lcd,
  102. const unsigned char *wbuf,
  103. unsigned int len)
  104. {
  105. int ret = 0, i = 0;
  106. while (i < len) {
  107. if (i == 0)
  108. ret = lms501kf03_spi_write(lcd, COMMAND_ONLY, wbuf[i]);
  109. else
  110. ret = lms501kf03_spi_write(lcd, DATA_ONLY, wbuf[i]);
  111. if (ret)
  112. break;
  113. i += 1;
  114. }
  115. return ret;
  116. }
  117. static int lms501kf03_ldi_init(struct lms501kf03 *lcd)
  118. {
  119. int ret, i;
  120. static const unsigned char *init_seq[] = {
  121. seq_password,
  122. seq_power,
  123. seq_display,
  124. seq_rgb_if,
  125. seq_display_inv,
  126. seq_vcom,
  127. seq_gate,
  128. seq_panel,
  129. seq_col_mod,
  130. seq_w_gamma,
  131. seq_rgb_gamma,
  132. seq_sleep_out,
  133. };
  134. static const unsigned int size_seq[] = {
  135. ARRAY_SIZE(seq_password),
  136. ARRAY_SIZE(seq_power),
  137. ARRAY_SIZE(seq_display),
  138. ARRAY_SIZE(seq_rgb_if),
  139. ARRAY_SIZE(seq_display_inv),
  140. ARRAY_SIZE(seq_vcom),
  141. ARRAY_SIZE(seq_gate),
  142. ARRAY_SIZE(seq_panel),
  143. ARRAY_SIZE(seq_col_mod),
  144. ARRAY_SIZE(seq_w_gamma),
  145. ARRAY_SIZE(seq_rgb_gamma),
  146. ARRAY_SIZE(seq_sleep_out),
  147. };
  148. for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
  149. ret = lms501kf03_panel_send_sequence(lcd, init_seq[i],
  150. size_seq[i]);
  151. if (ret)
  152. break;
  153. }
  154. /*
  155. * According to the datasheet, 120ms delay time is required.
  156. * After sleep out sequence, command is blocked for 120ms.
  157. * Thus, LDI should wait for 120ms.
  158. */
  159. msleep(120);
  160. return ret;
  161. }
  162. static int lms501kf03_ldi_enable(struct lms501kf03 *lcd)
  163. {
  164. return lms501kf03_panel_send_sequence(lcd, seq_display_on,
  165. ARRAY_SIZE(seq_display_on));
  166. }
  167. static int lms501kf03_ldi_disable(struct lms501kf03 *lcd)
  168. {
  169. return lms501kf03_panel_send_sequence(lcd, seq_display_off,
  170. ARRAY_SIZE(seq_display_off));
  171. }
  172. static int lms501kf03_power_is_on(int power)
  173. {
  174. return (power) <= LCD_POWER_REDUCED;
  175. }
  176. static int lms501kf03_power_on(struct lms501kf03 *lcd)
  177. {
  178. int ret = 0;
  179. struct lcd_platform_data *pd;
  180. pd = lcd->lcd_pd;
  181. if (!pd->power_on) {
  182. dev_err(lcd->dev, "power_on is NULL.\n");
  183. return -EINVAL;
  184. }
  185. pd->power_on(lcd->ld, 1);
  186. msleep(pd->power_on_delay);
  187. if (!pd->reset) {
  188. dev_err(lcd->dev, "reset is NULL.\n");
  189. return -EINVAL;
  190. }
  191. pd->reset(lcd->ld);
  192. msleep(pd->reset_delay);
  193. ret = lms501kf03_ldi_init(lcd);
  194. if (ret) {
  195. dev_err(lcd->dev, "failed to initialize ldi.\n");
  196. return ret;
  197. }
  198. ret = lms501kf03_ldi_enable(lcd);
  199. if (ret) {
  200. dev_err(lcd->dev, "failed to enable ldi.\n");
  201. return ret;
  202. }
  203. return 0;
  204. }
  205. static int lms501kf03_power_off(struct lms501kf03 *lcd)
  206. {
  207. int ret = 0;
  208. struct lcd_platform_data *pd;
  209. pd = lcd->lcd_pd;
  210. ret = lms501kf03_ldi_disable(lcd);
  211. if (ret) {
  212. dev_err(lcd->dev, "lcd setting failed.\n");
  213. return -EIO;
  214. }
  215. msleep(pd->power_off_delay);
  216. pd->power_on(lcd->ld, 0);
  217. return 0;
  218. }
  219. static int lms501kf03_power(struct lms501kf03 *lcd, int power)
  220. {
  221. int ret = 0;
  222. if (lms501kf03_power_is_on(power) &&
  223. !lms501kf03_power_is_on(lcd->power))
  224. ret = lms501kf03_power_on(lcd);
  225. else if (!lms501kf03_power_is_on(power) &&
  226. lms501kf03_power_is_on(lcd->power))
  227. ret = lms501kf03_power_off(lcd);
  228. if (!ret)
  229. lcd->power = power;
  230. return ret;
  231. }
  232. static int lms501kf03_get_power(struct lcd_device *ld)
  233. {
  234. struct lms501kf03 *lcd = lcd_get_data(ld);
  235. return lcd->power;
  236. }
  237. static int lms501kf03_set_power(struct lcd_device *ld, int power)
  238. {
  239. struct lms501kf03 *lcd = lcd_get_data(ld);
  240. if (power != LCD_POWER_ON && power != LCD_POWER_OFF &&
  241. power != LCD_POWER_REDUCED) {
  242. dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
  243. return -EINVAL;
  244. }
  245. return lms501kf03_power(lcd, power);
  246. }
  247. static const struct lcd_ops lms501kf03_lcd_ops = {
  248. .get_power = lms501kf03_get_power,
  249. .set_power = lms501kf03_set_power,
  250. };
  251. static int lms501kf03_probe(struct spi_device *spi)
  252. {
  253. struct lms501kf03 *lcd = NULL;
  254. struct lcd_device *ld = NULL;
  255. int ret = 0;
  256. lcd = devm_kzalloc(&spi->dev, sizeof(struct lms501kf03), GFP_KERNEL);
  257. if (!lcd)
  258. return -ENOMEM;
  259. /* lms501kf03 lcd panel uses 3-wire 9-bit SPI Mode. */
  260. spi->bits_per_word = 9;
  261. ret = spi_setup(spi);
  262. if (ret < 0) {
  263. dev_err(&spi->dev, "spi setup failed.\n");
  264. return ret;
  265. }
  266. lcd->spi = spi;
  267. lcd->dev = &spi->dev;
  268. lcd->lcd_pd = dev_get_platdata(&spi->dev);
  269. if (!lcd->lcd_pd) {
  270. dev_err(&spi->dev, "platform data is NULL\n");
  271. return -EINVAL;
  272. }
  273. ld = devm_lcd_device_register(&spi->dev, "lms501kf03", &spi->dev, lcd,
  274. &lms501kf03_lcd_ops);
  275. if (IS_ERR(ld))
  276. return PTR_ERR(ld);
  277. lcd->ld = ld;
  278. if (!lcd->lcd_pd->lcd_enabled) {
  279. /*
  280. * if lcd panel was off from bootloader then
  281. * current lcd status is powerdown and then
  282. * it enables lcd panel.
  283. */
  284. lcd->power = LCD_POWER_OFF;
  285. lms501kf03_power(lcd, LCD_POWER_ON);
  286. } else {
  287. lcd->power = LCD_POWER_ON;
  288. }
  289. spi_set_drvdata(spi, lcd);
  290. dev_info(&spi->dev, "lms501kf03 panel driver has been probed.\n");
  291. return 0;
  292. }
  293. static void lms501kf03_remove(struct spi_device *spi)
  294. {
  295. struct lms501kf03 *lcd = spi_get_drvdata(spi);
  296. lms501kf03_power(lcd, LCD_POWER_OFF);
  297. }
  298. #ifdef CONFIG_PM_SLEEP
  299. static int lms501kf03_suspend(struct device *dev)
  300. {
  301. struct lms501kf03 *lcd = dev_get_drvdata(dev);
  302. dev_dbg(dev, "lcd->power = %d\n", lcd->power);
  303. /*
  304. * when lcd panel is suspend, lcd panel becomes off
  305. * regardless of status.
  306. */
  307. return lms501kf03_power(lcd, LCD_POWER_OFF);
  308. }
  309. static int lms501kf03_resume(struct device *dev)
  310. {
  311. struct lms501kf03 *lcd = dev_get_drvdata(dev);
  312. lcd->power = LCD_POWER_OFF;
  313. return lms501kf03_power(lcd, LCD_POWER_ON);
  314. }
  315. #endif
  316. static SIMPLE_DEV_PM_OPS(lms501kf03_pm_ops, lms501kf03_suspend,
  317. lms501kf03_resume);
  318. static void lms501kf03_shutdown(struct spi_device *spi)
  319. {
  320. struct lms501kf03 *lcd = spi_get_drvdata(spi);
  321. lms501kf03_power(lcd, LCD_POWER_OFF);
  322. }
  323. static struct spi_driver lms501kf03_driver = {
  324. .driver = {
  325. .name = "lms501kf03",
  326. .pm = &lms501kf03_pm_ops,
  327. },
  328. .probe = lms501kf03_probe,
  329. .remove = lms501kf03_remove,
  330. .shutdown = lms501kf03_shutdown,
  331. };
  332. module_spi_driver(lms501kf03_driver);
  333. MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
  334. MODULE_DESCRIPTION("lms501kf03 LCD Driver");
  335. MODULE_LICENSE("GPL");