panel-picodlp.c 14 KB

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