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 } 570 571 pd->reset(lcd->ld); 572 msleep(pd->reset_delay); 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_set_brightness(struct backlight_device *bd) 646{ 647 int ret = 0, brightness = bd->props.brightness; 648 struct ld9040 *lcd = bl_get_data(bd); 649 650 if (brightness < MIN_BRIGHTNESS || 651 brightness > bd->props.max_brightness) { 652 dev_err(&bd->dev, "lcd brightness should be %d to %d.\n", 653 MIN_BRIGHTNESS, MAX_BRIGHTNESS); 654 return -EINVAL; 655 } 656 657 ret = ld9040_gamma_ctl(lcd, bd->props.brightness); 658 if (ret) { 659 dev_err(&bd->dev, "lcd brightness setting failed.\n"); 660 return -EIO; 661 } 662 663 return ret; 664} 665 666static struct lcd_ops ld9040_lcd_ops = { 667 .set_power = ld9040_set_power, 668 .get_power = ld9040_get_power, 669}; 670 671static const struct backlight_ops ld9040_backlight_ops = { 672 .update_status = ld9040_set_brightness, 673}; 674 675static int ld9040_probe(struct spi_device *spi) 676{ 677 int ret = 0; 678 struct ld9040 *lcd = NULL; 679 struct lcd_device *ld = NULL; 680 struct backlight_device *bd = NULL; 681 struct backlight_properties props; 682 683 lcd = devm_kzalloc(&spi->dev, sizeof(struct ld9040), GFP_KERNEL); 684 if (!lcd) 685 return -ENOMEM; 686 687 /* ld9040 lcd panel uses 3-wire 9bits SPI Mode. */ 688 spi->bits_per_word = 9; 689 690 ret = spi_setup(spi); 691 if (ret < 0) { 692 dev_err(&spi->dev, "spi setup failed.\n"); 693 return ret; 694 } 695 696 lcd->spi = spi; 697 lcd->dev = &spi->dev; 698 699 lcd->lcd_pd = dev_get_platdata(&spi->dev); 700 if (!lcd->lcd_pd) { 701 dev_err(&spi->dev, "platform data is NULL.\n"); 702 return -EINVAL; 703 } 704 705 mutex_init(&lcd->lock); 706 707 ret = devm_regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies); 708 if (ret) { 709 dev_err(lcd->dev, "Failed to get regulators: %d\n", ret); 710 return ret; 711 } 712 713 ld = devm_lcd_device_register(&spi->dev, "ld9040", &spi->dev, lcd, 714 &ld9040_lcd_ops); 715 if (IS_ERR(ld)) 716 return PTR_ERR(ld); 717 718 lcd->ld = ld; 719 720 memset(&props, 0, sizeof(struct backlight_properties)); 721 props.type = BACKLIGHT_RAW; 722 props.max_brightness = MAX_BRIGHTNESS; 723 724 bd = devm_backlight_device_register(&spi->dev, "ld9040-bl", &spi->dev, 725 lcd, &ld9040_backlight_ops, &props); 726 if (IS_ERR(bd)) 727 return PTR_ERR(bd); 728 729 bd->props.brightness = MAX_BRIGHTNESS; 730 lcd->bd = bd; 731 732 /* 733 * if lcd panel was on from bootloader like u-boot then 734 * do not lcd on. 735 */ 736 if (!lcd->lcd_pd->lcd_enabled) { 737 /* 738 * if lcd panel was off from bootloader then 739 * current lcd status is powerdown and then 740 * it enables lcd panel. 741 */ 742 lcd->power = FB_BLANK_POWERDOWN; 743 744 ld9040_power(lcd, FB_BLANK_UNBLANK); 745 } else { 746 lcd->power = FB_BLANK_UNBLANK; 747 } 748 749 spi_set_drvdata(spi, lcd); 750 751 dev_info(&spi->dev, "ld9040 panel driver has been probed.\n"); 752 return 0; 753} 754 755static int ld9040_remove(struct spi_device *spi) 756{ 757 struct ld9040 *lcd = spi_get_drvdata(spi); 758 759 ld9040_power(lcd, FB_BLANK_POWERDOWN); 760 return 0; 761} 762 763#ifdef CONFIG_PM_SLEEP 764static int ld9040_suspend(struct device *dev) 765{ 766 struct ld9040 *lcd = dev_get_drvdata(dev); 767 768 dev_dbg(dev, "lcd->power = %d\n", lcd->power); 769 770 /* 771 * when lcd panel is suspend, lcd panel becomes off 772 * regardless of status. 773 */ 774 return ld9040_power(lcd, FB_BLANK_POWERDOWN); 775} 776 777static int ld9040_resume(struct device *dev) 778{ 779 struct ld9040 *lcd = dev_get_drvdata(dev); 780 781 lcd->power = FB_BLANK_POWERDOWN; 782 783 return ld9040_power(lcd, FB_BLANK_UNBLANK); 784} 785#endif 786 787static SIMPLE_DEV_PM_OPS(ld9040_pm_ops, ld9040_suspend, ld9040_resume); 788 789/* Power down all displays on reboot, poweroff or halt. */ 790static void ld9040_shutdown(struct spi_device *spi) 791{ 792 struct ld9040 *lcd = spi_get_drvdata(spi); 793 794 ld9040_power(lcd, FB_BLANK_POWERDOWN); 795} 796 797static struct spi_driver ld9040_driver = { 798 .driver = { 799 .name = "ld9040", 800 .owner = THIS_MODULE, 801 .pm = &ld9040_pm_ops, 802 }, 803 .probe = ld9040_probe, 804 .remove = ld9040_remove, 805 .shutdown = ld9040_shutdown, 806}; 807 808module_spi_driver(ld9040_driver); 809 810MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>"); 811MODULE_DESCRIPTION("ld9040 LCD Driver"); 812MODULE_LICENSE("GPL"); 813