linux/drivers/video/omap2/displays/panel-acx565akm.c
<<
>>
Prefs
   1/*
   2 * Support for ACX565AKM LCD Panel used on Nokia N900
   3 *
   4 * Copyright (C) 2010 Nokia Corporation
   5 *
   6 * Original Driver Author: Imre Deak <imre.deak@nokia.com>
   7 * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com>
   8 * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com>
   9 *
  10 * This program is free software; you can redistribute it and/or modify it
  11 * under the terms of the GNU General Public License version 2 as published by
  12 * the Free Software Foundation.
  13 *
  14 * This program is distributed in the hope that it will be useful, but WITHOUT
  15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  17 * more details.
  18 *
  19 * You should have received a copy of the GNU General Public License along with
  20 * this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22
  23#include <linux/kernel.h>
  24#include <linux/module.h>
  25#include <linux/platform_device.h>
  26#include <linux/delay.h>
  27#include <linux/spi/spi.h>
  28#include <linux/jiffies.h>
  29#include <linux/sched.h>
  30#include <linux/backlight.h>
  31#include <linux/fb.h>
  32#include <linux/gpio.h>
  33
  34#include <video/omapdss.h>
  35#include <video/omap-panel-data.h>
  36
  37#define MIPID_CMD_READ_DISP_ID          0x04
  38#define MIPID_CMD_READ_RED              0x06
  39#define MIPID_CMD_READ_GREEN            0x07
  40#define MIPID_CMD_READ_BLUE             0x08
  41#define MIPID_CMD_READ_DISP_STATUS      0x09
  42#define MIPID_CMD_RDDSDR                0x0F
  43#define MIPID_CMD_SLEEP_IN              0x10
  44#define MIPID_CMD_SLEEP_OUT             0x11
  45#define MIPID_CMD_DISP_OFF              0x28
  46#define MIPID_CMD_DISP_ON               0x29
  47#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51
  48#define MIPID_CMD_READ_DISP_BRIGHTNESS  0x52
  49#define MIPID_CMD_WRITE_CTRL_DISP       0x53
  50
  51#define CTRL_DISP_BRIGHTNESS_CTRL_ON    (1 << 5)
  52#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4)
  53#define CTRL_DISP_BACKLIGHT_ON          (1 << 2)
  54#define CTRL_DISP_AUTO_BRIGHTNESS_ON    (1 << 1)
  55
  56#define MIPID_CMD_READ_CTRL_DISP        0x54
  57#define MIPID_CMD_WRITE_CABC            0x55
  58#define MIPID_CMD_READ_CABC             0x56
  59
  60#define MIPID_VER_LPH8923               3
  61#define MIPID_VER_LS041Y3               4
  62#define MIPID_VER_L4F00311              8
  63#define MIPID_VER_ACX565AKM             9
  64
  65struct acx565akm_device {
  66        char            *name;
  67        int             enabled;
  68        int             model;
  69        int             revision;
  70        u8              display_id[3];
  71        unsigned        has_bc:1;
  72        unsigned        has_cabc:1;
  73        unsigned        cabc_mode;
  74        unsigned long   hw_guard_end;           /* next value of jiffies
  75                                                   when we can issue the
  76                                                   next sleep in/out command */
  77        unsigned long   hw_guard_wait;          /* max guard time in jiffies */
  78
  79        struct spi_device       *spi;
  80        struct mutex            mutex;
  81
  82        struct omap_dss_device  *dssdev;
  83        struct backlight_device *bl_dev;
  84};
  85
  86static struct acx565akm_device acx_dev;
  87static int acx565akm_bl_update_status(struct backlight_device *dev);
  88
  89/*--------------------MIPID interface-----------------------------*/
  90
  91static void acx565akm_transfer(struct acx565akm_device *md, int cmd,
  92                              const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
  93{
  94        struct spi_message      m;
  95        struct spi_transfer     *x, xfer[5];
  96        int                     r;
  97
  98        BUG_ON(md->spi == NULL);
  99
 100        spi_message_init(&m);
 101
 102        memset(xfer, 0, sizeof(xfer));
 103        x = &xfer[0];
 104
 105        cmd &=  0xff;
 106        x->tx_buf = &cmd;
 107        x->bits_per_word = 9;
 108        x->len = 2;
 109
 110        if (rlen > 1 && wlen == 0) {
 111                /*
 112                 * Between the command and the response data there is a
 113                 * dummy clock cycle. Add an extra bit after the command
 114                 * word to account for this.
 115                 */
 116                x->bits_per_word = 10;
 117                cmd <<= 1;
 118        }
 119        spi_message_add_tail(x, &m);
 120
 121        if (wlen) {
 122                x++;
 123                x->tx_buf = wbuf;
 124                x->len = wlen;
 125                x->bits_per_word = 9;
 126                spi_message_add_tail(x, &m);
 127        }
 128
 129        if (rlen) {
 130                x++;
 131                x->rx_buf       = rbuf;
 132                x->len          = rlen;
 133                spi_message_add_tail(x, &m);
 134        }
 135
 136        r = spi_sync(md->spi, &m);
 137        if (r < 0)
 138                dev_dbg(&md->spi->dev, "spi_sync %d\n", r);
 139}
 140
 141static inline void acx565akm_cmd(struct acx565akm_device *md, int cmd)
 142{
 143        acx565akm_transfer(md, cmd, NULL, 0, NULL, 0);
 144}
 145
 146static inline void acx565akm_write(struct acx565akm_device *md,
 147                               int reg, const u8 *buf, int len)
 148{
 149        acx565akm_transfer(md, reg, buf, len, NULL, 0);
 150}
 151
 152static inline void acx565akm_read(struct acx565akm_device *md,
 153                              int reg, u8 *buf, int len)
 154{
 155        acx565akm_transfer(md, reg, NULL, 0, buf, len);
 156}
 157
 158static void hw_guard_start(struct acx565akm_device *md, int guard_msec)
 159{
 160        md->hw_guard_wait = msecs_to_jiffies(guard_msec);
 161        md->hw_guard_end = jiffies + md->hw_guard_wait;
 162}
 163
 164static void hw_guard_wait(struct acx565akm_device *md)
 165{
 166        unsigned long wait = md->hw_guard_end - jiffies;
 167
 168        if ((long)wait > 0 && wait <= md->hw_guard_wait) {
 169                set_current_state(TASK_UNINTERRUPTIBLE);
 170                schedule_timeout(wait);
 171        }
 172}
 173
 174/*----------------------MIPID wrappers----------------------------*/
 175
 176static void set_sleep_mode(struct acx565akm_device *md, int on)
 177{
 178        int cmd;
 179
 180        if (on)
 181                cmd = MIPID_CMD_SLEEP_IN;
 182        else
 183                cmd = MIPID_CMD_SLEEP_OUT;
 184        /*
 185         * We have to keep 120msec between sleep in/out commands.
 186         * (8.2.15, 8.2.16).
 187         */
 188        hw_guard_wait(md);
 189        acx565akm_cmd(md, cmd);
 190        hw_guard_start(md, 120);
 191}
 192
 193static void set_display_state(struct acx565akm_device *md, int enabled)
 194{
 195        int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
 196
 197        acx565akm_cmd(md, cmd);
 198}
 199
 200static int panel_enabled(struct acx565akm_device *md)
 201{
 202        u32 disp_status;
 203        int enabled;
 204
 205        acx565akm_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
 206        disp_status = __be32_to_cpu(disp_status);
 207        enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
 208        dev_dbg(&md->spi->dev,
 209                "LCD panel %senabled by bootloader (status 0x%04x)\n",
 210                enabled ? "" : "not ", disp_status);
 211        return enabled;
 212}
 213
 214static int panel_detect(struct acx565akm_device *md)
 215{
 216        acx565akm_read(md, MIPID_CMD_READ_DISP_ID, md->display_id, 3);
 217        dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n",
 218                md->display_id[0], md->display_id[1], md->display_id[2]);
 219
 220        switch (md->display_id[0]) {
 221        case 0x10:
 222                md->model = MIPID_VER_ACX565AKM;
 223                md->name = "acx565akm";
 224                md->has_bc = 1;
 225                md->has_cabc = 1;
 226                break;
 227        case 0x29:
 228                md->model = MIPID_VER_L4F00311;
 229                md->name = "l4f00311";
 230                break;
 231        case 0x45:
 232                md->model = MIPID_VER_LPH8923;
 233                md->name = "lph8923";
 234                break;
 235        case 0x83:
 236                md->model = MIPID_VER_LS041Y3;
 237                md->name = "ls041y3";
 238                break;
 239        default:
 240                md->name = "unknown";
 241                dev_err(&md->spi->dev, "invalid display ID\n");
 242                return -ENODEV;
 243        }
 244
 245        md->revision = md->display_id[1];
 246
 247        dev_info(&md->spi->dev, "omapfb: %s rev %02x LCD detected\n",
 248                        md->name, md->revision);
 249
 250        return 0;
 251}
 252
 253/*----------------------Backlight Control-------------------------*/
 254
 255static void enable_backlight_ctrl(struct acx565akm_device *md, int enable)
 256{
 257        u16 ctrl;
 258
 259        acx565akm_read(md, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1);
 260        if (enable) {
 261                ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON |
 262                        CTRL_DISP_BACKLIGHT_ON;
 263        } else {
 264                ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON |
 265                          CTRL_DISP_BACKLIGHT_ON);
 266        }
 267
 268        ctrl |= 1 << 8;
 269        acx565akm_write(md, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2);
 270}
 271
 272static void set_cabc_mode(struct acx565akm_device *md, unsigned mode)
 273{
 274        u16 cabc_ctrl;
 275
 276        md->cabc_mode = mode;
 277        if (!md->enabled)
 278                return;
 279        cabc_ctrl = 0;
 280        acx565akm_read(md, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1);
 281        cabc_ctrl &= ~3;
 282        cabc_ctrl |= (1 << 8) | (mode & 3);
 283        acx565akm_write(md, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2);
 284}
 285
 286static unsigned get_cabc_mode(struct acx565akm_device *md)
 287{
 288        return md->cabc_mode;
 289}
 290
 291static unsigned get_hw_cabc_mode(struct acx565akm_device *md)
 292{
 293        u8 cabc_ctrl;
 294
 295        acx565akm_read(md, MIPID_CMD_READ_CABC, &cabc_ctrl, 1);
 296        return cabc_ctrl & 3;
 297}
 298
 299static void acx565akm_set_brightness(struct acx565akm_device *md, int level)
 300{
 301        int bv;
 302
 303        bv = level | (1 << 8);
 304        acx565akm_write(md, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2);
 305
 306        if (level)
 307                enable_backlight_ctrl(md, 1);
 308        else
 309                enable_backlight_ctrl(md, 0);
 310}
 311
 312static int acx565akm_get_actual_brightness(struct acx565akm_device *md)
 313{
 314        u8 bv;
 315
 316        acx565akm_read(md, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1);
 317
 318        return bv;
 319}
 320
 321
 322static int acx565akm_bl_update_status(struct backlight_device *dev)
 323{
 324        struct acx565akm_device *md = dev_get_drvdata(&dev->dev);
 325        int r;
 326        int level;
 327
 328        dev_dbg(&md->spi->dev, "%s\n", __func__);
 329
 330        mutex_lock(&md->mutex);
 331
 332        if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
 333                        dev->props.power == FB_BLANK_UNBLANK)
 334                level = dev->props.brightness;
 335        else
 336                level = 0;
 337
 338        r = 0;
 339        if (md->has_bc)
 340                acx565akm_set_brightness(md, level);
 341        else
 342                r = -ENODEV;
 343
 344        mutex_unlock(&md->mutex);
 345
 346        return r;
 347}
 348
 349static int acx565akm_bl_get_intensity(struct backlight_device *dev)
 350{
 351        struct acx565akm_device *md = dev_get_drvdata(&dev->dev);
 352
 353        dev_dbg(&dev->dev, "%s\n", __func__);
 354
 355        if (!md->has_bc)
 356                return -ENODEV;
 357
 358        if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
 359                        dev->props.power == FB_BLANK_UNBLANK) {
 360                if (md->has_bc)
 361                        return acx565akm_get_actual_brightness(md);
 362                else
 363                        return dev->props.brightness;
 364        }
 365
 366        return 0;
 367}
 368
 369static const struct backlight_ops acx565akm_bl_ops = {
 370        .get_brightness = acx565akm_bl_get_intensity,
 371        .update_status  = acx565akm_bl_update_status,
 372};
 373
 374/*--------------------Auto Brightness control via Sysfs---------------------*/
 375
 376static const char *cabc_modes[] = {
 377        "off",          /* always used when CABC is not supported */
 378        "ui",
 379        "still-image",
 380        "moving-image",
 381};
 382
 383static ssize_t show_cabc_mode(struct device *dev,
 384                struct device_attribute *attr,
 385                char *buf)
 386{
 387        struct acx565akm_device *md = dev_get_drvdata(dev);
 388        const char *mode_str;
 389        int mode;
 390        int len;
 391
 392        if (!md->has_cabc)
 393                mode = 0;
 394        else
 395                mode = get_cabc_mode(md);
 396        mode_str = "unknown";
 397        if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
 398                mode_str = cabc_modes[mode];
 399        len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
 400
 401        return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
 402}
 403
 404static ssize_t store_cabc_mode(struct device *dev,
 405                struct device_attribute *attr,
 406                const char *buf, size_t count)
 407{
 408        struct acx565akm_device *md = dev_get_drvdata(dev);
 409        int i;
 410
 411        for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
 412                const char *mode_str = cabc_modes[i];
 413                int cmp_len = strlen(mode_str);
 414
 415                if (count > 0 && buf[count - 1] == '\n')
 416                        count--;
 417                if (count != cmp_len)
 418                        continue;
 419
 420                if (strncmp(buf, mode_str, cmp_len) == 0)
 421                        break;
 422        }
 423
 424        if (i == ARRAY_SIZE(cabc_modes))
 425                return -EINVAL;
 426
 427        if (!md->has_cabc && i != 0)
 428                return -EINVAL;
 429
 430        mutex_lock(&md->mutex);
 431        set_cabc_mode(md, i);
 432        mutex_unlock(&md->mutex);
 433
 434        return count;
 435}
 436
 437static ssize_t show_cabc_available_modes(struct device *dev,
 438                struct device_attribute *attr,
 439                char *buf)
 440{
 441        struct acx565akm_device *md = dev_get_drvdata(dev);
 442        int len;
 443        int i;
 444
 445        if (!md->has_cabc)
 446                return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]);
 447
 448        for (i = 0, len = 0;
 449             len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
 450                len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
 451                        i ? " " : "", cabc_modes[i],
 452                        i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
 453
 454        return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
 455}
 456
 457static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
 458                show_cabc_mode, store_cabc_mode);
 459static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
 460                show_cabc_available_modes, NULL);
 461
 462static struct attribute *bldev_attrs[] = {
 463        &dev_attr_cabc_mode.attr,
 464        &dev_attr_cabc_available_modes.attr,
 465        NULL,
 466};
 467
 468static struct attribute_group bldev_attr_group = {
 469        .attrs = bldev_attrs,
 470};
 471
 472
 473/*---------------------------ACX Panel----------------------------*/
 474
 475static int acx_get_recommended_bpp(struct omap_dss_device *dssdev)
 476{
 477        return 16;
 478}
 479
 480static struct omap_video_timings acx_panel_timings = {
 481        .x_res          = 800,
 482        .y_res          = 480,
 483        .pixel_clock    = 24000,
 484        .hfp            = 28,
 485        .hsw            = 4,
 486        .hbp            = 24,
 487        .vfp            = 3,
 488        .vsw            = 3,
 489        .vbp            = 4,
 490
 491        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 492        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 493
 494        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 495        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 496        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 497};
 498
 499static struct panel_acx565akm_data *get_panel_data(struct omap_dss_device *dssdev)
 500{
 501        return (struct panel_acx565akm_data *) dssdev->data;
 502}
 503
 504static int acx_panel_probe(struct omap_dss_device *dssdev)
 505{
 506        int r;
 507        struct acx565akm_device *md = &acx_dev;
 508        struct panel_acx565akm_data *panel_data = get_panel_data(dssdev);
 509        struct backlight_device *bldev;
 510        int max_brightness, brightness;
 511        struct backlight_properties props;
 512
 513        dev_dbg(&dssdev->dev, "%s\n", __func__);
 514
 515        if (!panel_data)
 516                return -EINVAL;
 517
 518        /* FIXME AC bias ? */
 519        dssdev->panel.timings = acx_panel_timings;
 520
 521        if (gpio_is_valid(panel_data->reset_gpio)) {
 522                r = devm_gpio_request_one(&dssdev->dev, panel_data->reset_gpio,
 523                                GPIOF_OUT_INIT_LOW, "lcd reset");
 524                if (r)
 525                        return r;
 526        }
 527
 528        if (gpio_is_valid(panel_data->reset_gpio))
 529                gpio_set_value(panel_data->reset_gpio, 1);
 530
 531        /*
 532         * After reset we have to wait 5 msec before the first
 533         * command can be sent.
 534         */
 535        msleep(5);
 536
 537        md->enabled = panel_enabled(md);
 538
 539        r = panel_detect(md);
 540        if (r) {
 541                dev_err(&dssdev->dev, "%s panel detect error\n", __func__);
 542                if (!md->enabled && gpio_is_valid(panel_data->reset_gpio))
 543                        gpio_set_value(panel_data->reset_gpio, 0);
 544
 545                return r;
 546        }
 547
 548        mutex_lock(&acx_dev.mutex);
 549        acx_dev.dssdev = dssdev;
 550        mutex_unlock(&acx_dev.mutex);
 551
 552        if (!md->enabled) {
 553                if (gpio_is_valid(panel_data->reset_gpio))
 554                        gpio_set_value(panel_data->reset_gpio, 0);
 555        }
 556
 557        /*------- Backlight control --------*/
 558
 559        memset(&props, 0, sizeof(props));
 560        props.fb_blank = FB_BLANK_UNBLANK;
 561        props.power = FB_BLANK_UNBLANK;
 562        props.type = BACKLIGHT_RAW;
 563
 564        bldev = backlight_device_register("acx565akm", &md->spi->dev,
 565                        md, &acx565akm_bl_ops, &props);
 566        md->bl_dev = bldev;
 567        if (md->has_cabc) {
 568                r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
 569                if (r) {
 570                        dev_err(&bldev->dev,
 571                                "%s failed to create sysfs files\n", __func__);
 572                        backlight_device_unregister(bldev);
 573                        return r;
 574                }
 575                md->cabc_mode = get_hw_cabc_mode(md);
 576        }
 577
 578        max_brightness = 255;
 579
 580        if (md->has_bc)
 581                brightness = acx565akm_get_actual_brightness(md);
 582        else
 583                brightness = 0;
 584
 585        bldev->props.max_brightness = max_brightness;
 586        bldev->props.brightness = brightness;
 587
 588        acx565akm_bl_update_status(bldev);
 589        return 0;
 590}
 591
 592static void acx_panel_remove(struct omap_dss_device *dssdev)
 593{
 594        struct acx565akm_device *md = &acx_dev;
 595
 596        dev_dbg(&dssdev->dev, "%s\n", __func__);
 597        sysfs_remove_group(&md->bl_dev->dev.kobj, &bldev_attr_group);
 598        backlight_device_unregister(md->bl_dev);
 599        mutex_lock(&acx_dev.mutex);
 600        acx_dev.dssdev = NULL;
 601        mutex_unlock(&acx_dev.mutex);
 602}
 603
 604static int acx_panel_power_on(struct omap_dss_device *dssdev)
 605{
 606        struct acx565akm_device *md = &acx_dev;
 607        struct panel_acx565akm_data *panel_data = get_panel_data(dssdev);
 608        int r;
 609
 610        dev_dbg(&dssdev->dev, "%s\n", __func__);
 611
 612        if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
 613                return 0;
 614
 615        mutex_lock(&md->mutex);
 616
 617        omapdss_sdi_set_timings(dssdev, &dssdev->panel.timings);
 618        omapdss_sdi_set_datapairs(dssdev, dssdev->phy.sdi.datapairs);
 619
 620        r = omapdss_sdi_display_enable(dssdev);
 621        if (r) {
 622                pr_err("%s sdi enable failed\n", __func__);
 623                goto fail_unlock;
 624        }
 625
 626        /*FIXME tweak me */
 627        msleep(50);
 628
 629        if (gpio_is_valid(panel_data->reset_gpio))
 630                gpio_set_value(panel_data->reset_gpio, 1);
 631
 632        if (md->enabled) {
 633                dev_dbg(&md->spi->dev, "panel already enabled\n");
 634                mutex_unlock(&md->mutex);
 635                return 0;
 636        }
 637
 638        /*
 639         * We have to meet all the following delay requirements:
 640         * 1. tRW: reset pulse width 10usec (7.12.1)
 641         * 2. tRT: reset cancel time 5msec (7.12.1)
 642         * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst
 643         *    case (7.6.2)
 644         * 4. 120msec before the sleep out command (7.12.1)
 645         */
 646        msleep(120);
 647
 648        set_sleep_mode(md, 0);
 649        md->enabled = 1;
 650
 651        /* 5msec between sleep out and the next command. (8.2.16) */
 652        msleep(5);
 653        set_display_state(md, 1);
 654        set_cabc_mode(md, md->cabc_mode);
 655
 656        mutex_unlock(&md->mutex);
 657
 658        return acx565akm_bl_update_status(md->bl_dev);
 659
 660fail_unlock:
 661        mutex_unlock(&md->mutex);
 662        return r;
 663}
 664
 665static void acx_panel_power_off(struct omap_dss_device *dssdev)
 666{
 667        struct acx565akm_device *md = &acx_dev;
 668        struct panel_acx565akm_data *panel_data = get_panel_data(dssdev);
 669
 670        dev_dbg(&dssdev->dev, "%s\n", __func__);
 671
 672        if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
 673                return;
 674
 675        mutex_lock(&md->mutex);
 676
 677        if (!md->enabled) {
 678                mutex_unlock(&md->mutex);
 679                return;
 680        }
 681        set_display_state(md, 0);
 682        set_sleep_mode(md, 1);
 683        md->enabled = 0;
 684        /*
 685         * We have to provide PCLK,HS,VS signals for 2 frames (worst case
 686         * ~50msec) after sending the sleep in command and asserting the
 687         * reset signal. We probably could assert the reset w/o the delay
 688         * but we still delay to avoid possible artifacts. (7.6.1)
 689         */
 690        msleep(50);
 691
 692        if (gpio_is_valid(panel_data->reset_gpio))
 693                gpio_set_value(panel_data->reset_gpio, 0);
 694
 695        /* FIXME need to tweak this delay */
 696        msleep(100);
 697
 698        omapdss_sdi_display_disable(dssdev);
 699
 700        mutex_unlock(&md->mutex);
 701}
 702
 703static int acx_panel_enable(struct omap_dss_device *dssdev)
 704{
 705        int r;
 706
 707        dev_dbg(&dssdev->dev, "%s\n", __func__);
 708        r = acx_panel_power_on(dssdev);
 709
 710        if (r)
 711                return r;
 712
 713        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 714        return 0;
 715}
 716
 717static void acx_panel_disable(struct omap_dss_device *dssdev)
 718{
 719        dev_dbg(&dssdev->dev, "%s\n", __func__);
 720        acx_panel_power_off(dssdev);
 721        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 722}
 723
 724static void acx_panel_set_timings(struct omap_dss_device *dssdev,
 725                struct omap_video_timings *timings)
 726{
 727        omapdss_sdi_set_timings(dssdev, timings);
 728
 729        dssdev->panel.timings = *timings;
 730}
 731
 732static int acx_panel_check_timings(struct omap_dss_device *dssdev,
 733                struct omap_video_timings *timings)
 734{
 735        return 0;
 736}
 737
 738
 739static struct omap_dss_driver acx_panel_driver = {
 740        .probe          = acx_panel_probe,
 741        .remove         = acx_panel_remove,
 742
 743        .enable         = acx_panel_enable,
 744        .disable        = acx_panel_disable,
 745
 746        .set_timings    = acx_panel_set_timings,
 747        .check_timings  = acx_panel_check_timings,
 748
 749        .get_recommended_bpp = acx_get_recommended_bpp,
 750
 751        .driver         = {
 752                .name   = "panel-acx565akm",
 753                .owner  = THIS_MODULE,
 754        },
 755};
 756
 757/*--------------------SPI probe-------------------------*/
 758
 759static int acx565akm_spi_probe(struct spi_device *spi)
 760{
 761        struct acx565akm_device *md = &acx_dev;
 762
 763        dev_dbg(&spi->dev, "%s\n", __func__);
 764
 765        spi->mode = SPI_MODE_3;
 766        md->spi = spi;
 767        mutex_init(&md->mutex);
 768        dev_set_drvdata(&spi->dev, md);
 769
 770        omap_dss_register_driver(&acx_panel_driver);
 771
 772        return 0;
 773}
 774
 775static int acx565akm_spi_remove(struct spi_device *spi)
 776{
 777        struct acx565akm_device *md = dev_get_drvdata(&spi->dev);
 778
 779        dev_dbg(&md->spi->dev, "%s\n", __func__);
 780        omap_dss_unregister_driver(&acx_panel_driver);
 781
 782        return 0;
 783}
 784
 785static struct spi_driver acx565akm_spi_driver = {
 786        .driver = {
 787                .name   = "acx565akm",
 788                .owner  = THIS_MODULE,
 789        },
 790        .probe  = acx565akm_spi_probe,
 791        .remove = acx565akm_spi_remove,
 792};
 793
 794module_spi_driver(acx565akm_spi_driver);
 795
 796MODULE_AUTHOR("Nokia Corporation");
 797MODULE_DESCRIPTION("acx565akm LCD Driver");
 798MODULE_LICENSE("GPL");
 799