All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
To: linux-omap@vger.kernel.org
Cc: khilman@ti.com, santosh.shilimkar@ti.com, tony@atomide.com,
	linux-arm-kernel@lists.infradead.org,
	Tarun Kanti DebBarma <tarun.kanti@ti.com>
Subject: [PATCH v14 12/12] OMAP: dmtimer: Off mode support
Date: Mon, 11 Jul 2011 16:51:36 +0530	[thread overview]
Message-ID: <1310383296-18956-13-git-send-email-tarun.kanti@ti.com> (raw)
In-Reply-To: <1310383296-18956-1-git-send-email-tarun.kanti@ti.com>

Clock is enabled only when timer is started and disabled when the the timer
is stopped. Therefore before accessing registers in functions clock is enabled
and then disabled back at the end of access.
Context save and restore functions are called as needed based upon whether the
context is lost or not.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
---
 arch/arm/mach-omap2/timer.c               |   17 +++++
 arch/arm/plat-omap/dmtimer.c              |   95 +++++++++++++++++++++++++++--
 arch/arm/plat-omap/include/plat/dmtimer.h |    9 +++
 3 files changed, 116 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index a7ce240..1214851 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -44,6 +44,9 @@
 #include <plat/common.h>
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+
+#include "powerdomain.h"
 
 /* Parent clocks, eventually these will come from the clock framework */
 
@@ -408,6 +411,16 @@ static int omap2_dm_timer_set_src(struct platform_device *pdev, int source)
 	return ret;
 }
 
+#ifdef CONFIG_PM
+static int omap_timer_get_context_loss(struct device *dev)
+{
+	return omap_pm_get_dev_context_loss_count(dev);
+}
+
+#else
+#define omap_gpio_get_context_loss NULL
+#endif
+
 struct omap_device_pm_latency omap2_dmtimer_latency[] = {
 	{
 		.deactivate_func = omap_device_idle_hwmods,
@@ -436,6 +449,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 	struct dmtimer_platform_data *pdata;
 	struct omap_device *od;
 	struct omap_timer_capability_dev_attr *timer_dev_attr;
+	struct powerdomain *pwrdm;
 
 	pr_debug("%s: %s\n", __func__, oh->name);
 
@@ -466,6 +480,9 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 	pdata->set_timer_src = omap2_dm_timer_set_src;
 	pdata->timer_ip_type = oh->class->rev;
 	pdata->needs_manual_reset = 0;
+	pwrdm = omap_hwmod_get_pwrdm(oh);
+	pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
+	pdata->get_context_loss_count = omap_timer_get_context_loss;
 
 	od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
 			omap2_dmtimer_latency,
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 2405637..f0cb652 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -151,12 +151,14 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 
 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
+	omap_dm_timer_enable(timer);
 	if (timer->pdev->id != 1) {
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
 		omap_dm_timer_wait_for_reset(timer);
 	}
 
 	__omap_dm_timer_reset(timer->io_base, 0, 0, timer->func_offset);
+	omap_dm_timer_disable(timer);
 	timer->posted = 1;
 }
 
@@ -171,14 +173,13 @@ void omap_dm_timer_prepare(struct omap_dm_timer *timer)
 		return;
 	}
 
-	omap_dm_timer_enable(timer);
-
 	if (pdata->needs_manual_reset)
 		omap_dm_timer_reset(timer);
 
 	omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
 
 	timer->posted = 1;
+	timer->context_changed = true;
 }
 
 struct omap_dm_timer *omap_dm_timer_request(void)
