Commit ea7a5f90 authored by Thomas Gleixner's avatar Thomas Gleixner

Merge tag 'timers-v5.2' of http://git.linaro.org/people/daniel.lezcano/linux into timers/core

Pull clockevent updates from Daniel Lezcano:

 - Add compatible string for suniv for sun4i (Mesih Kilinc)

 - Add COMPILE_TEST option for sp804 (David Abdurachmanov)

 - Replace the compensation time when suspend happens on tegra with the one
   provided by the generic framework (Joseph Lo)

 - Cleanup, shutdown and oneshot mode fix on milbeaut timer (Sugaya Taichi)

 - Atmel TCB rework to fix boot failure on boards without PIT or misfunction
   on system using a preempt-rt kernel (Alexandre Belloni)
parents 13e792a1 8c937406
...@@ -2,7 +2,9 @@ Allwinner A1X SoCs Timer Controller ...@@ -2,7 +2,9 @@ Allwinner A1X SoCs Timer Controller
Required properties: Required properties:
- compatible : should be "allwinner,sun4i-a10-timer" - compatible : should be one of the following:
"allwinner,sun4i-a10-timer"
"allwinner,suniv-f1c100s-timer"
- reg : Specifies base physical address and size of the registers. - reg : Specifies base physical address and size of the registers.
- interrupts : The interrupt of the first timer - interrupts : The interrupt of the first timer
- clocks: phandle to the source clock (usually a 24 MHz fixed clock) - clocks: phandle to the source clock (usually a 24 MHz fixed clock)
......
...@@ -107,6 +107,29 @@ config SOC_AT91SAM9 ...@@ -107,6 +107,29 @@ config SOC_AT91SAM9
AT91SAM9X35 AT91SAM9X35
AT91SAM9XE AT91SAM9XE
comment "Clocksource driver selection"
config ATMEL_CLOCKSOURCE_PIT
bool "Periodic Interval Timer (PIT) support"
depends on SOC_AT91SAM9 || SOC_SAMA5
default SOC_AT91SAM9 || SOC_SAMA5
select ATMEL_PIT
help
Select this to get a clocksource based on the Atmel Periodic Interval
Timer. It has a relatively low resolution and the TC Block clocksource
should be preferred.
config ATMEL_CLOCKSOURCE_TCB
bool "Timer Counter Blocks (TCB) support"
default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
select ATMEL_TCB_CLKSRC
help
Select this to get a high precision clocksource based on a
TC block with a 5+ MHz base clock rate.
On platforms with 16-bit counters, two timer channels are combined
to make a single 32-bit timer.
It can also be used as a clock event device supporting oneshot mode.
config HAVE_AT91_UTMI config HAVE_AT91_UTMI
bool bool
......
...@@ -379,7 +379,7 @@ config ARM_GLOBAL_TIMER ...@@ -379,7 +379,7 @@ config ARM_GLOBAL_TIMER
This options enables support for the ARM global timer unit This options enables support for the ARM global timer unit
config ARM_TIMER_SP804 config ARM_TIMER_SP804
bool "Support for Dual Timer SP804 module" bool "Support for Dual Timer SP804 module" if COMPILE_TEST
depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP
select CLKSRC_MMIO select CLKSRC_MMIO
select TIMER_OF if OF select TIMER_OF if OF
...@@ -399,8 +399,11 @@ config ARMV7M_SYSTICK ...@@ -399,8 +399,11 @@ config ARMV7M_SYSTICK
This options enables support for the ARMv7M system timer unit This options enables support for the ARMv7M system timer unit
config ATMEL_PIT config ATMEL_PIT
bool "Atmel PIT support" if COMPILE_TEST
depends on HAS_IOMEM
select TIMER_OF if OF select TIMER_OF if OF
def_bool SOC_AT91SAM9 || SOC_SAMA5 help
Support for the Periodic Interval Timer found on Atmel SoCs.
config ATMEL_ST config ATMEL_ST
bool "Atmel ST timer support" if COMPILE_TEST bool "Atmel ST timer support" if COMPILE_TEST
...@@ -410,6 +413,13 @@ config ATMEL_ST ...@@ -410,6 +413,13 @@ config ATMEL_ST
help help
Support for the Atmel ST timer. Support for the Atmel ST timer.
config ATMEL_TCB_CLKSRC
bool "Atmel TC Block timer driver" if COMPILE_TEST
depends on HAS_IOMEM
select TIMER_OF if OF
help
Support for Timer Counter Blocks on Atmel SoCs.
config CLKSRC_EXYNOS_MCT config CLKSRC_EXYNOS_MCT
bool "Exynos multi core timer driver" if COMPILE_TEST bool "Exynos multi core timer driver" if COMPILE_TEST
depends on ARM || ARM64 depends on ARM || ARM64
......
...@@ -3,7 +3,7 @@ obj-$(CONFIG_TIMER_OF) += timer-of.o ...@@ -3,7 +3,7 @@ obj-$(CONFIG_TIMER_OF) += timer-of.o
obj-$(CONFIG_TIMER_PROBE) += timer-probe.o obj-$(CONFIG_TIMER_PROBE) += timer-probe.o
obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o
obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o
obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o obj-$(CONFIG_ATMEL_TCB_CLKSRC) += timer-atmel-tcb.o
obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o
obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += timer-cs5535.o obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += timer-cs5535.o
......
...@@ -9,9 +9,11 @@ ...@@ -9,9 +9,11 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_device.h> #include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <linux/atmel_tc.h> #include <soc/at91/atmel_tcb.h>
/* /*
...@@ -28,13 +30,6 @@ ...@@ -28,13 +30,6 @@
* source, used in either periodic or oneshot mode. This runs * source, used in either periodic or oneshot mode. This runs
* at 32 KiHZ, and can handle delays of up to two seconds. * at 32 KiHZ, and can handle delays of up to two seconds.
* *
* A boot clocksource and clockevent source are also currently needed,
* unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so
* this code can be used when init_timers() is called, well before most
* devices are set up. (Some low end AT91 parts, which can run uClinux,
* have only the timers in one TC block... they currently don't support
* the tclib code, because of that initialization issue.)
*
* REVISIT behavior during system suspend states... we should disable * REVISIT behavior during system suspend states... we should disable
* all clocks and save the power. Easily done for clockevent devices, * all clocks and save the power. Easily done for clockevent devices,
* but clocksources won't necessarily get the needed notifications. * but clocksources won't necessarily get the needed notifications.
...@@ -71,7 +66,7 @@ static u64 tc_get_cycles32(struct clocksource *cs) ...@@ -71,7 +66,7 @@ static u64 tc_get_cycles32(struct clocksource *cs)
return readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV)); return readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV));
} }
void tc_clksrc_suspend(struct clocksource *cs) static void tc_clksrc_suspend(struct clocksource *cs)
{ {
int i; int i;
...@@ -86,7 +81,7 @@ void tc_clksrc_suspend(struct clocksource *cs) ...@@ -86,7 +81,7 @@ void tc_clksrc_suspend(struct clocksource *cs)
bmr_cache = readl(tcaddr + ATMEL_TC_BMR); bmr_cache = readl(tcaddr + ATMEL_TC_BMR);
} }
void tc_clksrc_resume(struct clocksource *cs) static void tc_clksrc_resume(struct clocksource *cs)
{ {
int i; int i;
...@@ -112,7 +107,6 @@ void tc_clksrc_resume(struct clocksource *cs) ...@@ -112,7 +107,6 @@ void tc_clksrc_resume(struct clocksource *cs)
} }
static struct clocksource clksrc = { static struct clocksource clksrc = {
.name = "tcb_clksrc",
.rating = 200, .rating = 200,
.read = tc_get_cycles, .read = tc_get_cycles,
.mask = CLOCKSOURCE_MASK(32), .mask = CLOCKSOURCE_MASK(32),
...@@ -121,6 +115,16 @@ static struct clocksource clksrc = { ...@@ -121,6 +115,16 @@ static struct clocksource clksrc = {
.resume = tc_clksrc_resume, .resume = tc_clksrc_resume,
}; };
static u64 notrace tc_sched_clock_read(void)
{
return tc_get_cycles(&clksrc);
}
static u64 notrace tc_sched_clock_read32(void)
{
return tc_get_cycles32(&clksrc);
}
#ifdef CONFIG_GENERIC_CLOCKEVENTS #ifdef CONFIG_GENERIC_CLOCKEVENTS
struct tc_clkevt_device { struct tc_clkevt_device {
...@@ -214,7 +218,6 @@ static int tc_next_event(unsigned long delta, struct clock_event_device *d) ...@@ -214,7 +218,6 @@ static int tc_next_event(unsigned long delta, struct clock_event_device *d)
static struct tc_clkevt_device clkevt = { static struct tc_clkevt_device clkevt = {
.clkevt = { .clkevt = {
.name = "tc_clkevt",
.features = CLOCK_EVT_FEAT_PERIODIC | .features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT, CLOCK_EVT_FEAT_ONESHOT,
/* Should be lower than at91rm9200's system timer */ /* Should be lower than at91rm9200's system timer */
...@@ -330,39 +333,74 @@ static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_id ...@@ -330,39 +333,74 @@ static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_id
writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
} }
static int __init tcb_clksrc_init(void) static const u8 atmel_tcb_divisors[5] = { 2, 8, 32, 128, 0, };
{
static char bootinfo[] __initdata static const struct of_device_id atmel_tcb_of_match[] = {
= KERN_DEBUG "%s: tc%d at %d.%03d MHz\n"; { .compatible = "atmel,at91rm9200-tcb", .data = (void *)16, },
{ .compatible = "atmel,at91sam9x5-tcb", .data = (void *)32, },
{ /* sentinel */ }
};
struct platform_device *pdev; static int __init tcb_clksrc_init(struct device_node *node)
struct atmel_tc *tc; {
struct atmel_tc tc;
struct clk *t0_clk; struct clk *t0_clk;
const struct of_device_id *match;
u64 (*tc_sched_clock)(void);
u32 rate, divided_rate = 0; u32 rate, divided_rate = 0;
int best_divisor_idx = -1; int best_divisor_idx = -1;
int clk32k_divisor_idx = -1; int clk32k_divisor_idx = -1;
int bits;
int i; int i;
int ret; int ret;
tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK); /* Protect against multiple calls */
if (!tc) { if (tcaddr)
pr_debug("can't alloc TC for clocksource\n"); return 0;
return -ENODEV;
tc.regs = of_iomap(node->parent, 0);
if (!tc.regs)
return -ENXIO;
t0_clk = of_clk_get_by_name(node->parent, "t0_clk");
if (IS_ERR(t0_clk))
return PTR_ERR(t0_clk);
tc.slow_clk = of_clk_get_by_name(node->parent, "slow_clk");
if (IS_ERR(tc.slow_clk))
return PTR_ERR(tc.slow_clk);
tc.clk[0] = t0_clk;
tc.clk[1] = of_clk_get_by_name(node->parent, "t1_clk");
if (IS_ERR(tc.clk[1]))
tc.clk[1] = t0_clk;
tc.clk[2] = of_clk_get_by_name(node->parent, "t2_clk");
if (IS_ERR(tc.clk[2]))
tc.clk[2] = t0_clk;
tc.irq[2] = of_irq_get(node->parent, 2);
if (tc.irq[2] <= 0) {
tc.irq[2] = of_irq_get(node->parent, 0);
if (tc.irq[2] <= 0)
return -EINVAL;
} }
tcaddr = tc->regs;
pdev = tc->pdev;
t0_clk = tc->clk[0]; match = of_match_node(atmel_tcb_of_match, node->parent);
bits = (uintptr_t)match->data;
for (i = 0; i < ARRAY_SIZE(tc.irq); i++)
writel(ATMEL_TC_ALL_IRQ, tc.regs + ATMEL_TC_REG(i, IDR));
ret = clk_prepare_enable(t0_clk); ret = clk_prepare_enable(t0_clk);
if (ret) { if (ret) {
pr_debug("can't enable T0 clk\n"); pr_debug("can't enable T0 clk\n");
goto err_free_tc; return ret;
} }
/* How fast will we be counting? Pick something over 5 MHz. */ /* How fast will we be counting? Pick something over 5 MHz. */
rate = (u32) clk_get_rate(t0_clk); rate = (u32) clk_get_rate(t0_clk);
for (i = 0; i < 5; i++) { for (i = 0; i < ARRAY_SIZE(atmel_tcb_divisors); i++) {
unsigned divisor = atmel_tc_divisors[i]; unsigned divisor = atmel_tcb_divisors[i];
unsigned tmp; unsigned tmp;
/* remember 32 KiHz clock for later */ /* remember 32 KiHz clock for later */
...@@ -381,27 +419,31 @@ static int __init tcb_clksrc_init(void) ...@@ -381,27 +419,31 @@ static int __init tcb_clksrc_init(void)
best_divisor_idx = i; best_divisor_idx = i;
} }
clksrc.name = kbasename(node->parent->full_name);
printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK, clkevt.clkevt.name = kbasename(node->parent->full_name);
divided_rate / 1000000, pr_debug("%s at %d.%03d MHz\n", clksrc.name, divided_rate / 1000000,
((divided_rate % 1000000) + 500) / 1000); ((divided_rate % 1000000) + 500) / 1000);
if (tc->tcb_config && tc->tcb_config->counter_width == 32) { tcaddr = tc.regs;
if (bits == 32) {
/* use apropriate function to read 32 bit counter */ /* use apropriate function to read 32 bit counter */
clksrc.read = tc_get_cycles32; clksrc.read = tc_get_cycles32;
/* setup ony channel 0 */ /* setup ony channel 0 */
tcb_setup_single_chan(tc, best_divisor_idx); tcb_setup_single_chan(&tc, best_divisor_idx);
tc_sched_clock = tc_sched_clock_read32;
} else { } else {
/* tclib will give us three clocks no matter what the /* we have three clocks no matter what the
* underlying platform supports. * underlying platform supports.
*/ */
ret = clk_prepare_enable(tc->clk[1]); ret = clk_prepare_enable(tc.clk[1]);
if (ret) { if (ret) {
pr_debug("can't enable T1 clk\n"); pr_debug("can't enable T1 clk\n");
goto err_disable_t0; goto err_disable_t0;
} }
/* setup both channel 0 & 1 */ /* setup both channel 0 & 1 */
tcb_setup_dual_chan(tc, best_divisor_idx); tcb_setup_dual_chan(&tc, best_divisor_idx);
tc_sched_clock = tc_sched_clock_read;
} }
/* and away we go! */ /* and away we go! */
...@@ -410,24 +452,26 @@ static int __init tcb_clksrc_init(void) ...@@ -410,24 +452,26 @@ static int __init tcb_clksrc_init(void)
goto err_disable_t1; goto err_disable_t1;
/* channel 2: periodic and oneshot timer support */ /* channel 2: periodic and oneshot timer support */
ret = setup_clkevents(tc, clk32k_divisor_idx); ret = setup_clkevents(&tc, clk32k_divisor_idx);
if (ret) if (ret)
goto err_unregister_clksrc; goto err_unregister_clksrc;
sched_clock_register(tc_sched_clock, 32, divided_rate);
return 0; return 0;
err_unregister_clksrc: err_unregister_clksrc:
clocksource_unregister(&clksrc); clocksource_unregister(&clksrc);
err_disable_t1: err_disable_t1:
if (!tc->tcb_config || tc->tcb_config->counter_width != 32) if (bits != 32)
clk_disable_unprepare(tc->clk[1]); clk_disable_unprepare(tc.clk[1]);
err_disable_t0: err_disable_t0:
clk_disable_unprepare(t0_clk); clk_disable_unprepare(t0_clk);
err_free_tc: tcaddr = NULL;
atmel_tc_free(tc);
return ret; return ret;
} }
arch_initcall(tcb_clksrc_init); TIMER_OF_DECLARE(atmel_tcb_clksrc, "atmel,tcb-timer", tcb_clksrc_init);
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
#define MLB_TMR_TMCSR_CSL_DIV2 0 #define MLB_TMR_TMCSR_CSL_DIV2 0
#define MLB_TMR_DIV_CNT 2 #define MLB_TMR_DIV_CNT 2
#define MLB_TMR_SRC_CH (1) #define MLB_TMR_SRC_CH 1
#define MLB_TMR_EVT_CH (0) #define MLB_TMR_EVT_CH 0
#define MLB_TMR_SRC_CH_OFS (MLB_TMR_REGSZPCH * MLB_TMR_SRC_CH) #define MLB_TMR_SRC_CH_OFS (MLB_TMR_REGSZPCH * MLB_TMR_SRC_CH)
#define MLB_TMR_EVT_CH_OFS (MLB_TMR_REGSZPCH * MLB_TMR_EVT_CH) #define MLB_TMR_EVT_CH_OFS (MLB_TMR_REGSZPCH * MLB_TMR_EVT_CH)
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
#define MLB_TMR_EVT_TMRLR2_OFS (MLB_TMR_EVT_CH_OFS + MLB_TMR_TMRLR2_OFS) #define MLB_TMR_EVT_TMRLR2_OFS (MLB_TMR_EVT_CH_OFS + MLB_TMR_TMRLR2_OFS)
#define MLB_TIMER_RATING 500 #define MLB_TIMER_RATING 500
#define MLB_TIMER_ONESHOT 0
#define MLB_TIMER_PERIODIC 1
static irqreturn_t mlb_timer_interrupt(int irq, void *dev_id) static irqreturn_t mlb_timer_interrupt(int irq, void *dev_id)
{ {
...@@ -59,27 +61,53 @@ static irqreturn_t mlb_timer_interrupt(int irq, void *dev_id) ...@@ -59,27 +61,53 @@ static irqreturn_t mlb_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int mlb_set_state_periodic(struct clock_event_device *clk) static void mlb_evt_timer_start(struct timer_of *to, bool periodic)
{ {
struct timer_of *to = to_timer_of(clk);
u32 val = MLB_TMR_TMCSR_CSL_DIV2; u32 val = MLB_TMR_TMCSR_CSL_DIV2;
val |= MLB_TMR_TMCSR_CNTE | MLB_TMR_TMCSR_TRG | MLB_TMR_TMCSR_INTE;
if (periodic)
val |= MLB_TMR_TMCSR_RELD;
writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS);
}
writel_relaxed(to->of_clk.period, timer_of_base(to) + static void mlb_evt_timer_stop(struct timer_of *to)
MLB_TMR_EVT_TMRLR1_OFS); {
val |= MLB_TMR_TMCSR_RELD | MLB_TMR_TMCSR_CNTE | u32 val = readl_relaxed(timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS);
MLB_TMR_TMCSR_TRG | MLB_TMR_TMCSR_INTE;
val &= ~MLB_TMR_TMCSR_CNTE;
writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS);
}
static void mlb_evt_timer_register_count(struct timer_of *to, unsigned long cnt)
{
writel_relaxed(cnt, timer_of_base(to) + MLB_TMR_EVT_TMRLR1_OFS);
}
static int mlb_set_state_periodic(struct clock_event_device *clk)
{
struct timer_of *to = to_timer_of(clk);
mlb_evt_timer_stop(to);
mlb_evt_timer_register_count(to, to->of_clk.period);
mlb_evt_timer_start(to, MLB_TIMER_PERIODIC);
return 0; return 0;
} }
static int mlb_set_state_oneshot(struct clock_event_device *clk) static int mlb_set_state_oneshot(struct clock_event_device *clk)
{ {
struct timer_of *to = to_timer_of(clk); struct timer_of *to = to_timer_of(clk);
u32 val = MLB_TMR_TMCSR_CSL_DIV2;
writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); mlb_evt_timer_stop(to);
mlb_evt_timer_start(to, MLB_TIMER_ONESHOT);
return 0;
}
static int mlb_set_state_shutdown(struct clock_event_device *clk)
{
struct timer_of *to = to_timer_of(clk);
mlb_evt_timer_stop(to);
return 0; return 0;
} }
...@@ -88,22 +116,21 @@ static int mlb_clkevt_next_event(unsigned long event, ...@@ -88,22 +116,21 @@ static int mlb_clkevt_next_event(unsigned long event,
{ {
struct timer_of *to = to_timer_of(clk); struct timer_of *to = to_timer_of(clk);
writel_relaxed(event, timer_of_base(to) + MLB_TMR_EVT_TMRLR1_OFS); mlb_evt_timer_stop(to);
writel_relaxed(MLB_TMR_TMCSR_CSL_DIV2 | mlb_evt_timer_register_count(to, event);
MLB_TMR_TMCSR_CNTE | MLB_TMR_TMCSR_INTE | mlb_evt_timer_start(to, MLB_TIMER_ONESHOT);
MLB_TMR_TMCSR_TRG, timer_of_base(to) +
MLB_TMR_EVT_TMCSR_OFS);
return 0; return 0;
} }
static int mlb_config_clock_source(struct timer_of *to) static int mlb_config_clock_source(struct timer_of *to)
{ {
writel_relaxed(0, timer_of_base(to) + MLB_TMR_SRC_TMCSR_OFS); u32 val = MLB_TMR_TMCSR_CSL_DIV2;
writel_relaxed(~0, timer_of_base(to) + MLB_TMR_SRC_TMR_OFS);
writel_relaxed(val, timer_of_base(to) + MLB_TMR_SRC_TMCSR_OFS);
writel_relaxed(~0, timer_of_base(to) + MLB_TMR_SRC_TMRLR1_OFS); writel_relaxed(~0, timer_of_base(to) + MLB_TMR_SRC_TMRLR1_OFS);
writel_relaxed(~0, timer_of_base(to) + MLB_TMR_SRC_TMRLR2_OFS); writel_relaxed(~0, timer_of_base(to) + MLB_TMR_SRC_TMRLR2_OFS);
writel_relaxed(BIT(4) | BIT(1) | BIT(0), timer_of_base(to) + val |= MLB_TMR_TMCSR_RELD | MLB_TMR_TMCSR_CNTE | MLB_TMR_TMCSR_TRG;
MLB_TMR_SRC_TMCSR_OFS); writel_relaxed(val, timer_of_base(to) + MLB_TMR_SRC_TMCSR_OFS);
return 0; return 0;
} }
...@@ -123,6 +150,7 @@ static struct timer_of to = { ...@@ -123,6 +150,7 @@ static struct timer_of to = {
.features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_ONESHOT,
.set_state_oneshot = mlb_set_state_oneshot, .set_state_oneshot = mlb_set_state_oneshot,
.set_state_periodic = mlb_set_state_periodic, .set_state_periodic = mlb_set_state_periodic,
.set_state_shutdown = mlb_set_state_shutdown,
.set_next_event = mlb_clkevt_next_event, .set_next_event = mlb_clkevt_next_event,
}, },
......
...@@ -186,7 +186,8 @@ static int __init sun4i_timer_init(struct device_node *node) ...@@ -186,7 +186,8 @@ static int __init sun4i_timer_init(struct device_node *node)
*/ */
if (of_machine_is_compatible("allwinner,sun4i-a10") || if (of_machine_is_compatible("allwinner,sun4i-a10") ||
of_machine_is_compatible("allwinner,sun5i-a13") || of_machine_is_compatible("allwinner,sun5i-a13") ||
of_machine_is_compatible("allwinner,sun5i-a10s")) of_machine_is_compatible("allwinner,sun5i-a10s") ||
of_machine_is_compatible("allwinner,suniv-f1c100s"))
sched_clock_register(sun4i_timer_sched_read, 32, sched_clock_register(sun4i_timer_sched_read, 32,
timer_of_rate(&to)); timer_of_rate(&to));
...@@ -218,3 +219,5 @@ static int __init sun4i_timer_init(struct device_node *node) ...@@ -218,3 +219,5 @@ static int __init sun4i_timer_init(struct device_node *node)
} }
TIMER_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer", TIMER_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer",
sun4i_timer_init); sun4i_timer_init);
TIMER_OF_DECLARE(suniv, "allwinner,suniv-f1c100s-timer",
sun4i_timer_init);
...@@ -60,9 +60,6 @@ ...@@ -60,9 +60,6 @@
static u32 usec_config; static u32 usec_config;
static void __iomem *timer_reg_base; static void __iomem *timer_reg_base;
#ifdef CONFIG_ARM #ifdef CONFIG_ARM
static void __iomem *rtc_base;
static struct timespec64 persistent_ts;
static u64 persistent_ms, last_persistent_ms;
static struct delay_timer tegra_delay_timer; static struct delay_timer tegra_delay_timer;
#endif #endif
...@@ -199,40 +196,30 @@ static unsigned long tegra_delay_timer_read_counter_long(void) ...@@ -199,40 +196,30 @@ static unsigned long tegra_delay_timer_read_counter_long(void)
return readl(timer_reg_base + TIMERUS_CNTR_1US); return readl(timer_reg_base + TIMERUS_CNTR_1US);
} }
static struct timer_of suspend_rtc_to = {
.flags = TIMER_OF_BASE | TIMER_OF_CLOCK,
};
/* /*
* tegra_rtc_read - Reads the Tegra RTC registers * tegra_rtc_read - Reads the Tegra RTC registers
* Care must be taken that this funciton is not called while the * Care must be taken that this funciton is not called while the
* tegra_rtc driver could be executing to avoid race conditions * tegra_rtc driver could be executing to avoid race conditions
* on the RTC shadow register * on the RTC shadow register
*/ */
static u64 tegra_rtc_read_ms(void) static u64 tegra_rtc_read_ms(struct clocksource *cs)
{ {
u32 ms = readl(rtc_base + RTC_MILLISECONDS); u32 ms = readl(timer_of_base(&suspend_rtc_to) + RTC_MILLISECONDS);
u32 s = readl(rtc_base + RTC_SHADOW_SECONDS); u32 s = readl(timer_of_base(&suspend_rtc_to) + RTC_SHADOW_SECONDS);
return (u64)s * MSEC_PER_SEC + ms; return (u64)s * MSEC_PER_SEC + ms;
} }
/* static struct clocksource suspend_rtc_clocksource = {
* tegra_read_persistent_clock64 - Return time from a persistent clock. .name = "tegra_suspend_timer",
* .rating = 200,
* Reads the time from a source which isn't disabled during PM, the .read = tegra_rtc_read_ms,
* 32k sync timer. Convert the cycles elapsed since last read into .mask = CLOCKSOURCE_MASK(32),
* nsecs and adds to a monotonically increasing timespec64. .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,
* Care must be taken that this funciton is not called while the };
* tegra_rtc driver could be executing to avoid race conditions
* on the RTC shadow register
*/
static void tegra_read_persistent_clock64(struct timespec64 *ts)
{
u64 delta;
last_persistent_ms = persistent_ms;
persistent_ms = tegra_rtc_read_ms();
delta = persistent_ms - last_persistent_ms;
timespec64_add_ns(&persistent_ts, delta * NSEC_PER_MSEC);
*ts = persistent_ts;
}
#endif #endif
static int tegra_timer_common_init(struct device_node *np, struct timer_of *to) static int tegra_timer_common_init(struct device_node *np, struct timer_of *to)
...@@ -385,25 +372,15 @@ static int __init tegra_init_timer(struct device_node *np) ...@@ -385,25 +372,15 @@ static int __init tegra_init_timer(struct device_node *np)
static int __init tegra20_init_rtc(struct device_node *np) static int __init tegra20_init_rtc(struct device_node *np)
{ {
struct clk *clk; int ret;
rtc_base = of_iomap(np, 0); ret = timer_of_init(np, &suspend_rtc_to);
if (!rtc_base) { if (ret)
pr_err("Can't map RTC registers\n"); return ret;
return -ENXIO;
}
/* clocksource_register_hz(&suspend_rtc_clocksource, 1000);
* rtc registers are used by read_persistent_clock, keep the rtc clock
* enabled
*/
clk = of_clk_get(np, 0);
if (IS_ERR(clk))
pr_warn("Unable to get rtc-tegra clock\n");
else
clk_prepare_enable(clk);
return register_persistent_clock(tegra_read_persistent_clock64); return 0;
} }
TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc);
#endif #endif
......
...@@ -59,30 +59,6 @@ config ATMEL_TCLIB ...@@ -59,30 +59,6 @@ config ATMEL_TCLIB
blocks found on many Atmel processors. This facilitates using blocks found on many Atmel processors. This facilitates using
these blocks by different drivers despite processor differences. these blocks by different drivers despite processor differences.
config ATMEL_TCB_CLKSRC
bool "TC Block Clocksource"
depends on ATMEL_TCLIB
default y
help
Select this to get a high precision clocksource based on a
TC block with a 5+ MHz base clock rate. Two timer channels
are combined to make a single 32-bit timer.
When GENERIC_CLOCKEVENTS is defined, the third timer channel
may be used as a clock event device supporting oneshot mode
(delays of up to two seconds) based on the 32 KiHz clock.
config ATMEL_TCB_CLKSRC_BLOCK
int
depends on ATMEL_TCB_CLKSRC
default 0
range 0 1
help
Some chips provide more than one TC block, so you have the
choice of which one to use for the clock framework. The other
TC can be used for other purposes, such as PWM generation and
interval timing.
config DUMMY_IRQ config DUMMY_IRQ
tristate "Dummy IRQ handler" tristate "Dummy IRQ handler"
default n default n
......
#include <linux/atmel_tc.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -10,6 +9,7 @@ ...@@ -10,6 +9,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/of.h> #include <linux/of.h>
#include <soc/at91/atmel_tcb.h>
/* /*
* This is a thin library to solve the problem of how to portably allocate * This is a thin library to solve the problem of how to portably allocate
...@@ -111,6 +111,9 @@ static int __init tc_probe(struct platform_device *pdev) ...@@ -111,6 +111,9 @@ static int __init tc_probe(struct platform_device *pdev)
struct resource *r; struct resource *r;
unsigned int i; unsigned int i;
if (of_get_child_count(pdev->dev.of_node))
return -EBUSY;
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) if (irq < 0)
return -EINVAL; return -EINVAL;
......
...@@ -17,10 +17,10 @@ ...@@ -17,10 +17,10 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/atmel_tc.h>
#include <linux/pwm.h> #include <linux/pwm.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <soc/at91/atmel_tcb.h>
#define NPWM 6 #define NPWM 6
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
* (at your option) any later version. * (at your option) any later version.
*/ */
#ifndef ATMEL_TC_H #ifndef __SOC_ATMEL_TCB_H
#define ATMEL_TC_H #define __SOC_ATMEL_TCB_H
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/list.h> #include <linux/list.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment