summaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
authorJean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>2012-08-04 17:14:27 +0800
committerJean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>2012-10-04 18:54:12 +0800
commitebf6e1d052b6a846d0adab673385df6a427cfe51 (patch)
tree030bdf96fddb128411dea473ac4dfe88a8e244c5 /drivers/clocksource
parent0228863348ffb3938bb5115950e3737713b1c8f8 (diff)
downloadbarebox-ebf6e1d052b6a846d0adab673385df6a427cfe51.tar.gz
barebox-ebf6e1d052b6a846d0adab673385df6a427cfe51.tar.xz
arm: move nomadik timer to drivers/clocksource
as this timer is shared with multiple arch Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/Kconfig4
-rw-r--r--drivers/clocksource/Makefile1
-rw-r--r--drivers/clocksource/nomadik.c147
3 files changed, 152 insertions, 0 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 05c1f0a88e..9d6d293ee3 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -1,3 +1,7 @@
config ARM_SMP_TWD
bool
depends on ARM && CPU_V7
+
+config CLOCKSOURCE_NOMADIK
+ bool
+ depends on ARM
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 9186a5cf59..bef465cea7 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_ARM_SMP_TWD) += arm_smp_twd.o
+obj-$(CONFIG_CLOCKSOURCE_NOMADIK) += nomadik.o
diff --git a/drivers/clocksource/nomadik.c b/drivers/clocksource/nomadik.c
new file mode 100644
index 0000000000..8a3e6d930e
--- /dev/null
+++ b/drivers/clocksource/nomadik.c
@@ -0,0 +1,147 @@
+/*
+ * linux/arch/arm/mach-nomadik/timer.c
+ *
+ * Copyright (C) 2008 STMicroelectronics
+ * Copyright (C) 2009 Alessandro Rubini, somewhat based on at91sam926x
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+#include <common.h>
+#include <clock.h>
+#include <io.h>
+#include <init.h>
+#include <driver.h>
+#include <errno.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+/*
+ * The MTU device hosts four different counters, with 4 set of
+ * registers. These are register names.
+ */
+
+#define MTU_IMSC 0x00 /* Interrupt mask set/clear */
+#define MTU_RIS 0x04 /* Raw interrupt status */
+#define MTU_MIS 0x08 /* Masked interrupt status */
+#define MTU_ICR 0x0C /* Interrupt clear register */
+
+/* per-timer registers take 0..3 as argument */
+#define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */
+#define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */
+#define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */
+#define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */
+
+/* bits for the control register */
+#define MTU_CRn_ENA 0x80
+#define MTU_CRn_PERIODIC 0x40 /* if 0 = free-running */
+#define MTU_CRn_PRESCALE_MASK 0x0c
+#define MTU_CRn_PRESCALE_1 0x00
+#define MTU_CRn_PRESCALE_16 0x04
+#define MTU_CRn_PRESCALE_256 0x08
+#define MTU_CRn_32BITS 0x02
+#define MTU_CRn_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR*/
+
+/* Other registers are usual amba/primecell registers, currently not used */
+#define MTU_ITCR 0xff0
+#define MTU_ITOP 0xff4
+
+#define MTU_PERIPH_ID0 0xfe0
+#define MTU_PERIPH_ID1 0xfe4
+#define MTU_PERIPH_ID2 0xfe8
+#define MTU_PERIPH_ID3 0xfeC
+
+#define MTU_PCELL0 0xff0
+#define MTU_PCELL1 0xff4
+#define MTU_PCELL2 0xff8
+#define MTU_PCELL3 0xffC
+
+static __iomem void *mtu_base;
+static u32 clk_prescale;
+static u32 nmdk_cycle; /* write-once */
+
+/*
+ * clocksource: the MTU device is a decrementing counters, so we negate
+ * the value being read.
+ */
+static uint64_t nmdk_read_timer(void)
+{
+ return nmdk_cycle - readl(mtu_base + MTU_VAL(0));
+}
+
+static struct clocksource nmdk_clksrc = {
+ .read = nmdk_read_timer,
+ .shift = 20,
+ .mask = CLOCKSOURCE_MASK(32),
+};
+
+static void nmdk_timer_reset(void)
+{
+ u32 cr;
+
+ /* Disable */
+ writel(0, mtu_base + MTU_CR(0)); /* off */
+
+ /* configure load and background-load, and fire it up */
+ writel(nmdk_cycle, mtu_base + MTU_LR(0));
+ writel(nmdk_cycle, mtu_base + MTU_BGLR(0));
+
+ cr = clk_prescale | MTU_CRn_32BITS;
+ writel(cr, mtu_base + MTU_CR(0));
+ writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
+}
+
+static int nmdk_mtu_probe(struct device_d *dev)
+{
+ static struct clk *mtu_clk;
+ u32 rate;
+ int ret;
+
+ mtu_clk = clk_get(dev, NULL);
+ if (IS_ERR(mtu_clk)) {
+ ret = PTR_ERR(mtu_clk);
+ dev_err(dev, "clock not found: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(mtu_clk);
+ if (ret < 0) {
+ dev_err(dev, "clock failed to enable: %d\n", ret);
+ clk_put(mtu_clk);
+ return ret;
+ }
+
+ rate = clk_get_rate(mtu_clk);
+ if (rate > 32000000) {
+ rate /= 16;
+ clk_prescale = MTU_CRn_PRESCALE_16;
+ } else {
+ clk_prescale = MTU_CRn_PRESCALE_1;
+ }
+
+ nmdk_cycle = (rate + 1000 / 2) / 1000;
+
+ /* Save global pointer to mtu, used by functions above */
+ mtu_base = dev_request_mem_region(dev, 0);
+
+ /* Init the timer and register clocksource */
+ nmdk_timer_reset();
+
+ nmdk_clksrc.mult = clocksource_hz2mult(rate, nmdk_clksrc.shift);
+
+ init_clock(&nmdk_clksrc);
+
+ return 0;
+}
+
+static struct driver_d nmdk_mtu_driver = {
+ .name = "nomadik_mtu",
+ .probe = nmdk_mtu_probe,
+};
+
+static int nmdk_mtu_init(void)
+{
+ return platform_driver_register(&nmdk_mtu_driver);
+}
+coredevice_initcall(nmdk_mtu_init);