linux/drivers/video/backlight/ld9040.c
<<
>>
Prefs
   1/*
   2 * ld9040 AMOLED LCD panel driver.
   3 *
   4 * Copyright (c) 2011 Samsung Electronics
   5 * Author: Donghwa Lee  <dh09.lee@samsung.com>
   6 * Derived from drivers/video/backlight/s6e63m0.c
   7 *
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms of the GNU General Public License as published by the
  10 * Free Software Foundation; either version 2 of the License, or (at your
  11 * option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful, but
  14 * WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16 * General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License along
  19 * with this program; if not, write to the Free Software Foundation, Inc.,
  20 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  21 */
  22
  23#include <linux/wait.h>
  24#include <linux/fb.h>
  25#include <linux/delay.h>
  26#include <linux/gpio.h>
  27#include <linux/spi/spi.h>
  28#include <linux/irq.h>
  29#include <linux/interrupt.h>
  30#include <linux/kernel.h>
  31#include <linux/lcd.h>
  32#include <linux/backlight.h>
  33#include <linux/module.h>
  34#include <linux/regulator/consumer.h>
  35
  36#include "ld9040_gamma.h"
  37
  38#define SLEEPMSEC               0x1000
  39#define ENDDEF                  0x2000
  40#define DEFMASK                 0xFF00
  41#define COMMAND_ONLY            0xFE
  42#define DATA_ONLY               0xFF
  43
  44#define MIN_BRIGHTNESS          0
  45#define MAX_BRIGHTNESS          24
  46#define power_is_on(pwr)        ((pwr) <= FB_BLANK_NORMAL)
  47
  48struct ld9040 {
  49        struct device                   *dev;
  50        struct spi_device               *spi;
  51        unsigned int                    power;
  52        unsigned int                    current_brightness;
  53
  54        struct lcd_device               *ld;
  55        struct backlight_device         *bd;
  56        struct lcd_platform_data        *lcd_pd;
  57
  58        struct mutex                    lock;
  59        bool  enabled;
  60};
  61
  62static struct regulator_bulk_data supplies[] = {
  63        { .supply = "vdd3", },
  64        { .supply = "vci", },
  65};
  66
  67static void ld9040_regulator_enable(struct ld9040 *lcd)
  68{
  69        int ret = 0;
  70        struct lcd_platform_data *pd = NULL;
  71
  72        pd = lcd->lcd_pd;
  73        mutex_lock(&lcd->lock);
  74        if (!lcd->enabled) {
  75                ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
  76                if (ret)
  77                        goto out;
  78
  79                lcd->enabled = true;
  80        }
  81        mdelay(pd->power_on_delay);
  82out:
  83        mutex_unlock(&lcd->lock);
  84}
  85
  86static void ld9040_regulator_disable(struct ld9040 *lcd)
  87{
  88        int ret = 0;
  89
  90        mutex_lock(&lcd->lock);
  91        if (lcd->enabled) {
  92                ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
  93                if (ret)
  94                        goto out;
  95
  96                lcd->enabled = false;
  97        }
  98out:
  99        mutex_unlock(&lcd->lock);
 100}
 101
 102static const unsigned short seq_swreset[] = {
 103        0x01, COMMAND_ONLY,
 104        ENDDEF, 0x00
 105};
 106
 107static const unsigned short seq_user_setting[] = {
 108        0xF0, 0x5A,
 109
 110        DATA_ONLY, 0x5A,
 111        ENDDEF, 0x00
 112};
 113
 114static const unsigned short seq_elvss_on[] = {
 115        0xB1, 0x0D,
 116
 117        DATA_ONLY, 0x00,
 118        DATA_ONLY, 0x16,
 119        ENDDEF, 0x00
 120};
 121
 122static const unsigned short seq_gtcon[] = {
 123        0xF7, 0x09,
 124
 125        DATA_ONLY, 0x00,
 126        DATA_ONLY, 0x00,
 127        ENDDEF, 0x00
 128};
 129
 130static const unsigned short seq_panel_condition[] = {
 131        0xF8, 0x05,
 132
 133        DATA_ONLY, 0x65,
 134        DATA_ONLY, 0x96,
 135        DATA_ONLY, 0x71,
 136        DATA_ONLY, 0x7D,
 137        DATA_ONLY, 0x19,
 138        DATA_ONLY, 0x3B,
 139        DATA_ONLY, 0x0D,
 140        DATA_ONLY, 0x19,
 141        DATA_ONLY, 0x7E,
 142        DATA_ONLY, 0x0D,
 143        DATA_ONLY, 0xE2,
 144        DATA_ONLY, 0x00,
 145        DATA_ONLY, 0x00,
 146        DATA_ONLY, 0x7E,
 147        DATA_ONLY, 0x7D,
 148        DATA_ONLY, 0x07,
 149        DATA_ONLY, 0x07,
 150        DATA_ONLY, 0x20,
 151        DATA_ONLY, 0x20,
 152        DATA_ONLY, 0x20,
 153        DATA_ONLY, 0x02,
 154        DATA_ONLY, 0x02,
 155        ENDDEF, 0x00
 156};
 157
 158static const unsigned short seq_gamma_set1[] = {
 159        0xF9, 0x00,
 160
 161        DATA_ONLY, 0xA7,
 162        DATA_ONLY, 0xB4,
 163        DATA_ONLY, 0xAE,
 164        DATA_ONLY, 0xBF,
 165        DATA_ONLY, 0x00,
 166        DATA_ONLY, 0x91,
 167        DATA_ONLY, 0x00,
 168        DATA_ONLY, 0xB2,
 169        DATA_ONLY, 0xB4,
 170        DATA_ONLY, 0xAA,
 171        DATA_ONLY, 0xBB,
 172        DATA_ONLY, 0x00,
 173        DATA_ONLY, 0xAC,
 174        DATA_ONLY, 0x00,
 175        DATA_ONLY, 0xB3,
 176        DATA_ONLY, 0xB1,
 177        DATA_ONLY, 0xAA,
 178        DATA_ONLY, 0xBC,
 179        DATA_ONLY, 0x00,
 180        DATA_ONLY, 0xB3,
 181        ENDDEF, 0x00
 182};
 183
 184static const unsigned short seq_gamma_ctrl[] = {
 185        0xFB, 0x02,
 186
 187        DATA_ONLY, 0x5A,
 188        ENDDEF, 0x00
 189};
 190
 191static const unsigned short seq_gamma_start[] = {
 192        0xF9, COMMAND_ONLY,
 193
 194        ENDDEF, 0x00
 195};
 196
 197static const unsigned short seq_apon[] = {
 198        0xF3, 0x00,
 199
 200        DATA_ONLY, 0x00,
 201        DATA_ONLY, 0x00,
 202        DATA_ONLY, 0x0A,
 203        DATA_ONLY, 0x02,
 204        ENDDEF, 0x00
 205};
 206
 207static const unsigned short seq_display_ctrl[] = {
 208        0xF2, 0x02,
 209
 210        DATA_ONLY, 0x08,
 211        DATA_ONLY, 0x08,
 212        DATA_ONLY, 0x10,
 213        DATA_ONLY, 0x10,
 214        ENDDEF, 0x00
 215};
 216
 217static const unsigned short seq_manual_pwr[] = {
 218        0xB0, 0x04,
 219        ENDDEF, 0x00
 220};
 221
 222static const unsigned short seq_pwr_ctrl[] = {
 223        0xF4, 0x0A,
 224
 225        DATA_ONLY, 0x87,
 226        DATA_ONLY, 0x25,
 227        DATA_ONLY, 0x6A,
 228        DATA_ONLY, 0x44,
 229        DATA_ONLY, 0x02,
 230        DATA_ONLY, 0x88,
 231        ENDDEF, 0x00
 232};
 233
 234static const unsigned short seq_sleep_out[] = {
 235        0x11, COMMAND_ONLY,
 236        ENDDEF, 0x00
 237};
 238
 239static const unsigned short seq_sleep_in[] = {
 240        0x10, COMMAND_ONLY,
 241        ENDDEF, 0x00
 242};
 243
 244static const unsigned short seq_display_on[] = {
 245        0x29, COMMAND_ONLY,
 246        ENDDEF, 0x00
 247};
 248
 249static const unsigned short seq_display_off[] = {
 250        0x28, COMMAND_ONLY,
 251        ENDDEF, 0x00
 252};
 253
 254static const unsigned short seq_vci1_1st_en[] = {
 255        0xF3, 0x10,
 256
 257        DATA_ONLY, 0x00,
 258        DATA_ONLY, 0x00,
 259        DATA_ONLY, 0x00,
 260        DATA_ONLY, 0x02,
 261        ENDDEF, 0x00
 262};
 263
 264static const unsigned short seq_vl1_en[] = {
 265        0xF3, 0x11,
 266
 267        DATA_ONLY, 0x00,
 268        DATA_ONLY, 0x00,
 269        DATA_ONLY, 0x00,
 270        DATA_ONLY, 0x02,
 271        ENDDEF, 0x00
 272};
 273
 274static const unsigned short seq_vl2_en[] = {
 275        0xF3, 0x13,
 276
 277        DATA_ONLY, 0x00,
 278        DATA_ONLY, 0x00,
 279        DATA_ONLY, 0x00,
 280        DATA_ONLY, 0x02,
 281        ENDDEF, 0x00
 282};
 283
 284static const unsigned short seq_vci1_2nd_en[] = {
 285        0xF3, 0x33,
 286
 287        DATA_ONLY, 0x00,
 288        DATA_ONLY, 0x00,
 289        DATA_ONLY, 0x00,
 290        DATA_ONLY, 0x02,
 291        ENDDEF, 0x00
 292};
 293
 294static const unsigned short seq_vl3_en[] = {
 295        0xF3, 0x37,
 296
 297        DATA_ONLY, 0x00,
 298        DATA_ONLY, 0x00,
 299        DATA_ONLY, 0x00,
 300        DATA_ONLY, 0x02,
 301        ENDDEF, 0x00
 302};
 303
 304static const unsigned short seq_vreg1_amp_en[] = {
 305        0xF3, 0x37,
 306
 307        DATA_ONLY, 0x01,
 308        DATA_ONLY, 0x00,
 309        DATA_ONLY, 0x00,
 310        DATA_ONLY, 0x02,
 311        ENDDEF, 0x00
 312};
 313
 314static const unsigned short seq_vgh_amp_en[] = {
 315        0xF3, 0x37,
 316
 317        DATA_ONLY, 0x11,
 318        DATA_ONLY, 0x00,
 319        DATA_ONLY, 0x00,
 320        DATA_ONLY, 0x02,
 321        ENDDEF, 0x00
 322};
 323
 324static const unsigned short seq_vgl_amp_en[] = {
 325        0xF3, 0x37,
 326
 327        DATA_ONLY, 0x31,
 328        DATA_ONLY, 0x00,
 329        DATA_ONLY, 0x00,
 330        DATA_ONLY, 0x02,
 331        ENDDEF, 0x00
 332};
 333
 334static const unsigned short seq_vmos_amp_en[] = {
 335        0xF3, 0x37,
 336
 337        DATA_ONLY, 0xB1,
 338        DATA_ONLY, 0x00,
 339        DATA_ONLY, 0x00,
 340        DATA_ONLY, 0x03,
 341        ENDDEF, 0x00
 342};
 343
 344static const unsigned short seq_vint_amp_en[] = {
 345        0xF3, 0x37,
 346
 347        DATA_ONLY, 0xF1,
 348        /* DATA_ONLY, 0x71,     VMOS/VBL/VBH not used */
 349        DATA_ONLY, 0x00,
 350        DATA_ONLY, 0x00,
 351        DATA_ONLY, 0x03,
 352        /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
 353        ENDDEF, 0x00
 354};
 355
 356static const unsigned short seq_vbh_amp_en[] = {
 357        0xF3, 0x37,
 358
 359        DATA_ONLY, 0xF9,
 360        DATA_ONLY, 0x00,
 361        DATA_ONLY, 0x00,
 362        DATA_ONLY, 0x03,
 363        ENDDEF, 0x00
 364};
 365
 366static const unsigned short seq_vbl_amp_en[] = {
 367        0xF3, 0x37,
 368
 369        DATA_ONLY, 0xFD,
 370        DATA_ONLY, 0x00,
 371        DATA_ONLY, 0x00,
 372        DATA_ONLY, 0x03,
 373        ENDDEF, 0x00
 374};
 375
 376static const unsigned short seq_gam_amp_en[] = {
 377        0xF3, 0x37,
 378
 379        DATA_ONLY, 0xFF,
 380        /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
 381        DATA_ONLY, 0x00,
 382        DATA_ONLY, 0x00,
 383        DATA_ONLY, 0x03,
 384        /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
 385        ENDDEF, 0x00
 386};
 387
 388static const unsigned short seq_sd_amp_en[] = {
 389        0xF3, 0x37,
 390
 391        DATA_ONLY, 0xFF,
 392        /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
 393        DATA_ONLY, 0x80,
 394        DATA_ONLY, 0x00,
 395        DATA_ONLY, 0x03,
 396        /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
 397        ENDDEF, 0x00
 398};
 399
 400static const unsigned short seq_gls_en[] = {
 401        0xF3, 0x37,
 402
 403        DATA_ONLY, 0xFF,
 404        /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
 405        DATA_ONLY, 0x81,
 406        DATA_ONLY, 0x00,
 407        DATA_ONLY, 0x03,
 408        /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
 409        ENDDEF, 0x00
 410};
 411
 412static const unsigned short seq_els_en[] = {
 413        0xF3, 0x37,
 414
 415        DATA_ONLY, 0xFF,
 416        /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
 417        DATA_ONLY, 0x83,
 418        DATA_ONLY, 0x00,
 419        DATA_ONLY, 0x03,
 420        /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
 421        ENDDEF, 0x00
 422};
 423
 424static const unsigned short seq_el_on[] = {
 425        0xF3, 0x37,
 426
 427        DATA_ONLY, 0xFF,
 428        /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
 429        DATA_ONLY, 0x87,
 430        DATA_ONLY, 0x00,
 431        DATA_ONLY, 0x03,
 432        /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
 433        ENDDEF, 0x00
 434};
 435
 436static int ld9040_spi_write_byte(struct ld9040 *lcd, int addr, int data)
 437{
 438        u16 buf[1];
 439        struct spi_message msg;
 440
 441        struct spi_transfer xfer = {
 442                .len            = 2,
 443                .tx_buf         = buf,
 444        };
 445
 446        buf[0] = (addr << 8) | data;
 447
 448        spi_message_init(&msg);
 449        spi_message_add_tail(&xfer, &msg);
 450
 451        return spi_sync(lcd->spi, &msg);
 452}
 453
 454static int ld9040_spi_write(struct ld9040 *lcd, unsigned char address,
 455        unsigned char command)
 456{
 457        int ret = 0;
 458
 459        if (address != DATA_ONLY)
 460                ret = ld9040_spi_write_byte(lcd, 0x0, address);
 461        if (command != COMMAND_ONLY)
 462                ret = ld9040_spi_write_byte(lcd, 0x1, command);
 463
 464        return ret;
 465}
 466
 467static int ld9040_panel_send_sequence(struct ld9040 *lcd,
 468        const unsigned short *wbuf)
 469{
 470        int ret = 0, i = 0;
 471
 472        while ((wbuf[i] & DEFMASK) != ENDDEF) {
 473                if ((wbuf[i] & DEFMASK) != SLEEPMSEC) {
 474                        ret = ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]);
 475                        if (ret)
 476                                break;
 477                } else
 478                        udelay(wbuf[i+1]*1000);
 479                i += 2;
 480        }
 481
 482        return ret;
 483}
 484
 485static int _ld9040_gamma_ctl(struct ld9040 *lcd, const unsigned int *gamma)
 486{
 487        unsigned int i = 0;
 488        int ret = 0;
 489
 490        /* start gamma table updating. */
 491        ret = ld9040_panel_send_sequence(lcd, seq_gamma_start);
 492        if (ret) {
 493                dev_err(lcd->dev, "failed to disable gamma table updating.\n");
 494                goto gamma_err;
 495        }
 496
 497        for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) {
 498                ret = ld9040_spi_write(lcd, DATA_ONLY, gamma[i]);
 499                if (ret) {
 500                        dev_err(lcd->dev, "failed to set gamma table.\n");
 501                        goto gamma_err;
 502                }
 503        }
 504
 505        /* update gamma table. */
 506        ret = ld9040_panel_send_sequence(lcd, seq_gamma_ctrl);
 507        if (ret)
 508                dev_err(lcd->dev, "failed to update gamma table.\n");
 509
 510gamma_err:
 511        return ret;
 512}
 513
 514static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma)
 515{
 516        int ret = 0;
 517
 518        ret = _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
 519
 520        return ret;
 521}
 522
 523
 524static int ld9040_ldi_init(struct ld9040 *lcd)
 525{
 526        int ret, i;
 527        static const unsigned short *init_seq[] = {
 528                seq_user_setting,
 529                seq_panel_condition,
 530                seq_display_ctrl,
 531                seq_manual_pwr,
 532                seq_elvss_on,
 533                seq_gtcon,
 534                seq_gamma_set1,
 535                seq_gamma_ctrl,
 536                seq_sleep_out,
 537        };
 538
 539        for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
 540                ret = ld9040_panel_send_sequence(lcd, init_seq[i]);
 541                /* workaround: minimum delay time for transferring CMD */
 542                udelay(300);
 543                if (ret)
 544                        break;
 545        }
 546
 547        return ret;
 548}
 549
 550static int ld9040_ldi_enable(struct ld9040 *lcd)
 551{
 552        int ret = 0;
 553
 554        ret = ld9040_panel_send_sequence(lcd, seq_display_on);
 555
 556        return ret;
 557}
 558
 559static int ld9040_ldi_disable(struct ld9040 *lcd)
 560{
 561        int ret;
 562
 563        ret = ld9040_panel_send_sequence(lcd, seq_display_off);
 564        ret = ld9040_panel_send_sequence(lcd, seq_sleep_in);
 565
 566        return ret;
 567}
 568
 569static int ld9040_power_on(struct ld9040 *lcd)
 570{
 571        int ret = 0;
 572        struct lcd_platform_data *pd = NULL;
 573        pd = lcd->lcd_pd;
 574        if (!pd) {
 575                dev_err(lcd->dev, "platform data is NULL.\n");
 576                return -EFAULT;
 577        }
 578
 579        /* lcd power on */
 580        ld9040_regulator_enable(lcd);
 581
 582        if (!pd->reset) {
 583                dev_err(lcd->dev, "reset is NULL.\n");
 584                return -EFAULT;
 585        } else {
 586                pd->reset(lcd->ld);
 587                mdelay(pd->reset_delay);
 588        }
 589
 590        ret = ld9040_ldi_init(lcd);
 591        if (ret) {
 592                dev_err(lcd->dev, "failed to initialize ldi.\n");
 593                return ret;
 594        }
 595
 596        ret = ld9040_ldi_enable(lcd);
 597        if (ret) {
 598                dev_err(lcd->dev, "failed to enable ldi.\n");
 599                return ret;
 600        }
 601
 602        return 0;
 603}
 604
 605static int ld9040_power_off(struct ld9040 *lcd)
 606{
 607        int ret = 0;
 608        struct lcd_platform_data *pd = NULL;
 609
 610        pd = lcd->lcd_pd;
 611        if (!pd) {
 612                dev_err(lcd->dev, "platform data is NULL.\n");
 613                return -EFAULT;
 614        }
 615
 616        ret = ld9040_ldi_disable(lcd);
 617        if (ret) {
 618                dev_err(lcd->dev, "lcd setting failed.\n");
 619                return -EIO;
 620        }
 621
 622        mdelay(pd->power_off_delay);
 623
 624        /* lcd power off */
 625        ld9040_regulator_disable(lcd);
 626
 627        return 0;
 628}
 629
 630static int ld9040_power(struct ld9040 *lcd, int power)
 631{
 632        int ret = 0;
 633
 634        if (power_is_on(power) && !power_is_on(lcd->power))
 635                ret = ld9040_power_on(lcd);
 636        else if (!power_is_on(power) && power_is_on(lcd->power))
 637                ret = ld9040_power_off(lcd);
 638
 639        if (!ret)
 640                lcd->power = power;
 641
 642        return ret;
 643}
 644
 645static int ld9040_set_power(struct lcd_device *ld, int power)
 646{
 647        struct ld9040 *lcd = lcd_get_data(ld);
 648
 649        if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
 650                power != FB_BLANK_NORMAL) {
 651                dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
 652                return -EINVAL;
 653        }
 654
 655        return ld9040_power(lcd, power);
 656}
 657
 658static int ld9040_get_power(struct lcd_device *ld)
 659{
 660        struct ld9040 *lcd = lcd_get_data(ld);
 661
 662        return lcd->power;
 663}
 664
 665static int ld9040_get_brightness(struct backlight_device *bd)
 666{
 667        return bd->props.brightness;
 668}
 669
 670static int ld9040_set_brightness(struct backlight_device *bd)
 671{
 672        int ret = 0, brightness = bd->props.brightness;
 673        struct ld9040 *lcd = bl_get_data(bd);
 674
 675        if (brightness < MIN_BRIGHTNESS ||
 676                brightness > bd->props.max_brightness) {
 677                dev_err(&bd->dev, "lcd brightness should be %d to %d.\n",
 678                        MIN_BRIGHTNESS, MAX_BRIGHTNESS);
 679                return -EINVAL;
 680        }
 681
 682        ret = ld9040_gamma_ctl(lcd, bd->props.brightness);
 683        if (ret) {
 684                dev_err(&bd->dev, "lcd brightness setting failed.\n");
 685                return -EIO;
 686        }
 687
 688        return ret;
 689}
 690
 691static struct lcd_ops ld9040_lcd_ops = {
 692        .set_power = ld9040_set_power,
 693        .get_power = ld9040_get_power,
 694};
 695
 696static const struct backlight_ops ld9040_backlight_ops  = {
 697        .get_brightness = ld9040_get_brightness,
 698        .update_status = ld9040_set_brightness,
 699};
 700
 701
 702static int ld9040_probe(struct spi_device *spi)
 703{
 704        int ret = 0;
 705        struct ld9040 *lcd = NULL;
 706        struct lcd_device *ld = NULL;
 707        struct backlight_device *bd = NULL;
 708        struct backlight_properties props;
 709
 710        lcd = devm_kzalloc(&spi->dev, sizeof(struct ld9040), GFP_KERNEL);
 711        if (!lcd)
 712                return -ENOMEM;
 713
 714        /* ld9040 lcd panel uses 3-wire 9bits SPI Mode. */
 715        spi->bits_per_word = 9;
 716
 717        ret = spi_setup(spi);
 718        if (ret < 0) {
 719                dev_err(&spi->dev, "spi setup failed.\n");
 720                return ret;
 721        }
 722
 723        lcd->spi = spi;
 724        lcd->dev = &spi->dev;
 725
 726        lcd->lcd_pd = spi->dev.platform_data;
 727        if (!lcd->lcd_pd) {
 728                dev_err(&spi->dev, "platform data is NULL.\n");
 729                return -EFAULT;
 730        }
 731
 732        mutex_init(&lcd->lock);
 733
 734        ret = regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
 735        if (ret) {
 736                dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
 737                return ret;
 738        }
 739
 740        ld = lcd_device_register("ld9040", &spi->dev, lcd, &ld9040_lcd_ops);
 741        if (IS_ERR(ld)) {
 742                ret = PTR_ERR(ld);
 743                goto out_free_regulator;
 744        }
 745
 746        lcd->ld = ld;
 747
 748        memset(&props, 0, sizeof(struct backlight_properties));
 749        props.type = BACKLIGHT_RAW;
 750        props.max_brightness = MAX_BRIGHTNESS;
 751
 752        bd = backlight_device_register("ld9040-bl", &spi->dev,
 753                lcd, &ld9040_backlight_ops, &props);
 754        if (IS_ERR(bd)) {
 755                ret = PTR_ERR(bd);
 756                goto out_unregister_lcd;
 757        }
 758
 759        bd->props.brightness = MAX_BRIGHTNESS;
 760        lcd->bd = bd;
 761
 762        /*
 763         * if lcd panel was on from bootloader like u-boot then
 764         * do not lcd on.
 765         */
 766        if (!lcd->lcd_pd->lcd_enabled) {
 767                /*
 768                 * if lcd panel was off from bootloader then
 769                 * current lcd status is powerdown and then
 770                 * it enables lcd panel.
 771                 */
 772                lcd->power = FB_BLANK_POWERDOWN;
 773
 774                ld9040_power(lcd, FB_BLANK_UNBLANK);
 775        } else
 776                lcd->power = FB_BLANK_UNBLANK;
 777
 778        dev_set_drvdata(&spi->dev, lcd);
 779
 780        dev_info(&spi->dev, "ld9040 panel driver has been probed.\n");
 781        return 0;
 782
 783out_unregister_lcd:
 784        lcd_device_unregister(lcd->ld);
 785out_free_regulator:
 786        regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
 787
 788        return ret;
 789}
 790
 791static int __devexit ld9040_remove(struct spi_device *spi)
 792{
 793        struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
 794
 795        ld9040_power(lcd, FB_BLANK_POWERDOWN);
 796        backlight_device_unregister(lcd->bd);
 797        lcd_device_unregister(lcd->ld);
 798        regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
 799
 800        return 0;
 801}
 802
 803#if defined(CONFIG_PM)
 804static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg)
 805{
 806        int ret = 0;
 807        struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
 808
 809        dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
 810
 811        /*
 812         * when lcd panel is suspend, lcd panel becomes off
 813         * regardless of status.
 814         */
 815        ret = ld9040_power(lcd, FB_BLANK_POWERDOWN);
 816
 817        return ret;
 818}
 819
 820static int ld9040_resume(struct spi_device *spi)
 821{
 822        int ret = 0;
 823        struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
 824
 825        lcd->power = FB_BLANK_POWERDOWN;
 826
 827        ret = ld9040_power(lcd, FB_BLANK_UNBLANK);
 828
 829        return ret;
 830}
 831#else
 832#define ld9040_suspend          NULL
 833#define ld9040_resume           NULL
 834#endif
 835
 836/* Power down all displays on reboot, poweroff or halt. */
 837static void ld9040_shutdown(struct spi_device *spi)
 838{
 839        struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
 840
 841        ld9040_power(lcd, FB_BLANK_POWERDOWN);
 842}
 843
 844static struct spi_driver ld9040_driver = {
 845        .driver = {
 846                .name   = "ld9040",
 847                .owner  = THIS_MODULE,
 848        },
 849        .probe          = ld9040_probe,
 850        .remove         = __devexit_p(ld9040_remove),
 851        .shutdown       = ld9040_shutdown,
 852        .suspend        = ld9040_suspend,
 853        .resume         = ld9040_resume,
 854};
 855
 856module_spi_driver(ld9040_driver);
 857
 858MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
 859MODULE_DESCRIPTION("ld9040 LCD Driver");
 860MODULE_LICENSE("GPL");
 861