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

drivers/clocksource/timer-ti-dm: Don't call clk_get_rate() in stop function

clk_get_rate() might sleep, and that prevents dm-timer based PWM from being
used from atomic context.

Fix that by getting fclk rate in probe() and using a notifier in case rate
changes.

Fixes: af04aa856e93 ("ARM: OMAP: Move dmtimer driver out of plat-omap to drivers under clocksource")
Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
Reviewed-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/1696312220-11550-1-git-send-email-ivo.g.dimitrov.75@gmail.com

authored by

Ivaylo Dimitrov and committed by
Daniel Lezcano
12590d4d 8051a993

+28 -8
+28 -8
drivers/clocksource/timer-ti-dm.c
··· 140 140 struct platform_device *pdev; 141 141 struct list_head node; 142 142 struct notifier_block nb; 143 + struct notifier_block fclk_nb; 144 + unsigned long fclk_rate; 143 145 }; 144 146 145 147 static u32 omap_reserved_systimers; ··· 255 253 timer->posted = OMAP_TIMER_POSTED; 256 254 } 257 255 258 - static inline void __omap_dm_timer_stop(struct dmtimer *timer, 259 - unsigned long rate) 256 + static inline void __omap_dm_timer_stop(struct dmtimer *timer) 260 257 { 261 258 u32 l; 262 259 ··· 270 269 * Wait for functional clock period x 3.5 to make sure that 271 270 * timer is stopped 272 271 */ 273 - udelay(3500000 / rate + 1); 272 + udelay(3500000 / timer->fclk_rate + 1); 274 273 #endif 275 274 } 276 275 ··· 347 346 } 348 347 349 348 return NOTIFY_OK; 349 + } 350 + 351 + static int omap_timer_fclk_notifier(struct notifier_block *nb, 352 + unsigned long event, void *data) 353 + { 354 + struct clk_notifier_data *clk_data = data; 355 + struct dmtimer *timer = container_of(nb, struct dmtimer, fclk_nb); 356 + 357 + switch (event) { 358 + case POST_RATE_CHANGE: 359 + timer->fclk_rate = clk_data->new_rate; 360 + return NOTIFY_OK; 361 + default: 362 + return NOTIFY_DONE; 363 + } 350 364 } 351 365 352 366 static int omap_dm_timer_reset(struct dmtimer *timer) ··· 770 754 { 771 755 struct dmtimer *timer; 772 756 struct device *dev; 773 - unsigned long rate = 0; 774 757 775 758 timer = to_dmtimer(cookie); 776 759 if (unlikely(!timer)) ··· 777 762 778 763 dev = &timer->pdev->dev; 779 764 780 - if (!timer->omap1) 781 - rate = clk_get_rate(timer->fclk); 782 - 783 - __omap_dm_timer_stop(timer, rate); 765 + __omap_dm_timer_stop(timer); 784 766 785 767 pm_runtime_put_sync(dev); 786 768 ··· 1136 1124 timer->fclk = devm_clk_get(dev, "fck"); 1137 1125 if (IS_ERR(timer->fclk)) 1138 1126 return PTR_ERR(timer->fclk); 1127 + 1128 + timer->fclk_nb.notifier_call = omap_timer_fclk_notifier; 1129 + ret = devm_clk_notifier_register(dev, timer->fclk, 1130 + &timer->fclk_nb); 1131 + if (ret) 1132 + return ret; 1133 + 1134 + timer->fclk_rate = clk_get_rate(timer->fclk); 1139 1135 } else { 1140 1136 timer->fclk = ERR_PTR(-ENODEV); 1141 1137 }