ソースを参照

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
  ...
Linus Torvalds 11 年 前
コミット
82e627eb5e

+ 5 - 2
Documentation/devicetree/bindings/arm/global_timer.txt

@@ -4,8 +4,11 @@
 
 
 ** Timer node required properties:
 ** 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
 - interrupts : One interrupt to each core
 
 

+ 4 - 0
Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt

@@ -9,6 +9,9 @@ Required properties:
 		one)
 		one)
 - clocks: phandle to the source clock (usually the AHB clock)
 - clocks: phandle to the source clock (usually the AHB clock)
 
 
+Optionnal properties:
+- resets: phandle to a reset controller asserting the timer
+
 Example:
 Example:
 
 
 timer@01c60000 {
 timer@01c60000 {
@@ -19,4 +22,5 @@ timer@01c60000 {
 		     <0 53 1>,
 		     <0 53 1>,
 		     <0 54 1>;
 		     <0 54 1>;
 	clocks = <&ahb1_gates 19>;
 	clocks = <&ahb1_gates 19>;
+	resets = <&ahb1rst 19>;
 };
 };

+ 2 - 2
Documentation/devicetree/bindings/timer/efm32,timer.txt → Documentation/devicetree/bindings/timer/energymicro,efm32-timer.txt

@@ -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.
 are the cpu's HFPERCLK (with a 10-bit prescaler) or an external pin.
 
 
 Required properties:
 Required properties:
-- compatible : Should be efm32,timer
+- compatible : Should be "energymicro,efm32-timer"
 - reg : Address and length of the register set
 - reg : Address and length of the register set
 - clocks : Should contain a reference to the HFPERCLK
 - clocks : Should contain a reference to the HFPERCLK
 
 
@@ -16,7 +16,7 @@ Optional properties:
 Example:
 Example:
 
 
 timer@40010c00 {
 timer@40010c00 {
-	compatible = "efm32,timer";
+	compatible = "energymicro,efm32-timer";
 	reg = <0x40010c00 0x400>;
 	reg = <0x40010c00 0x400>;
 	interrupts = <14>;
 	interrupts = <14>;
 	clocks = <&cmu clk_HFPERCLKTIMER3>;
 	clocks = <&cmu clk_HFPERCLKTIMER3>;

+ 31 - 0
Documentation/devicetree/bindings/timer/fsl,ftm-timer.txt

@@ -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;
+};

+ 3 - 3
Documentation/timers/timer_stats.txt

@@ -39,9 +39,9 @@ To stop a sample period issue:
 The statistics can be retrieved by:
 The statistics can be retrieved by:
 # cat /proc/timer_stats
 # 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:
 Sample output of /proc/timer_stats:
 
 

+ 11 - 0
arch/arm/boot/dts/sun6i-a31.dtsi

@@ -621,6 +621,17 @@
 			status = "disabled";
 			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 {
 		spi0: spi@01c68000 {
 			compatible = "allwinner,sun6i-a31-spi";
 			compatible = "allwinner,sun6i-a31-spi";
 			reg = <0x01c68000 0x1000>;
 			reg = <0x01c68000 0x1000>;

+ 9 - 1
arch/arm/boot/dts/vexpress-v2p-ca5s.dts

@@ -88,6 +88,14 @@
 		interrupts = <1 13 0x304>;
 		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 {
 	watchdog@2c000620 {
 		compatible = "arm,cortex-a5-twd-wdt";
 		compatible = "arm,cortex-a5-twd-wdt";
 		reg = <0x2c000620 0x20>;
 		reg = <0x2c000620 0x20>;
@@ -120,7 +128,7 @@
 		compatible = "arm,vexpress,config-bus";
 		compatible = "arm,vexpress,config-bus";
 		arm,vexpress,config-bridge = <&v2m_sysreg>;
 		arm,vexpress,config-bridge = <&v2m_sysreg>;
 
 
-		osc@0 {
+		oscclk0: osc@0 {
 			/* CPU and internal AXI reference clock */
 			/* CPU and internal AXI reference clock */
 			compatible = "arm,vexpress-osc";
 			compatible = "arm,vexpress-osc";
 			arm,vexpress-sysreg,func = <1 0>;
 			arm,vexpress-sysreg,func = <1 0>;

+ 13 - 0
arch/arm/boot/dts/vf610.dtsi

@@ -371,6 +371,19 @@
 				status = "disabled";
 				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 {
 			fec0: ethernet@400d0000 {
 				compatible = "fsl,mvf600-fec";
 				compatible = "fsl,mvf600-fec";
 				reg = <0x400d0000 0x1000>;
 				reg = <0x400d0000 0x1000>;

+ 1 - 0
arch/arm/mach-vexpress/Kconfig

@@ -4,6 +4,7 @@ config ARCH_VEXPRESS
 	select ARCH_SUPPORTS_BIG_ENDIAN
 	select ARCH_SUPPORTS_BIG_ENDIAN
 	select ARM_AMBA
 	select ARM_AMBA
 	select ARM_GIC
 	select ARM_GIC
+	select ARM_GLOBAL_TIMER
 	select ARM_TIMER_SP804
 	select ARM_TIMER_SP804
 	select COMMON_CLK_VERSATILE
 	select COMMON_CLK_VERSATILE
 	select HAVE_ARM_SCU if SMP
 	select HAVE_ARM_SCU if SMP

+ 5 - 0
drivers/clocksource/Kconfig

@@ -136,6 +136,11 @@ config CLKSRC_SAMSUNG_PWM
 	  for all devicetree enabled platforms. This driver will be
 	  for all devicetree enabled platforms. This driver will be
 	  needed only on systems that do not have the Exynos MCT available.
 	  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
 config VF_PIT_TIMER
 	bool
 	bool
 	help
 	help

+ 1 - 0
drivers/clocksource/Makefile

@@ -31,6 +31,7 @@ obj-$(CONFIG_CADENCE_TTC_TIMER)	+= cadence_ttc_timer.o
 obj-$(CONFIG_CLKSRC_EFM32)	+= time-efm32.o
 obj-$(CONFIG_CLKSRC_EFM32)	+= time-efm32.o
 obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
 obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
 obj-$(CONFIG_CLKSRC_SAMSUNG_PWM)	+= samsung_pwm_timer.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_VF_PIT_TIMER)	+= vf_pit_timer.o
 obj-$(CONFIG_CLKSRC_QCOM)	+= qcom-timer.o
 obj-$(CONFIG_CLKSRC_QCOM)	+= qcom-timer.o
 
 

+ 3 - 2
drivers/clocksource/arm_global_timer.c

@@ -246,11 +246,12 @@ static void __init global_timer_of_register(struct device_node *np)
 	int err = 0;
 	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
 	 * fire when the timer value is greater than or equal to. In previous
 	 * revisions the comparators fired when the timer value was equal to.
 	 * 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");
 		pr_warn("global-timer: non support for this cpu version.\n");
 		return;
 		return;
 	}
 	}

+ 1 - 1
drivers/clocksource/dw_apb_timer_of.c

@@ -106,7 +106,7 @@ static void __init add_clocksource(struct device_node *source_timer)
 	sched_rate = rate;
 	sched_rate = rate;
 }
 }
 
 
-static u64 read_sched_clock(void)
+static u64 notrace read_sched_clock(void)
 {
 {
 	return ~__raw_readl(sched_io_base);
 	return ~__raw_readl(sched_io_base);
 }
 }

+ 1 - 3
drivers/clocksource/em_sti.c

@@ -318,10 +318,8 @@ static int em_sti_probe(struct platform_device *pdev)
 	int irq;
 	int irq;
 
 
 	p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
 	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;
 		return -ENOMEM;
-	}
 
 
 	p->pdev = pdev;
 	p->pdev = pdev;
 	platform_set_drvdata(pdev, p);
 	platform_set_drvdata(pdev, p);

+ 367 - 0
drivers/clocksource/fsl_ftm_timer.c

@@ -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);

+ 4 - 4
drivers/clocksource/mmio.c

@@ -22,22 +22,22 @@ static inline struct clocksource_mmio *to_mmio_clksrc(struct clocksource *c)
 
 
 cycle_t clocksource_mmio_readl_up(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)
 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)
 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)
 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;
 }
 }
 
 
 /**
 /**

+ 13 - 0
drivers/clocksource/qcom-timer.c

@@ -26,6 +26,8 @@
 #include <linux/of_irq.h>
 #include <linux/of_irq.h>
 #include <linux/sched_clock.h>
 #include <linux/sched_clock.h>
 
 
+#include <asm/delay.h>
+
 #define TIMER_MATCH_VAL			0x0000
 #define TIMER_MATCH_VAL			0x0000
 #define TIMER_COUNT_VAL			0x0004
 #define TIMER_COUNT_VAL			0x0004
 #define TIMER_ENABLE			0x0008
 #define TIMER_ENABLE			0x0008
@@ -179,6 +181,15 @@ static u64 notrace msm_sched_clock_read(void)
 	return msm_clocksource.read(&msm_clocksource);
 	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,
 static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq,
 				  bool percpu)
 				  bool percpu)
 {
 {
@@ -217,6 +228,8 @@ err:
 	if (res)
 	if (res)
 		pr_err("clocksource_register failed\n");
 		pr_err("clocksource_register failed\n");
 	sched_clock_register(msm_sched_clock_read, sched_bits, dgt_hz);
 	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
 #ifdef CONFIG_ARCH_QCOM

+ 1 - 3
drivers/clocksource/sh_cmt.c

@@ -1106,10 +1106,8 @@ static int sh_cmt_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	cmt = kzalloc(sizeof(*cmt), GFP_KERNEL);
 	cmt = kzalloc(sizeof(*cmt), GFP_KERNEL);
-	if (cmt == NULL) {
-		dev_err(&pdev->dev, "failed to allocate driver data\n");
+	if (cmt == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
-	}
 
 
 	ret = sh_cmt_setup(cmt, pdev);
 	ret = sh_cmt_setup(cmt, pdev);
 	if (ret) {
 	if (ret) {

+ 1 - 3
drivers/clocksource/sh_mtu2.c

@@ -533,10 +533,8 @@ static int sh_mtu2_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	mtu = kzalloc(sizeof(*mtu), GFP_KERNEL);
 	mtu = kzalloc(sizeof(*mtu), GFP_KERNEL);
-	if (mtu == NULL) {
-		dev_err(&pdev->dev, "failed to allocate driver data\n");
+	if (mtu == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
-	}
 
 
 	ret = sh_mtu2_setup(mtu, pdev);
 	ret = sh_mtu2_setup(mtu, pdev);
 	if (ret) {
 	if (ret) {

+ 2 - 4
drivers/clocksource/sh_tmu.c

@@ -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->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) {
 	if (ch->irq < 0) {
 		dev_err(&tmu->pdev->dev, "ch%u: failed to get irq\n",
 		dev_err(&tmu->pdev->dev, "ch%u: failed to get irq\n",
 			ch->index);
 			ch->index);
@@ -644,10 +644,8 @@ static int sh_tmu_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	tmu = kzalloc(sizeof(*tmu), GFP_KERNEL);
 	tmu = kzalloc(sizeof(*tmu), GFP_KERNEL);
-	if (tmu == NULL) {
-		dev_err(&pdev->dev, "failed to allocate driver data\n");
+	if (tmu == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
-	}
 
 
 	ret = sh_tmu_setup(tmu, pdev);
 	ret = sh_tmu_setup(tmu, pdev);
 	if (ret) {
 	if (ret) {

+ 2 - 1
drivers/clocksource/time-efm32.c

@@ -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);

+ 6 - 0
drivers/clocksource/timer-sun5i.c

@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irq.h>
 #include <linux/irqreturn.h>
 #include <linux/irqreturn.h>
+#include <linux/reset.h>
 #include <linux/sched_clock.h>
 #include <linux/sched_clock.h>
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_address.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)
 static void __init sun5i_timer_init(struct device_node *node)
 {
 {
+	struct reset_control *rstc;
 	unsigned long rate;
 	unsigned long rate;
 	struct clk *clk;
 	struct clk *clk;
 	int ret, irq;
 	int ret, irq;
@@ -162,6 +164,10 @@ static void __init sun5i_timer_init(struct device_node *node)
 	clk_prepare_enable(clk);
 	clk_prepare_enable(clk);
 	rate = clk_get_rate(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(~0, timer_base + TIMER_INTVAL_LO_REG(1));
 	writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
 	writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
 	       timer_base + TIMER_CTL_REG(1));
 	       timer_base + TIMER_CTL_REG(1));

+ 0 - 1
include/linux/sched_clock.h

@@ -14,7 +14,6 @@ extern void sched_clock_postinit(void);
 static inline void sched_clock_postinit(void) { }
 static inline void sched_clock_postinit(void) { }
 #endif
 #endif
 
 
-extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate);
 extern void sched_clock_register(u64 (*read)(void), int bits,
 extern void sched_clock_register(u64 (*read)(void), int bits,
 				 unsigned long rate);
 				 unsigned long rate);
 
 

+ 10 - 7
kernel/time/ntp.c

@@ -165,21 +165,21 @@ static inline void pps_set_freq(s64 freq)
 
 
 static inline int is_error_status(int status)
 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 signal lost when either PPS time or
 		 * PPS frequency synchronization requested
 		 * 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 jitter exceeded when
 		 * PPS time synchronization requested */
 		 * PPS time synchronization requested */
-		|| ((time_status & (STA_PPSTIME|STA_PPSJITTER))
+		|| ((status & (STA_PPSTIME|STA_PPSJITTER))
 			== (STA_PPSTIME|STA_PPSJITTER))
 			== (STA_PPSTIME|STA_PPSJITTER))
 		/* PPS wander exceeded or calibration error when
 		/* PPS wander exceeded or calibration error when
 		 * PPS frequency synchronization requested
 		 * 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)
 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)
 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;
 	ntp_tick_adj <<= NTP_SCALE_SHIFT;
 
 
 	return 1;
 	return 1;

+ 0 - 13
kernel/time/sched_clock.c

@@ -49,13 +49,6 @@ static u64 notrace jiffy_sched_clock_read(void)
 	return (u64)(jiffies - INITIAL_JIFFIES);
 	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 u64 __read_mostly (*read_sched_clock)(void) = jiffy_sched_clock_read;
 
 
 static inline u64 notrace cyc_to_ns(u64 cyc, u32 mult, u32 shift)
 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);
 	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)
 void __init sched_clock_postinit(void)
 {
 {
 	/*
 	/*