diff options
-rw-r--r-- | drivers/clocksource/timer-atmel-st.c | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/drivers/clocksource/timer-atmel-st.c b/drivers/clocksource/timer-atmel-st.c index 41b7b6dc1d0d..29d21d68df5a 100644 --- a/drivers/clocksource/timer-atmel-st.c +++ b/drivers/clocksource/timer-atmel-st.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/irq.h> | 24 | #include <linux/irq.h> |
25 | #include <linux/clk.h> | ||
25 | #include <linux/clockchips.h> | 26 | #include <linux/clockchips.h> |
26 | #include <linux/export.h> | 27 | #include <linux/export.h> |
27 | #include <linux/mfd/syscon.h> | 28 | #include <linux/mfd/syscon.h> |
@@ -33,9 +34,7 @@ static unsigned long last_crtr; | |||
33 | static u32 irqmask; | 34 | static u32 irqmask; |
34 | static struct clock_event_device clkevt; | 35 | static struct clock_event_device clkevt; |
35 | static struct regmap *regmap_st; | 36 | static struct regmap *regmap_st; |
36 | 37 | static int timer_latch; | |
37 | #define AT91_SLOW_CLOCK 32768 | ||
38 | #define RM9200_TIMER_LATCH ((AT91_SLOW_CLOCK + HZ/2) / HZ) | ||
39 | 38 | ||
40 | /* | 39 | /* |
41 | * The ST_CRTR is updated asynchronously to the master clock ... but | 40 | * The ST_CRTR is updated asynchronously to the master clock ... but |
@@ -82,8 +81,8 @@ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id) | |||
82 | if (sr & AT91_ST_PITS) { | 81 | if (sr & AT91_ST_PITS) { |
83 | u32 crtr = read_CRTR(); | 82 | u32 crtr = read_CRTR(); |
84 | 83 | ||
85 | while (((crtr - last_crtr) & AT91_ST_CRTV) >= RM9200_TIMER_LATCH) { | 84 | while (((crtr - last_crtr) & AT91_ST_CRTV) >= timer_latch) { |
86 | last_crtr += RM9200_TIMER_LATCH; | 85 | last_crtr += timer_latch; |
87 | clkevt.event_handler(&clkevt); | 86 | clkevt.event_handler(&clkevt); |
88 | } | 87 | } |
89 | return IRQ_HANDLED; | 88 | return IRQ_HANDLED; |
@@ -144,7 +143,7 @@ static int clkevt32k_set_periodic(struct clock_event_device *dev) | |||
144 | 143 | ||
145 | /* PIT for periodic irqs; fixed rate of 1/HZ */ | 144 | /* PIT for periodic irqs; fixed rate of 1/HZ */ |
146 | irqmask = AT91_ST_PITS; | 145 | irqmask = AT91_ST_PITS; |
147 | regmap_write(regmap_st, AT91_ST_PIMR, RM9200_TIMER_LATCH); | 146 | regmap_write(regmap_st, AT91_ST_PIMR, timer_latch); |
148 | regmap_write(regmap_st, AT91_ST_IER, irqmask); | 147 | regmap_write(regmap_st, AT91_ST_IER, irqmask); |
149 | return 0; | 148 | return 0; |
150 | } | 149 | } |
@@ -197,7 +196,8 @@ static struct clock_event_device clkevt = { | |||
197 | */ | 196 | */ |
198 | static void __init atmel_st_timer_init(struct device_node *node) | 197 | static void __init atmel_st_timer_init(struct device_node *node) |
199 | { | 198 | { |
200 | unsigned int val; | 199 | struct clk *sclk; |
200 | unsigned int sclk_rate, val; | ||
201 | int irq, ret; | 201 | int irq, ret; |
202 | 202 | ||
203 | regmap_st = syscon_node_to_regmap(node); | 203 | regmap_st = syscon_node_to_regmap(node); |
@@ -221,6 +221,19 @@ static void __init atmel_st_timer_init(struct device_node *node) | |||
221 | if (ret) | 221 | if (ret) |
222 | panic(pr_fmt("Unable to setup IRQ\n")); | 222 | panic(pr_fmt("Unable to setup IRQ\n")); |
223 | 223 | ||
224 | sclk = of_clk_get(node, 0); | ||
225 | if (IS_ERR(sclk)) | ||
226 | panic(pr_fmt("Unable to get slow clock\n")); | ||
227 | |||
228 | clk_prepare_enable(sclk); | ||
229 | if (ret) | ||
230 | panic(pr_fmt("Could not enable slow clock\n")); | ||
231 | |||
232 | sclk_rate = clk_get_rate(sclk); | ||
233 | if (!sclk_rate) | ||
234 | panic(pr_fmt("Invalid slow clock rate\n")); | ||
235 | timer_latch = (sclk_rate + HZ / 2) / HZ; | ||
236 | |||
224 | /* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used | 237 | /* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used |
225 | * directly for the clocksource and all clockevents, after adjusting | 238 | * directly for the clocksource and all clockevents, after adjusting |
226 | * its prescaler from the 1 Hz default. | 239 | * its prescaler from the 1 Hz default. |
@@ -229,11 +242,11 @@ static void __init atmel_st_timer_init(struct device_node *node) | |||
229 | 242 | ||
230 | /* Setup timer clockevent, with minimum of two ticks (important!!) */ | 243 | /* Setup timer clockevent, with minimum of two ticks (important!!) */ |
231 | clkevt.cpumask = cpumask_of(0); | 244 | clkevt.cpumask = cpumask_of(0); |
232 | clockevents_config_and_register(&clkevt, AT91_SLOW_CLOCK, | 245 | clockevents_config_and_register(&clkevt, sclk_rate, |
233 | 2, AT91_ST_ALMV); | 246 | 2, AT91_ST_ALMV); |
234 | 247 | ||
235 | /* register clocksource */ | 248 | /* register clocksource */ |
236 | clocksource_register_hz(&clk32k, AT91_SLOW_CLOCK); | 249 | clocksource_register_hz(&clk32k, sclk_rate); |
237 | } | 250 | } |
238 | CLOCKSOURCE_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st", | 251 | CLOCKSOURCE_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st", |
239 | atmel_st_timer_init); | 252 | atmel_st_timer_init); |