ld9040.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. /*
  2. * ld9040 AMOLED LCD panel driver.
  3. *
  4. * Copyright (c) 2011 Samsung Electronics
  5. * Author: Donghwa Lee <dh09.lee@samsung.com>
  6. * Derived from drivers/video/backlight/s6e63m0.c
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2 of the License, or (at your
  11. * option) any later version.
  12. */
  13. #include <linux/backlight.h>
  14. #include <linux/delay.h>
  15. #include <linux/fb.h>
  16. #include <linux/gpio.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/irq.h>
  19. #include <linux/kernel.h>
  20. #include <linux/lcd.h>
  21. #include <linux/module.h>
  22. #include <linux/regulator/consumer.h>
  23. #include <linux/spi/spi.h>
  24. #include <linux/wait.h>
  25. #include "ld9040_gamma.h"
  26. #define SLEEPMSEC 0x1000
  27. #define ENDDEF 0x2000
  28. #define DEFMASK 0xFF00
  29. #define COMMAND_ONLY 0xFE
  30. #define DATA_ONLY 0xFF
  31. #define MIN_BRIGHTNESS 0
  32. #define MAX_BRIGHTNESS 24
  33. struct ld9040 {
  34. struct device *dev;
  35. struct spi_device *spi;
  36. unsigned int power;
  37. unsigned int current_brightness;
  38. struct lcd_device *ld;
  39. struct backlight_device *bd;
  40. struct lcd_platform_data *lcd_pd;
  41. struct mutex lock;
  42. bool enabled;
  43. };
  44. static struct regulator_bulk_data supplies[] = {
  45. { .supply = "vdd3", },
  46. { .supply = "vci", },
  47. };
  48. static void ld9040_regulator_enable(struct ld9040 *lcd)
  49. {
  50. int ret = 0;
  51. struct lcd_platform_data *pd = NULL;
  52. pd = lcd->lcd_pd;
  53. mutex_lock(&lcd->lock);
  54. if (!lcd->enabled) {
  55. ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
  56. if (ret)
  57. goto out;
  58. lcd->enabled = true;
  59. }
  60. msleep(pd->power_on_delay);
  61. out:
  62. mutex_unlock(&lcd->lock);
  63. }
  64. static void ld9040_regulator_disable(struct ld9040 *lcd)
  65. {
  66. int ret = 0;
  67. mutex_lock(&lcd->lock);
  68. if (lcd->enabled) {
  69. ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
  70. if (ret)
  71. goto out;
  72. lcd->enabled = false;
  73. }
  74. out:
  75. mutex_unlock(&lcd->lock);
  76. }
  77. static const unsigned short seq_swreset[] = {
  78. 0x01, COMMAND_ONLY,
  79. ENDDEF, 0x00
  80. };
  81. static const unsigned short seq_user_setting[] = {
  82. 0xF0, 0x5A,
  83. DATA_ONLY, 0x5A,
  84. ENDDEF, 0x00
  85. };
  86. static const unsigned short seq_elvss_on[] = {
  87. 0xB1, 0x0D,
  88. DATA_ONLY, 0x00,
  89. DATA_ONLY, 0x16,
  90. ENDDEF, 0x00
  91. };
  92. static const unsigned short seq_gtcon[] = {
  93. 0xF7, 0x09,
  94. DATA_ONLY, 0x00,
  95. DATA_ONLY, 0x00,
  96. ENDDEF, 0x00
  97. };
  98. static const unsigned short seq_panel_condition[] = {
  99. 0xF8, 0x05,
  100. DATA_ONLY, 0x65,
  101. DATA_ONLY, 0x96,
  102. DATA_ONLY, 0x71,
  103. DATA_ONLY, 0x7D,
  104. DATA_ONLY, 0x19,
  105. DATA_ONLY, 0x3B,
  106. DATA_ONLY, 0x0D,
  107. DATA_ONLY, 0x19,
  108. DATA_ONLY, 0x7E,
  109. DATA_ONLY, 0x0D,
  110. DATA_ONLY, 0xE2,
  111. DATA_ONLY, 0x00,
  112. DATA_ONLY, 0x00,
  113. DATA_ONLY, 0x7E,
  114. DATA_ONLY, 0x7D,
  115. DATA_ONLY, 0x07,
  116. DATA_ONLY, 0x07,
  117. DATA_ONLY, 0x20,
  118. DATA_ONLY, 0x20,
  119. DATA_ONLY, 0x20,
  120. DATA_ONLY, 0x02,
  121. DATA_ONLY, 0x02,
  122. ENDDEF, 0x00
  123. };
  124. static const unsigned short seq_gamma_set1[] = {
  125. 0xF9, 0x00,
  126. DATA_ONLY, 0xA7,
  127. DATA_ONLY, 0xB4,
  128. DATA_ONLY, 0xAE,
  129. DATA_ONLY, 0xBF,
  130. DATA_ONLY, 0x00,
  131. DATA_ONLY, 0x91,
  132. DATA_ONLY, 0x00,
  133. DATA_ONLY, 0xB2,
  134. DATA_ONLY, 0xB4,
  135. DATA_ONLY, 0xAA,
  136. DATA_ONLY, 0xBB,
  137. DATA_ONLY, 0x00,
  138. DATA_ONLY, 0xAC,
  139. DATA_ONLY, 0x00,
  140. DATA_ONLY, 0xB3,
  141. DATA_ONLY, 0xB1,
  142. DATA_ONLY, 0xAA,
  143. DATA_ONLY, 0xBC,
  144. DATA_ONLY, 0x00,
  145. DATA_ONLY, 0xB3,
  146. ENDDEF, 0x00
  147. };
  148. static const unsigned short seq_gamma_ctrl[] = {
  149. 0xFB, 0x02,
  150. DATA_ONLY, 0x5A,
  151. ENDDEF, 0x00
  152. };
  153. static const unsigned short seq_gamma_start[] = {
  154. 0xF9, COMMAND_ONLY,
  155. ENDDEF, 0x00
  156. };
  157. static const unsigned short seq_apon[] = {
  158. 0xF3, 0x00,
  159. DATA_ONLY, 0x00,
  160. DATA_ONLY, 0x00,
  161. DATA_ONLY, 0x0A,
  162. DATA_ONLY, 0x02,
  163. ENDDEF, 0x00
  164. };
  165. static const unsigned short seq_display_ctrl[] = {
  166. 0xF2, 0x02,
  167. DATA_ONLY, 0x08,
  168. DATA_ONLY, 0x08,
  169. DATA_ONLY, 0x10,
  170. DATA_ONLY, 0x10,
  171. ENDDEF, 0x00
  172. };
  173. static const unsigned short seq_manual_pwr[] = {
  174. 0xB0, 0x04,
  175. ENDDEF, 0x00
  176. };
  177. static const unsigned short seq_pwr_ctrl[] = {
  178. 0xF4, 0x0A,
  179. DATA_ONLY, 0x87,
  180. DATA_ONLY, 0x25,
  181. DATA_ONLY, 0x6A,
  182. DATA_ONLY, 0x44,
  183. DATA_ONLY, 0x02,
  184. DATA_ONLY, 0x88,
  185. ENDDEF, 0x00
  186. };
  187. static const unsigned short seq_sleep_out[] = {
  188. 0x11, COMMAND_ONLY,
  189. ENDDEF, 0x00
  190. };
  191. static const unsigned short seq_sleep_in[] = {
  192. 0x10, COMMAND_ONLY,
  193. ENDDEF, 0x00
  194. };
  195. static const unsigned short seq_display_on[] = {
  196. 0x29, COMMAND_ONLY,
  197. ENDDEF, 0x00
  198. };
  199. static const unsigned short seq_display_off[] = {
  200. 0x28, COMMAND_ONLY,
  201. ENDDEF, 0x00
  202. };
  203. static const unsigned short seq_vci1_1st_en[] = {
  204. 0xF3, 0x10,
  205. DATA_ONLY, 0x00,
  206. DATA_ONLY, 0x00,
  207. DATA_ONLY, 0x00,
  208. DATA_ONLY, 0x02,
  209. ENDDEF, 0x00
  210. };
  211. static const unsigned short seq_vl1_en[] = {
  212. 0xF3, 0x11,
  213. DATA_ONLY, 0x00,
  214. DATA_ONLY, 0x00,
  215. DATA_ONLY, 0x00,
  216. DATA_ONLY, 0x02,
  217. ENDDEF, 0x00
  218. };
  219. static const unsigned short seq_vl2_en[] = {
  220. 0xF3, 0x13,
  221. DATA_ONLY, 0x00,
  222. DATA_ONLY, 0x00,
  223. DATA_ONLY, 0x00,
  224. DATA_ONLY, 0x02,
  225. ENDDEF, 0x00
  226. };
  227. static const unsigned short seq_vci1_2nd_en[] = {
  228. 0xF3, 0x33,
  229. DATA_ONLY, 0x00,
  230. DATA_ONLY, 0x00,
  231. DATA_ONLY, 0x00,
  232. DATA_ONLY, 0x02,
  233. ENDDEF, 0x00
  234. };
  235. static const unsigned short seq_vl3_en[] = {
  236. 0xF3, 0x37,
  237. DATA_ONLY, 0x00,
  238. DATA_ONLY, 0x00,
  239. DATA_ONLY, 0x00,
  240. DATA_ONLY, 0x02,
  241. ENDDEF, 0x00
  242. };
  243. static const unsigned short seq_vreg1_amp_en[] = {
  244. 0xF3, 0x37,
  245. DATA_ONLY, 0x01,
  246. DATA_ONLY, 0x00,
  247. DATA_ONLY, 0x00,
  248. DATA_ONLY, 0x02,
  249. ENDDEF, 0x00
  250. };
  251. static const unsigned short seq_vgh_amp_en[] = {
  252. 0xF3, 0x37,
  253. DATA_ONLY, 0x11,
  254. DATA_ONLY, 0x00,
  255. DATA_ONLY, 0x00,
  256. DATA_ONLY, 0x02,
  257. ENDDEF, 0x00
  258. };
  259. static const unsigned short seq_vgl_amp_en[] = {
  260. 0xF3, 0x37,
  261. DATA_ONLY, 0x31,
  262. DATA_ONLY, 0x00,
  263. DATA_ONLY, 0x00,
  264. DATA_ONLY, 0x02,
  265. ENDDEF, 0x00
  266. };
  267. static const unsigned short seq_vmos_amp_en[] = {
  268. 0xF3, 0x37,
  269. DATA_ONLY, 0xB1,
  270. DATA_ONLY, 0x00,
  271. DATA_ONLY, 0x00,
  272. DATA_ONLY, 0x03,
  273. ENDDEF, 0x00
  274. };
  275. static const unsigned short seq_vint_amp_en[] = {
  276. 0xF3, 0x37,
  277. DATA_ONLY, 0xF1,
  278. /* DATA_ONLY, 0x71, VMOS/VBL/VBH not used */
  279. DATA_ONLY, 0x00,
  280. DATA_ONLY, 0x00,
  281. DATA_ONLY, 0x03,
  282. /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */
  283. ENDDEF, 0x00
  284. };
  285. static const unsigned short seq_vbh_amp_en[] = {
  286. 0xF3, 0x37,
  287. DATA_ONLY, 0xF9,
  288. DATA_ONLY, 0x00,
  289. DATA_ONLY, 0x00,
  290. DATA_ONLY, 0x03,
  291. ENDDEF, 0x00
  292. };
  293. static const unsigned short seq_vbl_amp_en[] = {
  294. 0xF3, 0x37,
  295. DATA_ONLY, 0xFD,
  296. DATA_ONLY, 0x00,
  297. DATA_ONLY, 0x00,
  298. DATA_ONLY, 0x03,
  299. ENDDEF, 0x00
  300. };
  301. static const unsigned short seq_gam_amp_en[] = {
  302. 0xF3, 0x37,
  303. DATA_ONLY, 0xFF,
  304. /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */
  305. DATA_ONLY, 0x00,
  306. DATA_ONLY, 0x00,
  307. DATA_ONLY, 0x03,
  308. /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */
  309. ENDDEF, 0x00
  310. };
  311. static const unsigned short seq_sd_amp_en[] = {
  312. 0xF3, 0x37,
  313. DATA_ONLY, 0xFF,
  314. /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */
  315. DATA_ONLY, 0x80,
  316. DATA_ONLY, 0x00,
  317. DATA_ONLY, 0x03,
  318. /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */
  319. ENDDEF, 0x00
  320. };
  321. static const unsigned short seq_gls_en[] = {
  322. 0xF3, 0x37,
  323. DATA_ONLY, 0xFF,
  324. /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */
  325. DATA_ONLY, 0x81,
  326. DATA_ONLY, 0x00,
  327. DATA_ONLY, 0x03,
  328. /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */
  329. ENDDEF, 0x00
  330. };
  331. static const unsigned short seq_els_en[] = {
  332. 0xF3, 0x37,
  333. DATA_ONLY, 0xFF,
  334. /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */
  335. DATA_ONLY, 0x83,
  336. DATA_ONLY, 0x00,
  337. DATA_ONLY, 0x03,
  338. /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */
  339. ENDDEF, 0x00
  340. };
  341. static const unsigned short seq_el_on[] = {
  342. 0xF3, 0x37,
  343. DATA_ONLY, 0xFF,
  344. /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */
  345. DATA_ONLY, 0x87,
  346. DATA_ONLY, 0x00,
  347. DATA_ONLY, 0x03,
  348. /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */
  349. ENDDEF, 0x00
  350. };
  351. static int ld9040_spi_write_byte(struct ld9040 *lcd, int addr, int data)
  352. {
  353. u16 buf[1];
  354. struct spi_message msg;
  355. struct spi_transfer xfer = {
  356. .len = 2,
  357. .tx_buf = buf,
  358. };
  359. buf[0] = (addr << 8) | data;
  360. spi_message_init(&msg);
  361. spi_message_add_tail(&xfer, &msg);
  362. return spi_sync(lcd->spi, &msg);
  363. }
  364. static int ld9040_spi_write(struct ld9040 *lcd, unsigned char address,
  365. unsigned char command)
  366. {
  367. int ret = 0;
  368. if (address != DATA_ONLY)
  369. ret = ld9040_spi_write_byte(lcd, 0x0, address);
  370. if (command != COMMAND_ONLY)
  371. ret = ld9040_spi_write_byte(lcd, 0x1, command);
  372. return ret;
  373. }
  374. static int ld9040_panel_send_sequence(struct ld9040 *lcd,
  375. const unsigned short *wbuf)
  376. {
  377. int ret = 0, i = 0;
  378. while ((wbuf[i] & DEFMASK) != ENDDEF) {
  379. if ((wbuf[i] & DEFMASK) != SLEEPMSEC) {
  380. ret = ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]);
  381. if (ret)
  382. break;
  383. } else {
  384. msleep(wbuf[i+1]);
  385. }
  386. i += 2;
  387. }
  388. return ret;
  389. }
  390. static int _ld9040_gamma_ctl(struct ld9040 *lcd, const unsigned int *gamma)
  391. {
  392. unsigned int i = 0;
  393. int ret = 0;
  394. /* start gamma table updating. */
  395. ret = ld9040_panel_send_sequence(lcd, seq_gamma_start);
  396. if (ret) {
  397. dev_err(lcd->dev, "failed to disable gamma table updating.\n");
  398. goto gamma_err;
  399. }
  400. for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) {
  401. ret = ld9040_spi_write(lcd, DATA_ONLY, gamma[i]);
  402. if (ret) {
  403. dev_err(lcd->dev, "failed to set gamma table.\n");
  404. goto gamma_err;
  405. }
  406. }
  407. /* update gamma table. */
  408. ret = ld9040_panel_send_sequence(lcd, seq_gamma_ctrl);
  409. if (ret)
  410. dev_err(lcd->dev, "failed to update gamma table.\n");
  411. gamma_err:
  412. return ret;
  413. }
  414. static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma)
  415. {
  416. return _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
  417. }
  418. static int ld9040_ldi_init(struct ld9040 *lcd)
  419. {
  420. int ret, i;
  421. static const unsigned short *init_seq[] = {
  422. seq_user_setting,
  423. seq_panel_condition,
  424. seq_display_ctrl,
  425. seq_manual_pwr,
  426. seq_elvss_on,
  427. seq_gtcon,
  428. seq_gamma_set1,
  429. seq_gamma_ctrl,
  430. seq_sleep_out,
  431. };
  432. for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
  433. ret = ld9040_panel_send_sequence(lcd, init_seq[i]);
  434. /* workaround: minimum delay time for transferring CMD */
  435. usleep_range(300, 310);
  436. if (ret)
  437. break;
  438. }
  439. return ret;
  440. }
  441. static int ld9040_ldi_enable(struct ld9040 *lcd)
  442. {
  443. return ld9040_panel_send_sequence(lcd, seq_display_on);
  444. }
  445. static int ld9040_ldi_disable(struct ld9040 *lcd)
  446. {
  447. int ret;
  448. ret = ld9040_panel_send_sequence(lcd, seq_display_off);
  449. ret = ld9040_panel_send_sequence(lcd, seq_sleep_in);
  450. return ret;
  451. }
  452. static int ld9040_power_is_on(int power)
  453. {
  454. return power <= FB_BLANK_NORMAL;
  455. }
  456. static int ld9040_power_on(struct ld9040 *lcd)
  457. {
  458. int ret = 0;
  459. struct lcd_platform_data *pd;
  460. pd = lcd->lcd_pd;
  461. /* lcd power on */
  462. ld9040_regulator_enable(lcd);
  463. if (!pd->reset) {
  464. dev_err(lcd->dev, "reset is NULL.\n");
  465. return -EINVAL;
  466. } else {
  467. pd->reset(lcd->ld);
  468. msleep(pd->reset_delay);
  469. }
  470. ret = ld9040_ldi_init(lcd);
  471. if (ret) {
  472. dev_err(lcd->dev, "failed to initialize ldi.\n");
  473. return ret;
  474. }
  475. ret = ld9040_ldi_enable(lcd);
  476. if (ret) {
  477. dev_err(lcd->dev, "failed to enable ldi.\n");
  478. return ret;
  479. }
  480. return 0;
  481. }
  482. static int ld9040_power_off(struct ld9040 *lcd)
  483. {
  484. int ret;
  485. struct lcd_platform_data *pd;
  486. pd = lcd->lcd_pd;
  487. ret = ld9040_ldi_disable(lcd);
  488. if (ret) {
  489. dev_err(lcd->dev, "lcd setting failed.\n");
  490. return -EIO;
  491. }
  492. msleep(pd->power_off_delay);
  493. /* lcd power off */
  494. ld9040_regulator_disable(lcd);
  495. return 0;
  496. }
  497. static int ld9040_power(struct ld9040 *lcd, int power)
  498. {
  499. int ret = 0;
  500. if (ld9040_power_is_on(power) && !ld9040_power_is_on(lcd->power))
  501. ret = ld9040_power_on(lcd);
  502. else if (!ld9040_power_is_on(power) && ld9040_power_is_on(lcd->power))
  503. ret = ld9040_power_off(lcd);
  504. if (!ret)
  505. lcd->power = power;
  506. return ret;
  507. }
  508. static int ld9040_set_power(struct lcd_device *ld, int power)
  509. {
  510. struct ld9040 *lcd = lcd_get_data(ld);
  511. if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
  512. power != FB_BLANK_NORMAL) {
  513. dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
  514. return -EINVAL;
  515. }
  516. return ld9040_power(lcd, power);
  517. }
  518. static int ld9040_get_power(struct lcd_device *ld)
  519. {
  520. struct ld9040 *lcd = lcd_get_data(ld);
  521. return lcd->power;
  522. }
  523. static int ld9040_get_brightness(struct backlight_device *bd)
  524. {
  525. return bd->props.brightness;
  526. }
  527. static int ld9040_set_brightness(struct backlight_device *bd)
  528. {
  529. int ret = 0, brightness = bd->props.brightness;
  530. struct ld9040 *lcd = bl_get_data(bd);
  531. if (brightness < MIN_BRIGHTNESS ||
  532. brightness > bd->props.max_brightness) {
  533. dev_err(&bd->dev, "lcd brightness should be %d to %d.\n",
  534. MIN_BRIGHTNESS, MAX_BRIGHTNESS);
  535. return -EINVAL;
  536. }
  537. ret = ld9040_gamma_ctl(lcd, bd->props.brightness);
  538. if (ret) {
  539. dev_err(&bd->dev, "lcd brightness setting failed.\n");
  540. return -EIO;
  541. }
  542. return ret;
  543. }
  544. static struct lcd_ops ld9040_lcd_ops = {
  545. .set_power = ld9040_set_power,
  546. .get_power = ld9040_get_power,
  547. };
  548. static const struct backlight_ops ld9040_backlight_ops = {
  549. .get_brightness = ld9040_get_brightness,
  550. .update_status = ld9040_set_brightness,
  551. };
  552. static int ld9040_probe(struct spi_device *spi)
  553. {
  554. int ret = 0;
  555. struct ld9040 *lcd = NULL;
  556. struct lcd_device *ld = NULL;
  557. struct backlight_device *bd = NULL;
  558. struct backlight_properties props;
  559. lcd = devm_kzalloc(&spi->dev, sizeof(struct ld9040), GFP_KERNEL);
  560. if (!lcd)
  561. return -ENOMEM;
  562. /* ld9040 lcd panel uses 3-wire 9bits SPI Mode. */
  563. spi->bits_per_word = 9;
  564. ret = spi_setup(spi);
  565. if (ret < 0) {
  566. dev_err(&spi->dev, "spi setup failed.\n");
  567. return ret;
  568. }
  569. lcd->spi = spi;
  570. lcd->dev = &spi->dev;
  571. lcd->lcd_pd = spi->dev.platform_data;
  572. if (!lcd->lcd_pd) {
  573. dev_err(&spi->dev, "platform data is NULL.\n");
  574. return -EINVAL;
  575. }
  576. mutex_init(&lcd->lock);
  577. ret = devm_regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
  578. if (ret) {
  579. dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
  580. return ret;
  581. }
  582. ld = lcd_device_register("ld9040", &spi->dev, lcd, &ld9040_lcd_ops);
  583. if (IS_ERR(ld))
  584. return PTR_ERR(ld);
  585. lcd->ld = ld;
  586. memset(&props, 0, sizeof(struct backlight_properties));
  587. props.type = BACKLIGHT_RAW;
  588. props.max_brightness = MAX_BRIGHTNESS;
  589. bd = backlight_device_register("ld9040-bl", &spi->dev,
  590. lcd, &ld9040_backlight_ops, &props);
  591. if (IS_ERR(bd)) {
  592. ret = PTR_ERR(bd);
  593. goto out_unregister_lcd;
  594. }
  595. bd->props.brightness = MAX_BRIGHTNESS;
  596. lcd->bd = bd;
  597. /*
  598. * if lcd panel was on from bootloader like u-boot then
  599. * do not lcd on.
  600. */
  601. if (!lcd->lcd_pd->lcd_enabled) {
  602. /*
  603. * if lcd panel was off from bootloader then
  604. * current lcd status is powerdown and then
  605. * it enables lcd panel.
  606. */
  607. lcd->power = FB_BLANK_POWERDOWN;
  608. ld9040_power(lcd, FB_BLANK_UNBLANK);
  609. } else {
  610. lcd->power = FB_BLANK_UNBLANK;
  611. }
  612. spi_set_drvdata(spi, lcd);
  613. dev_info(&spi->dev, "ld9040 panel driver has been probed.\n");
  614. return 0;
  615. out_unregister_lcd:
  616. lcd_device_unregister(lcd->ld);
  617. return ret;
  618. }
  619. static int ld9040_remove(struct spi_device *spi)
  620. {
  621. struct ld9040 *lcd = spi_get_drvdata(spi);
  622. ld9040_power(lcd, FB_BLANK_POWERDOWN);
  623. backlight_device_unregister(lcd->bd);
  624. lcd_device_unregister(lcd->ld);
  625. return 0;
  626. }
  627. #if defined(CONFIG_PM)
  628. static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg)
  629. {
  630. struct ld9040 *lcd = spi_get_drvdata(spi);
  631. dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
  632. /*
  633. * when lcd panel is suspend, lcd panel becomes off
  634. * regardless of status.
  635. */
  636. return ld9040_power(lcd, FB_BLANK_POWERDOWN);
  637. }
  638. static int ld9040_resume(struct spi_device *spi)
  639. {
  640. struct ld9040 *lcd = spi_get_drvdata(spi);
  641. lcd->power = FB_BLANK_POWERDOWN;
  642. return ld9040_power(lcd, FB_BLANK_UNBLANK);
  643. }
  644. #else
  645. #define ld9040_suspend NULL
  646. #define ld9040_resume NULL
  647. #endif
  648. /* Power down all displays on reboot, poweroff or halt. */
  649. static void ld9040_shutdown(struct spi_device *spi)
  650. {
  651. struct ld9040 *lcd = spi_get_drvdata(spi);
  652. ld9040_power(lcd, FB_BLANK_POWERDOWN);
  653. }
  654. static struct spi_driver ld9040_driver = {
  655. .driver = {
  656. .name = "ld9040",
  657. .owner = THIS_MODULE,
  658. },
  659. .probe = ld9040_probe,
  660. .remove = ld9040_remove,
  661. .shutdown = ld9040_shutdown,
  662. .suspend = ld9040_suspend,
  663. .resume = ld9040_resume,
  664. };
  665. module_spi_driver(ld9040_driver);
  666. MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
  667. MODULE_DESCRIPTION("ld9040 LCD Driver");
  668. MODULE_LICENSE("GPL");