Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into next
Pull timer core updates from Thomas Gleixner: "This time you get nothing really exciting: - A huge update to the sh* clocksource drivers - Support for two more ARM SoCs - Removal of the deprecated setup_sched_clock() API - The usual pile of fixlets all over the place" * 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (23 commits) clocksource: Add Freescale FlexTimer Module (FTM) timer support ARM: dts: vf610: Add Freescale FlexTimer Module timer node. clocksource: ftm: Add FlexTimer Module (FTM) Timer devicetree Documentation clocksource: sh_tmu: Remove unnecessary OOM messages clocksource: sh_mtu2: Remove unnecessary OOM messages clocksource: sh_cmt: Remove unnecessary OOM messages clocksource: em_sti: Remove unnecessary OOM messages clocksource: dw_apb_timer_of: Do not trace read_sched_clock clocksource: Fix clocksource_mmio_readX_down clocksource: Fix type confusion for clocksource_mmio_readX_Y clocksource: sh_tmu: Fix channel IRQ retrieval in legacy case clocksource: qcom: Implement read_current_timer for udelay ntp: Make is_error_status() use its argument ntp: Convert simple_strtol to kstrtol timer_stats/doc: Fix /proc/timer_stats documentation sched_clock: Remove deprecated setup_sched_clock() API ARM: sun6i: a31: Add support for the High Speed Timers clocksource: sun5i: Add support for reset controller clocksource: efm32: use $vendor,$device scheme for compatible string KConfig: Vexpress: build the ARM_GLOBAL_TIMER with vexpress platform ...
This commit is contained in:
commit
82e627eb5e
@ -4,8 +4,11 @@
|
||||
|
||||
** Timer node required properties:
|
||||
|
||||
- compatible : Should be "arm,cortex-a9-global-timer"
|
||||
Driver supports versions r2p0 and above.
|
||||
- compatible : should contain
|
||||
* "arm,cortex-a5-global-timer" for Cortex-A5 global timers.
|
||||
* "arm,cortex-a9-global-timer" for Cortex-A9 global
|
||||
timers or any compatible implementation. Note: driver
|
||||
supports versions r2p0 and above.
|
||||
|
||||
- interrupts : One interrupt to each core
|
||||
|
||||
|
@ -9,6 +9,9 @@ Required properties:
|
||||
one)
|
||||
- clocks: phandle to the source clock (usually the AHB clock)
|
||||
|
||||
Optionnal properties:
|
||||
- resets: phandle to a reset controller asserting the timer
|
||||
|
||||
Example:
|
||||
|
||||
timer@01c60000 {
|
||||
@ -19,4 +22,5 @@ timer@01c60000 {
|
||||
<0 53 1>,
|
||||
<0 54 1>;
|
||||
clocks = <&ahb1_gates 19>;
|
||||
resets = <&ahb1rst 19>;
|
||||
};
|
||||
|
@ -6,7 +6,7 @@ channels and can be used as PWM or Quadrature Decoder. Available clock sources
|
||||
are the cpu's HFPERCLK (with a 10-bit prescaler) or an external pin.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be efm32,timer
|
||||
- compatible : Should be "energymicro,efm32-timer"
|
||||
- reg : Address and length of the register set
|
||||
- clocks : Should contain a reference to the HFPERCLK
|
||||
|
||||
@ -16,7 +16,7 @@ Optional properties:
|
||||
Example:
|
||||
|
||||
timer@40010c00 {
|
||||
compatible = "efm32,timer";
|
||||
compatible = "energymicro,efm32-timer";
|
||||
reg = <0x40010c00 0x400>;
|
||||
interrupts = <14>;
|
||||
clocks = <&cmu clk_HFPERCLKTIMER3>;
|
31
Documentation/devicetree/bindings/timer/fsl,ftm-timer.txt
Normal file
31
Documentation/devicetree/bindings/timer/fsl,ftm-timer.txt
Normal file
@ -0,0 +1,31 @@
|
||||
Freescale FlexTimer Module (FTM) Timer
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "fsl,ftm-timer"
|
||||
- reg : Specifies base physical address and size of the register sets for the
|
||||
clock event device and clock source device.
|
||||
- interrupts : Should be the clock event device interrupt.
|
||||
- clocks : The clocks provided by the SoC to drive the timer, must contain an
|
||||
entry for each entry in clock-names.
|
||||
- clock-names : Must include the following entries:
|
||||
o "ftm-evt"
|
||||
o "ftm-src"
|
||||
o "ftm-evt-counter-en"
|
||||
o "ftm-src-counter-en"
|
||||
- big-endian: One boolean property, the big endian mode will be in use if it is
|
||||
present, or the little endian mode will be in use for all the device registers.
|
||||
|
||||
Example:
|
||||
ftm: ftm@400b8000 {
|
||||
compatible = "fsl,ftm-timer";
|
||||
reg = <0x400b8000 0x1000 0x400b9000 0x1000>;
|
||||
interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clock-names = "ftm-evt", "ftm-src",
|
||||
"ftm-evt-counter-en", "ftm-src-counter-en";
|
||||
clocks = <&clks VF610_CLK_FTM2>,
|
||||
<&clks VF610_CLK_FTM3>,
|
||||
<&clks VF610_CLK_FTM2_EXT_FIX_EN>,
|
||||
<&clks VF610_CLK_FTM3_EXT_FIX_EN>;
|
||||
big-endian;
|
||||
};
|
@ -39,9 +39,9 @@ To stop a sample period issue:
|
||||
The statistics can be retrieved by:
|
||||
# cat /proc/timer_stats
|
||||
|
||||
The readout of /proc/timer_stats automatically disables sampling. The sampled
|
||||
information is kept until a new sample period is started. This allows multiple
|
||||
readouts.
|
||||
While sampling is enabled, each readout from /proc/timer_stats will see
|
||||
newly updated statistics. Once sampling is disabled, the sampled information
|
||||
is kept until a new sample period is started. This allows multiple readouts.
|
||||
|
||||
Sample output of /proc/timer_stats:
|
||||
|
||||
|
@ -621,6 +621,17 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
timer@01c60000 {
|
||||
compatible = "allwinner,sun6i-a31-hstimer", "allwinner,sun7i-a20-hstimer";
|
||||
reg = <0x01c60000 0x1000>;
|
||||
interrupts = <0 51 4>,
|
||||
<0 52 4>,
|
||||
<0 53 4>,
|
||||
<0 54 4>;
|
||||
clocks = <&ahb1_gates 19>;
|
||||
resets = <&ahb1_rst 19>;
|
||||
};
|
||||
|
||||
spi0: spi@01c68000 {
|
||||
compatible = "allwinner,sun6i-a31-spi";
|
||||
reg = <0x01c68000 0x1000>;
|
||||
|
@ -88,6 +88,14 @@
|
||||
interrupts = <1 13 0x304>;
|
||||
};
|
||||
|
||||
timer@2c000200 {
|
||||
compatible = "arm,cortex-a5-global-timer",
|
||||
"arm,cortex-a9-global-timer";
|
||||
reg = <0x2c000200 0x20>;
|
||||
interrupts = <1 11 0x304>;
|
||||
clocks = <&oscclk0>;
|
||||
};
|
||||
|
||||
watchdog@2c000620 {
|
||||
compatible = "arm,cortex-a5-twd-wdt";
|
||||
reg = <0x2c000620 0x20>;
|
||||
@ -120,7 +128,7 @@
|
||||
compatible = "arm,vexpress,config-bus";
|
||||
arm,vexpress,config-bridge = <&v2m_sysreg>;
|
||||
|
||||
osc@0 {
|
||||
oscclk0: osc@0 {
|
||||
/* CPU and internal AXI reference clock */
|
||||
compatible = "arm,vexpress-osc";
|
||||
arm,vexpress-sysreg,func = <1 0>;
|
||||
|
@ -371,6 +371,19 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
ftm: ftm@400b8000 {
|
||||
compatible = "fsl,ftm-timer";
|
||||
reg = <0x400b8000 0x1000 0x400b9000 0x1000>;
|
||||
interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clock-names = "ftm-evt", "ftm-src",
|
||||
"ftm-evt-counter-en", "ftm-src-counter-en";
|
||||
clocks = <&clks VF610_CLK_FTM2>,
|
||||
<&clks VF610_CLK_FTM3>,
|
||||
<&clks VF610_CLK_FTM2_EXT_FIX_EN>,
|
||||
<&clks VF610_CLK_FTM3_EXT_FIX_EN>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
fec0: ethernet@400d0000 {
|
||||
compatible = "fsl,mvf600-fec";
|
||||
reg = <0x400d0000 0x1000>;
|
||||
|
@ -4,6 +4,7 @@ config ARCH_VEXPRESS
|
||||
select ARCH_SUPPORTS_BIG_ENDIAN
|
||||
select ARM_AMBA
|
||||
select ARM_GIC
|
||||
select ARM_GLOBAL_TIMER
|
||||
select ARM_TIMER_SP804
|
||||
select COMMON_CLK_VERSATILE
|
||||
select HAVE_ARM_SCU if SMP
|
||||
|
@ -136,6 +136,11 @@ config CLKSRC_SAMSUNG_PWM
|
||||
for all devicetree enabled platforms. This driver will be
|
||||
needed only on systems that do not have the Exynos MCT available.
|
||||
|
||||
config FSL_FTM_TIMER
|
||||
bool
|
||||
help
|
||||
Support for Freescale FlexTimer Module (FTM) timer.
|
||||
|
||||
config VF_PIT_TIMER
|
||||
bool
|
||||
help
|
||||
|
@ -31,6 +31,7 @@ obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o
|
||||
obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o
|
||||
obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o
|
||||
obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o
|
||||
obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o
|
||||
obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o
|
||||
obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o
|
||||
|
||||
|
@ -246,11 +246,12 @@ static void __init global_timer_of_register(struct device_node *np)
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* In r2p0 the comparators for each processor with the global timer
|
||||
* In A9 r2p0 the comparators for each processor with the global timer
|
||||
* fire when the timer value is greater than or equal to. In previous
|
||||
* revisions the comparators fired when the timer value was equal to.
|
||||
*/
|
||||
if ((read_cpuid_id() & 0xf0000f) < 0x200000) {
|
||||
if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9
|
||||
&& (read_cpuid_id() & 0xf0000f) < 0x200000) {
|
||||
pr_warn("global-timer: non support for this cpu version.\n");
|
||||
return;
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ static void __init add_clocksource(struct device_node *source_timer)
|
||||
sched_rate = rate;
|
||||
}
|
||||
|
||||
static u64 read_sched_clock(void)
|
||||
static u64 notrace read_sched_clock(void)
|
||||
{
|
||||
return ~__raw_readl(sched_io_base);
|
||||
}
|
||||
|
@ -318,10 +318,8 @@ static int em_sti_probe(struct platform_device *pdev)
|
||||
int irq;
|
||||
|
||||
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
|
||||
if (p == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
if (p == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
p->pdev = pdev;
|
||||
platform_set_drvdata(pdev, p);
|
||||
|
367
drivers/clocksource/fsl_ftm_timer.c
Normal file
367
drivers/clocksource/fsl_ftm_timer.c
Normal file
@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Freescale FlexTimer Module (FTM) timer driver.
|
||||
*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/sched_clock.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define FTM_SC 0x00
|
||||
#define FTM_SC_CLK_SHIFT 3
|
||||
#define FTM_SC_CLK_MASK (0x3 << FTM_SC_CLK_SHIFT)
|
||||
#define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_SHIFT)
|
||||
#define FTM_SC_PS_MASK 0x7
|
||||
#define FTM_SC_TOIE BIT(6)
|
||||
#define FTM_SC_TOF BIT(7)
|
||||
|
||||
#define FTM_CNT 0x04
|
||||
#define FTM_MOD 0x08
|
||||
#define FTM_CNTIN 0x4C
|
||||
|
||||
#define FTM_PS_MAX 7
|
||||
|
||||
struct ftm_clock_device {
|
||||
void __iomem *clksrc_base;
|
||||
void __iomem *clkevt_base;
|
||||
unsigned long periodic_cyc;
|
||||
unsigned long ps;
|
||||
bool big_endian;
|
||||
};
|
||||
|
||||
static struct ftm_clock_device *priv;
|
||||
|
||||
static inline u32 ftm_readl(void __iomem *addr)
|
||||
{
|
||||
if (priv->big_endian)
|
||||
return ioread32be(addr);
|
||||
else
|
||||
return ioread32(addr);
|
||||
}
|
||||
|
||||
static inline void ftm_writel(u32 val, void __iomem *addr)
|
||||
{
|
||||
if (priv->big_endian)
|
||||
iowrite32be(val, addr);
|
||||
else
|
||||
iowrite32(val, addr);
|
||||
}
|
||||
|
||||
static inline void ftm_counter_enable(void __iomem *base)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* select and enable counter clock source */
|
||||
val = ftm_readl(base + FTM_SC);
|
||||
val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
|
||||
val |= priv->ps | FTM_SC_CLK(1);
|
||||
ftm_writel(val, base + FTM_SC);
|
||||
}
|
||||
|
||||
static inline void ftm_counter_disable(void __iomem *base)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* disable counter clock source */
|
||||
val = ftm_readl(base + FTM_SC);
|
||||
val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
|
||||
ftm_writel(val, base + FTM_SC);
|
||||
}
|
||||
|
||||
static inline void ftm_irq_acknowledge(void __iomem *base)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = ftm_readl(base + FTM_SC);
|
||||
val &= ~FTM_SC_TOF;
|
||||
ftm_writel(val, base + FTM_SC);
|
||||
}
|
||||
|
||||
static inline void ftm_irq_enable(void __iomem *base)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = ftm_readl(base + FTM_SC);
|
||||
val |= FTM_SC_TOIE;
|
||||
ftm_writel(val, base + FTM_SC);
|
||||
}
|
||||
|
||||
static inline void ftm_irq_disable(void __iomem *base)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = ftm_readl(base + FTM_SC);
|
||||
val &= ~FTM_SC_TOIE;
|
||||
ftm_writel(val, base + FTM_SC);
|
||||
}
|
||||
|
||||
static inline void ftm_reset_counter(void __iomem *base)
|
||||
{
|
||||
/*
|
||||
* The CNT register contains the FTM counter value.
|
||||
* Reset clears the CNT register. Writing any value to COUNT
|
||||
* updates the counter with its initial value, CNTIN.
|
||||
*/
|
||||
ftm_writel(0x00, base + FTM_CNT);
|
||||
}
|
||||
|
||||
static u64 ftm_read_sched_clock(void)
|
||||
{
|
||||
return ftm_readl(priv->clksrc_base + FTM_CNT);
|
||||
}
|
||||
|
||||
static int ftm_set_next_event(unsigned long delta,
|
||||
struct clock_event_device *unused)
|
||||
{
|
||||
/*
|
||||
* The CNNIN and MOD are all double buffer registers, writing
|
||||
* to the MOD register latches the value into a buffer. The MOD
|
||||
* register is updated with the value of its write buffer with
|
||||
* the following scenario:
|
||||
* a, the counter source clock is diabled.
|
||||
*/
|
||||
ftm_counter_disable(priv->clkevt_base);
|
||||
|
||||
/* Force the value of CNTIN to be loaded into the FTM counter */
|
||||
ftm_reset_counter(priv->clkevt_base);
|
||||
|
||||
/*
|
||||
* The counter increments until the value of MOD is reached,
|
||||
* at which point the counter is reloaded with the value of CNTIN.
|
||||
* The TOF (the overflow flag) bit is set when the FTM counter
|
||||
* changes from MOD to CNTIN. So we should using the delta - 1.
|
||||
*/
|
||||
ftm_writel(delta - 1, priv->clkevt_base + FTM_MOD);
|
||||
|
||||
ftm_counter_enable(priv->clkevt_base);
|
||||
|
||||
ftm_irq_enable(priv->clkevt_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ftm_set_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *evt)
|
||||
{
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
ftm_set_next_event(priv->periodic_cyc, evt);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
ftm_counter_disable(priv->clkevt_base);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct clock_event_device *evt = dev_id;
|
||||
|
||||
ftm_irq_acknowledge(priv->clkevt_base);
|
||||
|
||||
if (likely(evt->mode == CLOCK_EVT_MODE_ONESHOT)) {
|
||||
ftm_irq_disable(priv->clkevt_base);
|
||||
ftm_counter_disable(priv->clkevt_base);
|
||||
}
|
||||
|
||||
evt->event_handler(evt);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct clock_event_device ftm_clockevent = {
|
||||
.name = "Freescale ftm timer",
|
||||
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
|
||||
.set_mode = ftm_set_mode,
|
||||
.set_next_event = ftm_set_next_event,
|
||||
.rating = 300,
|
||||
};
|
||||
|
||||
static struct irqaction ftm_timer_irq = {
|
||||
.name = "Freescale ftm timer",
|
||||
.flags = IRQF_TIMER | IRQF_IRQPOLL,
|
||||
.handler = ftm_evt_interrupt,
|
||||
.dev_id = &ftm_clockevent,
|
||||
};
|
||||
|
||||
static int __init ftm_clockevent_init(unsigned long freq, int irq)
|
||||
{
|
||||
int err;
|
||||
|
||||
ftm_writel(0x00, priv->clkevt_base + FTM_CNTIN);
|
||||
ftm_writel(~0UL, priv->clkevt_base + FTM_MOD);
|
||||
|
||||
ftm_reset_counter(priv->clkevt_base);
|
||||
|
||||
err = setup_irq(irq, &ftm_timer_irq);
|
||||
if (err) {
|
||||
pr_err("ftm: setup irq failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ftm_clockevent.cpumask = cpumask_of(0);
|
||||
ftm_clockevent.irq = irq;
|
||||
|
||||
clockevents_config_and_register(&ftm_clockevent,
|
||||
freq / (1 << priv->ps),
|
||||
1, 0xffff);
|
||||
|
||||
ftm_counter_enable(priv->clkevt_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init ftm_clocksource_init(unsigned long freq)
|
||||
{
|
||||
int err;
|
||||
|
||||
ftm_writel(0x00, priv->clksrc_base + FTM_CNTIN);
|
||||
ftm_writel(~0UL, priv->clksrc_base + FTM_MOD);
|
||||
|
||||
ftm_reset_counter(priv->clksrc_base);
|
||||
|
||||
sched_clock_register(ftm_read_sched_clock, 16, freq / (1 << priv->ps));
|
||||
err = clocksource_mmio_init(priv->clksrc_base + FTM_CNT, "fsl-ftm",
|
||||
freq / (1 << priv->ps), 300, 16,
|
||||
clocksource_mmio_readl_up);
|
||||
if (err) {
|
||||
pr_err("ftm: init clock source mmio failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ftm_counter_enable(priv->clksrc_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init __ftm_clk_init(struct device_node *np, char *cnt_name,
|
||||
char *ftm_name)
|
||||
{
|
||||
struct clk *clk;
|
||||
int err;
|
||||
|
||||
clk = of_clk_get_by_name(np, cnt_name);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("ftm: Cannot get \"%s\": %ld\n", cnt_name, PTR_ERR(clk));
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
err = clk_prepare_enable(clk);
|
||||
if (err) {
|
||||
pr_err("ftm: clock failed to prepare+enable \"%s\": %d\n",
|
||||
cnt_name, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
clk = of_clk_get_by_name(np, ftm_name);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("ftm: Cannot get \"%s\": %ld\n", ftm_name, PTR_ERR(clk));
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
err = clk_prepare_enable(clk);
|
||||
if (err)
|
||||
pr_err("ftm: clock failed to prepare+enable \"%s\": %d\n",
|
||||
ftm_name, err);
|
||||
|
||||
return clk_get_rate(clk);
|
||||
}
|
||||
|
||||
static unsigned long __init ftm_clk_init(struct device_node *np)
|
||||
{
|
||||
unsigned long freq;
|
||||
|
||||
freq = __ftm_clk_init(np, "ftm-evt-counter-en", "ftm-evt");
|
||||
if (freq <= 0)
|
||||
return 0;
|
||||
|
||||
freq = __ftm_clk_init(np, "ftm-src-counter-en", "ftm-src");
|
||||
if (freq <= 0)
|
||||
return 0;
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
static int __init ftm_calc_closest_round_cyc(unsigned long freq)
|
||||
{
|
||||
priv->ps = 0;
|
||||
|
||||
/* The counter register is only using the lower 16 bits, and
|
||||
* if the 'freq' value is to big here, then the periodic_cyc
|
||||
* may exceed 0xFFFF.
|
||||
*/
|
||||
do {
|
||||
priv->periodic_cyc = DIV_ROUND_CLOSEST(freq,
|
||||
HZ * (1 << priv->ps++));
|
||||
} while (priv->periodic_cyc > 0xFFFF);
|
||||
|
||||
if (priv->ps > FTM_PS_MAX) {
|
||||
pr_err("ftm: the prescaler is %lu > %d\n",
|
||||
priv->ps, FTM_PS_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init ftm_timer_init(struct device_node *np)
|
||||
{
|
||||
unsigned long freq;
|
||||
int irq;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
priv->clkevt_base = of_iomap(np, 0);
|
||||
if (!priv->clkevt_base) {
|
||||
pr_err("ftm: unable to map event timer registers\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
priv->clksrc_base = of_iomap(np, 1);
|
||||
if (!priv->clksrc_base) {
|
||||
pr_err("ftm: unable to map source timer registers\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (irq <= 0) {
|
||||
pr_err("ftm: unable to get IRQ from DT, %d\n", irq);
|
||||
goto err;
|
||||
}
|
||||
|
||||
priv->big_endian = of_property_read_bool(np, "big-endian");
|
||||
|
||||
freq = ftm_clk_init(np);
|
||||
if (!freq)
|
||||
goto err;
|
||||
|
||||
if (ftm_calc_closest_round_cyc(freq))
|
||||
goto err;
|
||||
|
||||
if (ftm_clocksource_init(freq))
|
||||
goto err;
|
||||
|
||||
if (ftm_clockevent_init(freq, irq))
|
||||
goto err;
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
kfree(priv);
|
||||
}
|
||||
CLOCKSOURCE_OF_DECLARE(flextimer, "fsl,ftm-timer", ftm_timer_init);
|
@ -22,22 +22,22 @@ static inline struct clocksource_mmio *to_mmio_clksrc(struct clocksource *c)
|
||||
|
||||
cycle_t clocksource_mmio_readl_up(struct clocksource *c)
|
||||
{
|
||||
return readl_relaxed(to_mmio_clksrc(c)->reg);
|
||||
return (cycle_t)readl_relaxed(to_mmio_clksrc(c)->reg);
|
||||
}
|
||||
|
||||
cycle_t clocksource_mmio_readl_down(struct clocksource *c)
|
||||
{
|
||||
return ~readl_relaxed(to_mmio_clksrc(c)->reg);
|
||||
return ~(cycle_t)readl_relaxed(to_mmio_clksrc(c)->reg) & c->mask;
|
||||
}
|
||||
|
||||
cycle_t clocksource_mmio_readw_up(struct clocksource *c)
|
||||
{
|
||||
return readw_relaxed(to_mmio_clksrc(c)->reg);
|
||||
return (cycle_t)readw_relaxed(to_mmio_clksrc(c)->reg);
|
||||
}
|
||||
|
||||
cycle_t clocksource_mmio_readw_down(struct clocksource *c)
|
||||
{
|
||||
return ~(unsigned)readw_relaxed(to_mmio_clksrc(c)->reg);
|
||||
return ~(cycle_t)readw_relaxed(to_mmio_clksrc(c)->reg) & c->mask;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/sched_clock.h>
|
||||
|
||||
#include <asm/delay.h>
|
||||
|
||||
#define TIMER_MATCH_VAL 0x0000
|
||||
#define TIMER_COUNT_VAL 0x0004
|
||||
#define TIMER_ENABLE 0x0008
|
||||
@ -179,6 +181,15 @@ static u64 notrace msm_sched_clock_read(void)
|
||||
return msm_clocksource.read(&msm_clocksource);
|
||||
}
|
||||
|
||||
static unsigned long msm_read_current_timer(void)
|
||||
{
|
||||
return msm_clocksource.read(&msm_clocksource);
|
||||
}
|
||||
|
||||
static struct delay_timer msm_delay_timer = {
|
||||
.read_current_timer = msm_read_current_timer,
|
||||
};
|
||||
|
||||
static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq,
|
||||
bool percpu)
|
||||
{
|
||||
@ -217,6 +228,8 @@ err:
|
||||
if (res)
|
||||
pr_err("clocksource_register failed\n");
|
||||
sched_clock_register(msm_sched_clock_read, sched_bits, dgt_hz);
|
||||
msm_delay_timer.freq = dgt_hz;
|
||||
register_current_timer_delay(&msm_delay_timer);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_QCOM
|
||||
|
@ -1106,10 +1106,8 @@ static int sh_cmt_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
cmt = kzalloc(sizeof(*cmt), GFP_KERNEL);
|
||||
if (cmt == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
if (cmt == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = sh_cmt_setup(cmt, pdev);
|
||||
if (ret) {
|
||||
|
@ -533,10 +533,8 @@ static int sh_mtu2_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
mtu = kzalloc(sizeof(*mtu), GFP_KERNEL);
|
||||
if (mtu == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
if (mtu == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = sh_mtu2_setup(mtu, pdev);
|
||||
if (ret) {
|
||||
|
@ -498,7 +498,7 @@ static int sh_tmu_channel_setup(struct sh_tmu_channel *ch, unsigned int index,
|
||||
ch->base = tmu->mapbase + 8 + ch->index * 12;
|
||||
}
|
||||
|
||||
ch->irq = platform_get_irq(tmu->pdev, ch->index);
|
||||
ch->irq = platform_get_irq(tmu->pdev, index);
|
||||
if (ch->irq < 0) {
|
||||
dev_err(&tmu->pdev->dev, "ch%u: failed to get irq\n",
|
||||
ch->index);
|
||||
@ -644,10 +644,8 @@ static int sh_tmu_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
tmu = kzalloc(sizeof(*tmu), GFP_KERNEL);
|
||||
if (tmu == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
if (tmu == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = sh_tmu_setup(tmu, pdev);
|
||||
if (ret) {
|
||||
|
@ -272,4 +272,5 @@ static void __init efm32_timer_init(struct device_node *np)
|
||||
}
|
||||
}
|
||||
}
|
||||
CLOCKSOURCE_OF_DECLARE(efm32, "efm32,timer", efm32_timer_init);
|
||||
CLOCKSOURCE_OF_DECLARE(efm32compat, "efm32,timer", efm32_timer_init);
|
||||
CLOCKSOURCE_OF_DECLARE(efm32, "energymicro,efm32-timer", efm32_timer_init);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/sched_clock.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
@ -143,6 +144,7 @@ static u64 sun5i_timer_sched_read(void)
|
||||
|
||||
static void __init sun5i_timer_init(struct device_node *node)
|
||||
{
|
||||
struct reset_control *rstc;
|
||||
unsigned long rate;
|
||||
struct clk *clk;
|
||||
int ret, irq;
|
||||
@ -162,6 +164,10 @@ static void __init sun5i_timer_init(struct device_node *node)
|
||||
clk_prepare_enable(clk);
|
||||
rate = clk_get_rate(clk);
|
||||
|
||||
rstc = of_reset_control_get(node, NULL);
|
||||
if (!IS_ERR(rstc))
|
||||
reset_control_deassert(rstc);
|
||||
|
||||
writel(~0, timer_base + TIMER_INTVAL_LO_REG(1));
|
||||
writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
|
||||
timer_base + TIMER_CTL_REG(1));
|
||||
|
@ -14,7 +14,6 @@ extern void sched_clock_postinit(void);
|
||||
static inline void sched_clock_postinit(void) { }
|
||||
#endif
|
||||
|
||||
extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate);
|
||||
extern void sched_clock_register(u64 (*read)(void), int bits,
|
||||
unsigned long rate);
|
||||
|
||||
|
@ -165,21 +165,21 @@ static inline void pps_set_freq(s64 freq)
|
||||
|
||||
static inline int is_error_status(int status)
|
||||
{
|
||||
return (time_status & (STA_UNSYNC|STA_CLOCKERR))
|
||||
return (status & (STA_UNSYNC|STA_CLOCKERR))
|
||||
/* PPS signal lost when either PPS time or
|
||||
* PPS frequency synchronization requested
|
||||
*/
|
||||
|| ((time_status & (STA_PPSFREQ|STA_PPSTIME))
|
||||
&& !(time_status & STA_PPSSIGNAL))
|
||||
|| ((status & (STA_PPSFREQ|STA_PPSTIME))
|
||||
&& !(status & STA_PPSSIGNAL))
|
||||
/* PPS jitter exceeded when
|
||||
* PPS time synchronization requested */
|
||||
|| ((time_status & (STA_PPSTIME|STA_PPSJITTER))
|
||||
|| ((status & (STA_PPSTIME|STA_PPSJITTER))
|
||||
== (STA_PPSTIME|STA_PPSJITTER))
|
||||
/* PPS wander exceeded or calibration error when
|
||||
* PPS frequency synchronization requested
|
||||
*/
|
||||
|| ((time_status & STA_PPSFREQ)
|
||||
&& (time_status & (STA_PPSWANDER|STA_PPSERROR)));
|
||||
|| ((status & STA_PPSFREQ)
|
||||
&& (status & (STA_PPSWANDER|STA_PPSERROR)));
|
||||
}
|
||||
|
||||
static inline void pps_fill_timex(struct timex *txc)
|
||||
@ -923,7 +923,10 @@ void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
|
||||
|
||||
static int __init ntp_tick_adj_setup(char *str)
|
||||
{
|
||||
ntp_tick_adj = simple_strtol(str, NULL, 0);
|
||||
int rc = kstrtol(str, 0, (long *)&ntp_tick_adj);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
ntp_tick_adj <<= NTP_SCALE_SHIFT;
|
||||
|
||||
return 1;
|
||||
|
@ -49,13 +49,6 @@ static u64 notrace jiffy_sched_clock_read(void)
|
||||
return (u64)(jiffies - INITIAL_JIFFIES);
|
||||
}
|
||||
|
||||
static u32 __read_mostly (*read_sched_clock_32)(void);
|
||||
|
||||
static u64 notrace read_sched_clock_32_wrapper(void)
|
||||
{
|
||||
return read_sched_clock_32();
|
||||
}
|
||||
|
||||
static u64 __read_mostly (*read_sched_clock)(void) = jiffy_sched_clock_read;
|
||||
|
||||
static inline u64 notrace cyc_to_ns(u64 cyc, u32 mult, u32 shift)
|
||||
@ -176,12 +169,6 @@ void __init sched_clock_register(u64 (*read)(void), int bits,
|
||||
pr_debug("Registered %pF as sched_clock source\n", read);
|
||||
}
|
||||
|
||||
void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
|
||||
{
|
||||
read_sched_clock_32 = read;
|
||||
sched_clock_register(read_sched_clock_32_wrapper, bits, rate);
|
||||
}
|
||||
|
||||
void __init sched_clock_postinit(void)
|
||||
{
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user