All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tomi Valkeinen <tomi.valkeinen@ti.com>
To: linux-omap@vger.kernel.org, linux-fbdev@vger.kernel.org
Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
Subject: [PATCH 19/19] OMAP: DSS2: Taal: Implement ULPS functionality
Date: Tue, 19 Apr 2011 09:22:22 +0000	[thread overview]
Message-ID: <1303204942-25450-20-git-send-email-tomi.valkeinen@ti.com> (raw)
In-Reply-To: <1303204942-25450-1-git-send-email-tomi.valkeinen@ti.com>

ULPS is a low power state where the DSI lanes are kept at ground. This
patch implements ULPS by having a DSI bus inactivity timer which
triggers the entry to ULPS. ULPS exit will happen automatically when the
driver needs to do something on the DSI lanes.

The ulps_timeout is configurable from board file or via sysfs.
Additionally another sysfs file, "ulps", can be used to check the
current ULPS state, or to manually enter or exit ULPS.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 arch/arm/plat-omap/include/plat/nokia-dsi-panel.h |    2 +
 drivers/video/omap2/displays/panel-taal.c         |  310 ++++++++++++++++++++-
 2 files changed, 305 insertions(+), 7 deletions(-)

diff --git a/arch/arm/plat-omap/include/plat/nokia-dsi-panel.h b/arch/arm/plat-omap/include/plat/nokia-dsi-panel.h
index aaa1c14..36ba7bd 100644
--- a/arch/arm/plat-omap/include/plat/nokia-dsi-panel.h
+++ b/arch/arm/plat-omap/include/plat/nokia-dsi-panel.h
@@ -9,6 +9,7 @@
  * @use_ext_te: use external TE
  * @ext_te_gpio: external TE GPIO
  * @esd_interval: interval of ESD checks, 0 = disabled (ms)
+ * @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms)
  * @max_backlight_level: maximum backlight level
  * @set_backlight: pointer to backlight set function
  * @get_backlight: pointer to backlight get function
