diff options
Diffstat (limited to 'drivers/video/omap2/displays/panel-tpo-td043mtea1.c')
-rw-r--r-- | drivers/video/omap2/displays/panel-tpo-td043mtea1.c | 211 |
1 files changed, 79 insertions, 132 deletions
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index 6b6643911d2..2462b9ec666 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c | |||
@@ -47,20 +47,16 @@ | |||
47 | TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL) | 47 | TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL) |
48 | 48 | ||
49 | static const u16 tpo_td043_def_gamma[12] = { | 49 | static const u16 tpo_td043_def_gamma[12] = { |
50 | 105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023 | 50 | 106, 200, 289, 375, 460, 543, 625, 705, 785, 864, 942, 1020 |
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct tpo_td043_device { | 53 | struct tpo_td043_device { |
54 | struct spi_device *spi; | 54 | struct spi_device *spi; |
55 | struct regulator *vcc_reg; | 55 | struct regulator *vcc_reg; |
56 | int nreset_gpio; | ||
57 | u16 gamma[12]; | 56 | u16 gamma[12]; |
58 | u32 mode; | 57 | u32 mode; |
59 | u32 hmirror:1; | 58 | u32 hmirror:1; |
60 | u32 vmirror:1; | 59 | u32 vmirror:1; |
61 | u32 powered_on:1; | ||
62 | u32 spi_suspended:1; | ||
63 | u32 power_on_resume:1; | ||
64 | }; | 60 | }; |
65 | 61 | ||
66 | static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) | 62 | static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) |
@@ -267,27 +263,30 @@ static const struct omap_video_timings tpo_td043_timings = { | |||
267 | .vsw = 1, | 263 | .vsw = 1, |
268 | .vfp = 39, | 264 | .vfp = 39, |
269 | .vbp = 34, | 265 | .vbp = 34, |
270 | |||
271 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
272 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
273 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
274 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
275 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
276 | }; | 266 | }; |
277 | 267 | ||
278 | static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) | 268 | static int tpo_td043_power_on(struct omap_dss_device *dssdev) |
279 | { | 269 | { |
280 | int nreset_gpio = tpo_td043->nreset_gpio; | 270 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); |
271 | int nreset_gpio = dssdev->reset_gpio; | ||
281 | int r; | 272 | int r; |
282 | 273 | ||
283 | if (tpo_td043->powered_on) | 274 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
284 | return 0; | 275 | return 0; |
285 | 276 | ||
286 | r = regulator_enable(tpo_td043->vcc_reg); | 277 | r = omapdss_dpi_display_enable(dssdev); |
287 | if (r != 0) | 278 | if (r) |
288 | return r; | 279 | goto err0; |
280 | |||
281 | if (dssdev->platform_enable) { | ||
282 | r = dssdev->platform_enable(dssdev); | ||
283 | if (r) | ||
284 | goto err1; | ||
285 | } | ||
286 | |||
287 | regulator_enable(tpo_td043->vcc_reg); | ||
289 | 288 | ||
290 | /* wait for panel to stabilize */ | 289 | /* wait for power up */ |
291 | msleep(160); | 290 | msleep(160); |
292 | 291 | ||
293 | if (gpio_is_valid(nreset_gpio)) | 292 | if (gpio_is_valid(nreset_gpio)) |
@@ -302,15 +301,19 @@ static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) | |||
302 | tpo_td043->vmirror); | 301 | tpo_td043->vmirror); |
303 | tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); | 302 | tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); |
304 | 303 | ||
305 | tpo_td043->powered_on = 1; | ||
306 | return 0; | 304 | return 0; |
305 | err1: | ||
306 | omapdss_dpi_display_disable(dssdev); | ||
307 | err0: | ||
308 | return r; | ||
307 | } | 309 | } |
308 | 310 | ||
309 | static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043) | 311 | static void tpo_td043_power_off(struct omap_dss_device *dssdev) |
310 | { | 312 | { |
311 | int nreset_gpio = tpo_td043->nreset_gpio; | 313 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); |
314 | int nreset_gpio = dssdev->reset_gpio; | ||
312 | 315 | ||
313 | if (!tpo_td043->powered_on) | 316 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
314 | return; | 317 | return; |
315 | 318 | ||
316 | tpo_td043_write(tpo_td043->spi, 3, | 319 | tpo_td043_write(tpo_td043->spi, 3, |
@@ -326,79 +329,54 @@ static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043) | |||
326 | 329 | ||
327 | regulator_disable(tpo_td043->vcc_reg); | 330 | regulator_disable(tpo_td043->vcc_reg); |
328 | 331 | ||
329 | tpo_td043->powered_on = 0; | 332 | if (dssdev->platform_disable) |
333 | dssdev->platform_disable(dssdev); | ||
334 | |||
335 | omapdss_dpi_display_disable(dssdev); | ||
330 | } | 336 | } |
331 | 337 | ||
332 | static int tpo_td043_enable_dss(struct omap_dss_device *dssdev) | 338 | static int tpo_td043_enable(struct omap_dss_device *dssdev) |
333 | { | 339 | { |
334 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 340 | int ret; |
335 | int r; | ||
336 | |||
337 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
338 | return 0; | ||
339 | |||
340 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
341 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
342 | |||
343 | r = omapdss_dpi_display_enable(dssdev); | ||
344 | if (r) | ||
345 | goto err0; | ||
346 | 341 | ||
347 | if (dssdev->platform_enable) { | 342 | dev_dbg(&dssdev->dev, "enable\n"); |
348 | r = dssdev->platform_enable(dssdev); | ||
349 | if (r) | ||
350 | goto err1; | ||
351 | } | ||
352 | 343 | ||
353 | /* | 344 | ret = tpo_td043_power_on(dssdev); |
354 | * If we are resuming from system suspend, SPI clocks might not be | 345 | if (ret) |
355 | * enabled yet, so we'll program the LCD from SPI PM resume callback. | 346 | return ret; |
356 | */ | ||
357 | if (!tpo_td043->spi_suspended) { | ||
358 | r = tpo_td043_power_on(tpo_td043); | ||
359 | if (r) | ||
360 | goto err1; | ||
361 | } | ||
362 | 347 | ||
363 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 348 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
364 | 349 | ||
365 | return 0; | 350 | return 0; |
366 | err1: | ||
367 | omapdss_dpi_display_disable(dssdev); | ||
368 | err0: | ||
369 | return r; | ||
370 | } | 351 | } |
371 | 352 | ||
372 | static void tpo_td043_disable_dss(struct omap_dss_device *dssdev) | 353 | static void tpo_td043_disable(struct omap_dss_device *dssdev) |
373 | { | 354 | { |
374 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 355 | dev_dbg(&dssdev->dev, "disable\n"); |
375 | |||
376 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
377 | return; | ||
378 | |||
379 | if (dssdev->platform_disable) | ||
380 | dssdev->platform_disable(dssdev); | ||
381 | 356 | ||
382 | omapdss_dpi_display_disable(dssdev); | 357 | tpo_td043_power_off(dssdev); |
383 | 358 | ||
384 | if (!tpo_td043->spi_suspended) | 359 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
385 | tpo_td043_power_off(tpo_td043); | ||
386 | } | 360 | } |
387 | 361 | ||
388 | static int tpo_td043_enable(struct omap_dss_device *dssdev) | 362 | static int tpo_td043_suspend(struct omap_dss_device *dssdev) |
389 | { | 363 | { |
390 | dev_dbg(&dssdev->dev, "enable\n"); | 364 | tpo_td043_power_off(dssdev); |
391 | 365 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | |
392 | return tpo_td043_enable_dss(dssdev); | 366 | return 0; |
393 | } | 367 | } |
394 | 368 | ||
395 | static void tpo_td043_disable(struct omap_dss_device *dssdev) | 369 | static int tpo_td043_resume(struct omap_dss_device *dssdev) |
396 | { | 370 | { |
397 | dev_dbg(&dssdev->dev, "disable\n"); | 371 | int r = 0; |
372 | |||
373 | r = tpo_td043_power_on(dssdev); | ||
374 | if (r) | ||
375 | return r; | ||
398 | 376 | ||
399 | tpo_td043_disable_dss(dssdev); | 377 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
400 | 378 | ||
401 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 379 | return 0; |
402 | } | 380 | } |
403 | 381 | ||
404 | static int tpo_td043_probe(struct omap_dss_device *dssdev) | 382 | static int tpo_td043_probe(struct omap_dss_device *dssdev) |
@@ -414,6 +392,8 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) | |||
414 | return -ENODEV; | 392 | return -ENODEV; |
415 | } | 393 | } |
416 | 394 | ||
395 | dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IHS | | ||
396 | OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IPC; | ||
417 | dssdev->panel.timings = tpo_td043_timings; | 397 | dssdev->panel.timings = tpo_td043_timings; |
418 | dssdev->ctrl.pixel_size = 24; | 398 | dssdev->ctrl.pixel_size = 24; |
419 | 399 | ||
@@ -428,12 +408,17 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) | |||
428 | } | 408 | } |
429 | 409 | ||
430 | if (gpio_is_valid(nreset_gpio)) { | 410 | if (gpio_is_valid(nreset_gpio)) { |
431 | ret = gpio_request_one(nreset_gpio, GPIOF_OUT_INIT_LOW, | 411 | ret = gpio_request(nreset_gpio, "lcd reset"); |
432 | "lcd reset"); | ||
433 | if (ret < 0) { | 412 | if (ret < 0) { |
434 | dev_err(&dssdev->dev, "couldn't request reset GPIO\n"); | 413 | dev_err(&dssdev->dev, "couldn't request reset GPIO\n"); |
435 | goto fail_gpio_req; | 414 | goto fail_gpio_req; |
436 | } | 415 | } |
416 | |||
417 | ret = gpio_direction_output(nreset_gpio, 0); | ||
418 | if (ret < 0) { | ||
419 | dev_err(&dssdev->dev, "couldn't set GPIO direction\n"); | ||
420 | goto fail_gpio_direction; | ||
421 | } | ||
437 | } | 422 | } |
438 | 423 | ||
439 | ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group); | 424 | ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group); |
@@ -442,6 +427,8 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) | |||
442 | 427 | ||
443 | return 0; | 428 | return 0; |
444 | 429 | ||
430 | fail_gpio_direction: | ||
431 | gpio_free(nreset_gpio); | ||
445 | fail_gpio_req: | 432 | fail_gpio_req: |
446 | regulator_put(tpo_td043->vcc_reg); | 433 | regulator_put(tpo_td043->vcc_reg); |
447 | fail_regulator: | 434 | fail_regulator: |
@@ -462,32 +449,17 @@ static void tpo_td043_remove(struct omap_dss_device *dssdev) | |||
462 | gpio_free(nreset_gpio); | 449 | gpio_free(nreset_gpio); |
463 | } | 450 | } |
464 | 451 | ||
465 | static void tpo_td043_set_timings(struct omap_dss_device *dssdev, | ||
466 | struct omap_video_timings *timings) | ||
467 | { | ||
468 | omapdss_dpi_set_timings(dssdev, timings); | ||
469 | |||
470 | dssdev->panel.timings = *timings; | ||
471 | } | ||
472 | |||
473 | static int tpo_td043_check_timings(struct omap_dss_device *dssdev, | ||
474 | struct omap_video_timings *timings) | ||
475 | { | ||
476 | return dpi_check_timings(dssdev, timings); | ||
477 | } | ||
478 | |||
479 | static struct omap_dss_driver tpo_td043_driver = { | 452 | static struct omap_dss_driver tpo_td043_driver = { |
480 | .probe = tpo_td043_probe, | 453 | .probe = tpo_td043_probe, |
481 | .remove = tpo_td043_remove, | 454 | .remove = tpo_td043_remove, |
482 | 455 | ||
483 | .enable = tpo_td043_enable, | 456 | .enable = tpo_td043_enable, |
484 | .disable = tpo_td043_disable, | 457 | .disable = tpo_td043_disable, |
458 | .suspend = tpo_td043_suspend, | ||
459 | .resume = tpo_td043_resume, | ||
485 | .set_mirror = tpo_td043_set_hmirror, | 460 | .set_mirror = tpo_td043_set_hmirror, |
486 | .get_mirror = tpo_td043_get_hmirror, | 461 | .get_mirror = tpo_td043_get_hmirror, |
487 | 462 | ||
488 | .set_timings = tpo_td043_set_timings, | ||
489 | .check_timings = tpo_td043_check_timings, | ||
490 | |||
491 | .driver = { | 463 | .driver = { |
492 | .name = "tpo_td043mtea1_panel", | 464 | .name = "tpo_td043mtea1_panel", |
493 | .owner = THIS_MODULE, | 465 | .owner = THIS_MODULE, |
@@ -519,7 +491,6 @@ static int tpo_td043_spi_probe(struct spi_device *spi) | |||
519 | return -ENOMEM; | 491 | return -ENOMEM; |
520 | 492 | ||
521 | tpo_td043->spi = spi; | 493 | tpo_td043->spi = spi; |
522 | tpo_td043->nreset_gpio = dssdev->reset_gpio; | ||
523 | dev_set_drvdata(&spi->dev, tpo_td043); | 494 | dev_set_drvdata(&spi->dev, tpo_td043); |
524 | dev_set_drvdata(&dssdev->dev, tpo_td043); | 495 | dev_set_drvdata(&dssdev->dev, tpo_td043); |
525 | 496 | ||
@@ -528,7 +499,7 @@ static int tpo_td043_spi_probe(struct spi_device *spi) | |||
528 | return 0; | 499 | return 0; |
529 | } | 500 | } |
530 | 501 | ||
531 | static int tpo_td043_spi_remove(struct spi_device *spi) | 502 | static int __devexit tpo_td043_spi_remove(struct spi_device *spi) |
532 | { | 503 | { |
533 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev); | 504 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev); |
534 | 505 | ||
@@ -538,52 +509,28 @@ static int tpo_td043_spi_remove(struct spi_device *spi) | |||
538 | return 0; | 509 | return 0; |
539 | } | 510 | } |
540 | 511 | ||
541 | #ifdef CONFIG_PM_SLEEP | ||
542 | static int tpo_td043_spi_suspend(struct device *dev) | ||
543 | { | ||
544 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
545 | |||
546 | dev_dbg(dev, "tpo_td043_spi_suspend, tpo %p\n", tpo_td043); | ||
547 | |||
548 | tpo_td043->power_on_resume = tpo_td043->powered_on; | ||
549 | tpo_td043_power_off(tpo_td043); | ||
550 | tpo_td043->spi_suspended = 1; | ||
551 | |||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | static int tpo_td043_spi_resume(struct device *dev) | ||
556 | { | ||
557 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
558 | int ret; | ||
559 | |||
560 | dev_dbg(dev, "tpo_td043_spi_resume\n"); | ||
561 | |||
562 | if (tpo_td043->power_on_resume) { | ||
563 | ret = tpo_td043_power_on(tpo_td043); | ||
564 | if (ret) | ||
565 | return ret; | ||
566 | } | ||
567 | tpo_td043->spi_suspended = 0; | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | #endif | ||
572 | |||
573 | static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm, | ||
574 | tpo_td043_spi_suspend, tpo_td043_spi_resume); | ||
575 | |||
576 | static struct spi_driver tpo_td043_spi_driver = { | 512 | static struct spi_driver tpo_td043_spi_driver = { |
577 | .driver = { | 513 | .driver = { |
578 | .name = "tpo_td043mtea1_panel_spi", | 514 | .name = "tpo_td043mtea1_panel_spi", |
515 | .bus = &spi_bus_type, | ||
579 | .owner = THIS_MODULE, | 516 | .owner = THIS_MODULE, |
580 | .pm = &tpo_td043_spi_pm, | ||
581 | }, | 517 | }, |
582 | .probe = tpo_td043_spi_probe, | 518 | .probe = tpo_td043_spi_probe, |
583 | .remove = tpo_td043_spi_remove, | 519 | .remove = __devexit_p(tpo_td043_spi_remove), |
584 | }; | 520 | }; |
585 | 521 | ||
586 | module_spi_driver(tpo_td043_spi_driver); | 522 | static int __init tpo_td043_init(void) |
523 | { | ||
524 | return spi_register_driver(&tpo_td043_spi_driver); | ||
525 | } | ||
526 | |||
527 | static void __exit tpo_td043_exit(void) | ||
528 | { | ||
529 | spi_unregister_driver(&tpo_td043_spi_driver); | ||
530 | } | ||
531 | |||
532 | module_init(tpo_td043_init); | ||
533 | module_exit(tpo_td043_exit); | ||
587 | 534 | ||
588 | MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>"); | 535 | MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>"); |
589 | MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); | 536 | MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); |