1
2
3
4
5
6
7
8
9
10
11
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
339 DATA_ONLY, 0x00,
340 DATA_ONLY, 0x00,
341 DATA_ONLY, 0x03,
342
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
371 DATA_ONLY, 0x00,
372 DATA_ONLY, 0x00,
373 DATA_ONLY, 0x03,
374
375 ENDDEF, 0x00
376};
377
378static const unsigned short seq_sd_amp_en[] = {
379 0xF3, 0x37,
380
381 DATA_ONLY, 0xFF,
382
383 DATA_ONLY, 0x80,
384 DATA_ONLY, 0x00,
385 DATA_ONLY, 0x03,
386
387 ENDDEF, 0x00
388};
389
390static const unsigned short seq_gls_en[] = {
391 0xF3, 0x37,
392
393 DATA_ONLY, 0xFF,
394
395 DATA_ONLY, 0x81,
396 DATA_ONLY, 0x00,
397 DATA_ONLY, 0x03,
398
399 ENDDEF, 0x00
400};
401
402static const unsigned short seq_els_en[] = {
403 0xF3, 0x37,
404
405 DATA_ONLY, 0xFF,
406
407 DATA_ONLY, 0x83,
408 DATA_ONLY, 0x00,
409 DATA_ONLY, 0x03,
410
411 ENDDEF, 0x00
412};
413
414static const unsigned short seq_el_on[] = {
415 0xF3, 0x37,
416
417 DATA_ONLY, 0xFF,
418
419 DATA_ONLY, 0x87,
420 DATA_ONLY, 0x00,
421 DATA_ONLY, 0x03,
422
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
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
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
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
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
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
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
734
735
736 if (!lcd->lcd_pd->lcd_enabled) {
737
738
739
740
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
772
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
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 .pm = &ld9040_pm_ops,
801 },
802 .probe = ld9040_probe,
803 .remove = ld9040_remove,
804 .shutdown = ld9040_shutdown,
805};
806
807module_spi_driver(ld9040_driver);
808
809MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
810MODULE_DESCRIPTION("ld9040 LCD Driver");
811MODULE_LICENSE("GPL");
812