]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/video/backlight/ld9040.c
spi: Drop owner assignment from spi_drivers
[karo-tx-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         }
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
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_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
666 static struct lcd_ops ld9040_lcd_ops = {
667         .set_power = ld9040_set_power,
668         .get_power = ld9040_get_power,
669 };
670
671 static const struct backlight_ops ld9040_backlight_ops  = {
672         .update_status = ld9040_set_brightness,
673 };
674
675 static 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
755 static 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
764 static 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
777 static 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
787 static SIMPLE_DEV_PM_OPS(ld9040_pm_ops, ld9040_suspend, ld9040_resume);
788
789 /* Power down all displays on reboot, poweroff or halt. */
790 static 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
797 static struct spi_driver ld9040_driver = {
798         .driver = {
799                 .name   = "ld9040",
800                 .pm     = &ld9040_pm_ops,
801         },
802         .probe          = ld9040_probe,
803         .remove         = ld9040_remove,
804         .shutdown       = ld9040_shutdown,
805 };
806
807 module_spi_driver(ld9040_driver);
808
809 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
810 MODULE_DESCRIPTION("ld9040 LCD Driver");
811 MODULE_LICENSE("GPL");