aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorGrazvydas Ignotas <notasas@gmail.com>2012-02-06 19:13:49 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2012-02-21 02:40:00 -0500
commit8df4f5ce64e9dc986570799f94c8850f57f8ced9 (patch)
treeff7a357cafd48cc0940f8f73ff393a89af5e1b55 /drivers
parentda8f14fc3bb054081c90abc9dd38679bb9308dbb (diff)
OMAPDSS: TPO-TD03MTEA1: fix suspend hang
During system suspend, at the time DSS is being suspended, SPI is already suspended and it's clocks are cut. Because of this trying to communicate with the LCD controller results in a deadlock. To fix this, split out LCD programming parts of display enable/disable functions and perform them from SPI PM callbacks instead when system is being suspended. If the display is just being enabled/disabled, do it from DSS callbacks as before. Signed-off-by: Grazvydas Ignotas <notasas@gmail.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/omap2/displays/panel-tpo-td043mtea1.c151
1 files changed, 108 insertions, 43 deletions
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
index e6649aa89591..741e9d7cec11 100644
--- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -53,10 +53,14 @@ static const u16 tpo_td043_def_gamma[12] = {
53struct tpo_td043_device { 53struct 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;
56 u16 gamma[12]; 57 u16 gamma[12];
57 u32 mode; 58 u32 mode;
58 u32 hmirror:1; 59 u32 hmirror:1;
59 u32 vmirror:1; 60 u32 vmirror:1;
61 u32 powered_on:1;
62 u32 spi_suspended:1;
63 u32 power_on_resume:1;
60}; 64};
61 65
62static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) 66static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
@@ -265,28 +269,16 @@ static const struct omap_video_timings tpo_td043_timings = {
265 .vbp = 34, 269 .vbp = 34,
266}; 270};
267 271
268static int tpo_td043_power_on(struct omap_dss_device *dssdev) 272static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043)
269{ 273{
270 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); 274 int nreset_gpio = tpo_td043->nreset_gpio;
271 int nreset_gpio = dssdev->reset_gpio;
272 int r;
273 275
274 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) 276 if (tpo_td043->powered_on)
275 return 0; 277 return 0;
276 278
277 r = omapdss_dpi_display_enable(dssdev);
278 if (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); 279 regulator_enable(tpo_td043->vcc_reg);
288 280
289 /* wait for power up */ 281 /* wait for regulator to stabilize */
290 msleep(160); 282 msleep(160);
291 283
292 if (gpio_is_valid(nreset_gpio)) 284 if (gpio_is_valid(nreset_gpio))
@@ -301,19 +293,15 @@ static int tpo_td043_power_on(struct omap_dss_device *dssdev)
301 tpo_td043->vmirror); 293 tpo_td043->vmirror);
302 tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); 294 tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);
303 295
296 tpo_td043->powered_on = 1;
304 return 0; 297 return 0;
305err1:
306 omapdss_dpi_display_disable(dssdev);
307err0:
308 return r;
309} 298}
310 299
311static void tpo_td043_power_off(struct omap_dss_device *dssdev) 300static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043)
312{ 301{
313 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); 302 int nreset_gpio = tpo_td043->nreset_gpio;
314 int nreset_gpio = dssdev->reset_gpio;
315 303
316 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) 304 if (!tpo_td043->powered_on)
317 return; 305 return;
318 306
319 tpo_td043_write(tpo_td043->spi, 3, 307 tpo_td043_write(tpo_td043->spi, 3,
@@ -329,54 +317,94 @@ static void tpo_td043_power_off(struct omap_dss_device *dssdev)
329 317
330 regulator_disable(tpo_td043->vcc_reg); 318 regulator_disable(tpo_td043->vcc_reg);
331 319
320 tpo_td043->powered_on = 0;
321}
322
323static int tpo_td043_enable_dss(struct omap_dss_device *dssdev)
324{
325 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
326 int r;
327
328 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
329 return 0;
330
331 r = omapdss_dpi_display_enable(dssdev);
332 if (r)
333 goto err0;
334
335 if (dssdev->platform_enable) {
336 r = dssdev->platform_enable(dssdev);
337 if (r)
338 goto err1;
339 }
340
341 /*
342 * If we are resuming from system suspend, SPI clocks might not be
343 * enabled yet, so we'll program the LCD from SPI PM resume callback.
344 */
345 if (!tpo_td043->spi_suspended) {
346 r = tpo_td043_power_on(tpo_td043);
347 if (r)
348 goto err1;
349 }
350
351 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
352
353 return 0;
354err1:
355 omapdss_dpi_display_disable(dssdev);
356err0:
357 return r;
358}
359
360static void tpo_td043_disable_dss(struct omap_dss_device *dssdev)
361{
362 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
363
364 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
365 return;
366
332 if (dssdev->platform_disable) 367 if (dssdev->platform_disable)
333 dssdev->platform_disable(dssdev); 368 dssdev->platform_disable(dssdev);
334 369
335 omapdss_dpi_display_disable(dssdev); 370 omapdss_dpi_display_disable(dssdev);
371
372 if (!tpo_td043->spi_suspended)
373 tpo_td043_power_off(tpo_td043);
336} 374}
337 375
338static int tpo_td043_enable(struct omap_dss_device *dssdev) 376static int tpo_td043_enable(struct omap_dss_device *dssdev)
339{ 377{
340 int ret;
341
342 dev_dbg(&dssdev->dev, "enable\n"); 378 dev_dbg(&dssdev->dev, "enable\n");
343 379
344 ret = tpo_td043_power_on(dssdev); 380 return tpo_td043_enable_dss(dssdev);
345 if (ret)
346 return ret;
347
348 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
349
350 return 0;
351} 381}
352 382
353static void tpo_td043_disable(struct omap_dss_device *dssdev) 383static void tpo_td043_disable(struct omap_dss_device *dssdev)
354{ 384{
355 dev_dbg(&dssdev->dev, "disable\n"); 385 dev_dbg(&dssdev->dev, "disable\n");
356 386
357 tpo_td043_power_off(dssdev); 387 tpo_td043_disable_dss(dssdev);
358 388
359 dssdev->state = OMAP_DSS_DISPLAY_DISABLED; 389 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
360} 390}
361 391
362static int tpo_td043_suspend(struct omap_dss_device *dssdev) 392static int tpo_td043_suspend(struct omap_dss_device *dssdev)
363{ 393{
364 tpo_td043_power_off(dssdev); 394 dev_dbg(&dssdev->dev, "suspend\n");
395
396 tpo_td043_disable_dss(dssdev);
397
365 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; 398 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
399
366 return 0; 400 return 0;
367} 401}
368 402
369static int tpo_td043_resume(struct omap_dss_device *dssdev) 403static int tpo_td043_resume(struct omap_dss_device *dssdev)
370{ 404{
371 int r = 0; 405 dev_dbg(&dssdev->dev, "resume\n");
372
373 r = tpo_td043_power_on(dssdev);
374 if (r)
375 return r;
376
377 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
378 406
379 return 0; 407 return tpo_td043_enable_dss(dssdev);
380} 408}
381 409
382static int tpo_td043_probe(struct omap_dss_device *dssdev) 410static int tpo_td043_probe(struct omap_dss_device *dssdev)
@@ -491,6 +519,7 @@ static int tpo_td043_spi_probe(struct spi_device *spi)
491 return -ENOMEM; 519 return -ENOMEM;
492 520
493 tpo_td043->spi = spi; 521 tpo_td043->spi = spi;
522 tpo_td043->nreset_gpio = dssdev->reset_gpio;
494 dev_set_drvdata(&spi->dev, tpo_td043); 523 dev_set_drvdata(&spi->dev, tpo_td043);
495 dev_set_drvdata(&dssdev->dev, tpo_td043); 524 dev_set_drvdata(&dssdev->dev, tpo_td043);
496 525
@@ -509,10 +538,46 @@ static int __devexit tpo_td043_spi_remove(struct spi_device *spi)
509 return 0; 538 return 0;
510} 539}
511 540
541#ifdef CONFIG_PM_SLEEP
542static 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
555static 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
573static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm,
574 tpo_td043_spi_suspend, tpo_td043_spi_resume);
575
512static struct spi_driver tpo_td043_spi_driver = { 576static struct spi_driver tpo_td043_spi_driver = {
513 .driver = { 577 .driver = {
514 .name = "tpo_td043mtea1_panel_spi", 578 .name = "tpo_td043mtea1_panel_spi",
515 .owner = THIS_MODULE, 579 .owner = THIS_MODULE,
580 .pm = &tpo_td043_spi_pm,
516 }, 581 },
517 .probe = tpo_td043_spi_probe, 582 .probe = tpo_td043_spi_probe,
518 .remove = __devexit_p(tpo_td043_spi_remove), 583 .remove = __devexit_p(tpo_td043_spi_remove),