panel-picodlp.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. /*
  2. * picodlp panel driver
  3. * picodlp_i2c_driver: i2c_client driver
  4. *
  5. * Copyright (C) 2009-2011 Texas Instruments
  6. * Author: Mythri P K <mythripk@ti.com>
  7. * Mayuresh Janorkar <mayur@ti.com>
  8. *
  9. * This program is free software; you can redistribute it and/or modify it
  10. * under the terms of the GNU General Public License version 2 as published by
  11. * the Free Software Foundation.
  12. *
  13. * This program is distributed in the hope that it will be useful, but WITHOUT
  14. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16. * more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along with
  19. * this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include <linux/input.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/interrupt.h>
  24. #include <linux/firmware.h>
  25. #include <linux/slab.h>
  26. #include <linux/mutex.h>
  27. #include <linux/i2c.h>
  28. #include <linux/delay.h>
  29. #include <linux/gpio.h>
  30. #include <video/omapdss.h>
  31. #include <video/omap-panel-picodlp.h>
  32. #include "panel-picodlp.h"
  33. struct picodlp_data {
  34. struct mutex lock;
  35. struct i2c_client *picodlp_i2c_client;
  36. };
  37. static struct i2c_board_info picodlp_i2c_board_info = {
  38. I2C_BOARD_INFO("picodlp_i2c_driver", 0x1b),
  39. };
  40. struct picodlp_i2c_data {
  41. struct mutex xfer_lock;
  42. };
  43. static struct i2c_device_id picodlp_i2c_id[] = {
  44. { "picodlp_i2c_driver", 0 },
  45. };
  46. struct picodlp_i2c_command {
  47. u8 reg;
  48. u32 value;
  49. };
  50. static struct omap_video_timings pico_ls_timings = {
  51. .x_res = 864,
  52. .y_res = 480,
  53. .hsw = 7,
  54. .hfp = 11,
  55. .hbp = 7,
  56. .pixel_clock = 19200,
  57. .vsw = 2,
  58. .vfp = 3,
  59. .vbp = 14,
  60. };
  61. static inline struct picodlp_panel_data
  62. *get_panel_data(const struct omap_dss_device *dssdev)
  63. {
  64. return (struct picodlp_panel_data *) dssdev->data;
  65. }
  66. static u32 picodlp_i2c_read(struct i2c_client *client, u8 reg)
  67. {
  68. u8 read_cmd[] = {READ_REG_SELECT, reg}, data[4];
  69. struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client);
  70. struct i2c_msg msg[2];
  71. mutex_lock(&picodlp_i2c_data->xfer_lock);
  72. msg[0].addr = client->addr;
  73. msg[0].flags = 0;
  74. msg[0].len = 2;
  75. msg[0].buf = read_cmd;
  76. msg[1].addr = client->addr;
  77. msg[1].flags = I2C_M_RD;
  78. msg[1].len = 4;
  79. msg[1].buf = data;
  80. i2c_transfer(client->adapter, msg, 2);
  81. mutex_unlock(&picodlp_i2c_data->xfer_lock);
  82. return (data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24));
  83. }
  84. static int picodlp_i2c_write_block(struct i2c_client *client,
  85. u8 *data, int len)
  86. {
  87. struct i2c_msg msg;
  88. int i, r, msg_count = 1;
  89. struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client);
  90. if (len < 1 || len > 32) {
  91. dev_err(&client->dev,
  92. "too long syn_write_block len %d\n", len);
  93. return -EIO;
  94. }
  95. mutex_lock(&picodlp_i2c_data->xfer_lock);
  96. msg.addr = client->addr;
  97. msg.flags = 0;
  98. msg.len = len;
  99. msg.buf = data;
  100. r = i2c_transfer(client->adapter, &msg, msg_count);
  101. mutex_unlock(&picodlp_i2c_data->xfer_lock);
  102. /*
  103. * i2c_transfer returns:
  104. * number of messages sent in case of success
  105. * a negative error number in case of failure
  106. */
  107. if (r != msg_count)
  108. goto err;
  109. /* In case of success */
  110. for (i = 0; i < len; i++)
  111. dev_dbg(&client->dev,
  112. "addr %x bw 0x%02x[%d]: 0x%02x\n",
  113. client->addr, data[0] + i, i, data[i]);
  114. return 0;
  115. err:
  116. dev_err(&client->dev, "picodlp_i2c_write error\n");
  117. return r;
  118. }
  119. static int picodlp_i2c_write(struct i2c_client *client, u8 reg, u32 value)
  120. {
  121. u8 data[5];
  122. int i;
  123. data[0] = reg;
  124. for (i = 1; i < 5; i++)
  125. data[i] = (value >> (32 - (i) * 8)) & 0xFF;
  126. return picodlp_i2c_write_block(client, data, 5);
  127. }
  128. static int picodlp_i2c_write_array(struct i2c_client *client,
  129. const struct picodlp_i2c_command commands[],
  130. int count)
  131. {
  132. int i, r = 0;
  133. for (i = 0; i < count; i++) {
  134. r = picodlp_i2c_write(client, commands[i].reg,
  135. commands[i].value);
  136. if (r)
  137. return r;
  138. }
  139. return r;
  140. }
  141. static int picodlp_wait_for_dma_done(struct i2c_client *client)
  142. {
  143. u8 trial = 100;
  144. do {
  145. msleep(1);
  146. if (!trial--)
  147. return -ETIMEDOUT;
  148. } while (picodlp_i2c_read(client, MAIN_STATUS) & DMA_STATUS);
  149. return 0;
  150. }
  151. /**
  152. * picodlp_i2c_init: i2c_initialization routine
  153. * client: i2c_client for communication
  154. *
  155. * return
  156. * 0 : Success, no error
  157. * error code : Failure
  158. */
  159. static int picodlp_i2c_init(struct i2c_client *client)
  160. {
  161. int r;
  162. static const struct picodlp_i2c_command init_cmd_set1[] = {
  163. {SOFT_RESET, 1},
  164. {DMD_PARK_TRIGGER, 1},
  165. {MISC_REG, 5},
  166. {SEQ_CONTROL, 0},
  167. {SEQ_VECTOR, 0x100},
  168. {DMD_BLOCK_COUNT, 7},
  169. {DMD_VCC_CONTROL, 0x109},
  170. {DMD_PARK_PULSE_COUNT, 0xA},
  171. {DMD_PARK_PULSE_WIDTH, 0xB},
  172. {DMD_PARK_DELAY, 0x2ED},
  173. {DMD_SHADOW_ENABLE, 0},
  174. {FLASH_OPCODE, 0xB},
  175. {FLASH_DUMMY_BYTES, 1},
  176. {FLASH_ADDR_BYTES, 3},
  177. {PBC_CONTROL, 0},
  178. {FLASH_START_ADDR, CMT_LUT_0_START_ADDR},
  179. {FLASH_READ_BYTES, CMT_LUT_0_SIZE},
  180. {CMT_SPLASH_LUT_START_ADDR, 0},
  181. {CMT_SPLASH_LUT_DEST_SELECT, CMT_LUT_ALL},
  182. {PBC_CONTROL, 1},
  183. };
  184. static const struct picodlp_i2c_command init_cmd_set2[] = {
  185. {PBC_CONTROL, 0},
  186. {CMT_SPLASH_LUT_DEST_SELECT, 0},
  187. {PBC_CONTROL, 0},
  188. {FLASH_START_ADDR, SEQUENCE_0_START_ADDR},
  189. {FLASH_READ_BYTES, SEQUENCE_0_SIZE},
  190. {SEQ_RESET_LUT_START_ADDR, 0},
  191. {SEQ_RESET_LUT_DEST_SELECT, SEQ_SEQ_LUT},
  192. {PBC_CONTROL, 1},
  193. };
  194. static const struct picodlp_i2c_command init_cmd_set3[] = {
  195. {PBC_CONTROL, 0},
  196. {SEQ_RESET_LUT_DEST_SELECT, 0},
  197. {PBC_CONTROL, 0},
  198. {FLASH_START_ADDR, DRC_TABLE_0_START_ADDR},
  199. {FLASH_READ_BYTES, DRC_TABLE_0_SIZE},
  200. {SEQ_RESET_LUT_START_ADDR, 0},
  201. {SEQ_RESET_LUT_DEST_SELECT, SEQ_DRC_LUT_ALL},
  202. {PBC_CONTROL, 1},
  203. };
  204. static const struct picodlp_i2c_command init_cmd_set4[] = {
  205. {PBC_CONTROL, 0},
  206. {SEQ_RESET_LUT_DEST_SELECT, 0},
  207. {SDC_ENABLE, 1},
  208. {AGC_CTRL, 7},
  209. {CCA_C1A, 0x100},
  210. {CCA_C1B, 0x0},
  211. {CCA_C1C, 0x0},
  212. {CCA_C2A, 0x0},
  213. {CCA_C2B, 0x100},
  214. {CCA_C2C, 0x0},
  215. {CCA_C3A, 0x0},
  216. {CCA_C3B, 0x0},
  217. {CCA_C3C, 0x100},
  218. {CCA_C7A, 0x100},
  219. {CCA_C7B, 0x100},
  220. {CCA_C7C, 0x100},
  221. {CCA_ENABLE, 1},
  222. {CPU_IF_MODE, 1},
  223. {SHORT_FLIP, 1},
  224. {CURTAIN_CONTROL, 0},
  225. {DMD_PARK_TRIGGER, 0},
  226. {R_DRIVE_CURRENT, 0x298},
  227. {G_DRIVE_CURRENT, 0x298},
  228. {B_DRIVE_CURRENT, 0x298},
  229. {RGB_DRIVER_ENABLE, 7},
  230. {SEQ_CONTROL, 0},
  231. {ACTGEN_CONTROL, 0x10},
  232. {SEQUENCE_MODE, SEQ_LOCK},
  233. {DATA_FORMAT, RGB888},
  234. {INPUT_RESOLUTION, WVGA_864_LANDSCAPE},
  235. {INPUT_SOURCE, PARALLEL_RGB},
  236. {CPU_IF_SYNC_METHOD, 1},
  237. {SEQ_CONTROL, 1}
  238. };
  239. r = picodlp_i2c_write_array(client, init_cmd_set1,
  240. ARRAY_SIZE(init_cmd_set1));
  241. if (r)
  242. return r;
  243. r = picodlp_wait_for_dma_done(client);
  244. if (r)
  245. return r;
  246. r = picodlp_i2c_write_array(client, init_cmd_set2,
  247. ARRAY_SIZE(init_cmd_set2));
  248. if (r)
  249. return r;
  250. r = picodlp_wait_for_dma_done(client);
  251. if (r)
  252. return r;
  253. r = picodlp_i2c_write_array(client, init_cmd_set3,
  254. ARRAY_SIZE(init_cmd_set3));
  255. if (r)
  256. return r;
  257. r = picodlp_wait_for_dma_done(client);
  258. if (r)
  259. return r;
  260. r = picodlp_i2c_write_array(client, init_cmd_set4,
  261. ARRAY_SIZE(init_cmd_set4));
  262. if (r)
  263. return r;
  264. return 0;
  265. }
  266. static int picodlp_i2c_probe(struct i2c_client *client,
  267. const struct i2c_device_id *id)
  268. {
  269. struct picodlp_i2c_data *picodlp_i2c_data;
  270. picodlp_i2c_data = kzalloc(sizeof(struct picodlp_i2c_data), GFP_KERNEL);
  271. if (!picodlp_i2c_data)
  272. return -ENOMEM;
  273. mutex_init(&picodlp_i2c_data->xfer_lock);
  274. i2c_set_clientdata(client, picodlp_i2c_data);
  275. return 0;
  276. }
  277. static int picodlp_i2c_remove(struct i2c_client *client)
  278. {
  279. struct picodlp_i2c_data *picodlp_i2c_data =
  280. i2c_get_clientdata(client);
  281. kfree(picodlp_i2c_data);
  282. return 0;
  283. }
  284. static struct i2c_driver picodlp_i2c_driver = {
  285. .driver = {
  286. .name = "picodlp_i2c_driver",
  287. },
  288. .probe = picodlp_i2c_probe,
  289. .remove = picodlp_i2c_remove,
  290. .id_table = picodlp_i2c_id,
  291. };
  292. static int picodlp_panel_power_on(struct omap_dss_device *dssdev)
  293. {
  294. int r, trial = 100;
  295. struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
  296. struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev);
  297. if (dssdev->platform_enable) {
  298. r = dssdev->platform_enable(dssdev);
  299. if (r)
  300. return r;
  301. }
  302. gpio_set_value(picodlp_pdata->pwrgood_gpio, 0);
  303. msleep(1);
  304. gpio_set_value(picodlp_pdata->pwrgood_gpio, 1);
  305. while (!gpio_get_value(picodlp_pdata->emu_done_gpio)) {
  306. if (!trial--) {
  307. dev_err(&dssdev->dev, "emu_done signal not"
  308. " going high\n");
  309. return -ETIMEDOUT;
  310. }
  311. msleep(5);
  312. }
  313. /*
  314. * As per dpp2600 programming guide,
  315. * it is required to sleep for 1000ms after emu_done signal goes high
  316. * then only i2c commands can be successfully sent to dpp2600
  317. */
  318. msleep(1000);
  319. r = omapdss_dpi_display_enable(dssdev);
  320. if (r) {
  321. dev_err(&dssdev->dev, "failed to enable DPI\n");
  322. goto err1;
  323. }
  324. r = picodlp_i2c_init(picod->picodlp_i2c_client);
  325. if (r)
  326. goto err;
  327. dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
  328. return r;
  329. err:
  330. omapdss_dpi_display_disable(dssdev);
  331. err1:
  332. if (dssdev->platform_disable)
  333. dssdev->platform_disable(dssdev);
  334. return r;
  335. }
  336. static void picodlp_panel_power_off(struct omap_dss_device *dssdev)
  337. {
  338. struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev);
  339. omapdss_dpi_display_disable(dssdev);
  340. gpio_set_value(picodlp_pdata->emu_done_gpio, 0);
  341. gpio_set_value(picodlp_pdata->pwrgood_gpio, 0);
  342. if (dssdev->platform_disable)
  343. dssdev->platform_disable(dssdev);
  344. }
  345. static int picodlp_panel_probe(struct omap_dss_device *dssdev)
  346. {
  347. struct picodlp_data *picod;
  348. struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev);
  349. struct i2c_adapter *adapter;
  350. struct i2c_client *picodlp_i2c_client;
  351. int r = 0, picodlp_adapter_id;
  352. dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_ONOFF |
  353. OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IVS;
  354. dssdev->panel.acb = 0x0;
  355. dssdev->panel.timings = pico_ls_timings;
  356. picod = kzalloc(sizeof(struct picodlp_data), GFP_KERNEL);
  357. if (!picod)
  358. return -ENOMEM;
  359. mutex_init(&picod->lock);
  360. picodlp_adapter_id = picodlp_pdata->picodlp_adapter_id;
  361. adapter = i2c_get_adapter(picodlp_adapter_id);
  362. if (!adapter) {
  363. dev_err(&dssdev->dev, "can't get i2c adapter\n");
  364. r = -ENODEV;
  365. goto err;
  366. }
  367. picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info);
  368. if (!picodlp_i2c_client) {
  369. dev_err(&dssdev->dev, "can't add i2c device::"
  370. " picodlp_i2c_client is NULL\n");
  371. r = -ENODEV;
  372. goto err;
  373. }
  374. picod->picodlp_i2c_client = picodlp_i2c_client;
  375. dev_set_drvdata(&dssdev->dev, picod);
  376. return r;
  377. err:
  378. kfree(picod);
  379. return r;
  380. }
  381. static void picodlp_panel_remove(struct omap_dss_device *dssdev)
  382. {
  383. struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
  384. i2c_unregister_device(picod->picodlp_i2c_client);
  385. dev_set_drvdata(&dssdev->dev, NULL);
  386. dev_dbg(&dssdev->dev, "removing picodlp panel\n");
  387. kfree(picod);
  388. }
  389. static int picodlp_panel_enable(struct omap_dss_device *dssdev)
  390. {
  391. struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
  392. int r;
  393. dev_dbg(&dssdev->dev, "enabling picodlp panel\n");
  394. mutex_lock(&picod->lock);
  395. if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
  396. mutex_unlock(&picod->lock);
  397. return -EINVAL;
  398. }
  399. r = picodlp_panel_power_on(dssdev);
  400. mutex_unlock(&picod->lock);
  401. return r;
  402. }
  403. static void picodlp_panel_disable(struct omap_dss_device *dssdev)
  404. {
  405. struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
  406. mutex_lock(&picod->lock);
  407. /* Turn off DLP Power */
  408. if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
  409. picodlp_panel_power_off(dssdev);
  410. dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
  411. mutex_unlock(&picod->lock);
  412. dev_dbg(&dssdev->dev, "disabling picodlp panel\n");
  413. }
  414. static int picodlp_panel_suspend(struct omap_dss_device *dssdev)
  415. {
  416. struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
  417. mutex_lock(&picod->lock);
  418. /* Turn off DLP Power */
  419. if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
  420. mutex_unlock(&picod->lock);
  421. dev_err(&dssdev->dev, "unable to suspend picodlp panel,"
  422. " panel is not ACTIVE\n");
  423. return -EINVAL;
  424. }
  425. picodlp_panel_power_off(dssdev);
  426. dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
  427. mutex_unlock(&picod->lock);
  428. dev_dbg(&dssdev->dev, "suspending picodlp panel\n");
  429. return 0;
  430. }
  431. static int picodlp_panel_resume(struct omap_dss_device *dssdev)
  432. {
  433. struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
  434. int r;
  435. mutex_lock(&picod->lock);
  436. if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
  437. mutex_unlock(&picod->lock);
  438. dev_err(&dssdev->dev, "unable to resume picodlp panel,"
  439. " panel is not ACTIVE\n");
  440. return -EINVAL;
  441. }
  442. r = picodlp_panel_power_on(dssdev);
  443. mutex_unlock(&picod->lock);
  444. dev_dbg(&dssdev->dev, "resuming picodlp panel\n");
  445. return r;
  446. }
  447. static void picodlp_get_resolution(struct omap_dss_device *dssdev,
  448. u16 *xres, u16 *yres)
  449. {
  450. *xres = dssdev->panel.timings.x_res;
  451. *yres = dssdev->panel.timings.y_res;
  452. }
  453. static struct omap_dss_driver picodlp_driver = {
  454. .probe = picodlp_panel_probe,
  455. .remove = picodlp_panel_remove,
  456. .enable = picodlp_panel_enable,
  457. .disable = picodlp_panel_disable,
  458. .get_resolution = picodlp_get_resolution,
  459. .suspend = picodlp_panel_suspend,
  460. .resume = picodlp_panel_resume,
  461. .driver = {
  462. .name = "picodlp_panel",
  463. .owner = THIS_MODULE,
  464. },
  465. };
  466. static int __init picodlp_init(void)
  467. {
  468. int r = 0;
  469. r = i2c_add_driver(&picodlp_i2c_driver);
  470. if (r) {
  471. printk(KERN_WARNING "picodlp_i2c_driver" \
  472. " registration failed\n");
  473. return r;
  474. }
  475. r = omap_dss_register_driver(&picodlp_driver);
  476. if (r)
  477. i2c_del_driver(&picodlp_i2c_driver);
  478. return r;
  479. }
  480. static void __exit picodlp_exit(void)
  481. {
  482. i2c_del_driver(&picodlp_i2c_driver);
  483. omap_dss_unregister_driver(&picodlp_driver);
  484. }
  485. module_init(picodlp_init);
  486. module_exit(picodlp_exit);
  487. MODULE_AUTHOR("Mythri P K <mythripk@ti.com>");
  488. MODULE_DESCRIPTION("picodlp driver");
  489. MODULE_LICENSE("GPL");