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