Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <fabrice.gasnier@foss.st.com>
Link: https://lore.kernel.org/r/20250224172101.3448398-1-fabrice.gasnier@foss.st.com
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>

authored by

Fabrice Gasnier and committed by
Daniel Lezcano
b5a497a7 f7803f79

+29 -3
+29 -3
drivers/clocksource/timer-stm32-lp.c
··· 24 24 struct regmap *reg; 25 25 struct clock_event_device clkevt; 26 26 unsigned long period; 27 + u32 psc; 27 28 struct device *dev; 29 + struct clk *clk; 28 30 }; 29 31 30 32 static struct stm32_lp_private* ··· 122 120 /* Adjust rate and period given the prescaler value */ 123 121 *rate = DIV_ROUND_CLOSEST(*rate, (1 << i)); 124 122 priv->period = DIV_ROUND_UP(*rate, HZ); 123 + priv->psc = i; 124 + } 125 + 126 + static void stm32_clkevent_lp_suspend(struct clock_event_device *clkevt) 127 + { 128 + struct stm32_lp_private *priv = to_priv(clkevt); 129 + 130 + stm32_clkevent_lp_shutdown(clkevt); 131 + 132 + /* balance clk_prepare_enable() from the probe */ 133 + clk_disable_unprepare(priv->clk); 134 + } 135 + 136 + static void stm32_clkevent_lp_resume(struct clock_event_device *clkevt) 137 + { 138 + struct stm32_lp_private *priv = to_priv(clkevt); 139 + 140 + clk_prepare_enable(priv->clk); 141 + 142 + /* restore prescaler */ 143 + regmap_write(priv->reg, STM32_LPTIM_CFGR, priv->psc << CFGR_PSC_OFFSET); 125 144 } 126 145 127 146 static void stm32_clkevent_lp_init(struct stm32_lp_private *priv, ··· 157 134 priv->clkevt.set_state_oneshot = stm32_clkevent_lp_set_oneshot; 158 135 priv->clkevt.set_next_event = stm32_clkevent_lp_set_next_event; 159 136 priv->clkevt.rating = STM32_LP_RATING; 137 + priv->clkevt.suspend = stm32_clkevent_lp_suspend; 138 + priv->clkevt.resume = stm32_clkevent_lp_resume; 160 139 161 140 clockevents_config_and_register(&priv->clkevt, rate, 0x1, 162 141 STM32_LPTIM_MAX_ARR); ··· 176 151 return -ENOMEM; 177 152 178 153 priv->reg = ddata->regmap; 179 - ret = clk_prepare_enable(ddata->clk); 154 + priv->clk = ddata->clk; 155 + ret = clk_prepare_enable(priv->clk); 180 156 if (ret) 181 157 return -EINVAL; 182 158 183 - rate = clk_get_rate(ddata->clk); 159 + rate = clk_get_rate(priv->clk); 184 160 if (!rate) { 185 161 ret = -EINVAL; 186 162 goto out_clk_disable; ··· 217 191 return 0; 218 192 219 193 out_clk_disable: 220 - clk_disable_unprepare(ddata->clk); 194 + clk_disable_unprepare(priv->clk); 221 195 return ret; 222 196 } 223 197