xref: /openbmc/linux/drivers/video/backlight/lms501kf03.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21be9ca25SJingoo Han /*
31be9ca25SJingoo Han  * lms501kf03 TFT LCD panel driver.
41be9ca25SJingoo Han  *
51be9ca25SJingoo Han  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
61be9ca25SJingoo Han  * Author: Jingoo Han  <jg1.han@samsung.com>
71be9ca25SJingoo Han  */
81be9ca25SJingoo Han 
91be9ca25SJingoo Han #include <linux/backlight.h>
101be9ca25SJingoo Han #include <linux/delay.h>
111be9ca25SJingoo Han #include <linux/fb.h>
121be9ca25SJingoo Han #include <linux/lcd.h>
131be9ca25SJingoo Han #include <linux/module.h>
141be9ca25SJingoo Han #include <linux/spi/spi.h>
151be9ca25SJingoo Han #include <linux/wait.h>
161be9ca25SJingoo Han 
171be9ca25SJingoo Han #define COMMAND_ONLY		0x00
181be9ca25SJingoo Han #define DATA_ONLY		0x01
191be9ca25SJingoo Han 
201be9ca25SJingoo Han struct lms501kf03 {
211be9ca25SJingoo Han 	struct device			*dev;
221be9ca25SJingoo Han 	struct spi_device		*spi;
231be9ca25SJingoo Han 	unsigned int			power;
241be9ca25SJingoo Han 	struct lcd_device		*ld;
251be9ca25SJingoo Han 	struct lcd_platform_data	*lcd_pd;
261be9ca25SJingoo Han };
271be9ca25SJingoo Han 
281be9ca25SJingoo Han static const unsigned char seq_password[] = {
291be9ca25SJingoo Han 	0xb9, 0xff, 0x83, 0x69,
301be9ca25SJingoo Han };
311be9ca25SJingoo Han 
321be9ca25SJingoo Han static const unsigned char seq_power[] = {
331be9ca25SJingoo Han 	0xb1, 0x01, 0x00, 0x34, 0x06, 0x00, 0x14, 0x14, 0x20, 0x28,
341be9ca25SJingoo Han 	0x12, 0x12, 0x17, 0x0a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
351be9ca25SJingoo Han };
361be9ca25SJingoo Han 
371be9ca25SJingoo Han static const unsigned char seq_display[] = {
381be9ca25SJingoo Han 	0xb2, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00, 0xff, 0x00, 0x00,
391be9ca25SJingoo Han 	0x00, 0x00, 0x03, 0x03, 0x00, 0x01,
401be9ca25SJingoo Han };
411be9ca25SJingoo Han 
421be9ca25SJingoo Han static const unsigned char seq_rgb_if[] = {
431be9ca25SJingoo Han 	0xb3, 0x09,
441be9ca25SJingoo Han };
451be9ca25SJingoo Han 
461be9ca25SJingoo Han static const unsigned char seq_display_inv[] = {
471be9ca25SJingoo Han 	0xb4, 0x01, 0x08, 0x77, 0x0e, 0x06,
481be9ca25SJingoo Han };
491be9ca25SJingoo Han 
501be9ca25SJingoo Han static const unsigned char seq_vcom[] = {
511be9ca25SJingoo Han 	0xb6, 0x4c, 0x2e,
521be9ca25SJingoo Han };
531be9ca25SJingoo Han 
541be9ca25SJingoo Han static const unsigned char seq_gate[] = {
551be9ca25SJingoo Han 	0xd5, 0x00, 0x05, 0x03, 0x29, 0x01, 0x07, 0x17, 0x68, 0x13,
561be9ca25SJingoo Han 	0x37, 0x20, 0x31, 0x8a, 0x46, 0x9b, 0x57, 0x13, 0x02, 0x75,
571be9ca25SJingoo Han 	0xb9, 0x64, 0xa8, 0x07, 0x0f, 0x04, 0x07,
581be9ca25SJingoo Han };
591be9ca25SJingoo Han 
601be9ca25SJingoo Han static const unsigned char seq_panel[] = {
611be9ca25SJingoo Han 	0xcc, 0x02,
621be9ca25SJingoo Han };
631be9ca25SJingoo Han 
641be9ca25SJingoo Han static const unsigned char seq_col_mod[] = {
651be9ca25SJingoo Han 	0x3a, 0x77,
661be9ca25SJingoo Han };
671be9ca25SJingoo Han 
681be9ca25SJingoo Han static const unsigned char seq_w_gamma[] = {
691be9ca25SJingoo Han 	0xe0, 0x00, 0x04, 0x09, 0x0f, 0x1f, 0x3f, 0x1f, 0x2f, 0x0a,
701be9ca25SJingoo Han 	0x0f, 0x10, 0x16, 0x18, 0x16, 0x17, 0x0d, 0x15, 0x00, 0x04,
711be9ca25SJingoo Han 	0x09, 0x0f, 0x38, 0x3f, 0x20, 0x39, 0x0a, 0x0f, 0x10, 0x16,
721be9ca25SJingoo Han 	0x18, 0x16, 0x17, 0x0d, 0x15,
731be9ca25SJingoo Han };
741be9ca25SJingoo Han 
751be9ca25SJingoo Han static const unsigned char seq_rgb_gamma[] = {
761be9ca25SJingoo Han 	0xc1, 0x01, 0x03, 0x07, 0x0f, 0x1a, 0x22, 0x2c, 0x33, 0x3c,
771be9ca25SJingoo Han 	0x46, 0x4f, 0x58, 0x60, 0x69, 0x71, 0x79, 0x82, 0x89, 0x92,
781be9ca25SJingoo Han 	0x9a, 0xa1, 0xa9, 0xb1, 0xb9, 0xc1, 0xc9, 0xcf, 0xd6, 0xde,
791be9ca25SJingoo Han 	0xe5, 0xec, 0xf3, 0xf9, 0xff, 0xdd, 0x39, 0x07, 0x1c, 0xcb,
801be9ca25SJingoo Han 	0xab, 0x5f, 0x49, 0x80, 0x03, 0x07, 0x0f, 0x19, 0x20, 0x2a,
811be9ca25SJingoo Han 	0x31, 0x39, 0x42, 0x4b, 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b,
821be9ca25SJingoo Han 	0x83, 0x8a, 0x92, 0x9b, 0xa2, 0xaa, 0xb2, 0xba, 0xc2, 0xca,
831be9ca25SJingoo Han 	0xd0, 0xd8, 0xe1, 0xe8, 0xf0, 0xf8, 0xff, 0xf7, 0xd8, 0xbe,
841be9ca25SJingoo Han 	0xa7, 0x39, 0x40, 0x85, 0x8c, 0xc0, 0x04, 0x07, 0x0c, 0x17,
851be9ca25SJingoo Han 	0x1c, 0x23, 0x2b, 0x34, 0x3b, 0x43, 0x4c, 0x54, 0x5b, 0x63,
861be9ca25SJingoo Han 	0x6a, 0x73, 0x7a, 0x82, 0x8a, 0x91, 0x98, 0xa1, 0xa8, 0xb0,
871be9ca25SJingoo Han 	0xb7, 0xc1, 0xc9, 0xcf, 0xd9, 0xe3, 0xea, 0xf4, 0xff, 0x00,
881be9ca25SJingoo Han 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
891be9ca25SJingoo Han };
901be9ca25SJingoo Han 
911be9ca25SJingoo Han static const unsigned char seq_sleep_out[] = {
921be9ca25SJingoo Han 	0x11,
931be9ca25SJingoo Han };
941be9ca25SJingoo Han 
951be9ca25SJingoo Han static const unsigned char seq_display_on[] = {
961be9ca25SJingoo Han 	0x29,
971be9ca25SJingoo Han };
981be9ca25SJingoo Han 
991be9ca25SJingoo Han static const unsigned char seq_display_off[] = {
1001be9ca25SJingoo Han 	0x10,
1011be9ca25SJingoo Han };
1021be9ca25SJingoo Han 
lms501kf03_spi_write_byte(struct lms501kf03 * lcd,int addr,int data)1031be9ca25SJingoo Han static int lms501kf03_spi_write_byte(struct lms501kf03 *lcd, int addr, int data)
1041be9ca25SJingoo Han {
1051be9ca25SJingoo Han 	u16 buf[1];
1061be9ca25SJingoo Han 	struct spi_message msg;
1071be9ca25SJingoo Han 
1081be9ca25SJingoo Han 	struct spi_transfer xfer = {
1091be9ca25SJingoo Han 		.len		= 2,
1101be9ca25SJingoo Han 		.tx_buf		= buf,
1111be9ca25SJingoo Han 	};
1121be9ca25SJingoo Han 
1131be9ca25SJingoo Han 	buf[0] = (addr << 8) | data;
1141be9ca25SJingoo Han 
1151be9ca25SJingoo Han 	spi_message_init(&msg);
1161be9ca25SJingoo Han 	spi_message_add_tail(&xfer, &msg);
1171be9ca25SJingoo Han 
1181be9ca25SJingoo Han 	return spi_sync(lcd->spi, &msg);
1191be9ca25SJingoo Han }
1201be9ca25SJingoo Han 
lms501kf03_spi_write(struct lms501kf03 * lcd,unsigned char address,unsigned char command)1211be9ca25SJingoo Han static int lms501kf03_spi_write(struct lms501kf03 *lcd, unsigned char address,
1221be9ca25SJingoo Han 				unsigned char command)
1231be9ca25SJingoo Han {
1241be9ca25SJingoo Han 	return lms501kf03_spi_write_byte(lcd, address, command);
1251be9ca25SJingoo Han }
1261be9ca25SJingoo Han 
lms501kf03_panel_send_sequence(struct lms501kf03 * lcd,const unsigned char * wbuf,unsigned int len)1271be9ca25SJingoo Han static int lms501kf03_panel_send_sequence(struct lms501kf03 *lcd,
1281be9ca25SJingoo Han 					const unsigned char *wbuf,
1291be9ca25SJingoo Han 					unsigned int len)
1301be9ca25SJingoo Han {
1311be9ca25SJingoo Han 	int ret = 0, i = 0;
1321be9ca25SJingoo Han 
1331be9ca25SJingoo Han 	while (i < len) {
1341be9ca25SJingoo Han 		if (i == 0)
1351be9ca25SJingoo Han 			ret = lms501kf03_spi_write(lcd, COMMAND_ONLY, wbuf[i]);
1361be9ca25SJingoo Han 		else
1371be9ca25SJingoo Han 			ret = lms501kf03_spi_write(lcd, DATA_ONLY, wbuf[i]);
1381be9ca25SJingoo Han 		if (ret)
1391be9ca25SJingoo Han 			break;
1401be9ca25SJingoo Han 		i += 1;
1411be9ca25SJingoo Han 	}
1421be9ca25SJingoo Han 
1431be9ca25SJingoo Han 	return ret;
1441be9ca25SJingoo Han }
1451be9ca25SJingoo Han 
lms501kf03_ldi_init(struct lms501kf03 * lcd)1461be9ca25SJingoo Han static int lms501kf03_ldi_init(struct lms501kf03 *lcd)
1471be9ca25SJingoo Han {
1481be9ca25SJingoo Han 	int ret, i;
1491be9ca25SJingoo Han 	static const unsigned char *init_seq[] = {
1501be9ca25SJingoo Han 		seq_password,
1511be9ca25SJingoo Han 		seq_power,
1521be9ca25SJingoo Han 		seq_display,
1531be9ca25SJingoo Han 		seq_rgb_if,
1541be9ca25SJingoo Han 		seq_display_inv,
1551be9ca25SJingoo Han 		seq_vcom,
1561be9ca25SJingoo Han 		seq_gate,
1571be9ca25SJingoo Han 		seq_panel,
1581be9ca25SJingoo Han 		seq_col_mod,
1591be9ca25SJingoo Han 		seq_w_gamma,
1601be9ca25SJingoo Han 		seq_rgb_gamma,
1611be9ca25SJingoo Han 		seq_sleep_out,
1621be9ca25SJingoo Han 	};
1631be9ca25SJingoo Han 
1641be9ca25SJingoo Han 	static const unsigned int size_seq[] = {
1651be9ca25SJingoo Han 		ARRAY_SIZE(seq_password),
1661be9ca25SJingoo Han 		ARRAY_SIZE(seq_power),
1671be9ca25SJingoo Han 		ARRAY_SIZE(seq_display),
1681be9ca25SJingoo Han 		ARRAY_SIZE(seq_rgb_if),
1691be9ca25SJingoo Han 		ARRAY_SIZE(seq_display_inv),
1701be9ca25SJingoo Han 		ARRAY_SIZE(seq_vcom),
1711be9ca25SJingoo Han 		ARRAY_SIZE(seq_gate),
1721be9ca25SJingoo Han 		ARRAY_SIZE(seq_panel),
1731be9ca25SJingoo Han 		ARRAY_SIZE(seq_col_mod),
1741be9ca25SJingoo Han 		ARRAY_SIZE(seq_w_gamma),
1751be9ca25SJingoo Han 		ARRAY_SIZE(seq_rgb_gamma),
1761be9ca25SJingoo Han 		ARRAY_SIZE(seq_sleep_out),
1771be9ca25SJingoo Han 	};
1781be9ca25SJingoo Han 
1791be9ca25SJingoo Han 	for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
1801be9ca25SJingoo Han 		ret = lms501kf03_panel_send_sequence(lcd, init_seq[i],
1811be9ca25SJingoo Han 						size_seq[i]);
1821be9ca25SJingoo Han 		if (ret)
1831be9ca25SJingoo Han 			break;
1841be9ca25SJingoo Han 	}
1851be9ca25SJingoo Han 	/*
1861be9ca25SJingoo Han 	 * According to the datasheet, 120ms delay time is required.
1871be9ca25SJingoo Han 	 * After sleep out sequence, command is blocked for 120ms.
1881be9ca25SJingoo Han 	 * Thus, LDI should wait for 120ms.
1891be9ca25SJingoo Han 	 */
1901be9ca25SJingoo Han 	msleep(120);
1911be9ca25SJingoo Han 
1921be9ca25SJingoo Han 	return ret;
1931be9ca25SJingoo Han }
1941be9ca25SJingoo Han 
lms501kf03_ldi_enable(struct lms501kf03 * lcd)1951be9ca25SJingoo Han static int lms501kf03_ldi_enable(struct lms501kf03 *lcd)
1961be9ca25SJingoo Han {
1971be9ca25SJingoo Han 	return lms501kf03_panel_send_sequence(lcd, seq_display_on,
1981be9ca25SJingoo Han 					ARRAY_SIZE(seq_display_on));
1991be9ca25SJingoo Han }
2001be9ca25SJingoo Han 
lms501kf03_ldi_disable(struct lms501kf03 * lcd)2011be9ca25SJingoo Han static int lms501kf03_ldi_disable(struct lms501kf03 *lcd)
2021be9ca25SJingoo Han {
2031be9ca25SJingoo Han 	return lms501kf03_panel_send_sequence(lcd, seq_display_off,
2041be9ca25SJingoo Han 					ARRAY_SIZE(seq_display_off));
2051be9ca25SJingoo Han }
2061be9ca25SJingoo Han 
lms501kf03_power_is_on(int power)2071be9ca25SJingoo Han static int lms501kf03_power_is_on(int power)
2081be9ca25SJingoo Han {
2091be9ca25SJingoo Han 	return (power) <= FB_BLANK_NORMAL;
2101be9ca25SJingoo Han }
2111be9ca25SJingoo Han 
lms501kf03_power_on(struct lms501kf03 * lcd)2121be9ca25SJingoo Han static int lms501kf03_power_on(struct lms501kf03 *lcd)
2131be9ca25SJingoo Han {
2141be9ca25SJingoo Han 	int ret = 0;
2151be9ca25SJingoo Han 	struct lcd_platform_data *pd;
2161be9ca25SJingoo Han 
2171be9ca25SJingoo Han 	pd = lcd->lcd_pd;
2181be9ca25SJingoo Han 
2191be9ca25SJingoo Han 	if (!pd->power_on) {
2201be9ca25SJingoo Han 		dev_err(lcd->dev, "power_on is NULL.\n");
2211be9ca25SJingoo Han 		return -EINVAL;
222b50ffb8aSJingoo Han 	}
223b50ffb8aSJingoo Han 
2241be9ca25SJingoo Han 	pd->power_on(lcd->ld, 1);
2251be9ca25SJingoo Han 	msleep(pd->power_on_delay);
2261be9ca25SJingoo Han 
2271be9ca25SJingoo Han 	if (!pd->reset) {
2281be9ca25SJingoo Han 		dev_err(lcd->dev, "reset is NULL.\n");
2291be9ca25SJingoo Han 		return -EINVAL;
230b50ffb8aSJingoo Han 	}
231b50ffb8aSJingoo Han 
2321be9ca25SJingoo Han 	pd->reset(lcd->ld);
2331be9ca25SJingoo Han 	msleep(pd->reset_delay);
2341be9ca25SJingoo Han 
2351be9ca25SJingoo Han 	ret = lms501kf03_ldi_init(lcd);
2361be9ca25SJingoo Han 	if (ret) {
2371be9ca25SJingoo Han 		dev_err(lcd->dev, "failed to initialize ldi.\n");
2381be9ca25SJingoo Han 		return ret;
2391be9ca25SJingoo Han 	}
2401be9ca25SJingoo Han 
2411be9ca25SJingoo Han 	ret = lms501kf03_ldi_enable(lcd);
2421be9ca25SJingoo Han 	if (ret) {
2431be9ca25SJingoo Han 		dev_err(lcd->dev, "failed to enable ldi.\n");
2441be9ca25SJingoo Han 		return ret;
2451be9ca25SJingoo Han 	}
2461be9ca25SJingoo Han 
2471be9ca25SJingoo Han 	return 0;
2481be9ca25SJingoo Han }
2491be9ca25SJingoo Han 
lms501kf03_power_off(struct lms501kf03 * lcd)2501be9ca25SJingoo Han static int lms501kf03_power_off(struct lms501kf03 *lcd)
2511be9ca25SJingoo Han {
2521be9ca25SJingoo Han 	int ret = 0;
2531be9ca25SJingoo Han 	struct lcd_platform_data *pd;
2541be9ca25SJingoo Han 
2551be9ca25SJingoo Han 	pd = lcd->lcd_pd;
2561be9ca25SJingoo Han 
2571be9ca25SJingoo Han 	ret = lms501kf03_ldi_disable(lcd);
2581be9ca25SJingoo Han 	if (ret) {
2591be9ca25SJingoo Han 		dev_err(lcd->dev, "lcd setting failed.\n");
2601be9ca25SJingoo Han 		return -EIO;
2611be9ca25SJingoo Han 	}
2621be9ca25SJingoo Han 
2631be9ca25SJingoo Han 	msleep(pd->power_off_delay);
2641be9ca25SJingoo Han 
2651be9ca25SJingoo Han 	pd->power_on(lcd->ld, 0);
2661be9ca25SJingoo Han 
2671be9ca25SJingoo Han 	return 0;
2681be9ca25SJingoo Han }
2691be9ca25SJingoo Han 
lms501kf03_power(struct lms501kf03 * lcd,int power)2701be9ca25SJingoo Han static int lms501kf03_power(struct lms501kf03 *lcd, int power)
2711be9ca25SJingoo Han {
2721be9ca25SJingoo Han 	int ret = 0;
2731be9ca25SJingoo Han 
2741be9ca25SJingoo Han 	if (lms501kf03_power_is_on(power) &&
2751be9ca25SJingoo Han 		!lms501kf03_power_is_on(lcd->power))
2761be9ca25SJingoo Han 		ret = lms501kf03_power_on(lcd);
2771be9ca25SJingoo Han 	else if (!lms501kf03_power_is_on(power) &&
2781be9ca25SJingoo Han 		lms501kf03_power_is_on(lcd->power))
2791be9ca25SJingoo Han 		ret = lms501kf03_power_off(lcd);
2801be9ca25SJingoo Han 
2811be9ca25SJingoo Han 	if (!ret)
2821be9ca25SJingoo Han 		lcd->power = power;
2831be9ca25SJingoo Han 
2841be9ca25SJingoo Han 	return ret;
2851be9ca25SJingoo Han }
2861be9ca25SJingoo Han 
lms501kf03_get_power(struct lcd_device * ld)2871be9ca25SJingoo Han static int lms501kf03_get_power(struct lcd_device *ld)
2881be9ca25SJingoo Han {
2891be9ca25SJingoo Han 	struct lms501kf03 *lcd = lcd_get_data(ld);
2901be9ca25SJingoo Han 
2911be9ca25SJingoo Han 	return lcd->power;
2921be9ca25SJingoo Han }
2931be9ca25SJingoo Han 
lms501kf03_set_power(struct lcd_device * ld,int power)2941be9ca25SJingoo Han static int lms501kf03_set_power(struct lcd_device *ld, int power)
2951be9ca25SJingoo Han {
2961be9ca25SJingoo Han 	struct lms501kf03 *lcd = lcd_get_data(ld);
2971be9ca25SJingoo Han 
2981be9ca25SJingoo Han 	if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
2991be9ca25SJingoo Han 		power != FB_BLANK_NORMAL) {
3001be9ca25SJingoo Han 		dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
3011be9ca25SJingoo Han 		return -EINVAL;
3021be9ca25SJingoo Han 	}
3031be9ca25SJingoo Han 
3041be9ca25SJingoo Han 	return lms501kf03_power(lcd, power);
3051be9ca25SJingoo Han }
3061be9ca25SJingoo Han 
3071be9ca25SJingoo Han static struct lcd_ops lms501kf03_lcd_ops = {
3081be9ca25SJingoo Han 	.get_power = lms501kf03_get_power,
3091be9ca25SJingoo Han 	.set_power = lms501kf03_set_power,
3101be9ca25SJingoo Han };
3111be9ca25SJingoo Han 
lms501kf03_probe(struct spi_device * spi)3121be9ca25SJingoo Han static int lms501kf03_probe(struct spi_device *spi)
3131be9ca25SJingoo Han {
3141be9ca25SJingoo Han 	struct lms501kf03 *lcd = NULL;
3151be9ca25SJingoo Han 	struct lcd_device *ld = NULL;
3161be9ca25SJingoo Han 	int ret = 0;
3171be9ca25SJingoo Han 
3181be9ca25SJingoo Han 	lcd = devm_kzalloc(&spi->dev, sizeof(struct lms501kf03), GFP_KERNEL);
3191be9ca25SJingoo Han 	if (!lcd)
3201be9ca25SJingoo Han 		return -ENOMEM;
3211be9ca25SJingoo Han 
3221be9ca25SJingoo Han 	/* lms501kf03 lcd panel uses 3-wire 9-bit SPI Mode. */
3231be9ca25SJingoo Han 	spi->bits_per_word = 9;
3241be9ca25SJingoo Han 
3251be9ca25SJingoo Han 	ret = spi_setup(spi);
3261be9ca25SJingoo Han 	if (ret < 0) {
3271be9ca25SJingoo Han 		dev_err(&spi->dev, "spi setup failed.\n");
3281be9ca25SJingoo Han 		return ret;
3291be9ca25SJingoo Han 	}
3301be9ca25SJingoo Han 
3311be9ca25SJingoo Han 	lcd->spi = spi;
3321be9ca25SJingoo Han 	lcd->dev = &spi->dev;
3331be9ca25SJingoo Han 
334c512794cSJingoo Han 	lcd->lcd_pd = dev_get_platdata(&spi->dev);
3351be9ca25SJingoo Han 	if (!lcd->lcd_pd) {
3361be9ca25SJingoo Han 		dev_err(&spi->dev, "platform data is NULL\n");
3371be9ca25SJingoo Han 		return -EINVAL;
3381be9ca25SJingoo Han 	}
3391be9ca25SJingoo Han 
3408358741aSJingoo Han 	ld = devm_lcd_device_register(&spi->dev, "lms501kf03", &spi->dev, lcd,
3411be9ca25SJingoo Han 					&lms501kf03_lcd_ops);
3421be9ca25SJingoo Han 	if (IS_ERR(ld))
3431be9ca25SJingoo Han 		return PTR_ERR(ld);
3441be9ca25SJingoo Han 
3451be9ca25SJingoo Han 	lcd->ld = ld;
3461be9ca25SJingoo Han 
3471be9ca25SJingoo Han 	if (!lcd->lcd_pd->lcd_enabled) {
3481be9ca25SJingoo Han 		/*
3491be9ca25SJingoo Han 		 * if lcd panel was off from bootloader then
3501be9ca25SJingoo Han 		 * current lcd status is powerdown and then
3511be9ca25SJingoo Han 		 * it enables lcd panel.
3521be9ca25SJingoo Han 		 */
3531be9ca25SJingoo Han 		lcd->power = FB_BLANK_POWERDOWN;
3541be9ca25SJingoo Han 
3551be9ca25SJingoo Han 		lms501kf03_power(lcd, FB_BLANK_UNBLANK);
3561be9ca25SJingoo Han 	} else {
3571be9ca25SJingoo Han 		lcd->power = FB_BLANK_UNBLANK;
3581be9ca25SJingoo Han 	}
3591be9ca25SJingoo Han 
360281ea16aSJingoo Han 	spi_set_drvdata(spi, lcd);
3611be9ca25SJingoo Han 
3621be9ca25SJingoo Han 	dev_info(&spi->dev, "lms501kf03 panel driver has been probed.\n");
3631be9ca25SJingoo Han 
3641be9ca25SJingoo Han 	return 0;
3651be9ca25SJingoo Han }
3661be9ca25SJingoo Han 
lms501kf03_remove(struct spi_device * spi)367*a0386bbaSUwe Kleine-König static void lms501kf03_remove(struct spi_device *spi)
3681be9ca25SJingoo Han {
369281ea16aSJingoo Han 	struct lms501kf03 *lcd = spi_get_drvdata(spi);
3701be9ca25SJingoo Han 
3711be9ca25SJingoo Han 	lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
3721be9ca25SJingoo Han }
3731be9ca25SJingoo Han 
37426cd2a44SJingoo Han #ifdef CONFIG_PM_SLEEP
lms501kf03_suspend(struct device * dev)37526cd2a44SJingoo Han static int lms501kf03_suspend(struct device *dev)
3761be9ca25SJingoo Han {
37726cd2a44SJingoo Han 	struct lms501kf03 *lcd = dev_get_drvdata(dev);
3781be9ca25SJingoo Han 
37926cd2a44SJingoo Han 	dev_dbg(dev, "lcd->power = %d\n", lcd->power);
3801be9ca25SJingoo Han 
3811be9ca25SJingoo Han 	/*
3821be9ca25SJingoo Han 	 * when lcd panel is suspend, lcd panel becomes off
3831be9ca25SJingoo Han 	 * regardless of status.
3841be9ca25SJingoo Han 	 */
3851be9ca25SJingoo Han 	return lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
3861be9ca25SJingoo Han }
3871be9ca25SJingoo Han 
lms501kf03_resume(struct device * dev)38826cd2a44SJingoo Han static int lms501kf03_resume(struct device *dev)
3891be9ca25SJingoo Han {
39026cd2a44SJingoo Han 	struct lms501kf03 *lcd = dev_get_drvdata(dev);
3911be9ca25SJingoo Han 
3921be9ca25SJingoo Han 	lcd->power = FB_BLANK_POWERDOWN;
3931be9ca25SJingoo Han 
3941be9ca25SJingoo Han 	return lms501kf03_power(lcd, FB_BLANK_UNBLANK);
3951be9ca25SJingoo Han }
3961be9ca25SJingoo Han #endif
3971be9ca25SJingoo Han 
39826cd2a44SJingoo Han static SIMPLE_DEV_PM_OPS(lms501kf03_pm_ops, lms501kf03_suspend,
39926cd2a44SJingoo Han 			lms501kf03_resume);
40026cd2a44SJingoo Han 
lms501kf03_shutdown(struct spi_device * spi)4011be9ca25SJingoo Han static void lms501kf03_shutdown(struct spi_device *spi)
4021be9ca25SJingoo Han {
403281ea16aSJingoo Han 	struct lms501kf03 *lcd = spi_get_drvdata(spi);
4041be9ca25SJingoo Han 
4051be9ca25SJingoo Han 	lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
4061be9ca25SJingoo Han }
4071be9ca25SJingoo Han 
4081be9ca25SJingoo Han static struct spi_driver lms501kf03_driver = {
4091be9ca25SJingoo Han 	.driver = {
4101be9ca25SJingoo Han 		.name	= "lms501kf03",
41126cd2a44SJingoo Han 		.pm	= &lms501kf03_pm_ops,
4121be9ca25SJingoo Han 	},
4131be9ca25SJingoo Han 	.probe		= lms501kf03_probe,
4141be9ca25SJingoo Han 	.remove		= lms501kf03_remove,
4151be9ca25SJingoo Han 	.shutdown	= lms501kf03_shutdown,
4161be9ca25SJingoo Han };
4171be9ca25SJingoo Han 
4181be9ca25SJingoo Han module_spi_driver(lms501kf03_driver);
4191be9ca25SJingoo Han 
4201be9ca25SJingoo Han MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
4211be9ca25SJingoo Han MODULE_DESCRIPTION("lms501kf03 LCD Driver");
4221be9ca25SJingoo Han MODULE_LICENSE("GPL");
423