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