|
@@ -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)
|
|
@@ -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))
|
|
@@ -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,
|
|
@@ -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)
|
|
@@ -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);
|
|
|
|
|
@@ -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),
|