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