0001
0002
0003
0004
0005
0006
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
0187
0188
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
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
0350
0351
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
0383
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");