1/* 2 * LCD panel driver for TPO TD043MTEA1 3 * 4 * Author: Gra��vydas Ignotas <notasas@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 12#include <linux/module.h> 13#include <linux/delay.h> 14#include <linux/spi/spi.h> 15#include <linux/regulator/consumer.h> 16#include <linux/gpio.h> 17#include <linux/err.h> 18#include <linux/slab.h> 19 20#include <plat/display.h> 21 22#define TPO_R02_MODE(x) ((x) & 7) 23#define TPO_R02_MODE_800x480 7 24#define TPO_R02_NCLK_RISING BIT(3) 25#define TPO_R02_HSYNC_HIGH BIT(4) 26#define TPO_R02_VSYNC_HIGH BIT(5) 27 28#define TPO_R03_NSTANDBY BIT(0) 29#define TPO_R03_EN_CP_CLK BIT(1) 30#define TPO_R03_EN_VGL_PUMP BIT(2) 31#define TPO_R03_EN_PWM BIT(3) 32#define TPO_R03_DRIVING_CAP_100 BIT(4) 33#define TPO_R03_EN_PRE_CHARGE BIT(6) 34#define TPO_R03_SOFTWARE_CTL BIT(7) 35 36#define TPO_R04_NFLIP_H BIT(0) 37#define TPO_R04_NFLIP_V BIT(1) 38#define TPO_R04_CP_CLK_FREQ_1H BIT(2) 39#define TPO_R04_VGL_FREQ_1H BIT(4) 40 41#define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \ 42 TPO_R03_EN_VGL_PUMP | TPO_R03_EN_PWM | \ 43 TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \ 44 TPO_R03_SOFTWARE_CTL) 45 46#define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \ 47 TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL) 48 49static const u16 tpo_td043_def_gamma[12] = { 50 106, 200, 289, 375, 460, 543, 625, 705, 785, 864, 942, 1020 51}; 52 53struct tpo_td043_device { 54 struct spi_device *spi; 55 struct regulator *vcc_reg; 56 u16 gamma[12]; 57 u32 mode; 58 u32 hmirror:1; 59 u32 vmirror:1; 60}; 61 62static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) 63{ 64 struct spi_message m; 65 struct spi_transfer xfer; 66 u16 w; 67 int r; 68 69 spi_message_init(&m); 70 71 memset(&xfer, 0, sizeof(xfer)); 72 73 w = ((u16)addr << 10) | (1 << 8) | data; 74 xfer.tx_buf = &w; 75 xfer.bits_per_word = 16; 76 xfer.len = 2; 77 spi_message_add_tail(&xfer, &m); 78 79 r = spi_sync(spi, &m); 80 if (r < 0) 81 dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r); 82 return r; 83} 84 85static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12]) 86{ 87 u8 i, val; 88 89 /* gamma bits [9:8] */ 90 for (val = i = 0; i < 4; i++) 91 val |= (gamma[i] & 0x300) >> ((i + 1) * 2); 92 tpo_td043_write(spi, 0x11, val); 93 94 for (val = i = 0; i < 4; i++) 95 val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2); 96 tpo_td043_write(spi, 0x12, val); 97 98 for (val = i = 0; i < 4; i++) 99 val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2); 100 tpo_td043_write(spi, 0x13, val); 101 102 /* gamma bits [7:0] */ 103 for (val = i = 0; i < 12; i++) 104 tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff); 105} 106 107static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v) 108{ 109 u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V | \ 110 TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H; 111 if (h) 112 reg4 &= ~TPO_R04_NFLIP_H; 113 if (v) 114 reg4 &= ~TPO_R04_NFLIP_V; 115 116 return tpo_td043_write(spi, 4, reg4); 117} 118 119static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable) 120{ 121 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); 122 123 tpo_td043->hmirror = enable; 124 return tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, 125 tpo_td043->vmirror); 126} 127 128static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev) 129{ 130 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); 131 132 return tpo_td043->hmirror; 133} 134 135static ssize_t tpo_td043_vmirror_show(struct device *dev, 136 struct device_attribute *attr, char *buf) 137{ 138 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); 139 140 return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->vmirror); 141} 142 143static ssize_t tpo_td043_vmirror_store(struct device *dev, 144 struct device_attribute *attr, const char *buf, size_t count) 145{ 146 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); 147 long val; 148 int ret; 149 150 ret = strict_strtol(buf, 0, &val); 151 if (ret < 0) 152 return ret; 153 154 ret = tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, val); 155 if (ret < 0) 156 return ret; 157 158 tpo_td043->vmirror = val; 159 160 return count; 161} 162 163static ssize_t tpo_td043_mode_show(struct device *dev, 164 struct device_attribute *attr, char *buf) 165{ 166 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); 167 168 return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->mode); 169} 170 171static ssize_t tpo_td043_mode_store(struct device *dev, 172 struct device_attribute *attr, const char *buf, size_t count) 173{ 174 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); 175 long val; 176 int ret; 177 178 ret = strict_strtol(buf, 0, &val); 179 if (ret != 0 || val & ~7) 180 return -EINVAL; 181 182 tpo_td043->mode = val; 183 184 val |= TPO_R02_NCLK_RISING; 185 tpo_td043_write(tpo_td043->spi, 2, val); 186 187 return count; 188} 189 190static ssize_t tpo_td043_gamma_show(struct device *dev, 191 struct device_attribute *attr, char *buf) 192{ 193 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); 194 ssize_t len = 0; 195 int ret; 196 int i; 197 198 for (i = 0; i < ARRAY_SIZE(tpo_td043->gamma); i++) { 199 ret = snprintf(buf + len, PAGE_SIZE - len, "%u ", 200 tpo_td043->gamma[i]); 201 if (ret < 0) 202 return ret; 203 len += ret; 204 } 205 buf[len - 1] = '\n'; 206 207 return len; 208} 209 210static ssize_t tpo_td043_gamma_store(struct device *dev, 211 struct device_attribute *attr, const char *buf, size_t count) 212{ 213 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); 214 unsigned int g[12]; 215 int ret; 216 int i; 217 218 ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u", 219 &g[0], &g[1], &g[2], &g[3], &g[4], &g[5], 220 &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]); 221 222 if (ret != 12) 223 return -EINVAL; 224 225 for (i = 0; i < 12; i++) 226 tpo_td043->gamma[i] = g[i]; 227 228 tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); 229 230 return count; 231} 232 233static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR, 234 tpo_td043_vmirror_show, tpo_td043_vmirror_store); 235static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, 236 tpo_td043_mode_show, tpo_td043_mode_store); 237static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR, 238 tpo_td043_gamma_show, tpo_td043_gamma_store); 239 240static struct attribute *tpo_td043_attrs[] = { 241 &dev_attr_vmirror.attr, 242 &dev_attr_mode.attr, 243 &dev_attr_gamma.attr, 244 NULL, 245}; 246 247static struct attribute_group tpo_td043_attr_group = { 248 .attrs = tpo_td043_attrs, 249}; 250 251static const struct omap_video_timings tpo_td043_timings = { 252 .x_res = 800, 253 .y_res = 480, 254 255 .pixel_clock = 36000, 256 257 .hsw = 1, 258 .hfp = 68, 259 .hbp = 214, 260 261 .vsw = 1, 262 .vfp = 39, 263 .vbp = 34, 264}; 265 266static int tpo_td043_power_on(struct omap_dss_device *dssdev) 267{ 268 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); 269 int nreset_gpio = dssdev->reset_gpio; 270 int r; 271 272 r = omapdss_dpi_display_enable(dssdev); 273 if (r) 274 goto err0; 275 276 if (dssdev->platform_enable) { 277 r = dssdev->platform_enable(dssdev); 278 if (r) 279 goto err1; 280 } 281 282 regulator_enable(tpo_td043->vcc_reg); 283 284 /* wait for power up */ 285 msleep(160); 286 287 if (gpio_is_valid(nreset_gpio)) 288 gpio_set_value(nreset_gpio, 1); 289 290 tpo_td043_write(tpo_td043->spi, 2, 291 TPO_R02_MODE(tpo_td043->mode) | TPO_R02_NCLK_RISING); 292 tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_NORMAL); 293 tpo_td043_write(tpo_td043->spi, 0x20, 0xf0); 294 tpo_td043_write(tpo_td043->spi, 0x21, 0xf0); 295 tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, 296 tpo_td043->vmirror); 297 tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); 298 299 return 0; 300err1: 301 omapdss_dpi_display_disable(dssdev); 302err0: 303 return r; 304} 305 306static void tpo_td043_power_off(struct omap_dss_device *dssdev) 307{ 308 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); 309 int nreset_gpio = dssdev->reset_gpio; 310 311 tpo_td043_write(tpo_td043->spi, 3, 312 TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM); 313 314 if (gpio_is_valid(nreset_gpio)) 315 gpio_set_value(nreset_gpio, 0); 316 317 /* wait for at least 2 vsyncs before cutting off power */ 318 msleep(50); 319 320 tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_STANDBY); 321 322 regulator_disable(tpo_td043->vcc_reg); 323 324 if (dssdev->platform_disable) 325 dssdev->platform_disable(dssdev); 326 327 omapdss_dpi_display_disable(dssdev); 328} 329 330static int tpo_td043_enable(struct omap_dss_device *dssdev) 331{ 332 int ret; 333 334 dev_dbg(&dssdev->dev, "enable\n"); 335 336 ret = tpo_td043_power_on(dssdev); 337 if (ret) 338 return ret; 339 340 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; 341 342 return 0; 343} 344 345static void tpo_td043_disable(struct omap_dss_device *dssdev) 346{ 347 dev_dbg(&dssdev->dev, "disable\n"); 348 349 tpo_td043_power_off(dssdev); 350 351 dssdev->state = OMAP_DSS_DISPLAY_DISABLED; 352} 353 354static int tpo_td043_suspend(struct omap_dss_device *dssdev) 355{ 356 tpo_td043_power_off(dssdev); 357 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; 358 return 0; 359} 360 361static int tpo_td043_resume(struct omap_dss_device *dssdev) 362{ 363 int r = 0; 364 365 r = tpo_td043_power_on(dssdev); 366 if (r) 367 return r; 368 369 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; 370 371 return 0; 372} 373 374static int tpo_td043_probe(struct omap_dss_device *dssdev) 375{ 376 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); 377 int nreset_gpio = dssdev->reset_gpio; 378 int ret = 0; 379 380 dev_dbg(&dssdev->dev, "probe\n"); 381 382 if (tpo_td043 == NULL) { 383 dev_err(&dssdev->dev, "missing tpo_td043_device\n"); 384 return -ENODEV; 385 } 386 387 dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IHS | 388 OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IPC; 389 dssdev->panel.timings = tpo_td043_timings; 390 dssdev->ctrl.pixel_size = 24; 391 392 tpo_td043->mode = TPO_R02_MODE_800x480; 393 memcpy(tpo_td043->gamma, tpo_td043_def_gamma, sizeof(tpo_td043->gamma)); 394 395 tpo_td043->vcc_reg = regulator_get(&dssdev->dev, "vcc"); 396 if (IS_ERR(tpo_td043->vcc_reg)) { 397 dev_err(&dssdev->dev, "failed to get LCD VCC regulator\n"); 398 ret = PTR_ERR(tpo_td043->vcc_reg); 399 goto fail_regulator; 400 } 401 402 if (gpio_is_valid(nreset_gpio)) { 403 ret = gpio_request(nreset_gpio, "lcd reset"); 404 if (ret < 0) { 405 dev_err(&dssdev->dev, "couldn't request reset GPIO\n"); 406 goto fail_gpio_req; 407 } 408 409 ret = gpio_direction_output(nreset_gpio, 0); 410 if (ret < 0) { 411 dev_err(&dssdev->dev, "couldn't set GPIO direction\n"); 412 goto fail_gpio_direction; 413 } 414 } 415 416 ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group); 417 if (ret) 418 dev_warn(&dssdev->dev, "failed to create sysfs files\n"); 419 420 return 0; 421 422fail_gpio_direction: 423 gpio_free(nreset_gpio); 424fail_gpio_req: 425 regulator_put(tpo_td043->vcc_reg); 426fail_regulator: 427 kfree(tpo_td043); 428 return ret; 429} 430 431static void tpo_td043_remove(struct omap_dss_device *dssdev) 432{ 433 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); 434 int nreset_gpio = dssdev->reset_gpio; 435 436 dev_dbg(&dssdev->dev, "remove\n"); 437 438 sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group); 439 regulator_put(tpo_td043->vcc_reg); 440 if (gpio_is_valid(nreset_gpio)) 441 gpio_free(nreset_gpio); 442} 443 444static struct omap_dss_driver tpo_td043_driver = { 445 .probe = tpo_td043_probe, 446 .remove = tpo_td043_remove, 447 448 .enable = tpo_td043_enable, 449 .disable = tpo_td043_disable, 450 .suspend = tpo_td043_suspend, 451 .resume = tpo_td043_resume, 452 .set_mirror = tpo_td043_set_hmirror, 453 .get_mirror = tpo_td043_get_hmirror, 454 455 .driver = { 456 .name = "tpo_td043mtea1_panel", 457 .owner = THIS_MODULE, 458 }, 459}; 460 461static int tpo_td043_spi_probe(struct spi_device *spi) 462{ 463 struct omap_dss_device *dssdev = spi->dev.platform_data; 464 struct tpo_td043_device *tpo_td043; 465 int ret; 466 467 if (dssdev == NULL) { 468 dev_err(&spi->dev, "missing dssdev\n"); 469 return -ENODEV; 470 } 471 472 spi->bits_per_word = 16; 473 spi->mode = SPI_MODE_0; 474 475 ret = spi_setup(spi); 476 if (ret < 0) { 477 dev_err(&spi->dev, "spi_setup failed: %d\n", ret); 478 return ret; 479 } 480 481 tpo_td043 = kzalloc(sizeof(*tpo_td043), GFP_KERNEL); 482 if (tpo_td043 == NULL) 483 return -ENOMEM; 484 485 tpo_td043->spi = spi; 486 dev_set_drvdata(&spi->dev, tpo_td043); 487 dev_set_drvdata(&dssdev->dev, tpo_td043); 488 489 omap_dss_register_driver(&tpo_td043_driver); 490 491 return 0; 492} 493 494static int __devexit tpo_td043_spi_remove(struct spi_device *spi) 495{ 496 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev); 497 498 omap_dss_unregister_driver(&tpo_td043_driver); 499 kfree(tpo_td043); 500 501 return 0; 502} 503 504static struct spi_driver tpo_td043_spi_driver = { 505 .driver = { 506 .name = "tpo_td043mtea1_panel_spi", 507 .bus = &spi_bus_type, 508 .owner = THIS_MODULE, 509 }, 510 .probe = tpo_td043_spi_probe, 511 .remove = __devexit_p(tpo_td043_spi_remove), 512}; 513 514static int __init tpo_td043_init(void) 515{ 516 return spi_register_driver(&tpo_td043_spi_driver); 517} 518 519static void __exit tpo_td043_exit(void) 520{ 521 spi_unregister_driver(&tpo_td043_spi_driver); 522} 523 524module_init(tpo_td043_init); 525module_exit(tpo_td043_exit); 526 527MODULE_AUTHOR("Gra��vydas Ignotas <notasas@gmail.com>"); 528MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); 529MODULE_LICENSE("GPL"); 530