Skip to content

Commit 12590d4

Browse files
freemangordondlezcano
authored andcommitted
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: af04aa8 ("ARM: OMAP: Move dmtimer driver out of plat-omap to drivers under clocksource") Signed-off-by: Ivaylo Dimitrov <[email protected]> Reviewed-by: Tony Lindgren <[email protected]> Signed-off-by: Daniel Lezcano <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 8051a99 commit 12590d4

File tree

1 file changed

+28
-8
lines changed

1 file changed

+28
-8
lines changed

drivers/clocksource/timer-ti-dm.c

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ struct dmtimer {
140140
struct platform_device *pdev;
141141
struct list_head node;
142142
struct notifier_block nb;
143+
struct notifier_block fclk_nb;
144+
unsigned long fclk_rate;
143145
};
144146

145147
static u32 omap_reserved_systimers;
@@ -253,8 +255,7 @@ static inline void __omap_dm_timer_enable_posted(struct dmtimer *timer)
253255
timer->posted = OMAP_TIMER_POSTED;
254256
}
255257

256-
static inline void __omap_dm_timer_stop(struct dmtimer *timer,
257-
unsigned long rate)
258+
static inline void __omap_dm_timer_stop(struct dmtimer *timer)
258259
{
259260
u32 l;
260261

@@ -269,7 +270,7 @@ static inline void __omap_dm_timer_stop(struct dmtimer *timer,
269270
* Wait for functional clock period x 3.5 to make sure that
270271
* timer is stopped
271272
*/
272-
udelay(3500000 / rate + 1);
273+
udelay(3500000 / timer->fclk_rate + 1);
273274
#endif
274275
}
275276

@@ -348,6 +349,21 @@ static int omap_timer_context_notifier(struct notifier_block *nb,
348349
return NOTIFY_OK;
349350
}
350351

352+
static int omap_timer_fclk_notifier(struct notifier_block *nb,
353+
unsigned long event, void *data)
354+
{
355+
struct clk_notifier_data *clk_data = data;
356+
struct dmtimer *timer = container_of(nb, struct dmtimer, fclk_nb);
357+
358+
switch (event) {
359+
case POST_RATE_CHANGE:
360+
timer->fclk_rate = clk_data->new_rate;
361+
return NOTIFY_OK;
362+
default:
363+
return NOTIFY_DONE;
364+
}
365+
}
366+
351367
static int omap_dm_timer_reset(struct dmtimer *timer)
352368
{
353369
u32 l, timeout = 100000;
@@ -754,18 +770,14 @@ static int omap_dm_timer_stop(struct omap_dm_timer *cookie)
754770
{
755771
struct dmtimer *timer;
756772
struct device *dev;
757-
unsigned long rate = 0;
758773

759774
timer = to_dmtimer(cookie);
760775
if (unlikely(!timer))
761776
return -EINVAL;
762777

763778
dev = &timer->pdev->dev;
764779

765-
if (!timer->omap1)
766-
rate = clk_get_rate(timer->fclk);
767-
768-
__omap_dm_timer_stop(timer, rate);
780+
__omap_dm_timer_stop(timer);
769781

770782
pm_runtime_put_sync(dev);
771783

@@ -1124,6 +1136,14 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
11241136
timer->fclk = devm_clk_get(dev, "fck");
11251137
if (IS_ERR(timer->fclk))
11261138
return PTR_ERR(timer->fclk);
1139+
1140+
timer->fclk_nb.notifier_call = omap_timer_fclk_notifier;
1141+
ret = devm_clk_notifier_register(dev, timer->fclk,
1142+
&timer->fclk_nb);
1143+
if (ret)
1144+
return ret;
1145+
1146+
timer->fclk_rate = clk_get_rate(timer->fclk);
11271147
} else {
11281148
timer->fclk = ERR_PTR(-ENODEV);
11291149
}

0 commit comments

Comments
 (0)