Merge branch 'for-3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
[deliverable/linux.git] / drivers / video / backlight / ld9040.c
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
38 struct 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
52 static struct regulator_bulk_data supplies[] = {
53 { .supply = "vdd3", },
54 { .supply = "vci", },
55 };
56
57 static 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);
72 out:
73 mutex_unlock(&lcd->lock);
74 }
75
76 static 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 }
88 out:
89 mutex_unlock(&lcd->lock);
90 }
91
92 static const unsigned short seq_swreset[] = {
93 0x01, COMMAND_ONLY,
94 ENDDEF, 0x00
95 };
96
97 static const unsigned short seq_user_setting[] = {
98 0xF0, 0x5A,
99
100 DATA_ONLY, 0x5A,
101 ENDDEF, 0x00
102 };
103
104 static const unsigned short seq_elvss_on[] = {
105 0xB1, 0x0D,
106
107 DATA_ONLY, 0x00,
108 DATA_ONLY, 0x16,
109 ENDDEF, 0x00
110 };
111
112 static const unsigned short seq_gtcon[] = {
113 0xF7, 0x09,
114
115 DATA_ONLY, 0x00,
116 DATA_ONLY, 0x00,
117 ENDDEF, 0x00
118 };
119
120 static 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
148 static 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
174 static const unsigned short seq_gamma_ctrl[] = {
175 0xFB, 0x02,
176
177 DATA_ONLY, 0x5A,
178 ENDDEF, 0x00
179 };
180
181 static const unsigned short seq_gamma_start[] = {
182 0xF9, COMMAND_ONLY,
183
184 ENDDEF, 0x00
185 };
186
187 static 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
197 static 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
207 static const unsigned short seq_manual_pwr[] = {
208 0xB0, 0x04,
209 ENDDEF, 0x00
210 };
211
212 static 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
224 static const unsigned short seq_sleep_out[] = {
225 0x11, COMMAND_ONLY,
226 ENDDEF, 0x00
227 };
228
229 static const unsigned short seq_sleep_in[] = {
230 0x10, COMMAND_ONLY,
231 ENDDEF, 0x00
232 };
233
234 static const unsigned short seq_display_on[] = {
235 0x29, COMMAND_ONLY,
236 ENDDEF, 0x00
237 };
238
239 static const unsigned short seq_display_off[] = {
240 0x28, COMMAND_ONLY,
241 ENDDEF, 0x00
242 };
243
244 static 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
254 static 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
264 static 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
274 static 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
284 static 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
294 static 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
304 static 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
314 static 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
324 static 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
334 static 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
346 static 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
356 static 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
366 static 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
378 static 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
390 static 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
402 static 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
414 static 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
426 static 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
444 static 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
457 static 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
476 static 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
501 gamma_err:
502 return ret;
503 }
504
505 static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma)
506 {
507 return _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
508 }
509
510 static 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
536 static int ld9040_ldi_enable(struct ld9040 *lcd)
537 {
538 return ld9040_panel_send_sequence(lcd, seq_display_on);
539 }
540
541 static 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
551 static int ld9040_power_is_on(int power)
552 {
553 return power <= FB_BLANK_NORMAL;
554 }
555
556 static 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
589 static 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
610 static 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
625 static 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
638 static int ld9040_get_power(struct lcd_device *ld)
639 {
640 struct ld9040 *lcd = lcd_get_data(ld);
641
642 return lcd->power;
643 }
644
645 static int ld9040_get_brightness(struct backlight_device *bd)
646 {
647 return bd->props.brightness;
648 }
649
650 static 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
671 static struct lcd_ops ld9040_lcd_ops = {
672 .set_power = ld9040_set_power,
673 .get_power = ld9040_get_power,
674 };
675
676 static const struct backlight_ops ld9040_backlight_ops = {
677 .get_brightness = ld9040_get_brightness,
678 .update_status = ld9040_set_brightness,
679 };
680
681 static 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
761 out_unregister_lcd:
762 lcd_device_unregister(lcd->ld);
763
764 return ret;
765 }
766
767 static 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
779 static 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
792 static 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
802 static SIMPLE_DEV_PM_OPS(ld9040_pm_ops, ld9040_suspend, ld9040_resume);
803
804 /* Power down all displays on reboot, poweroff or halt. */
805 static 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
812 static 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
823 module_spi_driver(ld9040_driver);
824
825 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
826 MODULE_DESCRIPTION("ld9040 LCD Driver");
827 MODULE_LICENSE("GPL");
This page took 0.050624 seconds and 5 git commands to generate.