@@ -230,7 +231,6 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 
 void omap_dm_timer_free(struct omap_dm_timer *timer)
 {
-	omap_dm_timer_disable(timer);
 	clk_put(timer->fclk);
 
 	WARN_ON(!timer->reserved);
@@ -311,6 +311,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
 void omap_dm_timer_trigger(struct omap_dm_timer *timer)
 {
+	if (unlikely(!timer->reserved)) {
+		pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+		return;
+	}
+
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
@@ -319,6 +324,19 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
 {
 	u32 l;
 
+	if (timer->loses_context) {
+		u32 ctx_loss_cnt_after;
+
+		omap_dm_timer_enable(timer);
+		ctx_loss_cnt_after =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if ((ctx_loss_cnt_after != timer->ctx_loss_count) &&
+					timer->context_saved) {
+			omap_timer_restore_context(timer);
+			timer->context_saved = false;
+		}
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (!(l & OMAP_TIMER_CTRL_ST)) {
 		l |= OMAP_TIMER_CTRL_ST;
@@ -340,6 +358,18 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
 
 	__omap_dm_timer_stop(timer->io_base, timer->posted, rate,
 			is_omap2, timer->intr_offset, timer->func_offset);
+
+	if (timer->loses_context) {
+		if (timer->get_context_loss_count)
+			timer->ctx_loss_count =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if (timer->context_changed) {
+			omap_timer_save_context(timer);
+			timer->context_saved = true;
+			timer->context_changed = false;
+		}
+		omap_dm_timer_disable(timer);
+	}
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
 
@@ -351,9 +381,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 	if (source < 0 || source >= 3)
 		return -EINVAL;
 
-	omap_dm_timer_disable(timer);
 	ret = pdata->set_timer_src(timer->pdev, source);
-	omap_dm_timer_enable(timer);
 
 	__delay(300000);
 
@@ -366,6 +394,7 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload)
 		l |= OMAP_TIMER_CTRL_AR;
@@ -375,6 +404,9 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
+	omap_dm_timer_disable(timer);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
 
@@ -384,6 +416,19 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 {
 	u32 l;
 
+	if (timer->loses_context) {
+		int ctx_loss_cnt_after;
+
+		omap_dm_timer_enable(timer);
+		ctx_loss_cnt_after =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if ((ctx_loss_cnt_after != timer->ctx_loss_count) &&
+				timer->context_saved) {
+			omap_timer_restore_context(timer);
+			timer->context_saved = false;
+		}
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload) {
 		l |= OMAP_TIMER_CTRL_AR;
@@ -395,6 +440,8 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 
 	__omap_dm_timer_load_start(timer->io_base, l, load, timer->posted,
 					timer->func_offset);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 
@@ -403,6 +450,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (enable)
 		l |= OMAP_TIMER_CTRL_CE;
@@ -410,6 +458,9 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 		l &= ~OMAP_TIMER_CTRL_CE;
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
+	omap_dm_timer_disable(timer);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
 
@@ -418,6 +469,7 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
 	       OMAP_TIMER_CTRL_PT | (0x03 << 10));
@@ -427,6 +479,9 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 		l |= OMAP_TIMER_CTRL_PT;
 	l |= trigger << 10;
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+	omap_dm_timer_disable(timer);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
 
@@ -434,6 +489,7 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
 	if (prescaler >= 0x00 && prescaler <= 0x07) {
@@ -441,14 +497,21 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 		l |= prescaler << 2;
 	}
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+	omap_dm_timer_disable(timer);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
 
 void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
 				  unsigned int value)
 {
+	omap_dm_timer_enable(timer);
 	__omap_dm_timer_int_enable(timer->io_base, value,
 					timer->intr_offset, timer->func_offset);
+	omap_dm_timer_disable(timer);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -456,6 +519,11 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 {
 	unsigned int l;
 
+	if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
+		pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+		return 0;
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
 
 	return l;
@@ -466,11 +534,17 @@ void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 {
 	__omap_dm_timer_write_status(timer->io_base, value,
 					timer->intr_offset, timer->func_offset);
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
 
 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 {
+	if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
+		pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+		return 0;
+	}
+
 	return __omap_dm_timer_read_counter(timer->io_base, timer->posted,
 						timer->func_offset);
 }
@@ -478,7 +552,14 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 
 void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
 {
+	if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
+		pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+		return;
+	}
+
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 
@@ -567,9 +648,13 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 	timer->irq = irq->start;
 	timer->pdev = pdev;
 	timer->reserved = 0;
+	timer->context_changed = false;
+	timer->loses_context = pdata->loses_context;
+	timer->get_context_loss_count = pdata->get_context_loss_count;
 
 	if (!pdata->needs_manual_reset) {
 		pm_runtime_enable(&pdev->dev);
+		pm_runtime_put_sync(&pdev->dev);
 
 		/* Mark clocksource and clockevent timers as reserved */
 		if ((sys_timer_reserved >> (pdev->id - 1)) & 0x1)
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 9a2d7e3..379b9c7 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -85,6 +85,9 @@ struct dmtimer_platform_data {
 	int (*set_timer_src)(struct platform_device *pdev, int source);
 	int timer_ip_type;
 	u32 needs_manual_reset:1;
+	bool loses_context;
+
+	int (*get_context_loss_count)(struct device *dev);
 };
 
 struct omap_dm_timer *omap_dm_timer_request(void);
@@ -269,8 +272,14 @@ struct omap_dm_timer {
 	u8 func_offset;
 	u8 intr_offset;
 	struct timer_regs context;
+	bool loses_context;
+	bool context_saved;
+	bool context_changed;
+	int ctx_loss_count;
 	struct platform_device *pdev;
 	struct list_head node;
+
+	int (*get_context_loss_count)(struct device *dev);
 };
 
 extern u32 sys_timer_reserved;
-- 
1.6.0.4


WARNING: multiple messages have this Message-ID (diff)
From: tarun.kanti@ti.com (Tarun Kanti DebBarma)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v14 12/12] OMAP: dmtimer: Off mode support
Date: Mon, 11 Jul 2011 16:51:36 +0530	[thread overview]
Message-ID: <1310383296-18956-13-git-send-email-tarun.kanti@ti.com> (raw)
In-Reply-To: <1310383296-18956-1-git-send-email-tarun.kanti@ti.com>

Clock is enabled only when timer is started and disabled when the the timer
is stopped. Therefore before accessing registers in functions clock is enabled
and then disabled back at the end of access.
Context save and restore functions are called as needed based upon whether the
context is lost or not.

Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
---
 arch/arm/mach-omap2/timer.c               |   17 +++++
 arch/arm/plat-omap/dmtimer.c              |   95 +++++++++++++++++++++++++++--
 arch/arm/plat-omap/include/plat/dmtimer.h |    9 +++
 3 files changed, 116 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index a7ce240..1214851 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -44,6 +44,9 @@
 #include <plat/common.h>
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+
+#include "powerdomain.h"
 
 /* Parent clocks, eventually these will come from the clock framework */
 
@@ -408,6 +411,16 @@ static int omap2_dm_timer_set_src(struct platform_device *pdev, int source)
 	return ret;
 }
 
+#ifdef CONFIG_PM
+static int omap_timer_get_context_loss(struct device *dev)
+{
+	return omap_pm_get_dev_context_loss_count(dev);
+}
+
+#else
+#define omap_gpio_get_context_loss NULL
+#endif
+
 struct omap_device_pm_latency omap2_dmtimer_latency[] = {
 	{
 		.deactivate_func = omap_device_idle_hwmods,
@@ -436,6 +449,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 	struct dmtimer_platform_data *pdata;
 	struct omap_device *od;
 	struct omap_timer_capability_dev_attr *timer_dev_attr;
+	struct powerdomain *pwrdm;
 
 	pr_debug("%s: %s\n", __func__, oh->name);
 
@@ -466,6 +480,9 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
 	pdata->set_timer_src = omap2_dm_timer_set_src;
 	pdata->timer_ip_type = oh->class->rev;
 	pdata->needs_manual_reset = 0;
+	pwrdm = omap_hwmod_get_pwrdm(oh);
+	pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
+	pdata->get_context_loss_count = omap_timer_get_context_loss;
 
 	od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
 			omap2_dmtimer_latency,
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 2405637..f0cb652 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -151,12 +151,14 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
 
 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
+	omap_dm_timer_enable(timer);
 	if (timer->pdev->id != 1) {
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
 		omap_dm_timer_wait_for_reset(timer);
 	}
 
 	__omap_dm_timer_reset(timer->io_base, 0, 0, timer->func_offset);
+	omap_dm_timer_disable(timer);
 	timer->posted = 1;
 }
 
@@ -171,14 +173,13 @@ void omap_dm_timer_prepare(struct omap_dm_timer *timer)
 		return;
 	}
 
-	omap_dm_timer_enable(timer);
-
 	if (pdata->needs_manual_reset)
 		omap_dm_timer_reset(timer);
 
 	omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
 
 	timer->posted = 1;
+	timer->context_changed = true;
 }
 
 struct omap_dm_timer *omap_dm_timer_request(void)
@@ -230,7 +231,6 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
 
 void omap_dm_timer_free(struct omap_dm_timer *timer)
 {
-	omap_dm_timer_disable(timer);
 	clk_put(timer->fclk);
 
 	WARN_ON(!timer->reserved);
@@ -311,6 +311,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
 
 void omap_dm_timer_trigger(struct omap_dm_timer *timer)
 {
+	if (unlikely(!timer->reserved)) {
+		pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+		return;
+	}
+
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
@@ -319,6 +324,19 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
 {
 	u32 l;
 
+	if (timer->loses_context) {
+		u32 ctx_loss_cnt_after;
+
+		omap_dm_timer_enable(timer);
+		ctx_loss_cnt_after =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if ((ctx_loss_cnt_after != timer->ctx_loss_count) &&
+					timer->context_saved) {
+			omap_timer_restore_context(timer);
+			timer->context_saved = false;
+		}
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (!(l & OMAP_TIMER_CTRL_ST)) {
 		l |= OMAP_TIMER_CTRL_ST;
@@ -340,6 +358,18 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
 
 	__omap_dm_timer_stop(timer->io_base, timer->posted, rate,
 			is_omap2, timer->intr_offset, timer->func_offset);
+
+	if (timer->loses_context) {
+		if (timer->get_context_loss_count)
+			timer->ctx_loss_count =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if (timer->context_changed) {
+			omap_timer_save_context(timer);
+			timer->context_saved = true;
+			timer->context_changed = false;
+		}
+		omap_dm_timer_disable(timer);
+	}
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
 
@@ -351,9 +381,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 	if (source < 0 || source >= 3)
 		return -EINVAL;
 
-	omap_dm_timer_disable(timer);
 	ret = pdata->set_timer_src(timer->pdev, source);
-	omap_dm_timer_enable(timer);
 
 	__delay(300000);
 
@@ -366,6 +394,7 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload)
 		l |= OMAP_TIMER_CTRL_AR;
@@ -375,6 +404,9 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
+	omap_dm_timer_disable(timer);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
 
@@ -384,6 +416,19 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 {
 	u32 l;
 
+	if (timer->loses_context) {
+		int ctx_loss_cnt_after;
+
+		omap_dm_timer_enable(timer);
+		ctx_loss_cnt_after =
+			timer->get_context_loss_count(&timer->pdev->dev);
+		if ((ctx_loss_cnt_after != timer->ctx_loss_count) &&
+				timer->context_saved) {
+			omap_timer_restore_context(timer);
+			timer->context_saved = false;
+		}
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (autoreload) {
 		l |= OMAP_TIMER_CTRL_AR;
@@ -395,6 +440,8 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 
 	__omap_dm_timer_load_start(timer->io_base, l, load, timer->posted,
 					timer->func_offset);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
 
@@ -403,6 +450,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	if (enable)
 		l |= OMAP_TIMER_CTRL_CE;
@@ -410,6 +458,9 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 		l &= ~OMAP_TIMER_CTRL_CE;
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
+	omap_dm_timer_disable(timer);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
 
@@ -418,6 +469,7 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
 	       OMAP_TIMER_CTRL_PT | (0x03 << 10));
@@ -427,6 +479,9 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 		l |= OMAP_TIMER_CTRL_PT;
 	l |= trigger << 10;
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+	omap_dm_timer_disable(timer);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
 
@@ -434,6 +489,7 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 {
 	u32 l;
 
+	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
 	if (prescaler >= 0x00 && prescaler <= 0x07) {
@@ -441,14 +497,21 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 		l |= prescaler << 2;
 	}
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+	omap_dm_timer_disable(timer);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
 
 void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
 				  unsigned int value)
 {
+	omap_dm_timer_enable(timer);
 	__omap_dm_timer_int_enable(timer->io_base, value,
 					timer->intr_offset, timer->func_offset);
+	omap_dm_timer_disable(timer);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
 
@@ -456,6 +519,11 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 {
 	unsigned int l;
 
+	if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
+		pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+		return 0;
+	}
+
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
 
 	return l;
@@ -466,11 +534,17 @@ void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 {
 	__omap_dm_timer_write_status(timer->io_base, value,
 					timer->intr_offset, timer->func_offset);
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
 
 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 {
+	if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
+		pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+		return 0;
+	}
+
 	return __omap_dm_timer_read_counter(timer->io_base, timer->posted,
 						timer->func_offset);
 }
@@ -478,7 +552,14 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
 
 void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
 {
+	if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
+		pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
+		return;
+	}
+
 	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
+
+	timer->context_changed = true;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
 
@@ -567,9 +648,13 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
 	timer->irq = irq->start;
 	timer->pdev = pdev;
 	timer->reserved = 0;
+	timer->context_changed = false;
+	timer->loses_context = pdata->loses_context;
+	timer->get_context_loss_count = pdata->get_context_loss_count;
 
 	if (!pdata->needs_manual_reset) {
 		pm_runtime_enable(&pdev->dev);
+		pm_runtime_put_sync(&pdev->dev);
 
 		/* Mark clocksource and clockevent timers as reserved */
 		if ((sys_timer_reserved >> (pdev->id - 1)) & 0x1)
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 9a2d7e3..379b9c7 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -85,6 +85,9 @@ struct dmtimer_platform_data {
 	int (*set_timer_src)(struct platform_device *pdev, int source);
 	int timer_ip_type;
 	u32 needs_manual_reset:1;
+	bool loses_context;
+
+	int (*get_context_loss_count)(struct device *dev);
 };
 
 struct omap_dm_timer *omap_dm_timer_request(void);
@@ -269,8 +272,14 @@ struct omap_dm_timer {
 	u8 func_offset;
 	u8 intr_offset;
 	struct timer_regs context;
+	bool loses_context;
+	bool context_saved;
+	bool context_changed;
+	int ctx_loss_count;
 	struct platform_device *pdev;
 	struct list_head node;
+
+	int (*get_context_loss_count)(struct device *dev);
 };
 
 extern u32 sys_timer_reserved;
-- 
1.6.0.4

  parent reply	other threads:[~2011-07-11 12:48 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-07-11 11:21 [PATCH v14 00/12] dmtimer adaptation to platform_driver Tarun Kanti DebBarma
2011-07-11 11:21 ` Tarun Kanti DebBarma
2011-07-11 11:21 ` [PATCH v14 01/12] OMAP2+: dmtimer: add device names to flck nodes Tarun Kanti DebBarma
2011-07-11 11:21   ` Tarun Kanti DebBarma
2011-07-11 11:21 ` [PATCH v14 02/12] OMAP4: hwmod data: add dmtimer version information Tarun Kanti DebBarma
2011-07-11 11:21   ` Tarun Kanti DebBarma
2011-07-11 11:21 ` [PATCH v14 03/12] OMAP1: dmtimer: conversion to platform devices Tarun Kanti DebBarma
2011-07-11 11:21   ` Tarun Kanti DebBarma
2011-07-11 11:21 ` [PATCH v14 04/12] OMAP2+: dmtimer: convert " Tarun Kanti DebBarma
2011-07-11 11:21   ` Tarun Kanti DebBarma
2011-07-11 11:21 ` [PATCH v14 05/12] OMAP: dmtimer: platform driver Tarun Kanti DebBarma
2011-07-11 11:21   ` Tarun Kanti DebBarma
2011-07-11 11:21 ` [PATCH v14 06/12] OMAP: dmtimer: switch-over to platform device driver Tarun Kanti DebBarma
2011-07-11 11:21   ` Tarun Kanti DebBarma
2011-07-11 11:21 ` [PATCH v14 07/12] OMAP: dmtimer: pm_runtime support Tarun Kanti DebBarma
2011-07-11 11:21   ` Tarun Kanti DebBarma
2011-07-11 11:21 ` [PATCH v14 08/12] OMAP: dmtimer: add timeout to low-level routines Tarun Kanti DebBarma
2011-07-11 11:21   ` Tarun Kanti DebBarma
2011-07-11 11:21 ` [PATCH v14 09/12] OMAP: dmtimer: use mutex instead of spinlock Tarun Kanti DebBarma
2011-07-11 11:21   ` Tarun Kanti DebBarma
2011-07-11 11:21 ` [PATCH v14 10/12] OMAP: dmtimer: mark clocksource and clockevent timers reserved Tarun Kanti DebBarma
2011-07-11 11:21   ` Tarun Kanti DebBarma
2011-07-11 11:21 ` [PATCH v14 11/12] OMAP: dmtimer: add context save/restore routines Tarun Kanti DebBarma
2011-07-11 11:21   ` Tarun Kanti DebBarma
2011-07-11 11:21 ` Tarun Kanti DebBarma [this message]
2011-07-11 11:21   ` [PATCH v14 12/12] OMAP: dmtimer: Off mode support Tarun Kanti DebBarma
2011-07-11 11:29 [PATCH v14 00/12] dmtimer adaptation to platform_driver Tarun Kanti DebBarma
2011-07-11 11:29 ` [PATCH v14 12/12] OMAP: dmtimer: Off mode support Tarun Kanti DebBarma
2011-07-11 11:29   ` Tarun Kanti DebBarma

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=1310383296-18956-13-git-send-email-tarun.kanti@ti.com \
    --to=tarun.kanti@ti.com \
    --cc=khilman@ti.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=santosh.shilimkar@ti.com \
    --cc=tony@atomide.com \
    /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.