aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/tcb_clksrc.c
diff options
context:
space:
mode:
authorBoris BREZILLON <b.brezillon@overkiz.com>2013-10-02 08:35:41 -0400
committerDaniel Lezcano <daniel.lezcano@linaro.org>2013-10-03 10:28:30 -0400
commit5b3c11da141c27df6f8dd8acf90c0046ebab3a07 (patch)
tree95b7895c4423232cbd9d94f6a377ffcd168cb360 /drivers/clocksource/tcb_clksrc.c
parent0e746ec55812a2f8f5ab986aeedd5291e3b6fad4 (diff)
clocksource: tcb_clksrc: Improve driver robustness
Check function return values to avoid false positive driver init. Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Diffstat (limited to 'drivers/clocksource/tcb_clksrc.c')
-rw-r--r--drivers/clocksource/tcb_clksrc.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c
index 048156291fa0..10a5d9ef23f5 100644
--- a/drivers/clocksource/tcb_clksrc.c
+++ b/drivers/clocksource/tcb_clksrc.c
@@ -184,11 +184,18 @@ static struct irqaction tc_irqaction = {
184 .handler = ch2_irq, 184 .handler = ch2_irq,
185}; 185};
186 186
187static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) 187static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
188{ 188{
189 int ret;
189 struct clk *t2_clk = tc->clk[2]; 190 struct clk *t2_clk = tc->clk[2];
190 int irq = tc->irq[2]; 191 int irq = tc->irq[2];
191 192
193 /* try to enable t2 clk to avoid future errors in mode change */
194 ret = clk_prepare_enable(t2_clk);
195 if (ret)
196 return ret;
197 clk_disable_unprepare(t2_clk);
198
192 clkevt.regs = tc->regs; 199 clkevt.regs = tc->regs;
193 clkevt.clk = t2_clk; 200 clkevt.clk = t2_clk;
194 tc_irqaction.dev_id = &clkevt; 201 tc_irqaction.dev_id = &clkevt;
@@ -197,16 +204,21 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
197 204
198 clkevt.clkevt.cpumask = cpumask_of(0); 205 clkevt.clkevt.cpumask = cpumask_of(0);
199 206
207 ret = setup_irq(irq, &tc_irqaction);
208 if (ret)
209 return ret;
210
200 clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff); 211 clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff);
201 212
202 setup_irq(irq, &tc_irqaction); 213 return ret;
203} 214}
204 215
205#else /* !CONFIG_GENERIC_CLOCKEVENTS */ 216#else /* !CONFIG_GENERIC_CLOCKEVENTS */
206 217
207static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) 218static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
208{ 219{
209 /* NOTHING */ 220 /* NOTHING */
221 return 0;
210} 222}
211 223
212#endif 224#endif
@@ -328,13 +340,24 @@ static int __init tcb_clksrc_init(void)
328 } 340 }
329 341
330 /* and away we go! */ 342 /* and away we go! */
331 clocksource_register_hz(&clksrc, divided_rate); 343 ret = clocksource_register_hz(&clksrc, divided_rate);
344 if (ret)
345 goto err_disable_t1;
332 346
333 /* channel 2: periodic and oneshot timer support */ 347 /* channel 2: periodic and oneshot timer support */
334 setup_clkevents(tc, clk32k_divisor_idx); 348 ret = setup_clkevents(tc, clk32k_divisor_idx);
349 if (ret)
350 goto err_unregister_clksrc;
335 351
336 return 0; 352 return 0;
337 353
354err_unregister_clksrc:
355 clocksource_unregister(&clksrc);
356
357err_disable_t1:
358 if (!tc->tcb_config || tc->tcb_config->counter_width != 32)
359 clk_disable_unprepare(tc->clk[1]);
360
338err_disable_t0: 361err_disable_t0:
339 clk_disable_unprepare(t0_clk); 362 clk_disable_unprepare(t0_clk);
340 363