ld9040.c 16 KB

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