1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * lms501kf03 TFT LCD panel driver. 4 * 5 * Copyright (c) 2012 Samsung Electronics Co., Ltd. 6 * Author: Jingoo Han <jg1.han@samsung.com> 7 */ 8 9 #include <linux/backlight.h> 10 #include <linux/delay.h> 11 #include <linux/fb.h> 12 #include <linux/gpio.h> 13 #include <linux/lcd.h> 14 #include <linux/module.h> 15 #include <linux/spi/spi.h> 16 #include <linux/wait.h> 17 18 #define COMMAND_ONLY 0x00 19 #define DATA_ONLY 0x01 20 21 struct lms501kf03 { 22 struct device *dev; 23 struct spi_device *spi; 24 unsigned int power; 25 struct lcd_device *ld; 26 struct lcd_platform_data *lcd_pd; 27 }; 28 29 static const unsigned char seq_password[] = { 30 0xb9, 0xff, 0x83, 0x69, 31 }; 32 33 static const unsigned char seq_power[] = { 34 0xb1, 0x01, 0x00, 0x34, 0x06, 0x00, 0x14, 0x14, 0x20, 0x28, 35 0x12, 0x12, 0x17, 0x0a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 36 }; 37 38 static const unsigned char seq_display[] = { 39 0xb2, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00, 0xff, 0x00, 0x00, 40 0x00, 0x00, 0x03, 0x03, 0x00, 0x01, 41 }; 42 43 static const unsigned char seq_rgb_if[] = { 44 0xb3, 0x09, 45 }; 46 47 static const unsigned char seq_display_inv[] = { 48 0xb4, 0x01, 0x08, 0x77, 0x0e, 0x06, 49 }; 50 51 static const unsigned char seq_vcom[] = { 52 0xb6, 0x4c, 0x2e, 53 }; 54 55 static const unsigned char seq_gate[] = { 56 0xd5, 0x00, 0x05, 0x03, 0x29, 0x01, 0x07, 0x17, 0x68, 0x13, 57 0x37, 0x20, 0x31, 0x8a, 0x46, 0x9b, 0x57, 0x13, 0x02, 0x75, 58 0xb9, 0x64, 0xa8, 0x07, 0x0f, 0x04, 0x07, 59 }; 60 61 static const unsigned char seq_panel[] = { 62 0xcc, 0x02, 63 }; 64 65 static const unsigned char seq_col_mod[] = { 66 0x3a, 0x77, 67 }; 68 69 static const unsigned char seq_w_gamma[] = { 70 0xe0, 0x00, 0x04, 0x09, 0x0f, 0x1f, 0x3f, 0x1f, 0x2f, 0x0a, 71 0x0f, 0x10, 0x16, 0x18, 0x16, 0x17, 0x0d, 0x15, 0x00, 0x04, 72 0x09, 0x0f, 0x38, 0x3f, 0x20, 0x39, 0x0a, 0x0f, 0x10, 0x16, 73 0x18, 0x16, 0x17, 0x0d, 0x15, 74 }; 75 76 static const unsigned char seq_rgb_gamma[] = { 77 0xc1, 0x01, 0x03, 0x07, 0x0f, 0x1a, 0x22, 0x2c, 0x33, 0x3c, 78 0x46, 0x4f, 0x58, 0x60, 0x69, 0x71, 0x79, 0x82, 0x89, 0x92, 79 0x9a, 0xa1, 0xa9, 0xb1, 0xb9, 0xc1, 0xc9, 0xcf, 0xd6, 0xde, 80 0xe5, 0xec, 0xf3, 0xf9, 0xff, 0xdd, 0x39, 0x07, 0x1c, 0xcb, 81 0xab, 0x5f, 0x49, 0x80, 0x03, 0x07, 0x0f, 0x19, 0x20, 0x2a, 82 0x31, 0x39, 0x42, 0x4b, 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b, 83 0x83, 0x8a, 0x92, 0x9b, 0xa2, 0xaa, 0xb2, 0xba, 0xc2, 0xca, 84 0xd0, 0xd8, 0xe1, 0xe8, 0xf0, 0xf8, 0xff, 0xf7, 0xd8, 0xbe, 85 0xa7, 0x39, 0x40, 0x85, 0x8c, 0xc0, 0x04, 0x07, 0x0c, 0x17, 86 0x1c, 0x23, 0x2b, 0x34, 0x3b, 0x43, 0x4c, 0x54, 0x5b, 0x63, 87 0x6a, 0x73, 0x7a, 0x82, 0x8a, 0x91, 0x98, 0xa1, 0xa8, 0xb0, 88 0xb7, 0xc1, 0xc9, 0xcf, 0xd9, 0xe3, 0xea, 0xf4, 0xff, 0x00, 89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 90 }; 91 92 static const unsigned char seq_up_dn[] = { 93 0x36, 0x10, 94 }; 95 96 static const unsigned char seq_sleep_in[] = { 97 0x10, 98 }; 99 100 static const unsigned char seq_sleep_out[] = { 101 0x11, 102 }; 103 104 static const unsigned char seq_display_on[] = { 105 0x29, 106 }; 107 108 static const unsigned char seq_display_off[] = { 109 0x10, 110 }; 111 112 static int lms501kf03_spi_write_byte(struct lms501kf03 *lcd, int addr, int data) 113 { 114 u16 buf[1]; 115 struct spi_message msg; 116 117 struct spi_transfer xfer = { 118 .len = 2, 119 .tx_buf = buf, 120 }; 121 122 buf[0] = (addr << 8) | data; 123 124 spi_message_init(&msg); 125 spi_message_add_tail(&xfer, &msg); 126 127 return spi_sync(lcd->spi, &msg); 128 } 129 130 static int lms501kf03_spi_write(struct lms501kf03 *lcd, unsigned char address, 131 unsigned char command) 132 { 133 return lms501kf03_spi_write_byte(lcd, address, command); 134 } 135 136 static int lms501kf03_panel_send_sequence(struct lms501kf03 *lcd, 137 const unsigned char *wbuf, 138 unsigned int len) 139 { 140 int ret = 0, i = 0; 141 142 while (i < len) { 143 if (i == 0) 144 ret = lms501kf03_spi_write(lcd, COMMAND_ONLY, wbuf[i]); 145 else 146 ret = lms501kf03_spi_write(lcd, DATA_ONLY, wbuf[i]); 147 if (ret) 148 break; 149 i += 1; 150 } 151 152 return ret; 153 } 154 155 static int lms501kf03_ldi_init(struct lms501kf03 *lcd) 156 { 157 int ret, i; 158 static const unsigned char *init_seq[] = { 159 seq_password, 160 seq_power, 161 seq_display, 162 seq_rgb_if, 163 seq_display_inv, 164 seq_vcom, 165 seq_gate, 166 seq_panel, 167 seq_col_mod, 168 seq_w_gamma, 169 seq_rgb_gamma, 170 seq_sleep_out, 171 }; 172 173 static const unsigned int size_seq[] = { 174 ARRAY_SIZE(seq_password), 175 ARRAY_SIZE(seq_power), 176 ARRAY_SIZE(seq_display), 177 ARRAY_SIZE(seq_rgb_if), 178 ARRAY_SIZE(seq_display_inv), 179 ARRAY_SIZE(seq_vcom), 180 ARRAY_SIZE(seq_gate), 181 ARRAY_SIZE(seq_panel), 182 ARRAY_SIZE(seq_col_mod), 183 ARRAY_SIZE(seq_w_gamma), 184 ARRAY_SIZE(seq_rgb_gamma), 185 ARRAY_SIZE(seq_sleep_out), 186 }; 187 188 for (i = 0; i < ARRAY_SIZE(init_seq); i++) { 189 ret = lms501kf03_panel_send_sequence(lcd, init_seq[i], 190 size_seq[i]); 191 if (ret) 192 break; 193 } 194 /* 195 * According to the datasheet, 120ms delay time is required. 196 * After sleep out sequence, command is blocked for 120ms. 197 * Thus, LDI should wait for 120ms. 198 */ 199 msleep(120); 200 201 return ret; 202 } 203 204 static int lms501kf03_ldi_enable(struct lms501kf03 *lcd) 205 { 206 return lms501kf03_panel_send_sequence(lcd, seq_display_on, 207 ARRAY_SIZE(seq_display_on)); 208 } 209 210 static int lms501kf03_ldi_disable(struct lms501kf03 *lcd) 211 { 212 return lms501kf03_panel_send_sequence(lcd, seq_display_off, 213 ARRAY_SIZE(seq_display_off)); 214 } 215 216 static int lms501kf03_power_is_on(int power) 217 { 218 return (power) <= FB_BLANK_NORMAL; 219 } 220 221 static int lms501kf03_power_on(struct lms501kf03 *lcd) 222 { 223 int ret = 0; 224 struct lcd_platform_data *pd; 225 226 pd = lcd->lcd_pd; 227 228 if (!pd->power_on) { 229 dev_err(lcd->dev, "power_on is NULL.\n"); 230 return -EINVAL; 231 } 232 233 pd->power_on(lcd->ld, 1); 234 msleep(pd->power_on_delay); 235 236 if (!pd->reset) { 237 dev_err(lcd->dev, "reset is NULL.\n"); 238 return -EINVAL; 239 } 240 241 pd->reset(lcd->ld); 242 msleep(pd->reset_delay); 243 244 ret = lms501kf03_ldi_init(lcd); 245 if (ret) { 246 dev_err(lcd->dev, "failed to initialize ldi.\n"); 247 return ret; 248 } 249 250 ret = lms501kf03_ldi_enable(lcd); 251 if (ret) { 252 dev_err(lcd->dev, "failed to enable ldi.\n"); 253 return ret; 254 } 255 256 return 0; 257 } 258 259 static int lms501kf03_power_off(struct lms501kf03 *lcd) 260 { 261 int ret = 0; 262 struct lcd_platform_data *pd; 263 264 pd = lcd->lcd_pd; 265 266 ret = lms501kf03_ldi_disable(lcd); 267 if (ret) { 268 dev_err(lcd->dev, "lcd setting failed.\n"); 269 return -EIO; 270 } 271 272 msleep(pd->power_off_delay); 273 274 pd->power_on(lcd->ld, 0); 275 276 return 0; 277 } 278 279 static int lms501kf03_power(struct lms501kf03 *lcd, int power) 280 { 281 int ret = 0; 282 283 if (lms501kf03_power_is_on(power) && 284 !lms501kf03_power_is_on(lcd->power)) 285 ret = lms501kf03_power_on(lcd); 286 else if (!lms501kf03_power_is_on(power) && 287 lms501kf03_power_is_on(lcd->power)) 288 ret = lms501kf03_power_off(lcd); 289 290 if (!ret) 291 lcd->power = power; 292 293 return ret; 294 } 295 296 static int lms501kf03_get_power(struct lcd_device *ld) 297 { 298 struct lms501kf03 *lcd = lcd_get_data(ld); 299 300 return lcd->power; 301 } 302 303 static int lms501kf03_set_power(struct lcd_device *ld, int power) 304 { 305 struct lms501kf03 *lcd = lcd_get_data(ld); 306 307 if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && 308 power != FB_BLANK_NORMAL) { 309 dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); 310 return -EINVAL; 311 } 312 313 return lms501kf03_power(lcd, power); 314 } 315 316 static struct lcd_ops lms501kf03_lcd_ops = { 317 .get_power = lms501kf03_get_power, 318 .set_power = lms501kf03_set_power, 319 }; 320 321 static int lms501kf03_probe(struct spi_device *spi) 322 { 323 struct lms501kf03 *lcd = NULL; 324 struct lcd_device *ld = NULL; 325 int ret = 0; 326 327 lcd = devm_kzalloc(&spi->dev, sizeof(struct lms501kf03), GFP_KERNEL); 328 if (!lcd) 329 return -ENOMEM; 330 331 /* lms501kf03 lcd panel uses 3-wire 9-bit SPI Mode. */ 332 spi->bits_per_word = 9; 333 334 ret = spi_setup(spi); 335 if (ret < 0) { 336 dev_err(&spi->dev, "spi setup failed.\n"); 337 return ret; 338 } 339 340 lcd->spi = spi; 341 lcd->dev = &spi->dev; 342 343 lcd->lcd_pd = dev_get_platdata(&spi->dev); 344 if (!lcd->lcd_pd) { 345 dev_err(&spi->dev, "platform data is NULL\n"); 346 return -EINVAL; 347 } 348 349 ld = devm_lcd_device_register(&spi->dev, "lms501kf03", &spi->dev, lcd, 350 &lms501kf03_lcd_ops); 351 if (IS_ERR(ld)) 352 return PTR_ERR(ld); 353 354 lcd->ld = ld; 355 356 if (!lcd->lcd_pd->lcd_enabled) { 357 /* 358 * if lcd panel was off from bootloader then 359 * current lcd status is powerdown and then 360 * it enables lcd panel. 361 */ 362 lcd->power = FB_BLANK_POWERDOWN; 363 364 lms501kf03_power(lcd, FB_BLANK_UNBLANK); 365 } else { 366 lcd->power = FB_BLANK_UNBLANK; 367 } 368 369 spi_set_drvdata(spi, lcd); 370 371 dev_info(&spi->dev, "lms501kf03 panel driver has been probed.\n"); 372 373 return 0; 374 } 375 376 static int lms501kf03_remove(struct spi_device *spi) 377 { 378 struct lms501kf03 *lcd = spi_get_drvdata(spi); 379 380 lms501kf03_power(lcd, FB_BLANK_POWERDOWN); 381 return 0; 382 } 383 384 #ifdef CONFIG_PM_SLEEP 385 static int lms501kf03_suspend(struct device *dev) 386 { 387 struct lms501kf03 *lcd = dev_get_drvdata(dev); 388 389 dev_dbg(dev, "lcd->power = %d\n", lcd->power); 390 391 /* 392 * when lcd panel is suspend, lcd panel becomes off 393 * regardless of status. 394 */ 395 return lms501kf03_power(lcd, FB_BLANK_POWERDOWN); 396 } 397 398 static int lms501kf03_resume(struct device *dev) 399 { 400 struct lms501kf03 *lcd = dev_get_drvdata(dev); 401 402 lcd->power = FB_BLANK_POWERDOWN; 403 404 return lms501kf03_power(lcd, FB_BLANK_UNBLANK); 405 } 406 #endif 407 408 static SIMPLE_DEV_PM_OPS(lms501kf03_pm_ops, lms501kf03_suspend, 409 lms501kf03_resume); 410 411 static void lms501kf03_shutdown(struct spi_device *spi) 412 { 413 struct lms501kf03 *lcd = spi_get_drvdata(spi); 414 415 lms501kf03_power(lcd, FB_BLANK_POWERDOWN); 416 } 417 418 static struct spi_driver lms501kf03_driver = { 419 .driver = { 420 .name = "lms501kf03", 421 .pm = &lms501kf03_pm_ops, 422 }, 423 .probe = lms501kf03_probe, 424 .remove = lms501kf03_remove, 425 .shutdown = lms501kf03_shutdown, 426 }; 427 428 module_spi_driver(lms501kf03_driver); 429 430 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); 431 MODULE_DESCRIPTION("lms501kf03 LCD Driver"); 432 MODULE_LICENSE("GPL"); 433