Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * lms501kf03 TFT LCD panel driver.
0004  *
0005  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
0006  * Author: Jingoo Han  <jg1.han@samsung.com>
0007  */
0008 
0009 #include <linux/backlight.h>
0010 #include <linux/delay.h>
0011 #include <linux/fb.h>
0012 #include <linux/lcd.h>
0013 #include <linux/module.h>
0014 #include <linux/spi/spi.h>
0015 #include <linux/wait.h>
0016 
0017 #define COMMAND_ONLY        0x00
0018 #define DATA_ONLY       0x01
0019 
0020 struct lms501kf03 {
0021     struct device           *dev;
0022     struct spi_device       *spi;
0023     unsigned int            power;
0024     struct lcd_device       *ld;
0025     struct lcd_platform_data    *lcd_pd;
0026 };
0027 
0028 static const unsigned char seq_password[] = {
0029     0xb9, 0xff, 0x83, 0x69,
0030 };
0031 
0032 static const unsigned char seq_power[] = {
0033     0xb1, 0x01, 0x00, 0x34, 0x06, 0x00, 0x14, 0x14, 0x20, 0x28,
0034     0x12, 0x12, 0x17, 0x0a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
0035 };
0036 
0037 static const unsigned char seq_display[] = {
0038     0xb2, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00, 0xff, 0x00, 0x00,
0039     0x00, 0x00, 0x03, 0x03, 0x00, 0x01,
0040 };
0041 
0042 static const unsigned char seq_rgb_if[] = {
0043     0xb3, 0x09,
0044 };
0045 
0046 static const unsigned char seq_display_inv[] = {
0047     0xb4, 0x01, 0x08, 0x77, 0x0e, 0x06,
0048 };
0049 
0050 static const unsigned char seq_vcom[] = {
0051     0xb6, 0x4c, 0x2e,
0052 };
0053 
0054 static const unsigned char seq_gate[] = {
0055     0xd5, 0x00, 0x05, 0x03, 0x29, 0x01, 0x07, 0x17, 0x68, 0x13,
0056     0x37, 0x20, 0x31, 0x8a, 0x46, 0x9b, 0x57, 0x13, 0x02, 0x75,
0057     0xb9, 0x64, 0xa8, 0x07, 0x0f, 0x04, 0x07,
0058 };
0059 
0060 static const unsigned char seq_panel[] = {
0061     0xcc, 0x02,
0062 };
0063 
0064 static const unsigned char seq_col_mod[] = {
0065     0x3a, 0x77,
0066 };
0067 
0068 static const unsigned char seq_w_gamma[] = {
0069     0xe0, 0x00, 0x04, 0x09, 0x0f, 0x1f, 0x3f, 0x1f, 0x2f, 0x0a,
0070     0x0f, 0x10, 0x16, 0x18, 0x16, 0x17, 0x0d, 0x15, 0x00, 0x04,
0071     0x09, 0x0f, 0x38, 0x3f, 0x20, 0x39, 0x0a, 0x0f, 0x10, 0x16,
0072     0x18, 0x16, 0x17, 0x0d, 0x15,
0073 };
0074 
0075 static const unsigned char seq_rgb_gamma[] = {
0076     0xc1, 0x01, 0x03, 0x07, 0x0f, 0x1a, 0x22, 0x2c, 0x33, 0x3c,
0077     0x46, 0x4f, 0x58, 0x60, 0x69, 0x71, 0x79, 0x82, 0x89, 0x92,
0078     0x9a, 0xa1, 0xa9, 0xb1, 0xb9, 0xc1, 0xc9, 0xcf, 0xd6, 0xde,
0079     0xe5, 0xec, 0xf3, 0xf9, 0xff, 0xdd, 0x39, 0x07, 0x1c, 0xcb,
0080     0xab, 0x5f, 0x49, 0x80, 0x03, 0x07, 0x0f, 0x19, 0x20, 0x2a,
0081     0x31, 0x39, 0x42, 0x4b, 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b,
0082     0x83, 0x8a, 0x92, 0x9b, 0xa2, 0xaa, 0xb2, 0xba, 0xc2, 0xca,
0083     0xd0, 0xd8, 0xe1, 0xe8, 0xf0, 0xf8, 0xff, 0xf7, 0xd8, 0xbe,
0084     0xa7, 0x39, 0x40, 0x85, 0x8c, 0xc0, 0x04, 0x07, 0x0c, 0x17,
0085     0x1c, 0x23, 0x2b, 0x34, 0x3b, 0x43, 0x4c, 0x54, 0x5b, 0x63,
0086     0x6a, 0x73, 0x7a, 0x82, 0x8a, 0x91, 0x98, 0xa1, 0xa8, 0xb0,
0087     0xb7, 0xc1, 0xc9, 0xcf, 0xd9, 0xe3, 0xea, 0xf4, 0xff, 0x00,
0088     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0089 };
0090 
0091 static const unsigned char seq_sleep_out[] = {
0092     0x11,
0093 };
0094 
0095 static const unsigned char seq_display_on[] = {
0096     0x29,
0097 };
0098 
0099 static const unsigned char seq_display_off[] = {
0100     0x10,
0101 };
0102 
0103 static int lms501kf03_spi_write_byte(struct lms501kf03 *lcd, int addr, int data)
0104 {
0105     u16 buf[1];
0106     struct spi_message msg;
0107 
0108     struct spi_transfer xfer = {
0109         .len        = 2,
0110         .tx_buf     = buf,
0111     };
0112 
0113     buf[0] = (addr << 8) | data;
0114 
0115     spi_message_init(&msg);
0116     spi_message_add_tail(&xfer, &msg);
0117 
0118     return spi_sync(lcd->spi, &msg);
0119 }
0120 
0121 static int lms501kf03_spi_write(struct lms501kf03 *lcd, unsigned char address,
0122                 unsigned char command)
0123 {
0124     return lms501kf03_spi_write_byte(lcd, address, command);
0125 }
0126 
0127 static int lms501kf03_panel_send_sequence(struct lms501kf03 *lcd,
0128                     const unsigned char *wbuf,
0129                     unsigned int len)
0130 {
0131     int ret = 0, i = 0;
0132 
0133     while (i < len) {
0134         if (i == 0)
0135             ret = lms501kf03_spi_write(lcd, COMMAND_ONLY, wbuf[i]);
0136         else
0137             ret = lms501kf03_spi_write(lcd, DATA_ONLY, wbuf[i]);
0138         if (ret)
0139             break;
0140         i += 1;
0141     }
0142 
0143     return ret;
0144 }
0145 
0146 static int lms501kf03_ldi_init(struct lms501kf03 *lcd)
0147 {
0148     int ret, i;
0149     static const unsigned char *init_seq[] = {
0150         seq_password,
0151         seq_power,
0152         seq_display,
0153         seq_rgb_if,
0154         seq_display_inv,
0155         seq_vcom,
0156         seq_gate,
0157         seq_panel,
0158         seq_col_mod,
0159         seq_w_gamma,
0160         seq_rgb_gamma,
0161         seq_sleep_out,
0162     };
0163 
0164     static const unsigned int size_seq[] = {
0165         ARRAY_SIZE(seq_password),
0166         ARRAY_SIZE(seq_power),
0167         ARRAY_SIZE(seq_display),
0168         ARRAY_SIZE(seq_rgb_if),
0169         ARRAY_SIZE(seq_display_inv),
0170         ARRAY_SIZE(seq_vcom),
0171         ARRAY_SIZE(seq_gate),
0172         ARRAY_SIZE(seq_panel),
0173         ARRAY_SIZE(seq_col_mod),
0174         ARRAY_SIZE(seq_w_gamma),
0175         ARRAY_SIZE(seq_rgb_gamma),
0176         ARRAY_SIZE(seq_sleep_out),
0177     };
0178 
0179     for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
0180         ret = lms501kf03_panel_send_sequence(lcd, init_seq[i],
0181                         size_seq[i]);
0182         if (ret)
0183             break;
0184     }
0185     /*
0186      * According to the datasheet, 120ms delay time is required.
0187      * After sleep out sequence, command is blocked for 120ms.
0188      * Thus, LDI should wait for 120ms.
0189      */
0190     msleep(120);
0191 
0192     return ret;
0193 }
0194 
0195 static int lms501kf03_ldi_enable(struct lms501kf03 *lcd)
0196 {
0197     return lms501kf03_panel_send_sequence(lcd, seq_display_on,
0198                     ARRAY_SIZE(seq_display_on));
0199 }
0200 
0201 static int lms501kf03_ldi_disable(struct lms501kf03 *lcd)
0202 {
0203     return lms501kf03_panel_send_sequence(lcd, seq_display_off,
0204                     ARRAY_SIZE(seq_display_off));
0205 }
0206 
0207 static int lms501kf03_power_is_on(int power)
0208 {
0209     return (power) <= FB_BLANK_NORMAL;
0210 }
0211 
0212 static int lms501kf03_power_on(struct lms501kf03 *lcd)
0213 {
0214     int ret = 0;
0215     struct lcd_platform_data *pd;
0216 
0217     pd = lcd->lcd_pd;
0218 
0219     if (!pd->power_on) {
0220         dev_err(lcd->dev, "power_on is NULL.\n");
0221         return -EINVAL;
0222     }
0223 
0224     pd->power_on(lcd->ld, 1);
0225     msleep(pd->power_on_delay);
0226 
0227     if (!pd->reset) {
0228         dev_err(lcd->dev, "reset is NULL.\n");
0229         return -EINVAL;
0230     }
0231 
0232     pd->reset(lcd->ld);
0233     msleep(pd->reset_delay);
0234 
0235     ret = lms501kf03_ldi_init(lcd);
0236     if (ret) {
0237         dev_err(lcd->dev, "failed to initialize ldi.\n");
0238         return ret;
0239     }
0240 
0241     ret = lms501kf03_ldi_enable(lcd);
0242     if (ret) {
0243         dev_err(lcd->dev, "failed to enable ldi.\n");
0244         return ret;
0245     }
0246 
0247     return 0;
0248 }
0249 
0250 static int lms501kf03_power_off(struct lms501kf03 *lcd)
0251 {
0252     int ret = 0;
0253     struct lcd_platform_data *pd;
0254 
0255     pd = lcd->lcd_pd;
0256 
0257     ret = lms501kf03_ldi_disable(lcd);
0258     if (ret) {
0259         dev_err(lcd->dev, "lcd setting failed.\n");
0260         return -EIO;
0261     }
0262 
0263     msleep(pd->power_off_delay);
0264 
0265     pd->power_on(lcd->ld, 0);
0266 
0267     return 0;
0268 }
0269 
0270 static int lms501kf03_power(struct lms501kf03 *lcd, int power)
0271 {
0272     int ret = 0;
0273 
0274     if (lms501kf03_power_is_on(power) &&
0275         !lms501kf03_power_is_on(lcd->power))
0276         ret = lms501kf03_power_on(lcd);
0277     else if (!lms501kf03_power_is_on(power) &&
0278         lms501kf03_power_is_on(lcd->power))
0279         ret = lms501kf03_power_off(lcd);
0280 
0281     if (!ret)
0282         lcd->power = power;
0283 
0284     return ret;
0285 }
0286 
0287 static int lms501kf03_get_power(struct lcd_device *ld)
0288 {
0289     struct lms501kf03 *lcd = lcd_get_data(ld);
0290 
0291     return lcd->power;
0292 }
0293 
0294 static int lms501kf03_set_power(struct lcd_device *ld, int power)
0295 {
0296     struct lms501kf03 *lcd = lcd_get_data(ld);
0297 
0298     if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
0299         power != FB_BLANK_NORMAL) {
0300         dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
0301         return -EINVAL;
0302     }
0303 
0304     return lms501kf03_power(lcd, power);
0305 }
0306 
0307 static struct lcd_ops lms501kf03_lcd_ops = {
0308     .get_power = lms501kf03_get_power,
0309     .set_power = lms501kf03_set_power,
0310 };
0311 
0312 static int lms501kf03_probe(struct spi_device *spi)
0313 {
0314     struct lms501kf03 *lcd = NULL;
0315     struct lcd_device *ld = NULL;
0316     int ret = 0;
0317 
0318     lcd = devm_kzalloc(&spi->dev, sizeof(struct lms501kf03), GFP_KERNEL);
0319     if (!lcd)
0320         return -ENOMEM;
0321 
0322     /* lms501kf03 lcd panel uses 3-wire 9-bit SPI Mode. */
0323     spi->bits_per_word = 9;
0324 
0325     ret = spi_setup(spi);
0326     if (ret < 0) {
0327         dev_err(&spi->dev, "spi setup failed.\n");
0328         return ret;
0329     }
0330 
0331     lcd->spi = spi;
0332     lcd->dev = &spi->dev;
0333 
0334     lcd->lcd_pd = dev_get_platdata(&spi->dev);
0335     if (!lcd->lcd_pd) {
0336         dev_err(&spi->dev, "platform data is NULL\n");
0337         return -EINVAL;
0338     }
0339 
0340     ld = devm_lcd_device_register(&spi->dev, "lms501kf03", &spi->dev, lcd,
0341                     &lms501kf03_lcd_ops);
0342     if (IS_ERR(ld))
0343         return PTR_ERR(ld);
0344 
0345     lcd->ld = ld;
0346 
0347     if (!lcd->lcd_pd->lcd_enabled) {
0348         /*
0349          * if lcd panel was off from bootloader then
0350          * current lcd status is powerdown and then
0351          * it enables lcd panel.
0352          */
0353         lcd->power = FB_BLANK_POWERDOWN;
0354 
0355         lms501kf03_power(lcd, FB_BLANK_UNBLANK);
0356     } else {
0357         lcd->power = FB_BLANK_UNBLANK;
0358     }
0359 
0360     spi_set_drvdata(spi, lcd);
0361 
0362     dev_info(&spi->dev, "lms501kf03 panel driver has been probed.\n");
0363 
0364     return 0;
0365 }
0366 
0367 static void lms501kf03_remove(struct spi_device *spi)
0368 {
0369     struct lms501kf03 *lcd = spi_get_drvdata(spi);
0370 
0371     lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
0372 }
0373 
0374 #ifdef CONFIG_PM_SLEEP
0375 static int lms501kf03_suspend(struct device *dev)
0376 {
0377     struct lms501kf03 *lcd = dev_get_drvdata(dev);
0378 
0379     dev_dbg(dev, "lcd->power = %d\n", lcd->power);
0380 
0381     /*
0382      * when lcd panel is suspend, lcd panel becomes off
0383      * regardless of status.
0384      */
0385     return lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
0386 }
0387 
0388 static int lms501kf03_resume(struct device *dev)
0389 {
0390     struct lms501kf03 *lcd = dev_get_drvdata(dev);
0391 
0392     lcd->power = FB_BLANK_POWERDOWN;
0393 
0394     return lms501kf03_power(lcd, FB_BLANK_UNBLANK);
0395 }
0396 #endif
0397 
0398 static SIMPLE_DEV_PM_OPS(lms501kf03_pm_ops, lms501kf03_suspend,
0399             lms501kf03_resume);
0400 
0401 static void lms501kf03_shutdown(struct spi_device *spi)
0402 {
0403     struct lms501kf03 *lcd = spi_get_drvdata(spi);
0404 
0405     lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
0406 }
0407 
0408 static struct spi_driver lms501kf03_driver = {
0409     .driver = {
0410         .name   = "lms501kf03",
0411         .pm = &lms501kf03_pm_ops,
0412     },
0413     .probe      = lms501kf03_probe,
0414     .remove     = lms501kf03_remove,
0415     .shutdown   = lms501kf03_shutdown,
0416 };
0417 
0418 module_spi_driver(lms501kf03_driver);
0419 
0420 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
0421 MODULE_DESCRIPTION("lms501kf03 LCD Driver");
0422 MODULE_LICENSE("GPL");