diff options
| -rw-r--r-- | drivers/video/omap2/displays/panel-ili9342.c | 323 |
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, }, }; |