s6e63m0.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. /*
  2. * S6E63M0 AMOLED LCD panel driver.
  3. *
  4. * Author: InKi Dae <inki.dae@samsung.com>
  5. *
  6. * Derived from drivers/video/omap/lcd-apollon.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/spi/spi.h>
  23. #include <linux/wait.h>
  24. #include "s6e63m0_gamma.h"
  25. #define SLEEPMSEC 0x1000
  26. #define ENDDEF 0x2000
  27. #define DEFMASK 0xFF00
  28. #define COMMAND_ONLY 0xFE
  29. #define DATA_ONLY 0xFF
  30. #define MIN_BRIGHTNESS 0
  31. #define MAX_BRIGHTNESS 10
  32. struct s6e63m0 {
  33. struct device *dev;
  34. struct spi_device *spi;
  35. unsigned int power;
  36. unsigned int current_brightness;
  37. unsigned int gamma_mode;
  38. unsigned int gamma_table_count;
  39. struct lcd_device *ld;
  40. struct backlight_device *bd;
  41. struct lcd_platform_data *lcd_pd;
  42. };
  43. static const unsigned short seq_panel_condition_set[] = {
  44. 0xF8, 0x01,
  45. DATA_ONLY, 0x27,
  46. DATA_ONLY, 0x27,
  47. DATA_ONLY, 0x07,
  48. DATA_ONLY, 0x07,
  49. DATA_ONLY, 0x54,
  50. DATA_ONLY, 0x9f,
  51. DATA_ONLY, 0x63,
  52. DATA_ONLY, 0x86,
  53. DATA_ONLY, 0x1a,
  54. DATA_ONLY, 0x33,
  55. DATA_ONLY, 0x0d,
  56. DATA_ONLY, 0x00,
  57. DATA_ONLY, 0x00,
  58. ENDDEF, 0x0000
  59. };
  60. static const unsigned short seq_display_condition_set[] = {
  61. 0xf2, 0x02,
  62. DATA_ONLY, 0x03,
  63. DATA_ONLY, 0x1c,
  64. DATA_ONLY, 0x10,
  65. DATA_ONLY, 0x10,
  66. 0xf7, 0x03,
  67. DATA_ONLY, 0x00,
  68. DATA_ONLY, 0x00,
  69. ENDDEF, 0x0000
  70. };
  71. static const unsigned short seq_gamma_setting[] = {
  72. 0xfa, 0x00,
  73. DATA_ONLY, 0x18,
  74. DATA_ONLY, 0x08,
  75. DATA_ONLY, 0x24,
  76. DATA_ONLY, 0x64,
  77. DATA_ONLY, 0x56,
  78. DATA_ONLY, 0x33,
  79. DATA_ONLY, 0xb6,
  80. DATA_ONLY, 0xba,
  81. DATA_ONLY, 0xa8,
  82. DATA_ONLY, 0xac,
  83. DATA_ONLY, 0xb1,
  84. DATA_ONLY, 0x9d,
  85. DATA_ONLY, 0xc1,
  86. DATA_ONLY, 0xc1,
  87. DATA_ONLY, 0xb7,
  88. DATA_ONLY, 0x00,
  89. DATA_ONLY, 0x9c,
  90. DATA_ONLY, 0x00,
  91. DATA_ONLY, 0x9f,
  92. DATA_ONLY, 0x00,
  93. DATA_ONLY, 0xd6,
  94. 0xfa, 0x01,
  95. ENDDEF, 0x0000
  96. };
  97. static const unsigned short seq_etc_condition_set[] = {
  98. 0xf6, 0x00,
  99. DATA_ONLY, 0x8c,
  100. DATA_ONLY, 0x07,
  101. 0xb3, 0xc,
  102. 0xb5, 0x2c,
  103. DATA_ONLY, 0x12,
  104. DATA_ONLY, 0x0c,
  105. DATA_ONLY, 0x0a,
  106. DATA_ONLY, 0x10,
  107. DATA_ONLY, 0x0e,
  108. DATA_ONLY, 0x17,
  109. DATA_ONLY, 0x13,
  110. DATA_ONLY, 0x1f,
  111. DATA_ONLY, 0x1a,
  112. DATA_ONLY, 0x2a,
  113. DATA_ONLY, 0x24,
  114. DATA_ONLY, 0x1f,
  115. DATA_ONLY, 0x1b,
  116. DATA_ONLY, 0x1a,
  117. DATA_ONLY, 0x17,
  118. DATA_ONLY, 0x2b,
  119. DATA_ONLY, 0x26,
  120. DATA_ONLY, 0x22,
  121. DATA_ONLY, 0x20,
  122. DATA_ONLY, 0x3a,
  123. DATA_ONLY, 0x34,
  124. DATA_ONLY, 0x30,
  125. DATA_ONLY, 0x2c,
  126. DATA_ONLY, 0x29,
  127. DATA_ONLY, 0x26,
  128. DATA_ONLY, 0x25,
  129. DATA_ONLY, 0x23,
  130. DATA_ONLY, 0x21,
  131. DATA_ONLY, 0x20,
  132. DATA_ONLY, 0x1e,
  133. DATA_ONLY, 0x1e,
  134. 0xb6, 0x00,
  135. DATA_ONLY, 0x00,
  136. DATA_ONLY, 0x11,
  137. DATA_ONLY, 0x22,
  138. DATA_ONLY, 0x33,
  139. DATA_ONLY, 0x44,
  140. DATA_ONLY, 0x44,
  141. DATA_ONLY, 0x44,
  142. DATA_ONLY, 0x55,
  143. DATA_ONLY, 0x55,
  144. DATA_ONLY, 0x66,
  145. DATA_ONLY, 0x66,
  146. DATA_ONLY, 0x66,
  147. DATA_ONLY, 0x66,
  148. DATA_ONLY, 0x66,
  149. DATA_ONLY, 0x66,
  150. 0xb7, 0x2c,
  151. DATA_ONLY, 0x12,
  152. DATA_ONLY, 0x0c,
  153. DATA_ONLY, 0x0a,
  154. DATA_ONLY, 0x10,
  155. DATA_ONLY, 0x0e,
  156. DATA_ONLY, 0x17,
  157. DATA_ONLY, 0x13,
  158. DATA_ONLY, 0x1f,
  159. DATA_ONLY, 0x1a,
  160. DATA_ONLY, 0x2a,
  161. DATA_ONLY, 0x24,
  162. DATA_ONLY, 0x1f,
  163. DATA_ONLY, 0x1b,
  164. DATA_ONLY, 0x1a,
  165. DATA_ONLY, 0x17,
  166. DATA_ONLY, 0x2b,
  167. DATA_ONLY, 0x26,
  168. DATA_ONLY, 0x22,
  169. DATA_ONLY, 0x20,
  170. DATA_ONLY, 0x3a,
  171. DATA_ONLY, 0x34,
  172. DATA_ONLY, 0x30,
  173. DATA_ONLY, 0x2c,
  174. DATA_ONLY, 0x29,
  175. DATA_ONLY, 0x26,
  176. DATA_ONLY, 0x25,
  177. DATA_ONLY, 0x23,
  178. DATA_ONLY, 0x21,
  179. DATA_ONLY, 0x20,
  180. DATA_ONLY, 0x1e,
  181. DATA_ONLY, 0x1e,
  182. 0xb8, 0x00,
  183. DATA_ONLY, 0x00,
  184. DATA_ONLY, 0x11,
  185. DATA_ONLY, 0x22,
  186. DATA_ONLY, 0x33,
  187. DATA_ONLY, 0x44,
  188. DATA_ONLY, 0x44,
  189. DATA_ONLY, 0x44,
  190. DATA_ONLY, 0x55,
  191. DATA_ONLY, 0x55,
  192. DATA_ONLY, 0x66,
  193. DATA_ONLY, 0x66,
  194. DATA_ONLY, 0x66,
  195. DATA_ONLY, 0x66,
  196. DATA_ONLY, 0x66,
  197. DATA_ONLY, 0x66,
  198. 0xb9, 0x2c,
  199. DATA_ONLY, 0x12,
  200. DATA_ONLY, 0x0c,
  201. DATA_ONLY, 0x0a,
  202. DATA_ONLY, 0x10,
  203. DATA_ONLY, 0x0e,
  204. DATA_ONLY, 0x17,
  205. DATA_ONLY, 0x13,
  206. DATA_ONLY, 0x1f,
  207. DATA_ONLY, 0x1a,
  208. DATA_ONLY, 0x2a,
  209. DATA_ONLY, 0x24,
  210. DATA_ONLY, 0x1f,
  211. DATA_ONLY, 0x1b,
  212. DATA_ONLY, 0x1a,
  213. DATA_ONLY, 0x17,
  214. DATA_ONLY, 0x2b,
  215. DATA_ONLY, 0x26,
  216. DATA_ONLY, 0x22,
  217. DATA_ONLY, 0x20,
  218. DATA_ONLY, 0x3a,
  219. DATA_ONLY, 0x34,
  220. DATA_ONLY, 0x30,
  221. DATA_ONLY, 0x2c,
  222. DATA_ONLY, 0x29,
  223. DATA_ONLY, 0x26,
  224. DATA_ONLY, 0x25,
  225. DATA_ONLY, 0x23,
  226. DATA_ONLY, 0x21,
  227. DATA_ONLY, 0x20,
  228. DATA_ONLY, 0x1e,
  229. DATA_ONLY, 0x1e,
  230. 0xba, 0x00,
  231. DATA_ONLY, 0x00,
  232. DATA_ONLY, 0x11,
  233. DATA_ONLY, 0x22,
  234. DATA_ONLY, 0x33,
  235. DATA_ONLY, 0x44,
  236. DATA_ONLY, 0x44,
  237. DATA_ONLY, 0x44,
  238. DATA_ONLY, 0x55,
  239. DATA_ONLY, 0x55,
  240. DATA_ONLY, 0x66,
  241. DATA_ONLY, 0x66,
  242. DATA_ONLY, 0x66,
  243. DATA_ONLY, 0x66,
  244. DATA_ONLY, 0x66,
  245. DATA_ONLY, 0x66,
  246. 0xc1, 0x4d,
  247. DATA_ONLY, 0x96,
  248. DATA_ONLY, 0x1d,
  249. DATA_ONLY, 0x00,
  250. DATA_ONLY, 0x00,
  251. DATA_ONLY, 0x01,
  252. DATA_ONLY, 0xdf,
  253. DATA_ONLY, 0x00,
  254. DATA_ONLY, 0x00,
  255. DATA_ONLY, 0x03,
  256. DATA_ONLY, 0x1f,
  257. DATA_ONLY, 0x00,
  258. DATA_ONLY, 0x00,
  259. DATA_ONLY, 0x00,
  260. DATA_ONLY, 0x00,
  261. DATA_ONLY, 0x00,
  262. DATA_ONLY, 0x00,
  263. DATA_ONLY, 0x00,
  264. DATA_ONLY, 0x00,
  265. DATA_ONLY, 0x03,
  266. DATA_ONLY, 0x06,
  267. DATA_ONLY, 0x09,
  268. DATA_ONLY, 0x0d,
  269. DATA_ONLY, 0x0f,
  270. DATA_ONLY, 0x12,
  271. DATA_ONLY, 0x15,
  272. DATA_ONLY, 0x18,
  273. 0xb2, 0x10,
  274. DATA_ONLY, 0x10,
  275. DATA_ONLY, 0x0b,
  276. DATA_ONLY, 0x05,
  277. ENDDEF, 0x0000
  278. };
  279. static const unsigned short seq_acl_on[] = {
  280. /* ACL on */
  281. 0xc0, 0x01,
  282. ENDDEF, 0x0000
  283. };
  284. static const unsigned short seq_acl_off[] = {
  285. /* ACL off */
  286. 0xc0, 0x00,
  287. ENDDEF, 0x0000
  288. };
  289. static const unsigned short seq_elvss_on[] = {
  290. /* ELVSS on */
  291. 0xb1, 0x0b,
  292. ENDDEF, 0x0000
  293. };
  294. static const unsigned short seq_elvss_off[] = {
  295. /* ELVSS off */
  296. 0xb1, 0x0a,
  297. ENDDEF, 0x0000
  298. };
  299. static const unsigned short seq_stand_by_off[] = {
  300. 0x11, COMMAND_ONLY,
  301. ENDDEF, 0x0000
  302. };
  303. static const unsigned short seq_stand_by_on[] = {
  304. 0x10, COMMAND_ONLY,
  305. ENDDEF, 0x0000
  306. };
  307. static const unsigned short seq_display_on[] = {
  308. 0x29, COMMAND_ONLY,
  309. ENDDEF, 0x0000
  310. };
  311. static int s6e63m0_spi_write_byte(struct s6e63m0 *lcd, int addr, int data)
  312. {
  313. u16 buf[1];
  314. struct spi_message msg;
  315. struct spi_transfer xfer = {
  316. .len = 2,
  317. .tx_buf = buf,
  318. };
  319. buf[0] = (addr << 8) | data;
  320. spi_message_init(&msg);
  321. spi_message_add_tail(&xfer, &msg);
  322. return spi_sync(lcd->spi, &msg);
  323. }
  324. static int s6e63m0_spi_write(struct s6e63m0 *lcd, unsigned char address,
  325. unsigned char command)
  326. {
  327. int ret = 0;
  328. if (address != DATA_ONLY)
  329. ret = s6e63m0_spi_write_byte(lcd, 0x0, address);
  330. if (command != COMMAND_ONLY)
  331. ret = s6e63m0_spi_write_byte(lcd, 0x1, command);
  332. return ret;
  333. }
  334. static int s6e63m0_panel_send_sequence(struct s6e63m0 *lcd,
  335. const unsigned short *wbuf)
  336. {
  337. int ret = 0, i = 0;
  338. while ((wbuf[i] & DEFMASK) != ENDDEF) {
  339. if ((wbuf[i] & DEFMASK) != SLEEPMSEC) {
  340. ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]);
  341. if (ret)
  342. break;
  343. } else {
  344. msleep(wbuf[i+1]);
  345. }
  346. i += 2;
  347. }
  348. return ret;
  349. }
  350. static int _s6e63m0_gamma_ctl(struct s6e63m0 *lcd, const unsigned int *gamma)
  351. {
  352. unsigned int i = 0;
  353. int ret = 0;
  354. /* disable gamma table updating. */
  355. ret = s6e63m0_spi_write(lcd, 0xfa, 0x00);
  356. if (ret) {
  357. dev_err(lcd->dev, "failed to disable gamma table updating.\n");
  358. goto gamma_err;
  359. }
  360. for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) {
  361. ret = s6e63m0_spi_write(lcd, DATA_ONLY, gamma[i]);
  362. if (ret) {
  363. dev_err(lcd->dev, "failed to set gamma table.\n");
  364. goto gamma_err;
  365. }
  366. }
  367. /* update gamma table. */
  368. ret = s6e63m0_spi_write(lcd, 0xfa, 0x01);
  369. if (ret)
  370. dev_err(lcd->dev, "failed to update gamma table.\n");
  371. gamma_err:
  372. return ret;
  373. }
  374. static int s6e63m0_gamma_ctl(struct s6e63m0 *lcd, int gamma)
  375. {
  376. int ret = 0;
  377. ret = _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
  378. return ret;
  379. }
  380. static int s6e63m0_ldi_init(struct s6e63m0 *lcd)
  381. {
  382. int ret, i;
  383. const unsigned short *init_seq[] = {
  384. seq_panel_condition_set,
  385. seq_display_condition_set,
  386. seq_gamma_setting,
  387. seq_etc_condition_set,
  388. seq_acl_on,
  389. seq_elvss_on,
  390. };
  391. for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
  392. ret = s6e63m0_panel_send_sequence(lcd, init_seq[i]);
  393. if (ret)
  394. break;
  395. }
  396. return ret;
  397. }
  398. static int s6e63m0_ldi_enable(struct s6e63m0 *lcd)
  399. {
  400. int ret = 0, i;
  401. const unsigned short *enable_seq[] = {
  402. seq_stand_by_off,
  403. seq_display_on,
  404. };
  405. for (i = 0; i < ARRAY_SIZE(enable_seq); i++) {
  406. ret = s6e63m0_panel_send_sequence(lcd, enable_seq[i]);
  407. if (ret)
  408. break;
  409. }
  410. return ret;
  411. }
  412. static int s6e63m0_ldi_disable(struct s6e63m0 *lcd)
  413. {
  414. int ret;
  415. ret = s6e63m0_panel_send_sequence(lcd, seq_stand_by_on);
  416. return ret;
  417. }
  418. static int s6e63m0_power_is_on(int power)
  419. {
  420. return power <= FB_BLANK_NORMAL;
  421. }
  422. static int s6e63m0_power_on(struct s6e63m0 *lcd)
  423. {
  424. int ret = 0;
  425. struct lcd_platform_data *pd;
  426. struct backlight_device *bd;
  427. pd = lcd->lcd_pd;
  428. bd = lcd->bd;
  429. if (!pd->power_on) {
  430. dev_err(lcd->dev, "power_on is NULL.\n");
  431. return -EINVAL;
  432. }
  433. pd->power_on(lcd->ld, 1);
  434. msleep(pd->power_on_delay);
  435. if (!pd->reset) {
  436. dev_err(lcd->dev, "reset is NULL.\n");
  437. return -EINVAL;
  438. }
  439. pd->reset(lcd->ld);
  440. msleep(pd->reset_delay);
  441. ret = s6e63m0_ldi_init(lcd);
  442. if (ret) {
  443. dev_err(lcd->dev, "failed to initialize ldi.\n");
  444. return ret;
  445. }
  446. ret = s6e63m0_ldi_enable(lcd);
  447. if (ret) {
  448. dev_err(lcd->dev, "failed to enable ldi.\n");
  449. return ret;
  450. }
  451. /* set brightness to current value after power on or resume. */
  452. ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness);
  453. if (ret) {
  454. dev_err(lcd->dev, "lcd gamma setting failed.\n");
  455. return ret;
  456. }
  457. return 0;
  458. }
  459. static int s6e63m0_power_off(struct s6e63m0 *lcd)
  460. {
  461. int ret;
  462. struct lcd_platform_data *pd;
  463. pd = lcd->lcd_pd;
  464. ret = s6e63m0_ldi_disable(lcd);
  465. if (ret) {
  466. dev_err(lcd->dev, "lcd setting failed.\n");
  467. return -EIO;
  468. }
  469. msleep(pd->power_off_delay);
  470. pd->power_on(lcd->ld, 0);
  471. return 0;
  472. }
  473. static int s6e63m0_power(struct s6e63m0 *lcd, int power)
  474. {
  475. int ret = 0;
  476. if (s6e63m0_power_is_on(power) && !s6e63m0_power_is_on(lcd->power))
  477. ret = s6e63m0_power_on(lcd);
  478. else if (!s6e63m0_power_is_on(power) && s6e63m0_power_is_on(lcd->power))
  479. ret = s6e63m0_power_off(lcd);
  480. if (!ret)
  481. lcd->power = power;
  482. return ret;
  483. }
  484. static int s6e63m0_set_power(struct lcd_device *ld, int power)
  485. {
  486. struct s6e63m0 *lcd = lcd_get_data(ld);
  487. if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
  488. power != FB_BLANK_NORMAL) {
  489. dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
  490. return -EINVAL;
  491. }
  492. return s6e63m0_power(lcd, power);
  493. }
  494. static int s6e63m0_get_power(struct lcd_device *ld)
  495. {
  496. struct s6e63m0 *lcd = lcd_get_data(ld);
  497. return lcd->power;
  498. }
  499. static int s6e63m0_set_brightness(struct backlight_device *bd)
  500. {
  501. int ret = 0, brightness = bd->props.brightness;
  502. struct s6e63m0 *lcd = bl_get_data(bd);
  503. if (brightness < MIN_BRIGHTNESS ||
  504. brightness > bd->props.max_brightness) {
  505. dev_err(&bd->dev, "lcd brightness should be %d to %d.\n",
  506. MIN_BRIGHTNESS, MAX_BRIGHTNESS);
  507. return -EINVAL;
  508. }
  509. ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness);
  510. if (ret) {
  511. dev_err(&bd->dev, "lcd brightness setting failed.\n");
  512. return -EIO;
  513. }
  514. return ret;
  515. }
  516. static struct lcd_ops s6e63m0_lcd_ops = {
  517. .set_power = s6e63m0_set_power,
  518. .get_power = s6e63m0_get_power,
  519. };
  520. static const struct backlight_ops s6e63m0_backlight_ops = {
  521. .update_status = s6e63m0_set_brightness,
  522. };
  523. static ssize_t s6e63m0_sysfs_show_gamma_mode(struct device *dev,
  524. struct device_attribute *attr, char *buf)
  525. {
  526. struct s6e63m0 *lcd = dev_get_drvdata(dev);
  527. char temp[10];
  528. switch (lcd->gamma_mode) {
  529. case 0:
  530. sprintf(temp, "2.2 mode\n");
  531. strcat(buf, temp);
  532. break;
  533. case 1:
  534. sprintf(temp, "1.9 mode\n");
  535. strcat(buf, temp);
  536. break;
  537. case 2:
  538. sprintf(temp, "1.7 mode\n");
  539. strcat(buf, temp);
  540. break;
  541. default:
  542. dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7)n");
  543. break;
  544. }
  545. return strlen(buf);
  546. }
  547. static ssize_t s6e63m0_sysfs_store_gamma_mode(struct device *dev,
  548. struct device_attribute *attr,
  549. const char *buf, size_t len)
  550. {
  551. struct s6e63m0 *lcd = dev_get_drvdata(dev);
  552. struct backlight_device *bd = NULL;
  553. int brightness, rc;
  554. rc = kstrtouint(buf, 0, &lcd->gamma_mode);
  555. if (rc < 0)
  556. return rc;
  557. bd = lcd->bd;
  558. brightness = bd->props.brightness;
  559. switch (lcd->gamma_mode) {
  560. case 0:
  561. _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]);
  562. break;
  563. case 1:
  564. _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_19_table[brightness]);
  565. break;
  566. case 2:
  567. _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_17_table[brightness]);
  568. break;
  569. default:
  570. dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7\n");
  571. _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]);
  572. break;
  573. }
  574. return len;
  575. }
  576. static DEVICE_ATTR(gamma_mode, 0644,
  577. s6e63m0_sysfs_show_gamma_mode, s6e63m0_sysfs_store_gamma_mode);
  578. static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev,
  579. struct device_attribute *attr, char *buf)
  580. {
  581. struct s6e63m0 *lcd = dev_get_drvdata(dev);
  582. char temp[3];
  583. sprintf(temp, "%u\n", lcd->gamma_table_count);
  584. strcpy(buf, temp);
  585. return strlen(buf);
  586. }
  587. static DEVICE_ATTR(gamma_table, 0444,
  588. s6e63m0_sysfs_show_gamma_table, NULL);
  589. static int s6e63m0_probe(struct spi_device *spi)
  590. {
  591. int ret = 0;
  592. struct s6e63m0 *lcd = NULL;
  593. struct lcd_device *ld = NULL;
  594. struct backlight_device *bd = NULL;
  595. struct backlight_properties props;
  596. lcd = devm_kzalloc(&spi->dev, sizeof(struct s6e63m0), GFP_KERNEL);
  597. if (!lcd)
  598. return -ENOMEM;
  599. /* s6e63m0 lcd panel uses 3-wire 9bits SPI Mode. */
  600. spi->bits_per_word = 9;
  601. ret = spi_setup(spi);
  602. if (ret < 0) {
  603. dev_err(&spi->dev, "spi setup failed.\n");
  604. return ret;
  605. }
  606. lcd->spi = spi;
  607. lcd->dev = &spi->dev;
  608. lcd->lcd_pd = dev_get_platdata(&spi->dev);
  609. if (!lcd->lcd_pd) {
  610. dev_err(&spi->dev, "platform data is NULL.\n");
  611. return -EINVAL;
  612. }
  613. ld = devm_lcd_device_register(&spi->dev, "s6e63m0", &spi->dev, lcd,
  614. &s6e63m0_lcd_ops);
  615. if (IS_ERR(ld))
  616. return PTR_ERR(ld);
  617. lcd->ld = ld;
  618. memset(&props, 0, sizeof(struct backlight_properties));
  619. props.type = BACKLIGHT_RAW;
  620. props.max_brightness = MAX_BRIGHTNESS;
  621. bd = devm_backlight_device_register(&spi->dev, "s6e63m0bl-bl",
  622. &spi->dev, lcd, &s6e63m0_backlight_ops,
  623. &props);
  624. if (IS_ERR(bd))
  625. return PTR_ERR(bd);
  626. bd->props.brightness = MAX_BRIGHTNESS;
  627. lcd->bd = bd;
  628. /*
  629. * it gets gamma table count available so it gets user
  630. * know that.
  631. */
  632. lcd->gamma_table_count =
  633. sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int *));
  634. ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode);
  635. if (ret < 0)
  636. dev_err(&(spi->dev), "failed to add sysfs entries\n");
  637. ret = device_create_file(&(spi->dev), &dev_attr_gamma_table);
  638. if (ret < 0)
  639. dev_err(&(spi->dev), "failed to add sysfs entries\n");
  640. /*
  641. * if lcd panel was on from bootloader like u-boot then
  642. * do not lcd on.
  643. */
  644. if (!lcd->lcd_pd->lcd_enabled) {
  645. /*
  646. * if lcd panel was off from bootloader then
  647. * current lcd status is powerdown and then
  648. * it enables lcd panel.
  649. */
  650. lcd->power = FB_BLANK_POWERDOWN;
  651. s6e63m0_power(lcd, FB_BLANK_UNBLANK);
  652. } else {
  653. lcd->power = FB_BLANK_UNBLANK;
  654. }
  655. spi_set_drvdata(spi, lcd);
  656. dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n");
  657. return 0;
  658. }
  659. static int s6e63m0_remove(struct spi_device *spi)
  660. {
  661. struct s6e63m0 *lcd = spi_get_drvdata(spi);
  662. s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
  663. device_remove_file(&spi->dev, &dev_attr_gamma_table);
  664. device_remove_file(&spi->dev, &dev_attr_gamma_mode);
  665. return 0;
  666. }
  667. #ifdef CONFIG_PM_SLEEP
  668. static int s6e63m0_suspend(struct device *dev)
  669. {
  670. struct s6e63m0 *lcd = dev_get_drvdata(dev);
  671. dev_dbg(dev, "lcd->power = %d\n", lcd->power);
  672. /*
  673. * when lcd panel is suspend, lcd panel becomes off
  674. * regardless of status.
  675. */
  676. return s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
  677. }
  678. static int s6e63m0_resume(struct device *dev)
  679. {
  680. struct s6e63m0 *lcd = dev_get_drvdata(dev);
  681. lcd->power = FB_BLANK_POWERDOWN;
  682. return s6e63m0_power(lcd, FB_BLANK_UNBLANK);
  683. }
  684. #endif
  685. static SIMPLE_DEV_PM_OPS(s6e63m0_pm_ops, s6e63m0_suspend, s6e63m0_resume);
  686. /* Power down all displays on reboot, poweroff or halt. */
  687. static void s6e63m0_shutdown(struct spi_device *spi)
  688. {
  689. struct s6e63m0 *lcd = spi_get_drvdata(spi);
  690. s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
  691. }
  692. static struct spi_driver s6e63m0_driver = {
  693. .driver = {
  694. .name = "s6e63m0",
  695. .pm = &s6e63m0_pm_ops,
  696. },
  697. .probe = s6e63m0_probe,
  698. .remove = s6e63m0_remove,
  699. .shutdown = s6e63m0_shutdown,
  700. };
  701. module_spi_driver(s6e63m0_driver);
  702. MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
  703. MODULE_DESCRIPTION("S6E63M0 LCD Driver");
  704. MODULE_LICENSE("GPL");