Skip to content

Commit b5a497a

Browse files
Fabrice Gasnierdlezcano
authored andcommitted
clocksource/drivers/stm32-lptimer: Add support for suspend / resume
Add support for power management on STM32 LPTIMER clocksource driver: - Upon clockevents_suspend(), shutdown the LPTIMER, and balance the clk_prepare_enable() from the probe routine. - Upon clockevents_resume(), restore the prescaler that may have been lost during low power mode, and restore the clock. Signed-off-by: Fabrice Gasnier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Daniel Lezcano <[email protected]>
1 parent f7803f7 commit b5a497a

File tree

1 file changed

+29
-3
lines changed

1 file changed

+29
-3
lines changed

drivers/clocksource/timer-stm32-lp.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ struct stm32_lp_private {
2424
struct regmap *reg;
2525
struct clock_event_device clkevt;
2626
unsigned long period;
27+
u32 psc;
2728
struct device *dev;
29+
struct clk *clk;
2830
};
2931

3032
static struct stm32_lp_private*
@@ -120,6 +122,27 @@ static void stm32_clkevent_lp_set_prescaler(struct stm32_lp_private *priv,
120122
/* Adjust rate and period given the prescaler value */
121123
*rate = DIV_ROUND_CLOSEST(*rate, (1 << i));
122124
priv->period = DIV_ROUND_UP(*rate, HZ);
125+
priv->psc = i;
126+
}
127+
128+
static void stm32_clkevent_lp_suspend(struct clock_event_device *clkevt)
129+
{
130+
struct stm32_lp_private *priv = to_priv(clkevt);
131+
132+
stm32_clkevent_lp_shutdown(clkevt);
133+
134+
/* balance clk_prepare_enable() from the probe */
135+
clk_disable_unprepare(priv->clk);
136+
}
137+
138+
static void stm32_clkevent_lp_resume(struct clock_event_device *clkevt)
139+
{
140+
struct stm32_lp_private *priv = to_priv(clkevt);
141+
142+
clk_prepare_enable(priv->clk);
143+
144+
/* restore prescaler */
145+
regmap_write(priv->reg, STM32_LPTIM_CFGR, priv->psc << CFGR_PSC_OFFSET);
123146
}
124147

125148
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,
134157
priv->clkevt.set_state_oneshot = stm32_clkevent_lp_set_oneshot;
135158
priv->clkevt.set_next_event = stm32_clkevent_lp_set_next_event;
136159
priv->clkevt.rating = STM32_LP_RATING;
160+
priv->clkevt.suspend = stm32_clkevent_lp_suspend;
161+
priv->clkevt.resume = stm32_clkevent_lp_resume;
137162

138163
clockevents_config_and_register(&priv->clkevt, rate, 0x1,
139164
STM32_LPTIM_MAX_ARR);
@@ -151,11 +176,12 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev)
151176
return -ENOMEM;
152177

153178
priv->reg = ddata->regmap;
154-
ret = clk_prepare_enable(ddata->clk);
179+
priv->clk = ddata->clk;
180+
ret = clk_prepare_enable(priv->clk);
155181
if (ret)
156182
return -EINVAL;
157183

158-
rate = clk_get_rate(ddata->clk);
184+
rate = clk_get_rate(priv->clk);
159185
if (!rate) {
160186
ret = -EINVAL;
161187
goto out_clk_disable;
@@ -191,7 +217,7 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev)
191217
return 0;
192218

193219
out_clk_disable:
194-
clk_disable_unprepare(ddata->clk);
220+
clk_disable_unprepare(priv->clk);
195221
return ret;
196222
}
197223

0 commit comments

Comments
 (0)