Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.8-rc5 860 lines 17 kB view raw
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 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 = 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");