summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/omap2/displays/panel-ili9342.c323
1 files changed, 111 insertions, 212 deletions
diff --git a/drivers/video/omap2/displays/panel-ili9342.c b/drivers/video/omap2/displays/panel-ili9342.c
index 42f23fdb4ff..228a69b7688 100644
--- a/drivers/video/omap2/displays/panel-ili9342.c
+++ b/drivers/video/omap2/displays/panel-ili9342.c
@@ -38,6 +38,11 @@
#define oliodebug(...)
#endif
+#define CMD_SLEEP_IN 0x10
+#define CMD_SLEEP_OUT 0x11
+#define CMD_DISP_OFF 0x28
+#define CMD_DISP_ON 0x29
+
struct panel_config {
struct omap_video_timings timings;
@@ -82,14 +87,86 @@ static struct panel_config ili9342_panels[] = {
};
struct panel_drv_data {
-
struct omap_dss_device *dssdev;
-
struct panel_config *panel_config;
+ unsigned long hw_guard_end; /* next value of jiffies
+ when we can issue the
+ next sleep in/out command */
+ unsigned long hw_guard_wait; /* max guard time in jiffies */
+ struct spi_device *spi;
+
struct mutex lock;
};
+static struct panel_drv_data ili9342_drv_data;
+
+static int ili9342_spi_write(struct spi_device *spi, bool cmd, unsigned char val) {
+ unsigned short buf;
+ struct spi_message m;
+ struct spi_transfer t = {
+ .tx_buf = &buf,
+ .len = 2,
+ .bits_per_word = 9,
+ };
+
+ buf = cmd ? 0 : (1 << 8);
+ buf |= val;
+ dev_dbg(&spi->dev, "SPI sync: %x", buf);
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+ if (spi_sync(spi, &m) < 0) {
+ dev_err(&spi->dev, "SPI sync failed.");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ili9342_write_cmd(struct spi_device *spi, unsigned char val) {
+ return ili9342_spi_write(spi, 1, val);
+}
+
+static int ili9342_write_data(struct spi_device *spi, unsigned char val) {
+ return ili9342_spi_write(spi, 0, val);
+}
+
+static void hw_guard_start(struct panel_drv_data *md, int guard_msec)
+{
+ md->hw_guard_wait = msecs_to_jiffies(guard_msec);
+ md->hw_guard_end = jiffies + md->hw_guard_wait;
+}
+
+static void hw_guard_wait(struct panel_drv_data *md)
+{
+ unsigned long wait = md->hw_guard_end - jiffies;
+
+ if ((long)wait > 0 && wait <= md->hw_guard_wait) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(wait);
+ }
+}
+
+static void set_sleep_mode(struct panel_drv_data *drv_data, int on)
+{
+ int cmd = on ? CMD_SLEEP_IN : CMD_SLEEP_OUT;
+ /*
+ * We have to keep 120msec between sleep in/out commands.
+ * (8.2.11, 8.2.12).
+ */
+ hw_guard_wait(drv_data);
+ ili9342_write_cmd(drv_data->spi, cmd);
+ hw_guard_start(drv_data, 120);
+}
+
+static void set_display_state(struct panel_drv_data *drv_data, int enabled)
+{
+ int cmd = enabled ? CMD_DISP_ON : CMD_DISP_OFF;
+
+ ili9342_write_cmd(drv_data->spi, cmd);
+}
+
static int ili9342_panel_power_on(struct omap_dss_device *dssdev)
{
int r;
@@ -104,11 +181,10 @@ static int ili9342_panel_power_on(struct omap_dss_device *dssdev)
r = omapdss_dpi_display_enable(dssdev);
if (r)
- goto err0;
+ return r;
/* wait couple of vsyncs until enabling the LCD */
- if (panel_config->power_on_delay)
- msleep(panel_config->power_on_delay);
+ msleep(panel_config->power_on_delay);
if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
@@ -116,10 +192,13 @@ static int ili9342_panel_power_on(struct omap_dss_device *dssdev)
goto err1;
}
+ set_sleep_mode(drv_data, 0);
+ usleep_range(5000, 10000);
+ set_display_state(drv_data, 1);
+
return 0;
err1:
omapdss_dpi_display_disable(dssdev);
-err0:
return r;
}
@@ -131,12 +210,15 @@ static void ili9342_panel_power_off(struct omap_dss_device *dssdev)
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
+ set_display_state(drv_data, 0);
+ set_sleep_mode(drv_data, 1);
+ msleep(100);
+
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
/* wait couple of vsyncs after disabling the LCD */
- if (panel_config->power_off_delay)
- msleep(panel_config->power_off_delay);
+ msleep(panel_config->power_off_delay);
omapdss_dpi_display_disable(dssdev);
}
@@ -144,12 +226,12 @@ static void ili9342_panel_power_off(struct omap_dss_device *dssdev)
static int ili9342_panel_probe(struct omap_dss_device *dssdev)
{
struct panel_config *panel_config = NULL;
- struct panel_drv_data *drv_data = NULL;
+ struct panel_drv_data *drv_data = &ili9342_drv_data;
int i;
dev_dbg(&dssdev->dev, "probe\n");
- printk ("OLIO %s entered\n", __FUNCTION__);
+ printk ("OLIO %s entered\n", __FUNCTION__);
if (!dssdev || !dssdev->name)
return -EINVAL;
@@ -168,10 +250,6 @@ static int ili9342_panel_probe(struct omap_dss_device *dssdev)
dssdev->panel.timings = panel_config->timings;
- drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
- if (!drv_data)
- return -ENOMEM;
-
drv_data->dssdev = dssdev;
drv_data->panel_config = panel_config;
@@ -198,10 +276,10 @@ static int ili9342_panel_enable(struct omap_dss_device *dssdev)
r = ili9342_panel_power_on(dssdev);
if (r)
- goto err;
+ goto ret;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-err:
+ret:
mutex_unlock(&drv_data->lock);
return r;
@@ -253,9 +331,7 @@ static int ili9342_panel_check_timings(struct omap_dss_device *dssdev,
int r;
mutex_lock(&drv_data->lock);
-
r = dpi_check_timings(dssdev, timings);
-
mutex_unlock(&drv_data->lock);
return r;
@@ -265,40 +341,6 @@ static int ili9342_get_recommended_bpp(struct omap_dss_device *dssdev) {
return 24;
}
-
-/***************************************************************************
- * suspend & resume
- *
- * For now, this is all handled by the SPI driver (see below).
- * Leaving this functions here should we change our minds.
- */
-
-static int ili9342_disp_suspend (struct device * dev) {
- printk ("OLIO: %s Suspending display.\n", __FUNCTION__);
- ili9342_panel_disable(to_dss_device(dev));
- return 0;
-}
-
-static int ili9342_disp_resume (struct device * dev) {
- printk ("OLIO: %s Resuming display.\n", __FUNCTION__);
- ili9342_panel_enable(to_dss_device(dev));
- return 0;
-}
-
-#if defined(CONFIG_HAS_AMBIENTMODE)
-static int ili9342_panel_disable_wrapper (struct omap_dss_device *display) {
- printk ("OLIO: %s Suspending display.\n", __FUNCTION__);
- ili9342_panel_disable(display);
- return 0;
-}
-#endif
-
-
-static struct dev_pm_ops ili9342_disp_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(ili9342_disp_suspend, ili9342_disp_resume)
-};
-
-
static struct omap_dss_driver ili9342_driver = {
.probe = ili9342_panel_probe,
.remove = __exit_p(ili9342_panel_remove),
@@ -312,66 +354,12 @@ static struct omap_dss_driver ili9342_driver = {
.get_recommended_bpp = ili9342_get_recommended_bpp,
-#if 0
-#if defined(CONFIG_HAS_AMBIENTMODE)
- .resume = ili9342_panel_enable,
- .suspend = ili9342_panel_disable_wrapper,
-#endif
-#endif
-
.driver = {
.name = "ili9342_panel",
.owner = THIS_MODULE,
- .pm = &ili9342_disp_pm_ops,
},
};
-/* ====================================================================== */
-
-/* Here follows the SPI driver - it's required by the panel, but the
- * coupling is rather weak. It registers another driver.
- */
-
-/* ====================================================================== */
-
-static struct regulator *spi_regulator;
-
-static int ili9342_spi_write(struct spi_device *spi, bool cmd, unsigned char val) {
- unsigned short buf;
- struct spi_message m;
- struct spi_transfer t = {
- .tx_buf = &buf,
- .len = 2,
- .bits_per_word = 9,
- };
- int r;
-
- if(cmd) {
- buf = 0;
- } else {
- buf = 1 << 8;
- }
- buf |= val;
-
- dev_dbg(&spi->dev, "SPI sync: %x", buf);
- spi_message_init(&m);
- spi_message_add_tail(&t, &m);
- r = spi_sync(spi, &m);
- if(r < 0) {
- dev_err(&spi->dev, "SPI sync failed.");
- return -EINVAL;
- }
- return 0;
-}
-
-static int ili9342_write_cmd(struct spi_device *spi, unsigned char val) {
- return ili9342_spi_write(spi, 1, val);
-}
-
-static int ili9342_write_data(struct spi_device *spi, unsigned char val) {
- return ili9342_spi_write(spi, 0, val);
-}
-
static inline void ili9342_init_seq(struct spi_device *spi) {
ili9342_write_cmd(spi, 0xC8);
ili9342_write_data(spi, 0xFF);
@@ -474,75 +462,41 @@ static inline void ili9342_init_seq(struct spi_device *spi) {
ili9342_write_cmd(spi, 0x29);
}
+static inline int ili9342_init_reset_gpio(int reset_gpio)
+{
+ if (gpio_request_one(reset_gpio, GPIOF_OUT_INIT_LOW, "ili9342-reset"))
+ return -EINVAL;
-static inline void init_ili9342_hw (struct spi_device *spi) {
- struct omap_dss_device *panel = spi->dev.platform_data;
-
- gpio_set_value(panel->reset_gpio, 1);
+ gpio_set_value(reset_gpio, 1);
mdelay(1);
- gpio_set_value(panel->reset_gpio, 0);
+ gpio_set_value(reset_gpio, 0);
mdelay(50);
- gpio_set_value(panel->reset_gpio, 1);
+ gpio_set_value(reset_gpio, 1);
mdelay(120);
- ili9342_init_seq(spi);
+ return 0;
}
-static inline int init_ili9342_spi(struct spi_device *spi) {
+static int ili9342_spi_probe(struct spi_device *spi)
+{
+ struct panel_drv_data *drv_data = &ili9342_drv_data;
struct omap_dss_device *panel = spi->dev.platform_data;
- int reset_gpio;
- if(!panel->reset_gpio) {
- dev_err(&spi->dev, "platform data requires reset\n");
- return -EINVAL;
- }
-
- reset_gpio = panel->reset_gpio;
+ printk ("OLIO %s entered\n", __FUNCTION__);
if (!panel) {
dev_err(&spi->dev, "no platform data\n");
return -EINVAL;
}
- if(gpio_request_one(reset_gpio, GPIOF_OUT_INIT_LOW, "ili9342-reset")) {
- dev_err(&spi->dev, "Could not request reset gpio %d", panel->reset_gpio);
+ if (ili9342_init_reset_gpio(panel->reset_gpio)) {
+ dev_err(&spi->dev, "Could not request reset gpio %d",
+ panel->reset_gpio);
return -EINVAL;
}
- if(gpio_export(reset_gpio, 0)) {
- dev_err(&spi->dev, "Could not export reset gpio %d", panel->reset_gpio);
- return -EINVAL;
- }
-
- init_ili9342_hw (spi);
-
- return 0;
-}
-
-static int ili9342_spi_probe(struct spi_device *spi)
-{
- int err;
- int ret;
-
- spi_regulator = devm_regulator_get(&spi->dev, "vdd");
-
- printk ("OLIO %s entered\n", __FUNCTION__);
-
- if (IS_ERR(spi_regulator)) {
- dev_err(&spi->dev, "regulator get failed\n");
- err = PTR_ERR(spi_regulator);
- spi_regulator = NULL;
- return err;
- }
-
- ret = regulator_enable(spi_regulator);
-
- if (ret) {
- dev_err(&spi->dev, "Failed to enable vdd: %d\n", ret);
- return ret;
- }
-
- init_ili9342_spi(spi);
+ drv_data->spi = spi;
+ ili9342_init_seq(spi);
return omap_dss_register_driver(&ili9342_driver);
}
@@ -555,67 +509,12 @@ static int ili9342_spi_remove(struct spi_device *spi)
return 0;
}
-static int ili9342_suspend(struct device *dev) {
- int ret;
-
- oliodebug ("OLIO %s:%s Suspending SPI for %s\n", __FILE__, __FUNCTION__, dev_name(dev));
-
- ret = regulator_disable(spi_regulator);
- if (ret) {
- dev_err(dev, "Failed to disable vdd:%d\n",
- ret);
- return ret;
- }
-
- return 0;
-}
-
-
-static int ili9342_resume(struct device *dev) {
- int ret;
-
- /* HACK WARNING: We need an spi_device here. If, as can be assumed,
- * the device pointer passed in points to a device in an spi_device,
- * it's the first device in the spi_device struct. In other words,
- * it's address is the same as the spi_device and a cast should be OK.
- */
-
- /* IF, otoh, that's an incorrect assumption ... then this will lead
- * to horrible crashes. But oh well, you can't win 'em all.
- */
-
- struct spi_device * spi = (struct spi_device *) dev;
-
- oliodebug ("OLIO %s:%s Resuming SPI for %s\n", __FILE__, __FUNCTION__, dev_name(dev));
-
- ret = regulator_enable(spi_regulator);
-
- if (ret) {
- dev_err(&spi->dev, "Failed to enable vdd: %d\n", ret);
- return ret;
- }
-
- /* ili9342_init_seq(spi); */
- init_ili9342_hw (spi);
-
- return 0;
-}
-
-
-static struct dev_pm_ops ili9342_pm_ops = {
- /* SET_SYSTEM_SLEEP_PM_OPS(ili9342_suspend, ili9342_resume) */
- .suspend_late = ili9342_suspend,
- .resume_early = ili9342_resume,
-};
-
-
static struct spi_driver ili9342_spi_driver = {
.probe = ili9342_spi_probe,
.remove = ili9342_spi_remove,
.driver = {
.name = "ili9342-spi",
.owner = THIS_MODULE,
- .pm = &ili9342_pm_ops,
},
};