aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/timer-ti-dm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource/timer-ti-dm.c')
-rw-r--r--drivers/clocksource/timer-ti-dm.c97
1 files changed, 57 insertions, 40 deletions
diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c
index fe939d1c0b38..1d1bea79cbf1 100644
--- a/drivers/clocksource/timer-ti-dm.c
+++ b/drivers/clocksource/timer-ti-dm.c
@@ -20,6 +20,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/cpu_pm.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/device.h>
@@ -92,6 +93,47 @@ static void omap_timer_restore_context(struct omap_dm_timer *timer)
timer->context.tclr);
}
+static void omap_timer_save_context(struct omap_dm_timer *timer)
+{
+ timer->context.tclr =
+ omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+ timer->context.twer =
+ omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG);
+ timer->context.tldr =
+ omap_dm_timer_read_reg(timer, OMAP_TIMER_LOAD_REG);
+ timer->context.tmar =
+ omap_dm_timer_read_reg(timer, OMAP_TIMER_MATCH_REG);
+ timer->context.tier = readl_relaxed(timer->irq_ena);
+ timer->context.tsicr =
+ omap_dm_timer_read_reg(timer, OMAP_TIMER_IF_CTRL_REG);
+}
+
+static int omap_timer_context_notifier(struct notifier_block *nb,
+ unsigned long cmd, void *v)
+{
+ struct omap_dm_timer *timer;
+
+ timer = container_of(nb, struct omap_dm_timer, nb);
+
+ switch (cmd) {
+ case CPU_CLUSTER_PM_ENTER:
+ if ((timer->capability & OMAP_TIMER_ALWON) ||
+ !atomic_read(&timer->enabled))
+ break;
+ omap_timer_save_context(timer);
+ break;
+ case CPU_CLUSTER_PM_ENTER_FAILED:
+ case CPU_CLUSTER_PM_EXIT:
+ if ((timer->capability & OMAP_TIMER_ALWON) ||
+ !atomic_read(&timer->enabled))
+ break;
+ omap_timer_restore_context(timer);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
static int omap_dm_timer_reset(struct omap_dm_timer *timer)
{
u32 l, timeout = 100000;
@@ -208,21 +250,7 @@ static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
static void omap_dm_timer_enable(struct omap_dm_timer *timer)
{
- int c;
-
pm_runtime_get_sync(&timer->pdev->dev);
-
- if (!(timer->capability & OMAP_TIMER_ALWON)) {
- if (timer->get_context_loss_count) {
- c = timer->get_context_loss_count(&timer->pdev->dev);
- if (c != timer->ctx_loss_count) {
- omap_timer_restore_context(timer);
- timer->ctx_loss_count = c;
- }
- } else {
- omap_timer_restore_context(timer);
- }
- }
}
static void omap_dm_timer_disable(struct omap_dm_timer *timer)
@@ -515,8 +543,6 @@ static int omap_dm_timer_start(struct omap_dm_timer *timer)
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
- /* Save the context */
- timer->context.tclr = l;
return 0;
}
@@ -532,13 +558,6 @@ static int omap_dm_timer_stop(struct omap_dm_timer *timer)
__omap_dm_timer_stop(timer, timer->posted, rate);
- /*
- * Since the register values are computed and written within
- * __omap_dm_timer_stop, we need to use read to retrieve the
- * context.
- */
- timer->context.tclr =
- omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
omap_dm_timer_disable(timer);
return 0;
}
@@ -561,9 +580,6 @@ static int 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);
- /* Save the context */
- timer->context.tclr = l;
- timer->context.tldr = load;
omap_dm_timer_disable(timer);
return 0;
}
@@ -585,9 +601,6 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
- /* Save the context */
- timer->context.tclr = l;
- timer->context.tmar = match;
omap_dm_timer_disable(timer);
return 0;
}
@@ -611,8 +624,6 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
l |= trigger << 10;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
- /* Save the context */
- timer->context.tclr = l;
omap_dm_timer_disable(timer);
return 0;
}
@@ -634,8 +645,6 @@ static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer,
}
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
- /* Save the context */
- timer->context.tclr = l;
omap_dm_timer_disable(timer);
return 0;
}
@@ -649,9 +658,6 @@ static int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
omap_dm_timer_enable(timer);
__omap_dm_timer_int_enable(timer, value);
- /* Save the context */
- timer->context.tier = value;
- timer->context.twer = value;
omap_dm_timer_disable(timer);
return 0;
}
@@ -679,9 +685,6 @@ static int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l);
- /* Save the context */
- timer->context.tier &= ~mask;
- timer->context.twer &= ~mask;
omap_dm_timer_disable(timer);
return 0;
}
@@ -756,6 +759,11 @@ static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev)
atomic_set(&timer->enabled, 0);
+ if (timer->capability & OMAP_TIMER_ALWON || !timer->func_base)
+ return 0;
+
+ omap_timer_save_context(timer);
+
return 0;
}
@@ -763,6 +771,9 @@ static int __maybe_unused omap_dm_timer_runtime_resume(struct device *dev)
{
struct omap_dm_timer *timer = dev_get_drvdata(dev);
+ if (!(timer->capability & OMAP_TIMER_ALWON) && timer->func_base)
+ omap_timer_restore_context(timer);
+
atomic_set(&timer->enabled, 1);
return 0;
@@ -829,7 +840,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
timer->id = pdev->id;
timer->capability = pdata->timer_capability;
timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
- timer->get_context_loss_count = pdata->get_context_loss_count;
+ }
+
+ if (!(timer->capability & OMAP_TIMER_ALWON)) {
+ timer->nb.notifier_call = omap_timer_context_notifier;
+ cpu_pm_register_notifier(&timer->nb);
}
if (pdata)
@@ -883,6 +898,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev)
list_for_each_entry(timer, &omap_timer_list, node)
if (!strcmp(dev_name(&timer->pdev->dev),
dev_name(&pdev->dev))) {
+ if (!(timer->capability & OMAP_TIMER_ALWON))
+ cpu_pm_unregister_notifier(&timer->nb);
list_del(&timer->node);
ret = 0;
break;