@@ -22,6 +23,7 @@ struct nokia_dsi_panel_data {
 	int ext_te_gpio;
 
 	unsigned esd_interval;
+	unsigned ulps_timeout;
 
 	int max_backlight_level;
 	int (*set_backlight)(struct omap_dss_device *dssdev, int level);
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 9626e49..78ad355 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -67,6 +67,8 @@ static irqreturn_t taal_te_isr(int irq, void *data);
 static void taal_te_timeout_work_callback(struct work_struct *work);
 static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
 
+static int taal_panel_reset(struct omap_dss_device *dssdev);
+
 struct panel_regulator {
 	struct regulator *regulator;
 	const char *name;
@@ -232,6 +234,10 @@ struct taal_data {
 	struct delayed_work esd_work;
 	unsigned esd_interval;
 
+	bool ulps_enabled;
+	unsigned ulps_timeout;
+	struct delayed_work ulps_work;
+
 	struct panel_config *panel_config;
 };
 
@@ -242,6 +248,7 @@ static inline struct nokia_dsi_panel_data
 }
 
 static void taal_esd_work(struct work_struct *work);
+static void taal_ulps_work(struct work_struct *work);
 
 static void hw_guard_start(struct taal_data *td, int guard_msec)
 {
@@ -437,6 +444,107 @@ static void taal_cancel_esd_work(struct omap_dss_device *dssdev)
 	cancel_delayed_work(&td->esd_work);
 }
 
+static void taal_queue_ulps_work(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+	if (td->ulps_timeout > 0)
+		queue_delayed_work(td->workqueue, &td->ulps_work,
+				msecs_to_jiffies(td->ulps_timeout));
+}
+
+static void taal_cancel_ulps_work(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+	cancel_delayed_work(&td->ulps_work);
+}
+
+static int taal_enter_ulps(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
+	int r;
+
+	if (td->ulps_enabled)
+		return 0;
+
+	taal_cancel_ulps_work(dssdev);
+
+	r = _taal_enable_te(dssdev, false);
+	if (r)
+		goto err;
+
+	disable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+
+	omapdss_dsi_display_disable(dssdev, false, true);
+
+	td->ulps_enabled = true;
+
+	return 0;
+
+err:
+	dev_err(&dssdev->dev, "enter ULPS failed");
+	taal_panel_reset(dssdev);
+
+	td->ulps_enabled = false;
+
+	taal_queue_ulps_work(dssdev);
+
+	return r;
+}
+
+static int taal_exit_ulps(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
+	int r;
+
+	if (!td->ulps_enabled)
+		return 0;
+
+	r = omapdss_dsi_display_enable(dssdev);
+	if (r)
+		goto err;
+
+	omapdss_dsi_vc_enable_hs(td->channel, true);
+
+	r = _taal_enable_te(dssdev, true);
+	if (r)
+		goto err;
+
+	enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+
+	taal_queue_ulps_work(dssdev);
+
+	td->ulps_enabled = false;
+
+	return 0;
+
+err:
+	dev_err(&dssdev->dev, "exit ULPS failed");
+	r = taal_panel_reset(dssdev);
+
+	enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+	td->ulps_enabled = false;
+
+	taal_queue_ulps_work(dssdev);
+
+	return r;
+}
+
+static int taal_wake_up(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+	if (td->ulps_enabled)
+		return taal_exit_ulps(dssdev);
+
+	taal_cancel_ulps_work(dssdev);
+	taal_queue_ulps_work(dssdev);
+	return 0;
+}
+
 static int taal_bl_update_status(struct backlight_device *dev)
 {
 	struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
@@ -458,7 +566,11 @@ static int taal_bl_update_status(struct backlight_device *dev)
 	if (td->use_dsi_bl) {
 		if (td->enabled) {
 			dsi_bus_lock();
-			r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
+
+			r = taal_wake_up(dssdev);
+			if (!r)
+				r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
+
 			dsi_bus_unlock();
 		} else {
 			r = 0;
@@ -521,7 +633,11 @@ static ssize_t taal_num_errors_show(struct device *dev,
 
 	if (td->enabled) {
 		dsi_bus_lock();
-		r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors);
+
+		r = taal_wake_up(dssdev);
+		if (!r)
+			r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors);
+
 		dsi_bus_unlock();
 	} else {
 		r = -ENODEV;
@@ -547,7 +663,11 @@ static ssize_t taal_hw_revision_show(struct device *dev,
 
 	if (td->enabled) {
 		dsi_bus_lock();
-		r = taal_get_id(td, &id1, &id2, &id3);
+
+		r = taal_wake_up(dssdev);
+		if (!r)
+			r = taal_get_id(td, &id1, &id2, &id3);
+
 		dsi_bus_unlock();
 	} else {
 		r = -ENODEV;
@@ -595,6 +715,7 @@ static ssize_t store_cabc_mode(struct device *dev,
 	struct omap_dss_device *dssdev = to_dss_device(dev);
 	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
 	int i;
+	int r;
 
 	for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
 		if (sysfs_streq(cabc_modes[i], buf))
@@ -608,8 +729,17 @@ static ssize_t store_cabc_mode(struct device *dev,
 
 	if (td->enabled) {
 		dsi_bus_lock();
-		if (!td->cabc_broken)
-			taal_dcs_write_1(td, DCS_WRITE_CABC, i);
+
+		if (!td->cabc_broken) {
+			r = taal_wake_up(dssdev);
+			if (r)
+				goto err;
+
+			r = taal_dcs_write_1(td, DCS_WRITE_CABC, i);
+			if (r)
+				goto err;
+		}
+
 		dsi_bus_unlock();
 	}
 
@@ -618,6 +748,10 @@ static ssize_t store_cabc_mode(struct device *dev,
 	mutex_unlock(&td->lock);
 
 	return count;
+err:
+	dsi_bus_unlock();
+	mutex_unlock(&td->lock);
+	return r;
 }
 
 static ssize_t show_cabc_available_modes(struct device *dev,
@@ -675,6 +809,101 @@ static ssize_t taal_show_esd_interval(struct device *dev,
 	return snprintf(buf, PAGE_SIZE, "%u\n", t);
 }
 
+static ssize_t taal_store_ulps(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned long t;
+	int r;
+
+	r = strict_strtoul(buf, 10, &t);
+	if (r)
+		return r;
+
+	mutex_lock(&td->lock);
+
+	if (td->enabled) {
+		dsi_bus_lock();
+
+		if (t)
+			r = taal_enter_ulps(dssdev);
+		else
+			r = taal_wake_up(dssdev);
+
+		dsi_bus_unlock();
+	}
+
+	mutex_unlock(&td->lock);
+
+	if (r)
+		return r;
+
+	return count;
+}
+
+static ssize_t taal_show_ulps(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned t;
+
+	mutex_lock(&td->lock);
+	t = td->ulps_enabled;
+	mutex_unlock(&td->lock);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
+static ssize_t taal_store_ulps_timeout(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned long t;
+	int r;
+
+	r = strict_strtoul(buf, 10, &t);
+	if (r)
+		return r;
+
+	mutex_lock(&td->lock);
+	td->ulps_timeout = t;
+
+	if (td->enabled) {
+		/* taal_wake_up will restart the timer */
+		dsi_bus_lock();
+		r = taal_wake_up(dssdev);
+		dsi_bus_unlock();
+	}
+
+	mutex_unlock(&td->lock);
+
+	if (r)
+		return r;
+
+	return count;
+}
+
+static ssize_t taal_show_ulps_timeout(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned t;
+
+	mutex_lock(&td->lock);
+	t = td->ulps_timeout;
+	mutex_unlock(&td->lock);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
 static DEVICE_ATTR(num_dsi_errors, S_IRUGO, taal_num_errors_show, NULL);
 static DEVICE_ATTR(hw_revision, S_IRUGO, taal_hw_revision_show, NULL);
 static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
@@ -683,6 +912,10 @@ static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
 		show_cabc_available_modes, NULL);
 static DEVICE_ATTR(esd_interval, S_IRUGO | S_IWUSR,
 		taal_show_esd_interval, taal_store_esd_interval);
+static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR,
+		taal_show_ulps, taal_store_ulps);
+static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR,
+		taal_show_ulps_timeout, taal_store_ulps_timeout);
 
 static struct attribute *taal_attrs[] = {
 	&dev_attr_num_dsi_errors.attr,
@@ -690,6 +923,8 @@ static struct attribute *taal_attrs[] = {
 	&dev_attr_cabc_mode.attr,
 	&dev_attr_cabc_available_modes.attr,
 	&dev_attr_esd_interval.attr,
+	&dev_attr_ulps.attr,
+	&dev_attr_ulps_timeout.attr,
 	NULL,
 };
 
@@ -759,6 +994,8 @@ static int taal_probe(struct omap_dss_device *dssdev)
 	td->dssdev = dssdev;
 	td->panel_config = panel_config;
 	td->esd_interval = panel_data->esd_interval;
+	td->ulps_enabled = false;
+	td->ulps_timeout = panel_data->ulps_timeout;
 
 	mutex_init(&td->lock);
 
@@ -776,6 +1013,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
 		goto err_wq;
 	}
 	INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
+	INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work);
 
 	dev_set_drvdata(&dssdev->dev, td);
 
@@ -900,6 +1138,7 @@ static void __exit taal_remove(struct omap_dss_device *dssdev)
 	taal_bl_update_status(bldev);
 	backlight_device_unregister(bldev);
 
+	taal_cancel_ulps_work(dssdev);
 	taal_cancel_esd_work(dssdev);
 	destroy_workqueue(td->workqueue);
 
@@ -1072,12 +1311,15 @@ static void taal_disable(struct omap_dss_device *dssdev)
 
 	mutex_lock(&td->lock);
 
+	taal_cancel_ulps_work(dssdev);
 	taal_cancel_esd_work(dssdev);
 
 	dsi_bus_lock();
 
-	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE)
+	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
+		taal_wake_up(dssdev);
 		taal_power_off(dssdev);
+	}
 
 	dsi_bus_unlock();
 
@@ -1100,11 +1342,14 @@ static int taal_suspend(struct omap_dss_device *dssdev)
 		goto err;
 	}
 
+	taal_cancel_ulps_work(dssdev);
 	taal_cancel_esd_work(dssdev);
 
 	dsi_bus_lock();
 
-	taal_power_off(dssdev);
+	r = taal_wake_up(dssdev);
+	if (!r)
+		taal_power_off(dssdev);
 
 	dsi_bus_unlock();
 
@@ -1213,6 +1458,10 @@ static int taal_update(struct omap_dss_device *dssdev,
 	mutex_lock(&td->lock);
 	dsi_bus_lock();
 
+	r = taal_wake_up(dssdev);
+	if (r)
+		goto err;
+
 	if (!td->enabled) {
 		r = 0;
 		goto err;
@@ -1300,6 +1549,10 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
 	dsi_bus_lock();
 
 	if (td->enabled) {
+		r = taal_wake_up(dssdev);
+		if (r)
+			goto err;
+
 		r = _taal_enable_te(dssdev, enable);
 		if (r)
 			goto err;
@@ -1346,6 +1599,10 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
 	dsi_bus_lock();
 
 	if (td->enabled) {
+		r = taal_wake_up(dssdev);
+		if (r)
+			goto err;
+
 		r = taal_set_addr_mode(td, rotate, td->mirror);
 		if (r)
 			goto err;
@@ -1389,6 +1646,10 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
 
 	dsi_bus_lock();
 	if (td->enabled) {
+		r = taal_wake_up(dssdev);
+		if (r)
+			goto err;
+
 		r = taal_set_addr_mode(td, td->rotate, enable);
 		if (r)
 			goto err;
@@ -1433,6 +1694,10 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
 
 	dsi_bus_lock();
 
+	r = taal_wake_up(dssdev);
+	if (r)
+		goto err2;
+
 	r = taal_dcs_read_1(td, DCS_GET_ID1, &id1);
 	if (r)
 		goto err2;
@@ -1479,6 +1744,10 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
 
 	dsi_bus_lock();
 
+	r = taal_wake_up(dssdev);
+	if (r)
+		goto err2;
+
 	/* plen 1 or 2 goes into short packet. until checksum error is fixed,
 	 * use short packets. plen 32 works, but bigger packets seem to cause
 	 * an error. */
@@ -1531,6 +1800,27 @@ err1:
 	return r;
 }
 
+static void taal_ulps_work(struct work_struct *work)
+{
+	struct taal_data *td = container_of(work, struct taal_data,
+			ulps_work.work);
+	struct omap_dss_device *dssdev = td->dssdev;
+
+	mutex_lock(&td->lock);
+
+	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || !td->enabled) {
+		mutex_unlock(&td->lock);
+		return;
+	}
+
+	dsi_bus_lock();
+
+	taal_enter_ulps(dssdev);
+
+	dsi_bus_unlock();
+	mutex_unlock(&td->lock);
+}
+
 static void taal_esd_work(struct work_struct *work)
 {
 	struct taal_data *td = container_of(work, struct taal_data,
@@ -1549,6 +1839,12 @@ static void taal_esd_work(struct work_struct *work)
 
 	dsi_bus_lock();
 
+	r = taal_wake_up(dssdev);
+	if (r) {
+		dev_err(&dssdev->dev, "failed to exit ULPS\n");
+		goto err;
+	}
+
 	r = taal_dcs_read_1(td, DCS_RDDSDR, &state1);
 	if (r) {
 		dev_err(&dssdev->dev, "failed to read Taal status\n");
-- 
1.7.1


WARNING: multiple messages have this Message-ID (diff)
From: Tomi Valkeinen <tomi.valkeinen@ti.com>
To: linux-omap@vger.kernel.org, linux-fbdev@vger.kernel.org
Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
Subject: [PATCH 19/19] OMAP: DSS2: Taal: Implement ULPS functionality
Date: Tue, 19 Apr 2011 12:22:22 +0300	[thread overview]
Message-ID: <1303204942-25450-20-git-send-email-tomi.valkeinen@ti.com> (raw)
In-Reply-To: <1303204942-25450-1-git-send-email-tomi.valkeinen@ti.com>

ULPS is a low power state where the DSI lanes are kept at ground. This
patch implements ULPS by having a DSI bus inactivity timer which
triggers the entry to ULPS. ULPS exit will happen automatically when the
driver needs to do something on the DSI lanes.

The ulps_timeout is configurable from board file or via sysfs.
Additionally another sysfs file, "ulps", can be used to check the
current ULPS state, or to manually enter or exit ULPS.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 arch/arm/plat-omap/include/plat/nokia-dsi-panel.h |    2 +
 drivers/video/omap2/displays/panel-taal.c         |  310 ++++++++++++++++++++-
 2 files changed, 305 insertions(+), 7 deletions(-)

diff --git a/arch/arm/plat-omap/include/plat/nokia-dsi-panel.h b/arch/arm/plat-omap/include/plat/nokia-dsi-panel.h
index aaa1c14..36ba7bd 100644
--- a/arch/arm/plat-omap/include/plat/nokia-dsi-panel.h
+++ b/arch/arm/plat-omap/include/plat/nokia-dsi-panel.h
@@ -9,6 +9,7 @@
  * @use_ext_te: use external TE
  * @ext_te_gpio: external TE GPIO
  * @esd_interval: interval of ESD checks, 0 = disabled (ms)
+ * @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms)
  * @max_backlight_level: maximum backlight level
  * @set_backlight: pointer to backlight set function
  * @get_backlight: pointer to backlight get function
@@ -22,6 +23,7 @@ struct nokia_dsi_panel_data {
 	int ext_te_gpio;
 
 	unsigned esd_interval;
+	unsigned ulps_timeout;
 
 	int max_backlight_level;
 	int (*set_backlight)(struct omap_dss_device *dssdev, int level);
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 9626e49..78ad355 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -67,6 +67,8 @@ static irqreturn_t taal_te_isr(int irq, void *data);
 static void taal_te_timeout_work_callback(struct work_struct *work);
 static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
 
+static int taal_panel_reset(struct omap_dss_device *dssdev);
+
 struct panel_regulator {
 	struct regulator *regulator;
 	const char *name;
@@ -232,6 +234,10 @@ struct taal_data {
 	struct delayed_work esd_work;
 	unsigned esd_interval;
 
+	bool ulps_enabled;
+	unsigned ulps_timeout;
+	struct delayed_work ulps_work;
+
 	struct panel_config *panel_config;
 };
 
@@ -242,6 +248,7 @@ static inline struct nokia_dsi_panel_data
 }
 
 static void taal_esd_work(struct work_struct *work);
+static void taal_ulps_work(struct work_struct *work);
 
 static void hw_guard_start(struct taal_data *td, int guard_msec)
 {
@@ -437,6 +444,107 @@ static void taal_cancel_esd_work(struct omap_dss_device *dssdev)
 	cancel_delayed_work(&td->esd_work);
 }
 
+static void taal_queue_ulps_work(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+	if (td->ulps_timeout > 0)
+		queue_delayed_work(td->workqueue, &td->ulps_work,
+				msecs_to_jiffies(td->ulps_timeout));
+}
+
+static void taal_cancel_ulps_work(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+	cancel_delayed_work(&td->ulps_work);
+}
+
+static int taal_enter_ulps(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
+	int r;
+
+	if (td->ulps_enabled)
+		return 0;
+
+	taal_cancel_ulps_work(dssdev);
+
+	r = _taal_enable_te(dssdev, false);
+	if (r)
+		goto err;
+
+	disable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+
+	omapdss_dsi_display_disable(dssdev, false, true);
+
+	td->ulps_enabled = true;
+
+	return 0;
+
+err:
+	dev_err(&dssdev->dev, "enter ULPS failed");
+	taal_panel_reset(dssdev);
+
+	td->ulps_enabled = false;
+
+	taal_queue_ulps_work(dssdev);
+
+	return r;
+}
+
+static int taal_exit_ulps(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
+	int r;
+
+	if (!td->ulps_enabled)
+		return 0;
+
+	r = omapdss_dsi_display_enable(dssdev);
+	if (r)
+		goto err;
+
+	omapdss_dsi_vc_enable_hs(td->channel, true);
+
+	r = _taal_enable_te(dssdev, true);
+	if (r)
+		goto err;
+
+	enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+
+	taal_queue_ulps_work(dssdev);
+
+	td->ulps_enabled = false;
+
+	return 0;
+
+err:
+	dev_err(&dssdev->dev, "exit ULPS failed");
+	r = taal_panel_reset(dssdev);
+
+	enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+	td->ulps_enabled = false;
+
+	taal_queue_ulps_work(dssdev);
+
+	return r;
+}
+
+static int taal_wake_up(struct omap_dss_device *dssdev)
+{
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+	if (td->ulps_enabled)
+		return taal_exit_ulps(dssdev);
+
+	taal_cancel_ulps_work(dssdev);
+	taal_queue_ulps_work(dssdev);
+	return 0;
+}
+
 static int taal_bl_update_status(struct backlight_device *dev)
 {
 	struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
@@ -458,7 +566,11 @@ static int taal_bl_update_status(struct backlight_device *dev)
 	if (td->use_dsi_bl) {
 		if (td->enabled) {
 			dsi_bus_lock();
-			r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
+
+			r = taal_wake_up(dssdev);
+			if (!r)
+				r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
+
 			dsi_bus_unlock();
 		} else {
 			r = 0;
@@ -521,7 +633,11 @@ static ssize_t taal_num_errors_show(struct device *dev,
 
 	if (td->enabled) {
 		dsi_bus_lock();
-		r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors);
+
+		r = taal_wake_up(dssdev);
+		if (!r)
+			r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors);
+
 		dsi_bus_unlock();
 	} else {
 		r = -ENODEV;
@@ -547,7 +663,11 @@ static ssize_t taal_hw_revision_show(struct device *dev,
 
 	if (td->enabled) {
 		dsi_bus_lock();
-		r = taal_get_id(td, &id1, &id2, &id3);
+
+		r = taal_wake_up(dssdev);
+		if (!r)
+			r = taal_get_id(td, &id1, &id2, &id3);
+
 		dsi_bus_unlock();
 	} else {
 		r = -ENODEV;
@@ -595,6 +715,7 @@ static ssize_t store_cabc_mode(struct device *dev,
 	struct omap_dss_device *dssdev = to_dss_device(dev);
 	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
 	int i;
+	int r;
 
 	for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
 		if (sysfs_streq(cabc_modes[i], buf))
@@ -608,8 +729,17 @@ static ssize_t store_cabc_mode(struct device *dev,
 
 	if (td->enabled) {
 		dsi_bus_lock();
-		if (!td->cabc_broken)
-			taal_dcs_write_1(td, DCS_WRITE_CABC, i);
+
+		if (!td->cabc_broken) {
+			r = taal_wake_up(dssdev);
+			if (r)
+				goto err;
+
+			r = taal_dcs_write_1(td, DCS_WRITE_CABC, i);
+			if (r)
+				goto err;
+		}
+
 		dsi_bus_unlock();
 	}
 
@@ -618,6 +748,10 @@ static ssize_t store_cabc_mode(struct device *dev,
 	mutex_unlock(&td->lock);
 
 	return count;
+err:
+	dsi_bus_unlock();
+	mutex_unlock(&td->lock);
+	return r;
 }
 
 static ssize_t show_cabc_available_modes(struct device *dev,
@@ -675,6 +809,101 @@ static ssize_t taal_show_esd_interval(struct device *dev,
 	return snprintf(buf, PAGE_SIZE, "%u\n", t);
 }
 
+static ssize_t taal_store_ulps(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned long t;
+	int r;
+
+	r = strict_strtoul(buf, 10, &t);
+	if (r)
+		return r;
+
+	mutex_lock(&td->lock);
+
+	if (td->enabled) {
+		dsi_bus_lock();
+
+		if (t)
+			r = taal_enter_ulps(dssdev);
+		else
+			r = taal_wake_up(dssdev);
+
+		dsi_bus_unlock();
+	}
+
+	mutex_unlock(&td->lock);
+
+	if (r)
+		return r;
+
+	return count;
+}
+
+static ssize_t taal_show_ulps(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned t;
+
+	mutex_lock(&td->lock);
+	t = td->ulps_enabled;
+	mutex_unlock(&td->lock);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
+static ssize_t taal_store_ulps_timeout(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned long t;
+	int r;
+
+	r = strict_strtoul(buf, 10, &t);
+	if (r)
+		return r;
+
+	mutex_lock(&td->lock);
+	td->ulps_timeout = t;
+
+	if (td->enabled) {
+		/* taal_wake_up will restart the timer */
+		dsi_bus_lock();
+		r = taal_wake_up(dssdev);
+		dsi_bus_unlock();
+	}
+
+	mutex_unlock(&td->lock);
+
+	if (r)
+		return r;
+
+	return count;
+}
+
+static ssize_t taal_show_ulps_timeout(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct omap_dss_device *dssdev = to_dss_device(dev);
+	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+	unsigned t;
+
+	mutex_lock(&td->lock);
+	t = td->ulps_timeout;
+	mutex_unlock(&td->lock);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
 static DEVICE_ATTR(num_dsi_errors, S_IRUGO, taal_num_errors_show, NULL);
 static DEVICE_ATTR(hw_revision, S_IRUGO, taal_hw_revision_show, NULL);
 static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
@@ -683,6 +912,10 @@ static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
 		show_cabc_available_modes, NULL);
 static DEVICE_ATTR(esd_interval, S_IRUGO | S_IWUSR,
 		taal_show_esd_interval, taal_store_esd_interval);
+static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR,
+		taal_show_ulps, taal_store_ulps);
+static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR,
+		taal_show_ulps_timeout, taal_store_ulps_timeout);
 
 static struct attribute *taal_attrs[] = {
 	&dev_attr_num_dsi_errors.attr,
@@ -690,6 +923,8 @@ static struct attribute *taal_attrs[] = {
 	&dev_attr_cabc_mode.attr,
 	&dev_attr_cabc_available_modes.attr,
 	&dev_attr_esd_interval.attr,
+	&dev_attr_ulps.attr,
+	&dev_attr_ulps_timeout.attr,
 	NULL,
 };
 
@@ -759,6 +994,8 @@ static int taal_probe(struct omap_dss_device *dssdev)
 	td->dssdev = dssdev;
 	td->panel_config = panel_config;
 	td->esd_interval = panel_data->esd_interval;
+	td->ulps_enabled = false;
+	td->ulps_timeout = panel_data->ulps_timeout;
 
 	mutex_init(&td->lock);
 
@@ -776,6 +1013,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
 		goto err_wq;
 	}
 	INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
+	INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work);
 
 	dev_set_drvdata(&dssdev->dev, td);
 
@@ -900,6 +1138,7 @@ static void __exit taal_remove(struct omap_dss_device *dssdev)
 	taal_bl_update_status(bldev);
 	backlight_device_unregister(bldev);
 
+	taal_cancel_ulps_work(dssdev);
 	taal_cancel_esd_work(dssdev);
 	destroy_workqueue(td->workqueue);
 
@@ -1072,12 +1311,15 @@ static void taal_disable(struct omap_dss_device *dssdev)
 
 	mutex_lock(&td->lock);
 
+	taal_cancel_ulps_work(dssdev);
 	taal_cancel_esd_work(dssdev);
 
 	dsi_bus_lock();
 
-	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+		taal_wake_up(dssdev);
 		taal_power_off(dssdev);
+	}
 
 	dsi_bus_unlock();
 
@@ -1100,11 +1342,14 @@ static int taal_suspend(struct omap_dss_device *dssdev)
 		goto err;
 	}
 
+	taal_cancel_ulps_work(dssdev);
 	taal_cancel_esd_work(dssdev);
 
 	dsi_bus_lock();
 
-	taal_power_off(dssdev);
+	r = taal_wake_up(dssdev);
+	if (!r)
+		taal_power_off(dssdev);
 
 	dsi_bus_unlock();
 
@@ -1213,6 +1458,10 @@ static int taal_update(struct omap_dss_device *dssdev,
 	mutex_lock(&td->lock);
 	dsi_bus_lock();
 
+	r = taal_wake_up(dssdev);
+	if (r)
+		goto err;
+
 	if (!td->enabled) {
 		r = 0;
 		goto err;
@@ -1300,6 +1549,10 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
 	dsi_bus_lock();
 
 	if (td->enabled) {
+		r = taal_wake_up(dssdev);
+		if (r)
+			goto err;
+
 		r = _taal_enable_te(dssdev, enable);
 		if (r)
 			goto err;
@@ -1346,6 +1599,10 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
 	dsi_bus_lock();
 
 	if (td->enabled) {
+		r = taal_wake_up(dssdev);
+		if (r)
+			goto err;
+
 		r = taal_set_addr_mode(td, rotate, td->mirror);
 		if (r)
 			goto err;
@@ -1389,6 +1646,10 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
 
 	dsi_bus_lock();
 	if (td->enabled) {
+		r = taal_wake_up(dssdev);
+		if (r)
+			goto err;
+
 		r = taal_set_addr_mode(td, td->rotate, enable);
 		if (r)
 			goto err;
@@ -1433,6 +1694,10 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
 
 	dsi_bus_lock();
 
+	r = taal_wake_up(dssdev);
+	if (r)
+		goto err2;
+
 	r = taal_dcs_read_1(td, DCS_GET_ID1, &id1);
 	if (r)
 		goto err2;
@@ -1479,6 +1744,10 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
 
 	dsi_bus_lock();
 
+	r = taal_wake_up(dssdev);
+	if (r)
+		goto err2;
+
 	/* plen 1 or 2 goes into short packet. until checksum error is fixed,
 	 * use short packets. plen 32 works, but bigger packets seem to cause
 	 * an error. */
@@ -1531,6 +1800,27 @@ err1:
 	return r;
 }
 
+static void taal_ulps_work(struct work_struct *work)
+{
+	struct taal_data *td = container_of(work, struct taal_data,
+			ulps_work.work);
+	struct omap_dss_device *dssdev = td->dssdev;
+
+	mutex_lock(&td->lock);
+
+	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || !td->enabled) {
+		mutex_unlock(&td->lock);
+		return;
+	}
+
+	dsi_bus_lock();
+
+	taal_enter_ulps(dssdev);
+
+	dsi_bus_unlock();
+	mutex_unlock(&td->lock);
+}
+
 static void taal_esd_work(struct work_struct *work)
 {
 	struct taal_data *td = container_of(work, struct taal_data,
@@ -1549,6 +1839,12 @@ static void taal_esd_work(struct work_struct *work)
 
 	dsi_bus_lock();
 
+	r = taal_wake_up(dssdev);
+	if (r) {
+		dev_err(&dssdev->dev, "failed to exit ULPS\n");
+		goto err;
+	}
+
 	r = taal_dcs_read_1(td, DCS_RDDSDR, &state1);
 	if (r) {
 		dev_err(&dssdev->dev, "failed to read Taal status\n");
-- 
1.7.1


  parent reply	other threads:[~2011-04-19  9:22 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-04-19  9:22 [PATCH 00/19] OMAP: DSS2: ULPS support Tomi Valkeinen
2011-04-19  9:22 ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 01/19] OMAP: DSS2: DSI: Add lane override functions Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 02/19] OMAP: DSS2: DSI: Remove CIO LDO status check Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 03/19] OMAP: DSS2: DSI: implement ULPS enter and exit Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 04/19] OMAP: DSS2: DSI: add option to leave DSI lanes powered on Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 05/19] OMAP: DSS2: DSI: rename complexio related functions Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 06/19] OMAP: DSS2: Add FEAT_DSI_REVERSE_TXCLKESC Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 07/19] OMAP: DSS2: DSI: fix _dsi_print_reset_status Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 08/19] OMAP: DSS2: DSI: implement enable/disable SCP clk Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 09/19] OMAP: DSS2: DSI: fix CIO init and uninit Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 10/19] OMAP: DSS2: DSI: wait for TXCLKESC domain to come out of reset Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 11/19] OMAP: DSS2: DSI: add parameter to enter ulps on disable Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 12/19] OMAP: DSS2: DSI: Add DSI pad muxing support Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 13/19] OMAP: DSS2: DSI: ensure VDDS_DSI is disabled on exit Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 14/19] OMAP: DSS2: Taal: Implement configurable ESD interval Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 15/19] OMAP: DSS2: Taal: Clean up ESD queueing Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 16/19] OMAP: DSS2: Taal: Add sysfs file for ESD interval Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 17/19] OMAP: DSS2: Taal: Separate panel reset Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` [PATCH 18/19] OMAP: DSS2: Taal: Rename esd_wq to workqueue Tomi Valkeinen
2011-04-19  9:22   ` Tomi Valkeinen
2011-04-19  9:22 ` Tomi Valkeinen [this message]
2011-04-19  9:22   ` [PATCH 19/19] OMAP: DSS2: Taal: Implement ULPS functionality Tomi Valkeinen
2011-04-20  5:43 ` [PATCH 00/19] OMAP: DSS2: ULPS support Archit Taneja
2011-04-20  5:55   ` Archit Taneja
2011-04-20  6:08   ` Tomi Valkeinen
2011-04-20  6:08     ` Tomi Valkeinen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1303204942-25450-20-git-send-email-tomi.valkeinen@ti.com \
    --to=tomi.valkeinen@ti.com \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.