Skip to content

Commit

Permalink
OMAPDSS: TPO-TD03MTEA1: fix suspend hang
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Grazvydas Ignotas authored and Tomi Valkeinen committed Feb 21, 2012
1 parent da8f14f commit 8df4f5c
Showing 1 changed file with 108 additions and 43 deletions.
151 changes: 108 additions & 43 deletions drivers/video/omap2/displays/panel-tpo-td043mtea1.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,14 @@ static const u16 tpo_td043_def_gamma[12] = {
struct tpo_td043_device {
struct spi_device *spi;
struct regulator *vcc_reg;
int nreset_gpio;
u16 gamma[12];
u32 mode;
u32 hmirror:1;
u32 vmirror:1;
u32 powered_on:1;
u32 spi_suspended:1;
u32 power_on_resume:1;
};

static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
Expand Down Expand Up @@ -265,28 +269,16 @@ static const struct omap_video_timings tpo_td043_timings = {
.vbp = 34,
};

static int tpo_td043_power_on(struct omap_dss_device *dssdev)
static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043)
{
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
int nreset_gpio = dssdev->reset_gpio;
int r;
int nreset_gpio = tpo_td043->nreset_gpio;

if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
if (tpo_td043->powered_on)
return 0;

r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;

if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
if (r)
goto err1;
}

regulator_enable(tpo_td043->vcc_reg);

/* wait for power up */
/* wait for regulator to stabilize */
msleep(160);

if (gpio_is_valid(nreset_gpio))
Expand All @@ -301,19 +293,15 @@ static int tpo_td043_power_on(struct omap_dss_device *dssdev)
tpo_td043->vmirror);
tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);

tpo_td043->powered_on = 1;
return 0;
err1:
omapdss_dpi_display_disable(dssdev);
err0:
return r;
}

static void tpo_td043_power_off(struct omap_dss_device *dssdev)
static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043)
{
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
int nreset_gpio = dssdev->reset_gpio;
int nreset_gpio = tpo_td043->nreset_gpio;

if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
if (!tpo_td043->powered_on)
return;

tpo_td043_write(tpo_td043->spi, 3,
Expand All @@ -329,54 +317,94 @@ static void tpo_td043_power_off(struct omap_dss_device *dssdev)

regulator_disable(tpo_td043->vcc_reg);

tpo_td043->powered_on = 0;
}

static int tpo_td043_enable_dss(struct omap_dss_device *dssdev)
{
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
int r;

if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;

r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;

if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
if (r)
goto err1;
}

/*
* If we are resuming from system suspend, SPI clocks might not be
* enabled yet, so we'll program the LCD from SPI PM resume callback.
*/
if (!tpo_td043->spi_suspended) {
r = tpo_td043_power_on(tpo_td043);
if (r)
goto err1;
}

dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;

return 0;
err1:
omapdss_dpi_display_disable(dssdev);
err0:
return r;
}

static void tpo_td043_disable_dss(struct omap_dss_device *dssdev)
{
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);

if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;

if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);

omapdss_dpi_display_disable(dssdev);

if (!tpo_td043->spi_suspended)
tpo_td043_power_off(tpo_td043);
}

static int tpo_td043_enable(struct omap_dss_device *dssdev)
{
int ret;

dev_dbg(&dssdev->dev, "enable\n");

ret = tpo_td043_power_on(dssdev);
if (ret)
return ret;

dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;

return 0;
return tpo_td043_enable_dss(dssdev);
}

static void tpo_td043_disable(struct omap_dss_device *dssdev)
{
dev_dbg(&dssdev->dev, "disable\n");

tpo_td043_power_off(dssdev);
tpo_td043_disable_dss(dssdev);

dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}

static int tpo_td043_suspend(struct omap_dss_device *dssdev)
{
tpo_td043_power_off(dssdev);
dev_dbg(&dssdev->dev, "suspend\n");

tpo_td043_disable_dss(dssdev);

dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;

return 0;
}

static int tpo_td043_resume(struct omap_dss_device *dssdev)
{
int r = 0;

r = tpo_td043_power_on(dssdev);
if (r)
return r;

dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
dev_dbg(&dssdev->dev, "resume\n");

return 0;
return tpo_td043_enable_dss(dssdev);
}

static int tpo_td043_probe(struct omap_dss_device *dssdev)
Expand Down Expand Up @@ -491,6 +519,7 @@ static int tpo_td043_spi_probe(struct spi_device *spi)
return -ENOMEM;

tpo_td043->spi = spi;
tpo_td043->nreset_gpio = dssdev->reset_gpio;
dev_set_drvdata(&spi->dev, tpo_td043);
dev_set_drvdata(&dssdev->dev, tpo_td043);

Expand All @@ -509,10 +538,46 @@ static int __devexit tpo_td043_spi_remove(struct spi_device *spi)
return 0;
}

#ifdef CONFIG_PM_SLEEP
static int tpo_td043_spi_suspend(struct device *dev)
{
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);

dev_dbg(dev, "tpo_td043_spi_suspend, tpo %p\n", tpo_td043);

tpo_td043->power_on_resume = tpo_td043->powered_on;
tpo_td043_power_off(tpo_td043);
tpo_td043->spi_suspended = 1;

return 0;
}

static int tpo_td043_spi_resume(struct device *dev)
{
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
int ret;

dev_dbg(dev, "tpo_td043_spi_resume\n");

if (tpo_td043->power_on_resume) {
ret = tpo_td043_power_on(tpo_td043);
if (ret)
return ret;
}
tpo_td043->spi_suspended = 0;

return 0;
}
#endif

static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm,
tpo_td043_spi_suspend, tpo_td043_spi_resume);

static struct spi_driver tpo_td043_spi_driver = {
.driver = {
.name = "tpo_td043mtea1_panel_spi",
.owner = THIS_MODULE,
.pm = &tpo_td043_spi_pm,
},
.probe = tpo_td043_spi_probe,
.remove = __devexit_p(tpo_td043_spi_remove),
Expand Down

0 comments on commit 8df4f5c

Please sign in to comment.