linux/drivers/video/omap2/displays/panel-picodlp.c
<<
>>
Prefs
   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