linux/drivers/video/fbdev/omap/lcd_mipid.c
<<
>>
Prefs
   1/*
   2 * LCD driver for MIPI DBI-C / DCS compatible LCDs
   3 *
   4 * Copyright (C) 2006 Nokia Corporation
   5 * Author: Imre Deak <imre.deak@nokia.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License as published by the
   9 * Free Software Foundation; either version 2 of the License, or (at your
  10 * option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful, but
  13 * WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License along
  18 * with this program; if not, write to the Free Software Foundation, Inc.,
  19 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20 */
  21#include <linux/device.h>
  22#include <linux/delay.h>
  23#include <linux/slab.h>
  24#include <linux/workqueue.h>
  25#include <linux/spi/spi.h>
  26#include <linux/module.h>
  27
  28#include <linux/platform_data/lcd-mipid.h>
  29
  30#include "omapfb.h"
  31
  32#define MIPID_MODULE_NAME               "lcd_mipid"
  33
  34#define MIPID_CMD_READ_DISP_ID          0x04
  35#define MIPID_CMD_READ_RED              0x06
  36#define MIPID_CMD_READ_GREEN            0x07
  37#define MIPID_CMD_READ_BLUE             0x08
  38#define MIPID_CMD_READ_DISP_STATUS      0x09
  39#define MIPID_CMD_RDDSDR                0x0F
  40#define MIPID_CMD_SLEEP_IN              0x10
  41#define MIPID_CMD_SLEEP_OUT             0x11
  42#define MIPID_CMD_DISP_OFF              0x28
  43#define MIPID_CMD_DISP_ON               0x29
  44
  45#define MIPID_ESD_CHECK_PERIOD          msecs_to_jiffies(5000)
  46
  47#define to_mipid_device(p)              container_of(p, struct mipid_device, \
  48                                                panel)
  49struct mipid_device {
  50        int             enabled;
  51        int             revision;
  52        unsigned int    saved_bklight_level;
  53        unsigned long   hw_guard_end;           /* next value of jiffies
  54                                                   when we can issue the
  55                                                   next sleep in/out command */
  56        unsigned long   hw_guard_wait;          /* max guard time in jiffies */
  57
  58        struct omapfb_device    *fbdev;
  59        struct spi_device       *spi;
  60        struct mutex            mutex;
  61        struct lcd_panel        panel;
  62
  63        struct delayed_work     esd_work;
  64        void                    (*esd_check)(struct mipid_device *m);
  65};
  66
  67static void mipid_transfer(struct mipid_device *md, int cmd, const u8 *wbuf,
  68                           int wlen, u8 *rbuf, int rlen)
  69{
  70        struct spi_message      m;
  71        struct spi_transfer     *x, xfer[4];
  72        u16                     w;
  73        int                     r;
  74
  75        BUG_ON(md->spi == NULL);
  76
  77        spi_message_init(&m);
  78
  79        memset(xfer, 0, sizeof(xfer));
  80        x = &xfer[0];
  81
  82        cmd &=  0xff;
  83        x->tx_buf               = &cmd;
  84        x->bits_per_word        = 9;
  85        x->len                  = 2;
  86        spi_message_add_tail(x, &m);
  87
  88        if (wlen) {
  89                x++;
  90                x->tx_buf               = wbuf;
  91                x->len                  = wlen;
  92                x->bits_per_word        = 9;
  93                spi_message_add_tail(x, &m);
  94        }
  95
  96        if (rlen) {
  97                x++;
  98                x->rx_buf       = &w;
  99                x->len          = 1;
 100                spi_message_add_tail(x, &m);
 101
 102                if (rlen > 1) {
 103                        /* Arrange for the extra clock before the first
 104                         * data bit.
 105                         */
 106                        x->bits_per_word = 9;
 107                        x->len           = 2;
 108
 109                        x++;
 110                        x->rx_buf        = &rbuf[1];
 111                        x->len           = rlen - 1;
 112                        spi_message_add_tail(x, &m);
 113                }
 114        }
 115
 116        r = spi_sync(md->spi, &m);
 117        if (r < 0)
 118                dev_dbg(&md->spi->dev, "spi_sync %d\n", r);
 119
 120        if (rlen)
 121                rbuf[0] = w & 0xff;
 122}
 123
 124static inline void mipid_cmd(struct mipid_device *md, int cmd)
 125{
 126        mipid_transfer(md, cmd, NULL, 0, NULL, 0);
 127}
 128
 129static inline void mipid_write(struct mipid_device *md,
 130                               int reg, const u8 *buf, int len)
 131{
 132        mipid_transfer(md, reg, buf, len, NULL, 0);
 133}
 134
 135static inline void mipid_read(struct mipid_device *md,
 136                              int reg, u8 *buf, int len)
 137{
 138        mipid_transfer(md, reg, NULL, 0, buf, len);
 139}
 140
 141static void set_data_lines(struct mipid_device *md, int data_lines)
 142{
 143        u16 par;
 144
 145        switch (data_lines) {
 146        case 16:
 147                par = 0x150;
 148                break;
 149        case 18:
 150                par = 0x160;
 151                break;
 152        case 24:
 153                par = 0x170;
 154                break;
 155        }
 156        mipid_write(md, 0x3a, (u8 *)&par, 2);
 157}
 158
 159static void send_init_string(struct mipid_device *md)
 160{
 161        u16 initpar[] = { 0x0102, 0x0100, 0x0100 };
 162
 163        mipid_write(md, 0xc2, (u8 *)initpar, sizeof(initpar));
 164        set_data_lines(md, md->panel.data_lines);
 165}
 166
 167static void hw_guard_start(struct mipid_device *md, int guard_msec)
 168{
 169        md->hw_guard_wait = msecs_to_jiffies(guard_msec);
 170        md->hw_guard_end = jiffies + md->hw_guard_wait;
 171}
 172
 173static void hw_guard_wait(struct mipid_device *md)
 174{
 175        unsigned long wait = md->hw_guard_end - jiffies;
 176
 177        if ((long)wait > 0 && time_before_eq(wait,  md->hw_guard_wait)) {
 178                set_current_state(TASK_UNINTERRUPTIBLE);
 179                schedule_timeout(wait);
 180        }
 181}
 182
 183static void set_sleep_mode(struct mipid_device *md, int on)
 184{
 185        int cmd, sleep_time = 50;
 186
 187        if (on)
 188                cmd = MIPID_CMD_SLEEP_IN;
 189        else
 190                cmd = MIPID_CMD_SLEEP_OUT;
 191        hw_guard_wait(md);
 192        mipid_cmd(md, cmd);
 193        hw_guard_start(md, 120);
 194        /*
 195         * When we enable the panel, it seems we _have_ to sleep
 196         * 120 ms before sending the init string. When disabling the
 197         * panel we'll sleep for the duration of 2 frames, so that the
 198         * controller can still provide the PCLK,HS,VS signals.
 199         */
 200        if (!on)
 201                sleep_time = 120;
 202        msleep(sleep_time);
 203}
 204
 205static void set_display_state(struct mipid_device *md, int enabled)
 206{
 207        int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
 208
 209        mipid_cmd(md, cmd);
 210}
 211
 212static int mipid_set_bklight_level(struct lcd_panel *panel, unsigned int level)
 213{
 214        struct mipid_device *md = to_mipid_device(panel);
 215        struct mipid_platform_data *pd = md->spi->dev.platform_data;
 216
 217        if (pd->get_bklight_max == NULL || pd->set_bklight_level == NULL)
 218                return -ENODEV;
 219        if (level > pd->get_bklight_max(pd))
 220                return -EINVAL;
 221        if (!md->enabled) {
 222                md->saved_bklight_level = level;
 223                return 0;
 224        }
 225        pd->set_bklight_level(pd, level);
 226
 227        return 0;
 228}
 229
 230static unsigned int mipid_get_bklight_level(struct lcd_panel *panel)
 231{
 232        struct mipid_device *md = to_mipid_device(panel);
 233        struct mipid_platform_data *pd = md->spi->dev.platform_data;
 234
 235        if (pd->get_bklight_level == NULL)
 236                return -ENODEV;
 237        return pd->get_bklight_level(pd);
 238}
 239
 240static unsigned int mipid_get_bklight_max(struct lcd_panel *panel)
 241{
 242        struct mipid_device *md = to_mipid_device(panel);
 243        struct mipid_platform_data *pd = md->spi->dev.platform_data;
 244
 245        if (pd->get_bklight_max == NULL)
 246                return -ENODEV;
 247
 248        return pd->get_bklight_max(pd);
 249}
 250
 251static unsigned long mipid_get_caps(struct lcd_panel *panel)
 252{
 253        return OMAPFB_CAPS_SET_BACKLIGHT;
 254}
 255
 256static u16 read_first_pixel(struct mipid_device *md)
 257{
 258        u16 pixel;
 259        u8 red, green, blue;
 260
 261        mutex_lock(&md->mutex);
 262        mipid_read(md, MIPID_CMD_READ_RED, &red, 1);
 263        mipid_read(md, MIPID_CMD_READ_GREEN, &green, 1);
 264        mipid_read(md, MIPID_CMD_READ_BLUE, &blue, 1);
 265        mutex_unlock(&md->mutex);
 266
 267        switch (md->panel.data_lines) {
 268        case 16:
 269                pixel = ((red >> 1) << 11) | (green << 5) | (blue >> 1);
 270                break;
 271        case 24:
 272                /* 24 bit -> 16 bit */
 273                pixel = ((red >> 3) << 11) | ((green >> 2) << 5) |
 274                        (blue >> 3);
 275                break;
 276        default:
 277                pixel = 0;
 278                BUG();
 279        }
 280
 281        return pixel;
 282}
 283
 284static int mipid_run_test(struct lcd_panel *panel, int test_num)
 285{
 286        struct mipid_device *md = to_mipid_device(panel);
 287        static const u16 test_values[4] = {
 288                0x0000, 0xffff, 0xaaaa, 0x5555,
 289        };
 290        int i;
 291
 292        if (test_num != MIPID_TEST_RGB_LINES)
 293                return MIPID_TEST_INVALID;
 294
 295        for (i = 0; i < ARRAY_SIZE(test_values); i++) {
 296                int delay;
 297                unsigned long tmo;
 298
 299                omapfb_write_first_pixel(md->fbdev, test_values[i]);
 300                tmo = jiffies + msecs_to_jiffies(100);
 301                delay = 25;
 302                while (1) {
 303                        u16 pixel;
 304
 305                        msleep(delay);
 306                        pixel = read_first_pixel(md);
 307                        if (pixel == test_values[i])
 308                                break;
 309                        if (time_after(jiffies, tmo)) {
 310                                dev_err(&md->spi->dev,
 311                                        "MIPI LCD RGB I/F test failed: "
 312                                        "expecting %04x, got %04x\n",
 313                                        test_values[i], pixel);
 314                                return MIPID_TEST_FAILED;
 315                        }
 316                        delay = 10;
 317                }
 318        }
 319
 320        return 0;
 321}
 322
 323static void ls041y3_esd_recover(struct mipid_device *md)
 324{
 325        dev_err(&md->spi->dev, "performing LCD ESD recovery\n");
 326        set_sleep_mode(md, 1);
 327        set_sleep_mode(md, 0);
 328}
 329
 330static void ls041y3_esd_check_mode1(struct mipid_device *md)
 331{
 332        u8 state1, state2;
 333
 334        mipid_read(md, MIPID_CMD_RDDSDR, &state1, 1);
 335        set_sleep_mode(md, 0);
 336        mipid_read(md, MIPID_CMD_RDDSDR, &state2, 1);
 337        dev_dbg(&md->spi->dev, "ESD mode 1 state1 %02x state2 %02x\n",
 338                state1, state2);
 339        /* Each sleep out command will trigger a self diagnostic and flip
 340        * Bit6 if the test passes.
 341        */
 342        if (!((state1 ^ state2) & (1 << 6)))
 343                ls041y3_esd_recover(md);
 344}
 345
 346static void ls041y3_esd_check_mode2(struct mipid_device *md)
 347{
 348        int i;
 349        u8 rbuf[2];
 350        static const struct {
 351                int     cmd;
 352                int     wlen;
 353                u16     wbuf[3];
 354        } *rd, rd_ctrl[7] = {
 355                { 0xb0, 4, { 0x0101, 0x01fe, } },
 356                { 0xb1, 4, { 0x01de, 0x0121, } },
 357                { 0xc2, 4, { 0x0100, 0x0100, } },
 358                { 0xbd, 2, { 0x0100, } },
 359                { 0xc2, 4, { 0x01fc, 0x0103, } },
 360                { 0xb4, 0, },
 361                { 0x00, 0, },
 362        };
 363
 364        rd = rd_ctrl;
 365        for (i = 0; i < 3; i++, rd++)
 366                mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen);
 367
 368        udelay(10);
 369        mipid_read(md, rd->cmd, rbuf, 2);
 370        rd++;
 371
 372        for (i = 0; i < 3; i++, rd++) {
 373                udelay(10);
 374                mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen);
 375        }
 376
 377        dev_dbg(&md->spi->dev, "ESD mode 2 state %02x\n", rbuf[1]);
 378        if (rbuf[1] == 0x00)
 379                ls041y3_esd_recover(md);
 380}
 381
 382static void ls041y3_esd_check(struct mipid_device *md)
 383{
 384        ls041y3_esd_check_mode1(md);
 385        if (md->revision >= 0x88)
 386                ls041y3_esd_check_mode2(md);
 387}
 388
 389static void mipid_esd_start_check(struct mipid_device *md)
 390{
 391        if (md->esd_check != NULL)
 392                schedule_delayed_work(&md->esd_work,
 393                                   MIPID_ESD_CHECK_PERIOD);
 394}
 395
 396static void mipid_esd_stop_check(struct mipid_device *md)
 397{
 398        if (md->esd_check != NULL)
 399                cancel_delayed_work_sync(&md->esd_work);
 400}
 401
 402static void mipid_esd_work(struct work_struct *work)
 403{
 404        struct mipid_device *md = container_of(work, struct mipid_device,
 405                                               esd_work.work);
 406
 407        mutex_lock(&md->mutex);
 408        md->esd_check(md);
 409        mutex_unlock(&md->mutex);
 410        mipid_esd_start_check(md);
 411}
 412
 413static int mipid_enable(struct lcd_panel *panel)
 414{
 415        struct mipid_device *md = to_mipid_device(panel);
 416
 417        mutex_lock(&md->mutex);
 418
 419        if (md->enabled) {
 420                mutex_unlock(&md->mutex);
 421                return 0;
 422        }
 423        set_sleep_mode(md, 0);
 424        md->enabled = 1;
 425        send_init_string(md);
 426        set_display_state(md, 1);
 427        mipid_set_bklight_level(panel, md->saved_bklight_level);
 428        mipid_esd_start_check(md);
 429
 430        mutex_unlock(&md->mutex);
 431        return 0;
 432}
 433
 434static void mipid_disable(struct lcd_panel *panel)
 435{
 436        struct mipid_device *md = to_mipid_device(panel);
 437
 438        /*
 439         * A final ESD work might be called before returning,
 440         * so do this without holding the lock.
 441         */
 442        mipid_esd_stop_check(md);
 443        mutex_lock(&md->mutex);
 444
 445        if (!md->enabled) {
 446                mutex_unlock(&md->mutex);
 447                return;
 448        }
 449        md->saved_bklight_level = mipid_get_bklight_level(panel);
 450        mipid_set_bklight_level(panel, 0);
 451        set_display_state(md, 0);
 452        set_sleep_mode(md, 1);
 453        md->enabled = 0;
 454
 455        mutex_unlock(&md->mutex);
 456}
 457
 458static int panel_enabled(struct mipid_device *md)
 459{
 460        u32 disp_status;
 461        int enabled;
 462
 463        mipid_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
 464        disp_status = __be32_to_cpu(disp_status);
 465        enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
 466        dev_dbg(&md->spi->dev,
 467                "LCD panel %senabled by bootloader (status 0x%04x)\n",
 468                enabled ? "" : "not ", disp_status);
 469        return enabled;
 470}
 471
 472static int mipid_init(struct lcd_panel *panel,
 473                            struct omapfb_device *fbdev)
 474{
 475        struct mipid_device *md = to_mipid_device(panel);
 476
 477        md->fbdev = fbdev;
 478        INIT_DELAYED_WORK(&md->esd_work, mipid_esd_work);
 479        mutex_init(&md->mutex);
 480
 481        md->enabled = panel_enabled(md);
 482
 483        if (md->enabled)
 484                mipid_esd_start_check(md);
 485        else
 486                md->saved_bklight_level = mipid_get_bklight_level(panel);
 487
 488        return 0;
 489}
 490
 491static void mipid_cleanup(struct lcd_panel *panel)
 492{
 493        struct mipid_device *md = to_mipid_device(panel);
 494
 495        if (md->enabled)
 496                mipid_esd_stop_check(md);
 497}
 498
 499static const struct lcd_panel mipid_panel = {
 500        .config         = OMAP_LCDC_PANEL_TFT,
 501
 502        .bpp            = 16,
 503        .x_res          = 800,
 504        .y_res          = 480,
 505        .pixel_clock    = 21940,
 506        .hsw            = 50,
 507        .hfp            = 20,
 508        .hbp            = 15,
 509        .vsw            = 2,
 510        .vfp            = 1,
 511        .vbp            = 3,
 512
 513        .init                   = mipid_init,
 514        .cleanup                = mipid_cleanup,
 515        .enable                 = mipid_enable,
 516        .disable                = mipid_disable,
 517        .get_caps               = mipid_get_caps,
 518        .set_bklight_level      = mipid_set_bklight_level,
 519        .get_bklight_level      = mipid_get_bklight_level,
 520        .get_bklight_max        = mipid_get_bklight_max,
 521        .run_test               = mipid_run_test,
 522};
 523
 524static int mipid_detect(struct mipid_device *md)
 525{
 526        struct mipid_platform_data *pdata;
 527        u8 display_id[3];
 528
 529        pdata = md->spi->dev.platform_data;
 530        if (pdata == NULL) {
 531                dev_err(&md->spi->dev, "missing platform data\n");
 532                return -ENOENT;
 533        }
 534
 535        mipid_read(md, MIPID_CMD_READ_DISP_ID, display_id, 3);
 536        dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n",
 537                display_id[0], display_id[1], display_id[2]);
 538
 539        switch (display_id[0]) {
 540        case 0x45:
 541                md->panel.name = "lph8923";
 542                break;
 543        case 0x83:
 544                md->panel.name = "ls041y3";
 545                md->esd_check = ls041y3_esd_check;
 546                break;
 547        default:
 548                md->panel.name = "unknown";
 549                dev_err(&md->spi->dev, "invalid display ID\n");
 550                return -ENODEV;
 551        }
 552
 553        md->revision = display_id[1];
 554        md->panel.data_lines = pdata->data_lines;
 555        pr_info("omapfb: %s rev %02x LCD detected, %d data lines\n",
 556                        md->panel.name, md->revision, md->panel.data_lines);
 557
 558        return 0;
 559}
 560
 561static int mipid_spi_probe(struct spi_device *spi)
 562{
 563        struct mipid_device *md;
 564        int r;
 565
 566        md = kzalloc(sizeof(*md), GFP_KERNEL);
 567        if (md == NULL) {
 568                dev_err(&spi->dev, "out of memory\n");
 569                return -ENOMEM;
 570        }
 571
 572        spi->mode = SPI_MODE_0;
 573        md->spi = spi;
 574        dev_set_drvdata(&spi->dev, md);
 575        md->panel = mipid_panel;
 576
 577        r = mipid_detect(md);
 578        if (r < 0)
 579                return r;
 580
 581        omapfb_register_panel(&md->panel);
 582
 583        return 0;
 584}
 585
 586static int mipid_spi_remove(struct spi_device *spi)
 587{
 588        struct mipid_device *md = dev_get_drvdata(&spi->dev);
 589
 590        mipid_disable(&md->panel);
 591        kfree(md);
 592
 593        return 0;
 594}
 595
 596static struct spi_driver mipid_spi_driver = {
 597        .driver = {
 598                .name   = MIPID_MODULE_NAME,
 599        },
 600        .probe  = mipid_spi_probe,
 601        .remove = mipid_spi_remove,
 602};
 603
 604module_spi_driver(mipid_spi_driver);
 605
 606MODULE_DESCRIPTION("MIPI display driver");
 607MODULE_LICENSE("GPL");
 608