aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlexandre Belloni <alexandre.belloni@bootlin.com>2019-04-26 17:47:11 -0400
committerDaniel Lezcano <daniel.lezcano@linaro.org>2019-05-02 15:55:58 -0400
commit86232bfd28d71db4a50562cf81ff88ef58a6d401 (patch)
tree8971cb2c6ae581a8acb5640b8276ca1843a4175d /drivers
parentc2c9136b7096f0583117d7d0486600feec387865 (diff)
clocksource/drivers/tcb_clksrc: Stop depending on atmel_tclib
atmel_tclib is probed too late in the boot process to be able to use the TCB as the boot clocksource. This is an issue for SoCs without the PIT (sams70, samv70 and samv71 families) as they simply currently can't boot. Get rid of the atmel_tclib dependency and probe everything on our own using the correct device tree binding. This also allows getting rid of ATMEL_TCB_CLKSRC_BLOCK and makes the driver a bit more flexible as the TCB is not hardcoded in the kernel anymore. Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clocksource/tcb_clksrc.c108
-rw-r--r--drivers/misc/Kconfig14
2 files changed, 70 insertions, 52 deletions
diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c
index 138a12090149..bf68504da94a 100644
--- a/drivers/clocksource/tcb_clksrc.c
+++ b/drivers/clocksource/tcb_clksrc.c
@@ -9,7 +9,8 @@
9#include <linux/err.h> 9#include <linux/err.h>
10#include <linux/ioport.h> 10#include <linux/ioport.h>
11#include <linux/io.h> 11#include <linux/io.h>
12#include <linux/platform_device.h> 12#include <linux/of_address.h>
13#include <linux/of_irq.h>
13#include <linux/syscore_ops.h> 14#include <linux/syscore_ops.h>
14#include <soc/at91/atmel_tcb.h> 15#include <soc/at91/atmel_tcb.h>
15 16
@@ -28,13 +29,6 @@
28 * source, used in either periodic or oneshot mode. This runs 29 * source, used in either periodic or oneshot mode. This runs
29 * at 32 KiHZ, and can handle delays of up to two seconds. 30 * at 32 KiHZ, and can handle delays of up to two seconds.
30 * 31 *
31 * A boot clocksource and clockevent source are also currently needed,
32 * unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so
33 * this code can be used when init_timers() is called, well before most
34 * devices are set up. (Some low end AT91 parts, which can run uClinux,
35 * have only the timers in one TC block... they currently don't support
36 * the tclib code, because of that initialization issue.)
37 *
38 * REVISIT behavior during system suspend states... we should disable 32 * REVISIT behavior during system suspend states... we should disable
39 * all clocks and save the power. Easily done for clockevent devices, 33 * all clocks and save the power. Easily done for clockevent devices,
40 * but clocksources won't necessarily get the needed notifications. 34 * but clocksources won't necessarily get the needed notifications.
@@ -112,7 +106,6 @@ void tc_clksrc_resume(struct clocksource *cs)
112} 106}
113 107
114static struct clocksource clksrc = { 108static struct clocksource clksrc = {
115 .name = "tcb_clksrc",
116 .rating = 200, 109 .rating = 200,
117 .read = tc_get_cycles, 110 .read = tc_get_cycles,
118 .mask = CLOCKSOURCE_MASK(32), 111 .mask = CLOCKSOURCE_MASK(32),
@@ -214,7 +207,6 @@ static int tc_next_event(unsigned long delta, struct clock_event_device *d)
214 207
215static struct tc_clkevt_device clkevt = { 208static struct tc_clkevt_device clkevt = {
216 .clkevt = { 209 .clkevt = {
217 .name = "tc_clkevt",
218 .features = CLOCK_EVT_FEAT_PERIODIC | 210 .features = CLOCK_EVT_FEAT_PERIODIC |
219 CLOCK_EVT_FEAT_ONESHOT, 211 CLOCK_EVT_FEAT_ONESHOT,
220 /* Should be lower than at91rm9200's system timer */ 212 /* Should be lower than at91rm9200's system timer */
@@ -330,39 +322,73 @@ static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_id
330 writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); 322 writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
331} 323}
332 324
333static int __init tcb_clksrc_init(void) 325static const u8 atmel_tcb_divisors[5] = { 2, 8, 32, 128, 0, };
334{ 326
335 static char bootinfo[] __initdata 327static const struct of_device_id atmel_tcb_of_match[] = {
336 = KERN_DEBUG "%s: tc%d at %d.%03d MHz\n"; 328 { .compatible = "atmel,at91rm9200-tcb", .data = (void *)16, },
329 { .compatible = "atmel,at91sam9x5-tcb", .data = (void *)32, },
330 { /* sentinel */ }
331};
337 332
338 struct platform_device *pdev; 333static int __init tcb_clksrc_init(struct device_node *node)
339 struct atmel_tc *tc; 334{
335 struct atmel_tc tc;
340 struct clk *t0_clk; 336 struct clk *t0_clk;
337 const struct of_device_id *match;
341 u32 rate, divided_rate = 0; 338 u32 rate, divided_rate = 0;
342 int best_divisor_idx = -1; 339 int best_divisor_idx = -1;
343 int clk32k_divisor_idx = -1; 340 int clk32k_divisor_idx = -1;
341 int bits;
344 int i; 342 int i;
345 int ret; 343 int ret;
346 344
347 tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK); 345 /* Protect against multiple calls */
348 if (!tc) { 346 if (tcaddr)
349 pr_debug("can't alloc TC for clocksource\n"); 347 return 0;
350 return -ENODEV; 348
349 tc.regs = of_iomap(node->parent, 0);
350 if (!tc.regs)
351 return -ENXIO;
352
353 t0_clk = of_clk_get_by_name(node->parent, "t0_clk");
354 if (IS_ERR(t0_clk))
355 return PTR_ERR(t0_clk);
356
357 tc.slow_clk = of_clk_get_by_name(node->parent, "slow_clk");
358 if (IS_ERR(tc.slow_clk))
359 return PTR_ERR(tc.slow_clk);
360
361 tc.clk[0] = t0_clk;
362 tc.clk[1] = of_clk_get_by_name(node->parent, "t1_clk");
363 if (IS_ERR(tc.clk[1]))
364 tc.clk[1] = t0_clk;
365 tc.clk[2] = of_clk_get_by_name(node->parent, "t2_clk");
366 if (IS_ERR(tc.clk[2]))
367 tc.clk[2] = t0_clk;
368
369 tc.irq[2] = of_irq_get(node->parent, 2);
370 if (tc.irq[2] <= 0) {
371 tc.irq[2] = of_irq_get(node->parent, 0);
372 if (tc.irq[2] <= 0)
373 return -EINVAL;
351 } 374 }
352 tcaddr = tc->regs;
353 pdev = tc->pdev;
354 375
355 t0_clk = tc->clk[0]; 376 match = of_match_node(atmel_tcb_of_match, node->parent);
377 bits = (uintptr_t)match->data;
378
379 for (i = 0; i < ARRAY_SIZE(tc.irq); i++)
380 writel(ATMEL_TC_ALL_IRQ, tc.regs + ATMEL_TC_REG(i, IDR));
381
356 ret = clk_prepare_enable(t0_clk); 382 ret = clk_prepare_enable(t0_clk);
357 if (ret) { 383 if (ret) {
358 pr_debug("can't enable T0 clk\n"); 384 pr_debug("can't enable T0 clk\n");
359 goto err_free_tc; 385 return ret;
360 } 386 }
361 387
362 /* How fast will we be counting? Pick something over 5 MHz. */ 388 /* How fast will we be counting? Pick something over 5 MHz. */
363 rate = (u32) clk_get_rate(t0_clk); 389 rate = (u32) clk_get_rate(t0_clk);
364 for (i = 0; i < 5; i++) { 390 for (i = 0; i < ARRAY_SIZE(atmel_tcb_divisors); i++) {
365 unsigned divisor = atmel_tc_divisors[i]; 391 unsigned divisor = atmel_tcb_divisors[i];
366 unsigned tmp; 392 unsigned tmp;
367 393
368 /* remember 32 KiHz clock for later */ 394 /* remember 32 KiHz clock for later */
@@ -381,27 +407,29 @@ static int __init tcb_clksrc_init(void)
381 best_divisor_idx = i; 407 best_divisor_idx = i;
382 } 408 }
383 409
384 410 clksrc.name = kbasename(node->parent->full_name);
385 printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK, 411 clkevt.clkevt.name = kbasename(node->parent->full_name);
386 divided_rate / 1000000, 412 pr_debug("%s at %d.%03d MHz\n", clksrc.name, divided_rate / 1000000,
387 ((divided_rate % 1000000) + 500) / 1000); 413 ((divided_rate % 1000000) + 500) / 1000);
388 414
389 if (tc->tcb_config && tc->tcb_config->counter_width == 32) { 415 tcaddr = tc.regs;
416
417 if (bits == 32) {
390 /* use apropriate function to read 32 bit counter */ 418 /* use apropriate function to read 32 bit counter */
391 clksrc.read = tc_get_cycles32; 419 clksrc.read = tc_get_cycles32;
392 /* setup ony channel 0 */ 420 /* setup ony channel 0 */
393 tcb_setup_single_chan(tc, best_divisor_idx); 421 tcb_setup_single_chan(&tc, best_divisor_idx);
394 } else { 422 } else {
395 /* tclib will give us three clocks no matter what the 423 /* we have three clocks no matter what the
396 * underlying platform supports. 424 * underlying platform supports.
397 */ 425 */
398 ret = clk_prepare_enable(tc->clk[1]); 426 ret = clk_prepare_enable(tc.clk[1]);
399 if (ret) { 427 if (ret) {
400 pr_debug("can't enable T1 clk\n"); 428 pr_debug("can't enable T1 clk\n");
401 goto err_disable_t0; 429 goto err_disable_t0;
402 } 430 }
403 /* setup both channel 0 & 1 */ 431 /* setup both channel 0 & 1 */
404 tcb_setup_dual_chan(tc, best_divisor_idx); 432 tcb_setup_dual_chan(&tc, best_divisor_idx);
405 } 433 }
406 434
407 /* and away we go! */ 435 /* and away we go! */
@@ -410,7 +438,7 @@ static int __init tcb_clksrc_init(void)
410 goto err_disable_t1; 438 goto err_disable_t1;
411 439
412 /* channel 2: periodic and oneshot timer support */ 440 /* channel 2: periodic and oneshot timer support */
413 ret = setup_clkevents(tc, clk32k_divisor_idx); 441 ret = setup_clkevents(&tc, clk32k_divisor_idx);
414 if (ret) 442 if (ret)
415 goto err_unregister_clksrc; 443 goto err_unregister_clksrc;
416 444
@@ -420,14 +448,14 @@ err_unregister_clksrc:
420 clocksource_unregister(&clksrc); 448 clocksource_unregister(&clksrc);
421 449
422err_disable_t1: 450err_disable_t1:
423 if (!tc->tcb_config || tc->tcb_config->counter_width != 32) 451 if (bits != 32)
424 clk_disable_unprepare(tc->clk[1]); 452 clk_disable_unprepare(tc.clk[1]);
425 453
426err_disable_t0: 454err_disable_t0:
427 clk_disable_unprepare(t0_clk); 455 clk_disable_unprepare(t0_clk);
428 456
429err_free_tc: 457 tcaddr = NULL;
430 atmel_tc_free(tc); 458
431 return ret; 459 return ret;
432} 460}
433arch_initcall(tcb_clksrc_init); 461TIMER_OF_DECLARE(atmel_tcb_clksrc, "atmel,tcb-timer", tcb_clksrc_init);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 42ab8ec92a04..268a01d3d6f3 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -61,7 +61,8 @@ config ATMEL_TCLIB
61 61
62config ATMEL_TCB_CLKSRC 62config ATMEL_TCB_CLKSRC
63 bool "TC Block Clocksource" 63 bool "TC Block Clocksource"
64 depends on ATMEL_TCLIB 64 depends on ARCH_AT91
65 select TIMER_OF if OF
65 default y 66 default y
66 help 67 help
67 Select this to get a high precision clocksource based on a 68 Select this to get a high precision clocksource based on a
@@ -72,17 +73,6 @@ config ATMEL_TCB_CLKSRC
72 may be used as a clock event device supporting oneshot mode 73 may be used as a clock event device supporting oneshot mode
73 (delays of up to two seconds) based on the 32 KiHz clock. 74 (delays of up to two seconds) based on the 32 KiHz clock.
74 75
75config ATMEL_TCB_CLKSRC_BLOCK
76 int
77 depends on ATMEL_TCB_CLKSRC
78 default 0
79 range 0 1
80 help
81 Some chips provide more than one TC block, so you have the
82 choice of which one to use for the clock framework. The other
83 TC can be used for other purposes, such as PWM generation and
84 interval timing.
85
86config DUMMY_IRQ 76config DUMMY_IRQ
87 tristate "Dummy IRQ handler" 77 tristate "Dummy IRQ handler"
88 default n 78 default n