18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * lms501kf03 TFT LCD panel driver. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2012 Samsung Electronics Co., Ltd. 68c2ecf20Sopenharmony_ci * Author: Jingoo Han <jg1.han@samsung.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/backlight.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/fb.h> 128c2ecf20Sopenharmony_ci#include <linux/lcd.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 158c2ecf20Sopenharmony_ci#include <linux/wait.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define COMMAND_ONLY 0x00 188c2ecf20Sopenharmony_ci#define DATA_ONLY 0x01 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct lms501kf03 { 218c2ecf20Sopenharmony_ci struct device *dev; 228c2ecf20Sopenharmony_ci struct spi_device *spi; 238c2ecf20Sopenharmony_ci unsigned int power; 248c2ecf20Sopenharmony_ci struct lcd_device *ld; 258c2ecf20Sopenharmony_ci struct lcd_platform_data *lcd_pd; 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic const unsigned char seq_password[] = { 298c2ecf20Sopenharmony_ci 0xb9, 0xff, 0x83, 0x69, 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic const unsigned char seq_power[] = { 338c2ecf20Sopenharmony_ci 0xb1, 0x01, 0x00, 0x34, 0x06, 0x00, 0x14, 0x14, 0x20, 0x28, 348c2ecf20Sopenharmony_ci 0x12, 0x12, 0x17, 0x0a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic const unsigned char seq_display[] = { 388c2ecf20Sopenharmony_ci 0xb2, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00, 0xff, 0x00, 0x00, 398c2ecf20Sopenharmony_ci 0x00, 0x00, 0x03, 0x03, 0x00, 0x01, 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const unsigned char seq_rgb_if[] = { 438c2ecf20Sopenharmony_ci 0xb3, 0x09, 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic const unsigned char seq_display_inv[] = { 478c2ecf20Sopenharmony_ci 0xb4, 0x01, 0x08, 0x77, 0x0e, 0x06, 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic const unsigned char seq_vcom[] = { 518c2ecf20Sopenharmony_ci 0xb6, 0x4c, 0x2e, 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic const unsigned char seq_gate[] = { 558c2ecf20Sopenharmony_ci 0xd5, 0x00, 0x05, 0x03, 0x29, 0x01, 0x07, 0x17, 0x68, 0x13, 568c2ecf20Sopenharmony_ci 0x37, 0x20, 0x31, 0x8a, 0x46, 0x9b, 0x57, 0x13, 0x02, 0x75, 578c2ecf20Sopenharmony_ci 0xb9, 0x64, 0xa8, 0x07, 0x0f, 0x04, 0x07, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic const unsigned char seq_panel[] = { 618c2ecf20Sopenharmony_ci 0xcc, 0x02, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic const unsigned char seq_col_mod[] = { 658c2ecf20Sopenharmony_ci 0x3a, 0x77, 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic const unsigned char seq_w_gamma[] = { 698c2ecf20Sopenharmony_ci 0xe0, 0x00, 0x04, 0x09, 0x0f, 0x1f, 0x3f, 0x1f, 0x2f, 0x0a, 708c2ecf20Sopenharmony_ci 0x0f, 0x10, 0x16, 0x18, 0x16, 0x17, 0x0d, 0x15, 0x00, 0x04, 718c2ecf20Sopenharmony_ci 0x09, 0x0f, 0x38, 0x3f, 0x20, 0x39, 0x0a, 0x0f, 0x10, 0x16, 728c2ecf20Sopenharmony_ci 0x18, 0x16, 0x17, 0x0d, 0x15, 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic const unsigned char seq_rgb_gamma[] = { 768c2ecf20Sopenharmony_ci 0xc1, 0x01, 0x03, 0x07, 0x0f, 0x1a, 0x22, 0x2c, 0x33, 0x3c, 778c2ecf20Sopenharmony_ci 0x46, 0x4f, 0x58, 0x60, 0x69, 0x71, 0x79, 0x82, 0x89, 0x92, 788c2ecf20Sopenharmony_ci 0x9a, 0xa1, 0xa9, 0xb1, 0xb9, 0xc1, 0xc9, 0xcf, 0xd6, 0xde, 798c2ecf20Sopenharmony_ci 0xe5, 0xec, 0xf3, 0xf9, 0xff, 0xdd, 0x39, 0x07, 0x1c, 0xcb, 808c2ecf20Sopenharmony_ci 0xab, 0x5f, 0x49, 0x80, 0x03, 0x07, 0x0f, 0x19, 0x20, 0x2a, 818c2ecf20Sopenharmony_ci 0x31, 0x39, 0x42, 0x4b, 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b, 828c2ecf20Sopenharmony_ci 0x83, 0x8a, 0x92, 0x9b, 0xa2, 0xaa, 0xb2, 0xba, 0xc2, 0xca, 838c2ecf20Sopenharmony_ci 0xd0, 0xd8, 0xe1, 0xe8, 0xf0, 0xf8, 0xff, 0xf7, 0xd8, 0xbe, 848c2ecf20Sopenharmony_ci 0xa7, 0x39, 0x40, 0x85, 0x8c, 0xc0, 0x04, 0x07, 0x0c, 0x17, 858c2ecf20Sopenharmony_ci 0x1c, 0x23, 0x2b, 0x34, 0x3b, 0x43, 0x4c, 0x54, 0x5b, 0x63, 868c2ecf20Sopenharmony_ci 0x6a, 0x73, 0x7a, 0x82, 0x8a, 0x91, 0x98, 0xa1, 0xa8, 0xb0, 878c2ecf20Sopenharmony_ci 0xb7, 0xc1, 0xc9, 0xcf, 0xd9, 0xe3, 0xea, 0xf4, 0xff, 0x00, 888c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic const unsigned char seq_sleep_out[] = { 928c2ecf20Sopenharmony_ci 0x11, 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic const unsigned char seq_display_on[] = { 968c2ecf20Sopenharmony_ci 0x29, 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic const unsigned char seq_display_off[] = { 1008c2ecf20Sopenharmony_ci 0x10, 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int lms501kf03_spi_write_byte(struct lms501kf03 *lcd, int addr, int data) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci u16 buf[1]; 1068c2ecf20Sopenharmony_ci struct spi_message msg; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci struct spi_transfer xfer = { 1098c2ecf20Sopenharmony_ci .len = 2, 1108c2ecf20Sopenharmony_ci .tx_buf = buf, 1118c2ecf20Sopenharmony_ci }; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci buf[0] = (addr << 8) | data; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci spi_message_init(&msg); 1168c2ecf20Sopenharmony_ci spi_message_add_tail(&xfer, &msg); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return spi_sync(lcd->spi, &msg); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int lms501kf03_spi_write(struct lms501kf03 *lcd, unsigned char address, 1228c2ecf20Sopenharmony_ci unsigned char command) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci return lms501kf03_spi_write_byte(lcd, address, command); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int lms501kf03_panel_send_sequence(struct lms501kf03 *lcd, 1288c2ecf20Sopenharmony_ci const unsigned char *wbuf, 1298c2ecf20Sopenharmony_ci unsigned int len) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci int ret = 0, i = 0; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci while (i < len) { 1348c2ecf20Sopenharmony_ci if (i == 0) 1358c2ecf20Sopenharmony_ci ret = lms501kf03_spi_write(lcd, COMMAND_ONLY, wbuf[i]); 1368c2ecf20Sopenharmony_ci else 1378c2ecf20Sopenharmony_ci ret = lms501kf03_spi_write(lcd, DATA_ONLY, wbuf[i]); 1388c2ecf20Sopenharmony_ci if (ret) 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci i += 1; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return ret; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int lms501kf03_ldi_init(struct lms501kf03 *lcd) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci int ret, i; 1498c2ecf20Sopenharmony_ci static const unsigned char *init_seq[] = { 1508c2ecf20Sopenharmony_ci seq_password, 1518c2ecf20Sopenharmony_ci seq_power, 1528c2ecf20Sopenharmony_ci seq_display, 1538c2ecf20Sopenharmony_ci seq_rgb_if, 1548c2ecf20Sopenharmony_ci seq_display_inv, 1558c2ecf20Sopenharmony_ci seq_vcom, 1568c2ecf20Sopenharmony_ci seq_gate, 1578c2ecf20Sopenharmony_ci seq_panel, 1588c2ecf20Sopenharmony_ci seq_col_mod, 1598c2ecf20Sopenharmony_ci seq_w_gamma, 1608c2ecf20Sopenharmony_ci seq_rgb_gamma, 1618c2ecf20Sopenharmony_ci seq_sleep_out, 1628c2ecf20Sopenharmony_ci }; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci static const unsigned int size_seq[] = { 1658c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_password), 1668c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_power), 1678c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_display), 1688c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_rgb_if), 1698c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_display_inv), 1708c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_vcom), 1718c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_gate), 1728c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_panel), 1738c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_col_mod), 1748c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_w_gamma), 1758c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_rgb_gamma), 1768c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_sleep_out), 1778c2ecf20Sopenharmony_ci }; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(init_seq); i++) { 1808c2ecf20Sopenharmony_ci ret = lms501kf03_panel_send_sequence(lcd, init_seq[i], 1818c2ecf20Sopenharmony_ci size_seq[i]); 1828c2ecf20Sopenharmony_ci if (ret) 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci /* 1868c2ecf20Sopenharmony_ci * According to the datasheet, 120ms delay time is required. 1878c2ecf20Sopenharmony_ci * After sleep out sequence, command is blocked for 120ms. 1888c2ecf20Sopenharmony_ci * Thus, LDI should wait for 120ms. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci msleep(120); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return ret; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int lms501kf03_ldi_enable(struct lms501kf03 *lcd) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci return lms501kf03_panel_send_sequence(lcd, seq_display_on, 1988c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_display_on)); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int lms501kf03_ldi_disable(struct lms501kf03 *lcd) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci return lms501kf03_panel_send_sequence(lcd, seq_display_off, 2048c2ecf20Sopenharmony_ci ARRAY_SIZE(seq_display_off)); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int lms501kf03_power_is_on(int power) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci return (power) <= FB_BLANK_NORMAL; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic int lms501kf03_power_on(struct lms501kf03 *lcd) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci int ret = 0; 2158c2ecf20Sopenharmony_ci struct lcd_platform_data *pd; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci pd = lcd->lcd_pd; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (!pd->power_on) { 2208c2ecf20Sopenharmony_ci dev_err(lcd->dev, "power_on is NULL.\n"); 2218c2ecf20Sopenharmony_ci return -EINVAL; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci pd->power_on(lcd->ld, 1); 2258c2ecf20Sopenharmony_ci msleep(pd->power_on_delay); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (!pd->reset) { 2288c2ecf20Sopenharmony_ci dev_err(lcd->dev, "reset is NULL.\n"); 2298c2ecf20Sopenharmony_ci return -EINVAL; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci pd->reset(lcd->ld); 2338c2ecf20Sopenharmony_ci msleep(pd->reset_delay); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci ret = lms501kf03_ldi_init(lcd); 2368c2ecf20Sopenharmony_ci if (ret) { 2378c2ecf20Sopenharmony_ci dev_err(lcd->dev, "failed to initialize ldi.\n"); 2388c2ecf20Sopenharmony_ci return ret; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci ret = lms501kf03_ldi_enable(lcd); 2428c2ecf20Sopenharmony_ci if (ret) { 2438c2ecf20Sopenharmony_ci dev_err(lcd->dev, "failed to enable ldi.\n"); 2448c2ecf20Sopenharmony_ci return ret; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int lms501kf03_power_off(struct lms501kf03 *lcd) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci int ret = 0; 2538c2ecf20Sopenharmony_ci struct lcd_platform_data *pd; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci pd = lcd->lcd_pd; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci ret = lms501kf03_ldi_disable(lcd); 2588c2ecf20Sopenharmony_ci if (ret) { 2598c2ecf20Sopenharmony_ci dev_err(lcd->dev, "lcd setting failed.\n"); 2608c2ecf20Sopenharmony_ci return -EIO; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci msleep(pd->power_off_delay); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci pd->power_on(lcd->ld, 0); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic int lms501kf03_power(struct lms501kf03 *lcd, int power) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci int ret = 0; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (lms501kf03_power_is_on(power) && 2758c2ecf20Sopenharmony_ci !lms501kf03_power_is_on(lcd->power)) 2768c2ecf20Sopenharmony_ci ret = lms501kf03_power_on(lcd); 2778c2ecf20Sopenharmony_ci else if (!lms501kf03_power_is_on(power) && 2788c2ecf20Sopenharmony_ci lms501kf03_power_is_on(lcd->power)) 2798c2ecf20Sopenharmony_ci ret = lms501kf03_power_off(lcd); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (!ret) 2828c2ecf20Sopenharmony_ci lcd->power = power; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return ret; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int lms501kf03_get_power(struct lcd_device *ld) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct lms501kf03 *lcd = lcd_get_data(ld); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return lcd->power; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int lms501kf03_set_power(struct lcd_device *ld, int power) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct lms501kf03 *lcd = lcd_get_data(ld); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && 2998c2ecf20Sopenharmony_ci power != FB_BLANK_NORMAL) { 3008c2ecf20Sopenharmony_ci dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); 3018c2ecf20Sopenharmony_ci return -EINVAL; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return lms501kf03_power(lcd, power); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic struct lcd_ops lms501kf03_lcd_ops = { 3088c2ecf20Sopenharmony_ci .get_power = lms501kf03_get_power, 3098c2ecf20Sopenharmony_ci .set_power = lms501kf03_set_power, 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic int lms501kf03_probe(struct spi_device *spi) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct lms501kf03 *lcd = NULL; 3158c2ecf20Sopenharmony_ci struct lcd_device *ld = NULL; 3168c2ecf20Sopenharmony_ci int ret = 0; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci lcd = devm_kzalloc(&spi->dev, sizeof(struct lms501kf03), GFP_KERNEL); 3198c2ecf20Sopenharmony_ci if (!lcd) 3208c2ecf20Sopenharmony_ci return -ENOMEM; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* lms501kf03 lcd panel uses 3-wire 9-bit SPI Mode. */ 3238c2ecf20Sopenharmony_ci spi->bits_per_word = 9; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci ret = spi_setup(spi); 3268c2ecf20Sopenharmony_ci if (ret < 0) { 3278c2ecf20Sopenharmony_ci dev_err(&spi->dev, "spi setup failed.\n"); 3288c2ecf20Sopenharmony_ci return ret; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci lcd->spi = spi; 3328c2ecf20Sopenharmony_ci lcd->dev = &spi->dev; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci lcd->lcd_pd = dev_get_platdata(&spi->dev); 3358c2ecf20Sopenharmony_ci if (!lcd->lcd_pd) { 3368c2ecf20Sopenharmony_ci dev_err(&spi->dev, "platform data is NULL\n"); 3378c2ecf20Sopenharmony_ci return -EINVAL; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci ld = devm_lcd_device_register(&spi->dev, "lms501kf03", &spi->dev, lcd, 3418c2ecf20Sopenharmony_ci &lms501kf03_lcd_ops); 3428c2ecf20Sopenharmony_ci if (IS_ERR(ld)) 3438c2ecf20Sopenharmony_ci return PTR_ERR(ld); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci lcd->ld = ld; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (!lcd->lcd_pd->lcd_enabled) { 3488c2ecf20Sopenharmony_ci /* 3498c2ecf20Sopenharmony_ci * if lcd panel was off from bootloader then 3508c2ecf20Sopenharmony_ci * current lcd status is powerdown and then 3518c2ecf20Sopenharmony_ci * it enables lcd panel. 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ci lcd->power = FB_BLANK_POWERDOWN; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci lms501kf03_power(lcd, FB_BLANK_UNBLANK); 3568c2ecf20Sopenharmony_ci } else { 3578c2ecf20Sopenharmony_ci lcd->power = FB_BLANK_UNBLANK; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci spi_set_drvdata(spi, lcd); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci dev_info(&spi->dev, "lms501kf03 panel driver has been probed.\n"); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return 0; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic int lms501kf03_remove(struct spi_device *spi) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct lms501kf03 *lcd = spi_get_drvdata(spi); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci lms501kf03_power(lcd, FB_BLANK_POWERDOWN); 3728c2ecf20Sopenharmony_ci return 0; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 3768c2ecf20Sopenharmony_cistatic int lms501kf03_suspend(struct device *dev) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct lms501kf03 *lcd = dev_get_drvdata(dev); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci dev_dbg(dev, "lcd->power = %d\n", lcd->power); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* 3838c2ecf20Sopenharmony_ci * when lcd panel is suspend, lcd panel becomes off 3848c2ecf20Sopenharmony_ci * regardless of status. 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_ci return lms501kf03_power(lcd, FB_BLANK_POWERDOWN); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int lms501kf03_resume(struct device *dev) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct lms501kf03 *lcd = dev_get_drvdata(dev); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci lcd->power = FB_BLANK_POWERDOWN; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci return lms501kf03_power(lcd, FB_BLANK_UNBLANK); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci#endif 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(lms501kf03_pm_ops, lms501kf03_suspend, 4008c2ecf20Sopenharmony_ci lms501kf03_resume); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic void lms501kf03_shutdown(struct spi_device *spi) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci struct lms501kf03 *lcd = spi_get_drvdata(spi); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci lms501kf03_power(lcd, FB_BLANK_POWERDOWN); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic struct spi_driver lms501kf03_driver = { 4108c2ecf20Sopenharmony_ci .driver = { 4118c2ecf20Sopenharmony_ci .name = "lms501kf03", 4128c2ecf20Sopenharmony_ci .pm = &lms501kf03_pm_ops, 4138c2ecf20Sopenharmony_ci }, 4148c2ecf20Sopenharmony_ci .probe = lms501kf03_probe, 4158c2ecf20Sopenharmony_ci .remove = lms501kf03_remove, 4168c2ecf20Sopenharmony_ci .shutdown = lms501kf03_shutdown, 4178c2ecf20Sopenharmony_ci}; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cimodule_spi_driver(lms501kf03_driver); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); 4228c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("lms501kf03 LCD Driver"); 4238c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 424