ld9040.c 15 KB

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