Commit ec14ba1e authored by Linus Walleij's avatar Linus Walleij Committed by Daniel Lezcano

clocksource/drivers/fttmr010: Merge Moxa into FTTMR010

This merges the Moxa Art timer driver into the Faraday FTTMR010
driver and replaces all Kconfig symbols to use the Faraday
driver instead. We are now so similar that the drivers can
be merged by just adding a few lines to the Faraday timer.

Differences:

- The Faraday driver explicitly sets the counter to count
  upwards for the clocksource, removing the need for the
  clocksource core to invert the value.

- The Faraday driver also handles sched_clock()

On the Aspeed, the counter can only count downwards, so support
the timers in downward-counting mode as well, and flag the
Aspeed to use this mode. This mode was tested on the Gemini so
I have high hopes that it'll work fine on the Aspeed as well.

After this we have one driver for all three SoCs and a generic
Faraday FTTMR010 timer driver, which is nice.

Cc: Joel Stanley <joel@jms.id.au>
Cc: Jonas Jensen <jonas.jensen@gmail.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Reviewed-by: default avatarJoel Stanley <joel@jms.id.au>
Tested-by: default avatarJoel Stanley <joel@jms.id.au>
Signed-off-by: default avatarDaniel Lezcano <daniel.lezcano@linaro.org>
parent b589da8b
...@@ -4,7 +4,7 @@ menuconfig ARCH_ASPEED ...@@ -4,7 +4,7 @@ menuconfig ARCH_ASPEED
select SRAM select SRAM
select WATCHDOG select WATCHDOG
select ASPEED_WATCHDOG select ASPEED_WATCHDOG
select MOXART_TIMER select FTTMR010_TIMER
select MFD_SYSCON select MFD_SYSCON
select PINCTRL select PINCTRL
help help
......
...@@ -4,7 +4,7 @@ menuconfig ARCH_MOXART ...@@ -4,7 +4,7 @@ menuconfig ARCH_MOXART
select CPU_FA526 select CPU_FA526
select ARM_DMA_MEM_BUFFERABLE select ARM_DMA_MEM_BUFFERABLE
select FARADAY_FTINTC010 select FARADAY_FTINTC010
select MOXART_TIMER select FTTMR010_TIMER
select GPIOLIB select GPIOLIB
select PHYLIB if NETDEVICES select PHYLIB if NETDEVICES
help help
......
...@@ -188,13 +188,6 @@ config ATLAS7_TIMER ...@@ -188,13 +188,6 @@ config ATLAS7_TIMER
help help
Enables support for the Atlas7 timer. Enables support for the Atlas7 timer.
config MOXART_TIMER
bool "Moxart timer driver" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS
select CLKSRC_MMIO
help
Enables support for the Moxart timer.
config MXS_TIMER config MXS_TIMER
bool "Mxs timer driver" if COMPILE_TEST bool "Mxs timer driver" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS depends on GENERIC_CLOCKEVENTS
......
...@@ -26,7 +26,6 @@ obj-$(CONFIG_ORION_TIMER) += time-orion.o ...@@ -26,7 +26,6 @@ obj-$(CONFIG_ORION_TIMER) += time-orion.o
obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o
obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o
obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o
obj-$(CONFIG_MOXART_TIMER) += moxart_timer.o
obj-$(CONFIG_MXS_TIMER) += mxs_timer.o obj-$(CONFIG_MXS_TIMER) += mxs_timer.o
obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o
obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o
......
/*
* MOXA ART SoCs timer handling.
*
* Copyright (C) 2013 Jonas Jensen
*
* Jonas Jensen <jonas.jensen@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqreturn.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/io.h>
#include <linux/clocksource.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#define TIMER1_BASE 0x00
#define TIMER2_BASE 0x10
#define TIMER3_BASE 0x20
#define REG_COUNT 0x0 /* writable */
#define REG_LOAD 0x4
#define REG_MATCH1 0x8
#define REG_MATCH2 0xC
#define TIMER_CR 0x30
#define TIMER_INTR_STATE 0x34
#define TIMER_INTR_MASK 0x38
/*
* Moxart TIMER_CR flags:
*
* MOXART_CR_*_CLOCK 0: PCLK, 1: EXT1CLK
* MOXART_CR_*_INT overflow interrupt enable bit
*/
#define MOXART_CR_1_ENABLE BIT(0)
#define MOXART_CR_1_CLOCK BIT(1)
#define MOXART_CR_1_INT BIT(2)
#define MOXART_CR_2_ENABLE BIT(3)
#define MOXART_CR_2_CLOCK BIT(4)
#define MOXART_CR_2_INT BIT(5)
#define MOXART_CR_3_ENABLE BIT(6)
#define MOXART_CR_3_CLOCK BIT(7)
#define MOXART_CR_3_INT BIT(8)
#define MOXART_CR_COUNT_UP BIT(9)
#define MOXART_TIMER1_ENABLE (MOXART_CR_2_ENABLE | MOXART_CR_1_ENABLE)
#define MOXART_TIMER1_DISABLE (MOXART_CR_2_ENABLE)
/*
* The ASpeed variant of the IP block has a different layout
* for the control register
*/
#define ASPEED_CR_1_ENABLE BIT(0)
#define ASPEED_CR_1_CLOCK BIT(1)
#define ASPEED_CR_1_INT BIT(2)
#define ASPEED_CR_2_ENABLE BIT(4)
#define ASPEED_CR_2_CLOCK BIT(5)
#define ASPEED_CR_2_INT BIT(6)
#define ASPEED_CR_3_ENABLE BIT(8)
#define ASPEED_CR_3_CLOCK BIT(9)
#define ASPEED_CR_3_INT BIT(10)
#define ASPEED_TIMER1_ENABLE (ASPEED_CR_2_ENABLE | ASPEED_CR_1_ENABLE)
#define ASPEED_TIMER1_DISABLE (ASPEED_CR_2_ENABLE)
struct moxart_timer {
void __iomem *base;
unsigned int t1_disable_val;
unsigned int t1_enable_val;
unsigned int count_per_tick;
struct clock_event_device clkevt;
};
static inline struct moxart_timer *to_moxart(struct clock_event_device *evt)
{
return container_of(evt, struct moxart_timer, clkevt);
}
static inline void moxart_disable(struct clock_event_device *evt)
{
struct moxart_timer *timer = to_moxart(evt);
writel(timer->t1_disable_val, timer->base + TIMER_CR);
}
static inline void moxart_enable(struct clock_event_device *evt)
{
struct moxart_timer *timer = to_moxart(evt);
writel(timer->t1_enable_val, timer->base + TIMER_CR);
}
static int moxart_shutdown(struct clock_event_device *evt)
{
moxart_disable(evt);
return 0;
}
static int moxart_set_oneshot(struct clock_event_device *evt)
{
moxart_disable(evt);
writel(~0, to_moxart(evt)->base + TIMER1_BASE + REG_LOAD);
return 0;
}
static int moxart_set_periodic(struct clock_event_device *evt)
{
struct moxart_timer *timer = to_moxart(evt);
moxart_disable(evt);
writel(timer->count_per_tick, timer->base + TIMER1_BASE + REG_LOAD);
writel(0, timer->base + TIMER1_BASE + REG_MATCH1);
moxart_enable(evt);
return 0;
}
static int moxart_clkevt_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
struct moxart_timer *timer = to_moxart(evt);
u32 u;
moxart_disable(evt);
u = readl(timer->base + TIMER1_BASE + REG_COUNT) - cycles;
writel(u, timer->base + TIMER1_BASE + REG_MATCH1);
moxart_enable(evt);
return 0;
}
static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = dev_id;
evt->event_handler(evt);
return IRQ_HANDLED;
}
static int __init moxart_timer_init(struct device_node *node)
{
int ret, irq;
unsigned long pclk;
struct clk *clk;
struct moxart_timer *timer;
timer = kzalloc(sizeof(*timer), GFP_KERNEL);
if (!timer)
return -ENOMEM;
timer->base = of_iomap(node, 0);
if (!timer->base) {
pr_err("%s: of_iomap failed\n", node->full_name);
ret = -ENXIO;
goto out_free;
}
irq = irq_of_parse_and_map(node, 0);
if (irq <= 0) {
pr_err("%s: irq_of_parse_and_map failed\n", node->full_name);
ret = -EINVAL;
goto out_unmap;
}
clk = of_clk_get(node, 0);
if (IS_ERR(clk)) {
pr_err("%s: of_clk_get failed\n", node->full_name);
ret = PTR_ERR(clk);
goto out_unmap;
}
pclk = clk_get_rate(clk);
if (of_device_is_compatible(node, "moxa,moxart-timer")) {
timer->t1_enable_val = MOXART_TIMER1_ENABLE;
timer->t1_disable_val = MOXART_TIMER1_DISABLE;
} else if (of_device_is_compatible(node, "aspeed,ast2400-timer")) {
timer->t1_enable_val = ASPEED_TIMER1_ENABLE;
timer->t1_disable_val = ASPEED_TIMER1_DISABLE;
} else {
pr_err("%s: unknown platform\n", node->full_name);
ret = -EINVAL;
goto out_unmap;
}
timer->count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ);
timer->clkevt.name = node->name;
timer->clkevt.rating = 200;
timer->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT;
timer->clkevt.set_state_shutdown = moxart_shutdown;
timer->clkevt.set_state_periodic = moxart_set_periodic;
timer->clkevt.set_state_oneshot = moxart_set_oneshot;
timer->clkevt.tick_resume = moxart_set_oneshot;
timer->clkevt.set_next_event = moxart_clkevt_next_event;
timer->clkevt.cpumask = cpumask_of(0);
timer->clkevt.irq = irq;
ret = clocksource_mmio_init(timer->base + TIMER2_BASE + REG_COUNT,
"moxart_timer", pclk, 200, 32,
clocksource_mmio_readl_down);
if (ret) {
pr_err("%s: clocksource_mmio_init failed\n", node->full_name);
goto out_unmap;
}
ret = request_irq(irq, moxart_timer_interrupt, IRQF_TIMER,
node->name, &timer->clkevt);
if (ret) {
pr_err("%s: setup_irq failed\n", node->full_name);
goto out_unmap;
}
/* Clear match registers */
writel(0, timer->base + TIMER1_BASE + REG_MATCH1);
writel(0, timer->base + TIMER1_BASE + REG_MATCH2);
writel(0, timer->base + TIMER2_BASE + REG_MATCH1);
writel(0, timer->base + TIMER2_BASE + REG_MATCH2);
/*
* Start timer 2 rolling as our main wall clock source, keep timer 1
* disabled
*/
writel(0, timer->base + TIMER_CR);
writel(~0, timer->base + TIMER2_BASE + REG_LOAD);
writel(timer->t1_disable_val, timer->base + TIMER_CR);
/*
* documentation is not publicly available:
* min_delta / max_delta obtained by trial-and-error,
* max_delta 0xfffffffe should be ok because count
* register size is u32
*/
clockevents_config_and_register(&timer->clkevt, pclk, 0x4, 0xfffffffe);
return 0;
out_unmap:
iounmap(timer->base);
out_free:
kfree(timer);
return ret;
}
CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init);
CLOCKSOURCE_OF_DECLARE(aspeed, "aspeed,ast2400-timer", moxart_timer_init);
...@@ -50,6 +50,20 @@ ...@@ -50,6 +50,20 @@
#define TIMER_2_CR_UPDOWN BIT(10) #define TIMER_2_CR_UPDOWN BIT(10)
#define TIMER_3_CR_UPDOWN BIT(11) #define TIMER_3_CR_UPDOWN BIT(11)
/*
* The Aspeed AST2400 moves bits around in the control register
* and lacks bits for setting the timer to count upwards.
*/
#define TIMER_1_CR_ASPEED_ENABLE BIT(0)
#define TIMER_1_CR_ASPEED_CLOCK BIT(1)
#define TIMER_1_CR_ASPEED_INT BIT(2)
#define TIMER_2_CR_ASPEED_ENABLE BIT(4)
#define TIMER_2_CR_ASPEED_CLOCK BIT(5)
#define TIMER_2_CR_ASPEED_INT BIT(6)
#define TIMER_3_CR_ASPEED_ENABLE BIT(8)
#define TIMER_3_CR_ASPEED_CLOCK BIT(9)
#define TIMER_3_CR_ASPEED_INT BIT(10)
#define TIMER_1_INT_MATCH1 BIT(0) #define TIMER_1_INT_MATCH1 BIT(0)
#define TIMER_1_INT_MATCH2 BIT(1) #define TIMER_1_INT_MATCH2 BIT(1)
#define TIMER_1_INT_OVERFLOW BIT(2) #define TIMER_1_INT_OVERFLOW BIT(2)
...@@ -64,6 +78,8 @@ ...@@ -64,6 +78,8 @@
struct fttmr010 { struct fttmr010 {
void __iomem *base; void __iomem *base;
unsigned int tick_rate; unsigned int tick_rate;
bool count_down;
u32 t1_enable_val;
struct clock_event_device clkevt; struct clock_event_device clkevt;
}; };
...@@ -77,6 +93,8 @@ static inline struct fttmr010 *to_fttmr010(struct clock_event_device *evt) ...@@ -77,6 +93,8 @@ static inline struct fttmr010 *to_fttmr010(struct clock_event_device *evt)
static u64 notrace fttmr010_read_sched_clock(void) static u64 notrace fttmr010_read_sched_clock(void)
{ {
if (local_fttmr->count_down)
return ~readl(local_fttmr->base + TIMER2_COUNT);
return readl(local_fttmr->base + TIMER2_COUNT); return readl(local_fttmr->base + TIMER2_COUNT);
} }
...@@ -86,11 +104,23 @@ static int fttmr010_timer_set_next_event(unsigned long cycles, ...@@ -86,11 +104,23 @@ static int fttmr010_timer_set_next_event(unsigned long cycles,
struct fttmr010 *fttmr010 = to_fttmr010(evt); struct fttmr010 *fttmr010 = to_fttmr010(evt);
u32 cr; u32 cr;
/* Setup the match register */ /* Stop */
cr = readl(fttmr010->base + TIMER_CR);
cr &= ~fttmr010->t1_enable_val;
writel(cr, fttmr010->base + TIMER_CR);
/* Setup the match register forward/backward in time */
cr = readl(fttmr010->base + TIMER1_COUNT); cr = readl(fttmr010->base + TIMER1_COUNT);
writel(cr + cycles, fttmr010->base + TIMER1_MATCH1); if (fttmr010->count_down)
if (readl(fttmr010->base + TIMER1_COUNT) - cr > cycles) cr -= cycles;
return -ETIME; else
cr += cycles;
writel(cr, fttmr010->base + TIMER1_MATCH1);
/* Start */
cr = readl(fttmr010->base + TIMER_CR);
cr |= fttmr010->t1_enable_val;
writel(cr, fttmr010->base + TIMER_CR);
return 0; return 0;
} }
...@@ -100,9 +130,9 @@ static int fttmr010_timer_shutdown(struct clock_event_device *evt) ...@@ -100,9 +130,9 @@ static int fttmr010_timer_shutdown(struct clock_event_device *evt)
struct fttmr010 *fttmr010 = to_fttmr010(evt); struct fttmr010 *fttmr010 = to_fttmr010(evt);
u32 cr; u32 cr;
/* Stop timer and interrupt. */ /* Stop */
cr = readl(fttmr010->base + TIMER_CR); cr = readl(fttmr010->base + TIMER_CR);
cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); cr &= ~fttmr010->t1_enable_val;
writel(cr, fttmr010->base + TIMER_CR); writel(cr, fttmr010->base + TIMER_CR);
return 0; return 0;
...@@ -113,13 +143,16 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt) ...@@ -113,13 +143,16 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
struct fttmr010 *fttmr010 = to_fttmr010(evt); struct fttmr010 *fttmr010 = to_fttmr010(evt);
u32 cr; u32 cr;
/* Stop timer and interrupt. */ /* Stop */
cr = readl(fttmr010->base + TIMER_CR); cr = readl(fttmr010->base + TIMER_CR);
cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); cr &= ~fttmr010->t1_enable_val;
writel(cr, fttmr010->base + TIMER_CR); writel(cr, fttmr010->base + TIMER_CR);
/* Setup counter start from 0 */ /* Setup counter start from 0 or ~0 */
writel(0, fttmr010->base + TIMER1_COUNT); writel(0, fttmr010->base + TIMER1_COUNT);
if (fttmr010->count_down)
writel(~0, fttmr010->base + TIMER1_LOAD);
else
writel(0, fttmr010->base + TIMER1_LOAD); writel(0, fttmr010->base + TIMER1_LOAD);
/* Enable interrupt */ /* Enable interrupt */
...@@ -128,11 +161,6 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt) ...@@ -128,11 +161,6 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
cr |= TIMER_1_INT_MATCH1; cr |= TIMER_1_INT_MATCH1;
writel(cr, fttmr010->base + TIMER_INTR_MASK); writel(cr, fttmr010->base + TIMER_INTR_MASK);
/* Start the timer */
cr = readl(fttmr010->base + TIMER_CR);
cr |= TIMER_1_CR_ENABLE;
writel(cr, fttmr010->base + TIMER_CR);
return 0; return 0;
} }
...@@ -142,26 +170,30 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt) ...@@ -142,26 +170,30 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ); u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ);
u32 cr; u32 cr;
/* Stop timer and interrupt */ /* Stop */
cr = readl(fttmr010->base + TIMER_CR); cr = readl(fttmr010->base + TIMER_CR);
cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); cr &= ~fttmr010->t1_enable_val;
writel(cr, fttmr010->base + TIMER_CR); writel(cr, fttmr010->base + TIMER_CR);
/* Setup timer to fire at 1/HT intervals. */ /* Setup timer to fire at 1/HZ intervals. */
if (fttmr010->count_down) {
writel(period, fttmr010->base + TIMER1_LOAD);
writel(0, fttmr010->base + TIMER1_MATCH1);
} else {
cr = 0xffffffff - (period - 1); cr = 0xffffffff - (period - 1);
writel(cr, fttmr010->base + TIMER1_COUNT); writel(cr, fttmr010->base + TIMER1_COUNT);
writel(cr, fttmr010->base + TIMER1_LOAD); writel(cr, fttmr010->base + TIMER1_LOAD);
/* enable interrupt on overflow */ /* Enable interrupt on overflow */
cr = readl(fttmr010->base + TIMER_INTR_MASK); cr = readl(fttmr010->base + TIMER_INTR_MASK);
cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2);
cr |= TIMER_1_INT_OVERFLOW; cr |= TIMER_1_INT_OVERFLOW;
writel(cr, fttmr010->base + TIMER_INTR_MASK); writel(cr, fttmr010->base + TIMER_INTR_MASK);
}
/* Start the timer */ /* Start the timer */
cr = readl(fttmr010->base + TIMER_CR); cr = readl(fttmr010->base + TIMER_CR);
cr |= TIMER_1_CR_ENABLE; cr |= fttmr010->t1_enable_val;
cr |= TIMER_1_CR_INT;
writel(cr, fttmr010->base + TIMER_CR); writel(cr, fttmr010->base + TIMER_CR);
return 0; return 0;
...@@ -181,9 +213,11 @@ static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id) ...@@ -181,9 +213,11 @@ static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id)
static int __init fttmr010_timer_init(struct device_node *np) static int __init fttmr010_timer_init(struct device_node *np)
{ {
struct fttmr010 *fttmr010; struct fttmr010 *fttmr010;
bool is_ast2400;
int irq; int irq;
struct clk *clk; struct clk *clk;
int ret; int ret;
u32 val;
/* /*
* These implementations require a clock reference. * These implementations require a clock reference.
...@@ -222,14 +256,38 @@ static int __init fttmr010_timer_init(struct device_node *np) ...@@ -222,14 +256,38 @@ static int __init fttmr010_timer_init(struct device_node *np)
goto out_unmap; goto out_unmap;
} }
/*
* The Aspeed AST2400 moves bits around in the control register,
* otherwise it works the same.
*/
is_ast2400 = of_device_is_compatible(np, "aspeed,ast2400-timer");
if (is_ast2400) {
fttmr010->t1_enable_val = TIMER_1_CR_ASPEED_ENABLE |
TIMER_1_CR_ASPEED_INT;
/* Downward not available */
fttmr010->count_down = true;
} else {
fttmr010->t1_enable_val = TIMER_1_CR_ENABLE | TIMER_1_CR_INT;
}
/* /*
* Reset the interrupt mask and status * Reset the interrupt mask and status
*/ */
writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK); writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK);
writel(0, fttmr010->base + TIMER_INTR_STATE); writel(0, fttmr010->base + TIMER_INTR_STATE);
/* Enable timer 1 count up, timer 2 count up */
writel((TIMER_1_CR_UPDOWN | TIMER_2_CR_ENABLE | TIMER_2_CR_UPDOWN), /*
fttmr010->base + TIMER_CR); * Enable timer 1 count up, timer 2 count up, except on Aspeed,
* where everything just counts down.
*/
if (is_ast2400)
val = TIMER_2_CR_ASPEED_ENABLE;
else {
val = TIMER_2_CR_ENABLE;
if (!fttmr010->count_down)
val |= TIMER_1_CR_UPDOWN | TIMER_2_CR_UPDOWN;
}
writel(val, fttmr010->base + TIMER_CR);
/* /*
* Setup free-running clocksource timer (interrupts * Setup free-running clocksource timer (interrupts
...@@ -237,13 +295,22 @@ static int __init fttmr010_timer_init(struct device_node *np) ...@@ -237,13 +295,22 @@ static int __init fttmr010_timer_init(struct device_node *np)
*/ */
local_fttmr = fttmr010; local_fttmr = fttmr010;
writel(0, fttmr010->base + TIMER2_COUNT); writel(0, fttmr010->base + TIMER2_COUNT);
writel(0, fttmr010->base + TIMER2_LOAD);
writel(0, fttmr010->base + TIMER2_MATCH1); writel(0, fttmr010->base + TIMER2_MATCH1);
writel(0, fttmr010->base + TIMER2_MATCH2); writel(0, fttmr010->base + TIMER2_MATCH2);
if (fttmr010->count_down) {
writel(~0, fttmr010->base + TIMER2_LOAD);
clocksource_mmio_init(fttmr010->base + TIMER2_COUNT,
"FTTMR010-TIMER2",
fttmr010->tick_rate,
300, 32, clocksource_mmio_readl_down);
} else {
writel(0, fttmr010->base + TIMER2_LOAD);
clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, clocksource_mmio_init(fttmr010->base + TIMER2_COUNT,
"FTTMR010-TIMER2", "FTTMR010-TIMER2",
fttmr010->tick_rate, fttmr010->tick_rate,
300, 32, clocksource_mmio_readl_up); 300, 32, clocksource_mmio_readl_up);
}
sched_clock_register(fttmr010_read_sched_clock, 32, sched_clock_register(fttmr010_read_sched_clock, 32,
fttmr010->tick_rate); fttmr010->tick_rate);
...@@ -290,3 +357,5 @@ static int __init fttmr010_timer_init(struct device_node *np) ...@@ -290,3 +357,5 @@ static int __init fttmr010_timer_init(struct device_node *np)
} }
CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init); CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init);
CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init); CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init);
CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", fttmr010_timer_init);
CLOCKSOURCE_OF_DECLARE(aspeed, "aspeed,ast2400-timer", fttmr010_timer_init);
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