diff options
Diffstat (limited to 'drivers/clocksource/timer-stm32-lp.c')
-rw-r--r-- | drivers/clocksource/timer-stm32-lp.c | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c index a4c95161cb22..928da2f6de69 100644 --- a/drivers/clocksource/timer-stm32-lp.c +++ b/drivers/clocksource/timer-stm32-lp.c @@ -24,7 +24,9 @@ struct stm32_lp_private { struct regmap *reg; struct clock_event_device clkevt; unsigned long period; + u32 psc; struct device *dev; + struct clk *clk; }; static struct stm32_lp_private* @@ -120,6 +122,27 @@ static void stm32_clkevent_lp_set_prescaler(struct stm32_lp_private *priv, /* Adjust rate and period given the prescaler value */ *rate = DIV_ROUND_CLOSEST(*rate, (1 << i)); priv->period = DIV_ROUND_UP(*rate, HZ); + priv->psc = i; +} + +static void stm32_clkevent_lp_suspend(struct clock_event_device *clkevt) +{ + struct stm32_lp_private *priv = to_priv(clkevt); + + stm32_clkevent_lp_shutdown(clkevt); + + /* balance clk_prepare_enable() from the probe */ + clk_disable_unprepare(priv->clk); +} + +static void stm32_clkevent_lp_resume(struct clock_event_device *clkevt) +{ + struct stm32_lp_private *priv = to_priv(clkevt); + + clk_prepare_enable(priv->clk); + + /* restore prescaler */ + regmap_write(priv->reg, STM32_LPTIM_CFGR, priv->psc << CFGR_PSC_OFFSET); } static void stm32_clkevent_lp_init(struct stm32_lp_private *priv, @@ -134,6 +157,8 @@ static void stm32_clkevent_lp_init(struct stm32_lp_private *priv, priv->clkevt.set_state_oneshot = stm32_clkevent_lp_set_oneshot; priv->clkevt.set_next_event = stm32_clkevent_lp_set_next_event; priv->clkevt.rating = STM32_LP_RATING; + priv->clkevt.suspend = stm32_clkevent_lp_suspend; + priv->clkevt.resume = stm32_clkevent_lp_resume; clockevents_config_and_register(&priv->clkevt, rate, 0x1, STM32_LPTIM_MAX_ARR); @@ -151,11 +176,12 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev) return -ENOMEM; priv->reg = ddata->regmap; - ret = clk_prepare_enable(ddata->clk); + priv->clk = ddata->clk; + ret = clk_prepare_enable(priv->clk); if (ret) return -EINVAL; - rate = clk_get_rate(ddata->clk); + rate = clk_get_rate(priv->clk); if (!rate) { ret = -EINVAL; goto out_clk_disable; @@ -168,9 +194,7 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev) } if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) { - ret = device_init_wakeup(&pdev->dev, true); - if (ret) - goto out_clk_disable; + device_set_wakeup_capable(&pdev->dev, true); ret = dev_pm_set_wake_irq(&pdev->dev, irq); if (ret) @@ -191,7 +215,7 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev) return 0; out_clk_disable: - clk_disable_unprepare(ddata->clk); + clk_disable_unprepare(priv->clk); return ret; } |