diff options
Diffstat (limited to 'arch/arm/plat-omap/dmtimer.c')
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 110 |
1 files changed, 105 insertions, 5 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index c8df3c36b3a..43eb75038ba 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -77,6 +77,29 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, __omap_dm_timer_write(timer, reg, value, timer->posted); } +static void omap_timer_restore_context(struct omap_dm_timer *timer) +{ + omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET, + timer->context.tiocp_cfg); + if (timer->revision > 1) + __raw_writel(timer->context.tistat, timer->sys_stat); + + __raw_writel(timer->context.tisr, timer->irq_stat); + omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, + timer->context.twer); + omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, + timer->context.tcrr); + omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, + timer->context.tldr); + omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, + timer->context.tmar); + omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, + timer->context.tsicr); + __raw_writel(timer->context.tier, timer->irq_ena); + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, + timer->context.tclr); +} + static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) { int c; @@ -96,12 +119,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, 0, 0); + omap_dm_timer_disable(timer); timer->posted = 1; } @@ -117,8 +142,6 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer) return -EINVAL; } - omap_dm_timer_enable(timer); - if (pdata->needs_manual_reset) omap_dm_timer_reset(timer); @@ -193,7 +216,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); @@ -275,6 +297,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask); void omap_dm_timer_trigger(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; + } + omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); } EXPORT_SYMBOL_GPL(omap_dm_timer_trigger); @@ -283,11 +310,23 @@ void omap_dm_timer_start(struct omap_dm_timer *timer) { u32 l; + omap_dm_timer_enable(timer); + + if (timer->loses_context) { + u32 ctx_loss_cnt_after = + timer->get_context_loss_count(&timer->pdev->dev); + if (ctx_loss_cnt_after != timer->ctx_loss_count) + omap_timer_restore_context(timer); + } + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); if (!(l & OMAP_TIMER_CTRL_ST)) { l |= OMAP_TIMER_CTRL_ST; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); } + + /* Save the context */ + timer->context.tclr = l; } EXPORT_SYMBOL_GPL(omap_dm_timer_start); @@ -311,9 +350,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); return ret; } @@ -324,6 +361,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; @@ -333,6 +371,10 @@ 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); + /* Save the context */ + timer->context.tclr = l; + timer->context.tldr = load; + omap_dm_timer_disable(timer); } EXPORT_SYMBOL_GPL(omap_dm_timer_set_load); @@ -342,6 +384,15 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, { u32 l; + omap_dm_timer_enable(timer); + + if (timer->loses_context) { + u32 ctx_loss_cnt_after = + timer->get_context_loss_count(&timer->pdev->dev); + if (ctx_loss_cnt_after != timer->ctx_loss_count) + omap_timer_restore_context(timer); + } + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); if (autoreload) { l |= OMAP_TIMER_CTRL_AR; @@ -352,6 +403,11 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, l |= OMAP_TIMER_CTRL_ST; __omap_dm_timer_load_start(timer, l, load, timer->posted); + + /* Save the context */ + timer->context.tclr = l; + timer->context.tldr = load; + timer->context.tcrr = load; } EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); @@ -360,6 +416,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; @@ -367,6 +424,11 @@ 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); + + /* Save the context */ + timer->context.tclr = l; + timer->context.tmar = match; + omap_dm_timer_disable(timer); } EXPORT_SYMBOL_GPL(omap_dm_timer_set_match); @@ -375,6 +437,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)); @@ -384,6 +447,10 @@ 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); + + /* Save the context */ + timer->context.tclr = l; + omap_dm_timer_disable(timer); } EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm); @@ -391,6 +458,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) { @@ -398,13 +466,23 @@ 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); + + /* Save the context */ + timer->context.tclr = l; + omap_dm_timer_disable(timer); } 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, value); + + /* Save the context */ + timer->context.tier = value; + timer->context.twer = value; + omap_dm_timer_disable(timer); } EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); @@ -412,6 +490,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 = __raw_readl(timer->irq_stat); return l; @@ -421,18 +504,33 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status); void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) { __omap_dm_timer_write_status(timer, value); + /* Save the context */ + timer->context.tisr = value; } 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, timer->posted); } 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); + + /* Save the context */ + timer->context.tcrr = value; } EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter); @@ -511,6 +609,8 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev) timer->irq = irq->start; timer->reserved = pdata->reserved; timer->pdev = pdev; + timer->loses_context = pdata->loses_context; + timer->get_context_loss_count = pdata->get_context_loss_count; /* Skip pm_runtime_enable for OMAP1 */ if (!pdata->needs_manual_reset) { |