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