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 
46 struct 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 
57 static const unsigned short seq_swreset[] = {
58 	0x01, COMMAND_ONLY,
59 	ENDDEF, 0x00
60 };
61 
62 static const unsigned short seq_user_setting[] = {
63 	0xF0, 0x5A,
64 
65 	DATA_ONLY, 0x5A,
66 	ENDDEF, 0x00
67 };
68 
69 static const unsigned short seq_elvss_on[] = {
70 	0xB1, 0x0D,
71 
72 	DATA_ONLY, 0x00,
73 	DATA_ONLY, 0x16,
74 	ENDDEF, 0x00
75 };
76 
77 static const unsigned short seq_gtcon[] = {
78 	0xF7, 0x09,
79 
80 	DATA_ONLY, 0x00,
81 	DATA_ONLY, 0x00,
82 	ENDDEF, 0x00
83 };
84 
85 static 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 
113 static 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 
139 static const unsigned short seq_gamma_ctrl[] = {
140 	0xFB, 0x02,
141 
142 	DATA_ONLY, 0x5A,
143 	ENDDEF, 0x00
144 };
145 
146 static const unsigned short seq_gamma_start[] = {
147 	0xF9, COMMAND_ONLY,
148 
149 	ENDDEF, 0x00
150 };
151 
152 static 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 
162 static 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 
172 static const unsigned short seq_manual_pwr[] = {
173 	0xB0, 0x04,
174 	ENDDEF, 0x00
175 };
176 
177 static 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 
189 static const unsigned short seq_sleep_out[] = {
190 	0x11, COMMAND_ONLY,
191 	ENDDEF, 0x00
192 };
193 
194 static const unsigned short seq_sleep_in[] = {
195 	0x10, COMMAND_ONLY,
196 	ENDDEF, 0x00
197 };
198 
199 static const unsigned short seq_display_on[] = {
200 	0x29, COMMAND_ONLY,
201 	ENDDEF, 0x00
202 };
203 
204 static const unsigned short seq_display_off[] = {
205 	0x28, COMMAND_ONLY,
206 	ENDDEF, 0x00
207 };
208 
209 static 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 
219 static 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 
229 static 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 
239 static 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 
249 static 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 
259 static 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 
269 static 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 
279 static 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 
289 static 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 
299 static 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 
311 static 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 
321 static 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 
331 static 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 
343 static 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 
355 static 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 
367 static 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 
379 static 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 
ld9040_spi_write_byte(struct ld9040 * lcd,int addr,int data)391 static 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 
ld9040_spi_write(struct ld9040 * lcd,unsigned char address,unsigned char command)409 static 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 
ld9040_panel_send_sequence(struct ld9040 * lcd,const unsigned short * wbuf)422 static 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 
_ld9040_gamma_ctl(struct ld9040 * lcd,const unsigned int * gamma)440 static 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 
465 gamma_err:
466 	return ret;
467 }
468 
ld9040_gamma_ctl(struct ld9040 * lcd,int gamma)469 static 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 
ld9040_ldi_init(struct ld9040 * lcd)479 static 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 
ld9040_ldi_enable(struct ld9040 * lcd)505 static 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 
ld9040_ldi_disable(struct ld9040 * lcd)514 static 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 
ld9040_power_on(struct ld9040 * lcd)524 static 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 
ld9040_power_off(struct ld9040 * lcd)565 static 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 
ld9040_power(struct ld9040 * lcd,int power)593 static 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 
ld9040_set_power(struct lcd_device * ld,int power)608 static 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 
ld9040_get_power(struct lcd_device * ld)621 static int ld9040_get_power(struct lcd_device *ld)
622 {
623 	struct ld9040 *lcd = lcd_get_data(ld);
624 
625 	return lcd->power;
626 }
627 
ld9040_get_brightness(struct backlight_device * bd)628 static int ld9040_get_brightness(struct backlight_device *bd)
629 {
630 	return bd->props.brightness;
631 }
632 
ld9040_set_brightness(struct backlight_device * bd)633 static 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 
654 static struct lcd_ops ld9040_lcd_ops = {
655 	.set_power = ld9040_set_power,
656 	.get_power = ld9040_get_power,
657 };
658 
659 static const struct backlight_ops ld9040_backlight_ops  = {
660 	.get_brightness = ld9040_get_brightness,
661 	.update_status = ld9040_set_brightness,
662 };
663 
664 
ld9040_probe(struct spi_device * spi)665 static 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 
734 out_free_lcd:
735 	kfree(lcd);
736 	return ret;
737 }
738 
ld9040_remove(struct spi_device * spi)739 static 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)
ld9040_suspend(struct spi_device * spi,pm_message_t mesg)751 static 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 
ld9040_resume(struct spi_device * spi)767 static 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. */
ld9040_shutdown(struct spi_device * spi)784 static 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 
791 static 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 
ld9040_init(void)804 static int __init ld9040_init(void)
805 {
806 	return spi_register_driver(&ld9040_driver);
807 }
808 
ld9040_exit(void)809 static void __exit ld9040_exit(void)
810 {
811 	spi_unregister_driver(&ld9040_driver);
812 }
813 
814 module_init(ld9040_init);
815 module_exit(ld9040_exit);
816 
817 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
818 MODULE_DESCRIPTION("ld9040 LCD Driver");
819 MODULE_LICENSE("GPL");
820