summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2014-11-20 17:13:55 +0100
committerArnd Bergmann <arnd@arndb.de>2014-11-20 17:13:55 +0100
commit4eca459bc10d8400407d0fc04e90dac45b571c87 (patch)
tree02dac5128653db41bc732c3649402b99d70d4c41
parentd686ce4204c5dc131396f1fca81beebc46cb8cdb (diff)
parentf956a785a282f6b5a3e7d59937548f8b7c04d1ac (diff)
Merge tag 'integrator-v3.19-arm-soc-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator into next/soc
Pull "ARM SoC Integrator updates for v3.19" from Linus Walleij: Integrator updates for the v3.19 merge cycle on top of the multiplatform patches, this moves out some drivers and reduced the amount of code carried in arch/arm/mach-integrator. - Move the Integrator/AP timer to drivers/clocksource - Move the restart functionality to the device tree, patches to enable restart for the Integrator have been merged to the reset tree (orthogonal) - Move debug LEDs to device tree (using the syscon LED driver merged for v3.18) - Move core module LEDs to device tree (using the syscon LED driver merged for v3.18) - Move the SoC driver (chip ID etc) to drivers/soc/versatile/soc-integrator.c * tag 'integrator-v3.19-arm-soc-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator: soc: move SoC driver for the ARM Integrator ARM: integrator: move core module LED to device tree ARM: integrator: move debug LEDs to syscon LED driver ARM: integrator: move restart to the device tree ARM: integrator: move AP timer to clocksource Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r--arch/arm/boot/dts/integrator.dtsi48
-rw-r--r--arch/arm/mach-integrator/Kconfig5
-rw-r--r--arch/arm/mach-integrator/Makefile2
-rw-r--r--arch/arm/mach-integrator/cm.h1
-rw-r--r--arch/arm/mach-integrator/common.h2
-rw-r--r--arch/arm/mach-integrator/core.c103
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c218
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c28
-rw-r--r--arch/arm/mach-integrator/leds.c124
-rw-r--r--drivers/clocksource/Makefile1
-rw-r--r--drivers/clocksource/timer-integrator-ap.c210
-rw-r--r--drivers/soc/versatile/Kconfig9
-rw-r--r--drivers/soc/versatile/Makefile1
-rw-r--r--drivers/soc/versatile/soc-integrator.c154
14 files changed, 428 insertions, 478 deletions
diff --git a/arch/arm/boot/dts/integrator.dtsi b/arch/arm/boot/dts/integrator.dtsi
index 88e3d477bf16..28e38f8c6b0f 100644
--- a/arch/arm/boot/dts/integrator.dtsi
+++ b/arch/arm/boot/dts/integrator.dtsi
@@ -6,8 +6,18 @@
/ {
core-module@10000000 {
- compatible = "arm,core-module-integrator";
+ compatible = "arm,core-module-integrator", "syscon";
reg = <0x10000000 0x200>;
+
+ /* Use core module LED to indicate CPU load */
+ led@0c.0 {
+ compatible = "register-bit-led";
+ offset = <0x0c>;
+ mask = <0x01>;
+ label = "integrator:core_module";
+ linux,default-trigger = "cpu0";
+ default-state = "on";
+ };
};
ebi@12000000 {
@@ -82,5 +92,41 @@
reg = <0x19000000 0x1000>;
interrupts = <4>;
};
+
+ syscon {
+ /* Debug registers mapped as syscon */
+ compatible = "syscon";
+ reg = <0x1a000000 0x10>;
+
+ led@04.0 {
+ compatible = "register-bit-led";
+ offset = <0x04>;
+ mask = <0x01>;
+ label = "integrator:green0";
+ linux,default-trigger = "heartbeat";
+ default-state = "on";
+ };
+ led@04.1 {
+ compatible = "register-bit-led";
+ offset = <0x04>;
+ mask = <0x02>;
+ label = "integrator:yellow";
+ default-state = "off";
+ };
+ led@04.2 {
+ compatible = "register-bit-led";
+ offset = <0x04>;
+ mask = <0x04>;
+ label = "integrator:red";
+ default-state = "off";
+ };
+ led@04.3 {
+ compatible = "register-bit-led";
+ offset = <0x04>;
+ mask = <0x08>;
+ label = "integrator:green1";
+ default-state = "off";
+ };
+ };
};
};
diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig
index aa7eb272e602..02d083489a26 100644
--- a/arch/arm/mach-integrator/Kconfig
+++ b/arch/arm/mach-integrator/Kconfig
@@ -8,8 +8,13 @@ config ARCH_INTEGRATOR
select GENERIC_CLOCKEVENTS
select HAVE_TCM
select ICST
+ select MFD_SYSCON
select MULTI_IRQ_HANDLER
select PLAT_VERSATILE
+ select POWER_RESET
+ select POWER_RESET_VERSATILE
+ select POWER_SUPPLY
+ select SOC_INTEGRATOR_CM
select SPARSE_IRQ
select USE_OF
select VERSATILE_FPGA_IRQ
diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile
index ec759ded7b60..1ebe45356b09 100644
--- a/arch/arm/mach-integrator/Makefile
+++ b/arch/arm/mach-integrator/Makefile
@@ -4,7 +4,7 @@
# Object file lists.
-obj-y := core.o lm.o leds.o
+obj-y := core.o lm.o
obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o
obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o
diff --git a/arch/arm/mach-integrator/cm.h b/arch/arm/mach-integrator/cm.h
index 4ecff7bff482..5b8ba8247f45 100644
--- a/arch/arm/mach-integrator/cm.h
+++ b/arch/arm/mach-integrator/cm.h
@@ -11,7 +11,6 @@ void cm_clear_irqs(void);
#define CM_CTRL_LED (1 << 0)
#define CM_CTRL_nMBDET (1 << 1)
#define CM_CTRL_REMAP (1 << 2)
-#define CM_CTRL_RESET (1 << 3)
/*
* Integrator/AP,PP2 specific
diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h
index ad0ac5547b2c..96c9dc56cabf 100644
--- a/arch/arm/mach-integrator/common.h
+++ b/arch/arm/mach-integrator/common.h
@@ -4,5 +4,3 @@ extern struct amba_pl010_data ap_uart_data;
void integrator_init_early(void);
int integrator_init(bool is_cp);
void integrator_reserve(void);
-void integrator_restart(enum reboot_mode, const char *);
-void integrator_init_sysfs(struct device *parent, u32 id);
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index e3f3aca43efb..948872a419c1 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -60,40 +60,6 @@ void cm_control(u32 mask, u32 set)
raw_spin_unlock_irqrestore(&cm_lock, flags);
}
-static const char *integrator_arch_str(u32 id)
-{
- switch ((id >> 16) & 0xff) {
- case 0x00:
- return "ASB little-endian";
- case 0x01:
- return "AHB little-endian";
- case 0x03:
- return "AHB-Lite system bus, bi-endian";
- case 0x04:
- return "AHB";
- case 0x08:
- return "AHB system bus, ASB processor bus";
- default:
- return "Unknown";
- }
-}
-
-static const char *integrator_fpga_str(u32 id)
-{
- switch ((id >> 12) & 0xf) {
- case 0x01:
- return "XC4062";
- case 0x02:
- return "XC4085";
- case 0x03:
- return "XVC600";
- case 0x04:
- return "EPM7256AE (Altera PLD)";
- default:
- return "Unknown";
- }
-}
-
void cm_clear_irqs(void)
{
/* disable core module IRQs */
@@ -109,7 +75,6 @@ static const struct of_device_id cm_match[] = {
void cm_init(void)
{
struct device_node *cm = of_find_matching_node(NULL, cm_match);
- u32 val;
if (!cm) {
pr_crit("no core module node found in device tree\n");
@@ -121,13 +86,6 @@ void cm_init(void)
return;
}
cm_clear_irqs();
- val = readl(cm_base + INTEGRATOR_HDR_ID_OFFSET);
- pr_info("Detected ARM core module:\n");
- pr_info(" Manufacturer: %02x\n", (val >> 24));
- pr_info(" Architecture: %s\n", integrator_arch_str(val));
- pr_info(" FPGA: %s\n", integrator_fpga_str(val));
- pr_info(" Build: %02x\n", (val >> 4) & 0xFF);
- pr_info(" Rev: %c\n", ('A' + (val & 0x03)));
}
/*
@@ -139,64 +97,3 @@ void __init integrator_reserve(void)
{
memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET);
}
-
-/*
- * To reset, we hit the on-board reset register in the system FPGA
- */
-void integrator_restart(enum reboot_mode mode, const char *cmd)
-{
- cm_control(CM_CTRL_RESET, CM_CTRL_RESET);
-}
-
-static u32 integrator_id;
-
-static ssize_t intcp_get_manf(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%02x\n", integrator_id >> 24);
-}
-
-static struct device_attribute intcp_manf_attr =
- __ATTR(manufacturer, S_IRUGO, intcp_get_manf, NULL);
-
-static ssize_t intcp_get_arch(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%s\n", integrator_arch_str(integrator_id));
-}
-
-static struct device_attribute intcp_arch_attr =
- __ATTR(architecture, S_IRUGO, intcp_get_arch, NULL);
-
-static ssize_t intcp_get_fpga(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%s\n", integrator_fpga_str(integrator_id));
-}
-
-static struct device_attribute intcp_fpga_attr =
- __ATTR(fpga, S_IRUGO, intcp_get_fpga, NULL);
-
-static ssize_t intcp_get_build(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%02x\n", (integrator_id >> 4) & 0xFF);
-}
-
-static struct device_attribute intcp_build_attr =
- __ATTR(build, S_IRUGO, intcp_get_build, NULL);
-
-
-
-void integrator_init_sysfs(struct device *parent, u32 id)
-{
- integrator_id = id;
- device_create_file(parent, &intcp_manf_attr);
- device_create_file(parent, &intcp_arch_attr);
- device_create_file(parent, &intcp_fpga_attr);
- device_create_file(parent, &intcp_build_attr);
-}
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 8ca290b479b1..30003ba447a5 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -27,22 +27,15 @@
#include <linux/syscore_ops.h>
#include <linux/amba/bus.h>
#include <linux/amba/kmi.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irqchip.h>
#include <linux/mtd/physmap.h>
-#include <linux/clk.h>
#include <linux/platform_data/clk-integrator.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/stat.h>
-#include <linux/sys_soc.h>
#include <linux/termios.h>
-#include <linux/sched_clock.h>
-#include <linux/clk-provider.h>
#include <asm/hardware/arm_timer.h>
#include <asm/setup.h>
@@ -89,11 +82,6 @@ static void __iomem *ebi_base;
static struct map_desc ap_io_desc[] __initdata __maybe_unused = {
{
- .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE),
- .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
.virtual = IO_ADDRESS(INTEGRATOR_IC_BASE),
.pfn = __phys_to_pfn(INTEGRATOR_IC_BASE),
.length = SZ_4K,
@@ -257,188 +245,10 @@ struct amba_pl010_data ap_uart_data = {
.set_mctrl = integrator_uart_set_mctrl,
};
-/*
- * Where is the timer (VA)?
- */
-#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE)
-#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE)
-#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE)
-
-static unsigned long timer_reload;
-
-static u64 notrace integrator_read_sched_clock(void)
-{
- return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE);
-}
-
-static void integrator_clocksource_init(unsigned long inrate,
- void __iomem *base)
-{
- u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
- unsigned long rate = inrate;
-
- if (rate >= 1500000) {
- rate /= 16;
- ctrl |= TIMER_CTRL_DIV16;
- }
-
- writel(0xffff, base + TIMER_LOAD);
- writel(ctrl, base + TIMER_CTRL);
-
- clocksource_mmio_init(base + TIMER_VALUE, "timer2",
- rate, 200, 16, clocksource_mmio_readl_down);
- sched_clock_register(integrator_read_sched_clock, 16, rate);
-}
-
-static void __iomem * clkevt_base;
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
-{
- struct clock_event_device *evt = dev_id;
-
- /* clear the interrupt */
- writel(1, clkevt_base + TIMER_INTCLR);
-
- evt->event_handler(evt);
-
- return IRQ_HANDLED;
-}
-
-static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
-{
- u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
-
- /* Disable timer */
- writel(ctrl, clkevt_base + TIMER_CTRL);
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- /* Enable the timer and start the periodic tick */
- writel(timer_reload, clkevt_base + TIMER_LOAD);
- ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
- writel(ctrl, clkevt_base + TIMER_CTRL);
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- /* Leave the timer disabled, .set_next_event will enable it */
- ctrl &= ~TIMER_CTRL_PERIODIC;
- writel(ctrl, clkevt_base + TIMER_CTRL);
- break;
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_RESUME:
- default:
- /* Just leave in disabled state */
- break;
- }
-
-}
-
-static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
-{
- unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
-
- writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
- writel(next, clkevt_base + TIMER_LOAD);
- writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
-
- return 0;
-}
-
-static struct clock_event_device integrator_clockevent = {
- .name = "timer1",
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .set_mode = clkevt_set_mode,
- .set_next_event = clkevt_set_next_event,
- .rating = 300,
-};
-
-static struct irqaction integrator_timer_irq = {
- .name = "timer",
- .flags = IRQF_TIMER | IRQF_IRQPOLL,
- .handler = integrator_timer_interrupt,
- .dev_id = &integrator_clockevent,
-};
-
-static void integrator_clockevent_init(unsigned long inrate,
- void __iomem *base, int irq)
-{
- unsigned long rate = inrate;
- unsigned int ctrl = 0;
-
- clkevt_base = base;
- /* Calculate and program a divisor */
- if (rate > 0x100000 * HZ) {
- rate /= 256;
- ctrl |= TIMER_CTRL_DIV256;
- } else if (rate > 0x10000 * HZ) {
- rate /= 16;
- ctrl |= TIMER_CTRL_DIV16;
- }
- timer_reload = rate / HZ;
- writel(ctrl, clkevt_base + TIMER_CTRL);
-
- setup_irq(irq, &integrator_timer_irq);
- clockevents_config_and_register(&integrator_clockevent,
- rate,
- 1,
- 0xffffU);
-}
-
void __init ap_init_early(void)
{
}
-static void __init ap_of_timer_init(void)
-{
- struct device_node *node;
- const char *path;
- void __iomem *base;
- int err;
- int irq;
- struct clk *clk;
- unsigned long rate;
-
- of_clk_init(NULL);
-
- err = of_property_read_string(of_aliases,
- "arm,timer-primary", &path);
- if (WARN_ON(err))
- return;
- node = of_find_node_by_path(path);
- base = of_iomap(node, 0);
- if (WARN_ON(!base))
- return;
-
- clk = of_clk_get(node, 0);
- BUG_ON(IS_ERR(clk));
- clk_prepare_enable(clk);
- rate = clk_get_rate(clk);
-
- writel(0, base + TIMER_CTRL);
- integrator_clocksource_init(rate, base);
-
- err = of_property_read_string(of_aliases,
- "arm,timer-secondary", &path);
- if (WARN_ON(err))
- return;
- node = of_find_node_by_path(path);
- base = of_iomap(node, 0);
- if (WARN_ON(!base))
- return;
- irq = irq_of_parse_and_map(node, 0);
-
- clk = of_clk_get(node, 0);
- BUG_ON(IS_ERR(clk));
- clk_prepare_enable(clk);
- rate = clk_get_rate(clk);
-
- writel(0, base + TIMER_CTRL);
- integrator_clockevent_init(rate, base, irq);
-}
-
static void __init ap_init_irq_of(void)
{
cm_init();
@@ -477,10 +287,6 @@ static void __init ap_init_of(void)
unsigned long sc_dec;
struct device_node *syscon;
struct device_node *ebi;
- struct device *parent;
- struct soc_device *soc_dev;
- struct soc_device_attribute *soc_dev_attr;
- u32 ap_sc_id;
int i;
syscon = of_find_matching_node(NULL, ap_syscon_match);
@@ -500,28 +306,6 @@ static void __init ap_init_of(void)
of_platform_populate(NULL, of_default_bus_match_table,
ap_auxdata_lookup, NULL);
- ap_sc_id = readl(ap_syscon_base);
-
- soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
- if (!soc_dev_attr)
- return;
-
- soc_dev_attr->soc_id = "XVC";
- soc_dev_attr->machine = "Integrator/AP";
- soc_dev_attr->family = "Integrator";
- soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c",
- 'A' + (ap_sc_id & 0x0f));
-
- soc_dev = soc_device_register(soc_dev_attr);
- if (IS_ERR(soc_dev)) {
- kfree(soc_dev_attr->revision);
- kfree(soc_dev_attr);
- return;
- }
-
- parent = soc_device_to_device(soc_dev);
- integrator_init_sysfs(parent, ap_sc_id);
-
sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET);
for (i = 0; i < 4; i++) {
struct lm_device *lmdev;
@@ -553,8 +337,6 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)")
.map_io = ap_map_io,
.init_early = ap_init_early,
.init_irq = ap_init_irq_of,
- .init_time = ap_of_timer_init,
.init_machine = ap_init_of,
- .restart = integrator_restart,
.dt_compat = ap_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index cca02eb75eb5..b5fb71a36ee6 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -27,7 +27,6 @@
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
-#include <linux/sys_soc.h>
#include <linux/sched_clock.h>
#include <asm/setup.h>
@@ -274,10 +273,6 @@ static const struct of_device_id intcp_syscon_match[] = {
static void __init intcp_init_of(void)
{
struct device_node *cpcon;
- struct device *parent;
- struct soc_device *soc_dev;
- struct soc_device_attribute *soc_dev_attr;
- u32 intcp_sc_id;
cpcon = of_find_matching_node(NULL, intcp_syscon_match);
if (!cpcon)
@@ -289,28 +284,6 @@ static void __init intcp_init_of(void)
of_platform_populate(NULL, of_default_bus_match_table,
intcp_auxdata_lookup, NULL);
-
- intcp_sc_id = readl(intcp_con_base);
-
- soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
- if (!soc_dev_attr)
- return;
-
- soc_dev_attr->soc_id = "XCV";
- soc_dev_attr->machine = "Integrator/CP";
- soc_dev_attr->family = "Integrator";
- soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c",
- 'A' + (intcp_sc_id & 0x0f));
-
- soc_dev = soc_device_register(soc_dev_attr);
- if (IS_ERR(soc_dev)) {
- kfree(soc_dev_attr->revision);
- kfree(soc_dev_attr);
- return;
- }
-
- parent = soc_device_to_device(soc_dev);
- integrator_init_sysfs(parent, intcp_sc_id);
}
static const char * intcp_dt_board_compat[] = {
@@ -324,6 +297,5 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)")
.init_early = intcp_init_early,
.init_irq = intcp_init_irq_of,
.init_machine = intcp_init_of,
- .restart = integrator_restart,
.dt_compat = intcp_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c
deleted file mode 100644
index f1dcb57a59e2..000000000000
--- a/arch/arm/mach-integrator/leds.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard
- * Based on Versatile and RealView machine LED code
- *
- * License terms: GNU General Public License (GPL) version 2
- * Author: Bryan Wu <bryan.wu@canonical.com>
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/leds.h>
-
-#include "hardware.h"
-#include "cm.h"
-
-#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
-
-#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE)
-#define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET)
-
-struct integrator_led {
- struct led_classdev cdev;
- u8 mask;
-};
-
-/*
- * The triggers lines up below will only be used if the
- * LED triggers are compiled in.
- */
-static const struct {
- const char *name;
- const char *trigger;
-} integrator_leds[] = {
- { "integrator:green0", "heartbeat", },
- { "integrator:yellow", },
- { "integrator:red", },
- { "integrator:green1", },
- { "integrator:core_module", "cpu0", },
-};
-
-static void integrator_led_set(struct led_classdev *cdev,
- enum led_brightness b)
-{
- struct integrator_led *led = container_of(cdev,
- struct integrator_led, cdev);
- u32 reg = __raw_readl(LEDREG);
-
- if (b != LED_OFF)
- reg |= led->mask;
- else
- reg &= ~led->mask;
-
- while (__raw_readl(ALPHA_REG) & 1)
- cpu_relax();
-
- __raw_writel(reg, LEDREG);
-}
-
-static enum led_brightness integrator_led_get(struct led_classdev *cdev)
-{
- struct integrator_led *led = container_of(cdev,
- struct integrator_led, cdev);
- u32 reg = __raw_readl(LEDREG);
-
- return (reg & led->mask) ? LED_FULL : LED_OFF;
-}
-
-static void cm_led_set(struct led_classdev *cdev,
- enum led_brightness b)
-{
- if (b != LED_OFF)
- cm_control(CM_CTRL_LED, CM_CTRL_LED);
- else
- cm_control(CM_CTRL_LED, 0);
-}
-
-static enum led_brightness cm_led_get(struct led_classdev *cdev)
-{
- u32 reg = cm_get();
-
- return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF;
-}
-
-static int __init integrator_leds_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) {
- struct integrator_led *led;
-
- led = kzalloc(sizeof(*led), GFP_KERNEL);
- if (!led)
- break;
-
-
- led->cdev.name = integrator_leds[i].name;
-
- if (i == 4) { /* Setting for LED in core module */
- led->cdev.brightness_set = cm_led_set;
- led->cdev.brightness_get = cm_led_get;
- } else {
- led->cdev.brightness_set = integrator_led_set;
- led->cdev.brightness_get = integrator_led_get;
- }
-
- led->cdev.default_trigger = integrator_leds[i].trigger;
- led->mask = BIT(i);
-
- if (led_classdev_register(NULL, &led->cdev) < 0) {
- kfree(led);
- break;
- }
- }
-
- return 0;
-}
-
-/*
- * Since we may have triggers on any subsystem, defer registration
- * until after subsystem_init.
- */
-fs_initcall(integrator_leds_init);
-#endif
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 756f6f10efa0..fae0435cc23d 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -45,4 +45,5 @@ obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o
+obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o
obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c
new file mode 100644
index 000000000000..b9efd30513d5
--- /dev/null
+++ b/drivers/clocksource/timer-integrator-ap.c
@@ -0,0 +1,210 @@
+/*
+ * Integrator/AP timer driver
+ * Copyright (C) 2000-2003 Deep Blue Solutions Ltd
+ * Copyright (c) 2014, Linaro Limited
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/sched_clock.h>
+#include <asm/hardware/arm_timer.h>
+
+static void __iomem * sched_clk_base;
+
+static u64 notrace integrator_read_sched_clock(void)
+{
+ return -readl(sched_clk_base + TIMER_VALUE);
+}
+
+static void integrator_clocksource_init(unsigned long inrate,
+ void __iomem *base)
+{
+ u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
+ unsigned long rate = inrate;
+
+ if (rate >= 1500000) {
+ rate /= 16;
+ ctrl |= TIMER_CTRL_DIV16;
+ }
+
+ writel(0xffff, base + TIMER_LOAD);
+ writel(ctrl, base + TIMER_CTRL);
+
+ clocksource_mmio_init(base + TIMER_VALUE, "timer2",
+ rate, 200, 16, clocksource_mmio_readl_down);
+
+ sched_clk_base = base;
+ sched_clock_register(integrator_read_sched_clock, 16, rate);
+}
+
+static unsigned long timer_reload;
+static void __iomem * clkevt_base;
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ /* clear the interrupt */
+ writel(1, clkevt_base + TIMER_INTCLR);
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
+{
+ u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
+
+ /* Disable timer */
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* Enable the timer and start the periodic tick */
+ writel(timer_reload, clkevt_base + TIMER_LOAD);
+ ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* Leave the timer disabled, .set_next_event will enable it */
+ ctrl &= ~TIMER_CTRL_PERIODIC;
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_RESUME:
+ default:
+ /* Just leave in disabled state */
+ break;
+ }
+
+}
+
+static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
+{
+ unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
+
+ writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
+ writel(next, clkevt_base + TIMER_LOAD);
+ writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
+
+ return 0;
+}
+
+static struct clock_event_device integrator_clockevent = {
+ .name = "timer1",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = clkevt_set_mode,
+ .set_next_event = clkevt_set_next_event,
+ .rating = 300,
+};
+
+static struct irqaction integrator_timer_irq = {
+ .name = "timer",
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = integrator_timer_interrupt,
+ .dev_id = &integrator_clockevent,
+};
+
+static void integrator_clockevent_init(unsigned long inrate,
+ void __iomem *base, int irq)
+{
+ unsigned long rate = inrate;
+ unsigned int ctrl = 0;
+
+ clkevt_base = base;
+ /* Calculate and program a divisor */
+ if (rate > 0x100000 * HZ) {
+ rate /= 256;
+ ctrl |= TIMER_CTRL_DIV256;
+ } else if (rate > 0x10000 * HZ) {
+ rate /= 16;
+ ctrl |= TIMER_CTRL_DIV16;
+ }
+ timer_reload = rate / HZ;
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+
+ setup_irq(irq, &integrator_timer_irq);
+ clockevents_config_and_register(&integrator_clockevent,
+ rate,
+ 1,
+ 0xffffU);
+}
+
+static void __init integrator_ap_timer_init_of(struct device_node *node)
+{
+ const char *path;
+ void __iomem *base;
+ int err;
+ int irq;
+ struct clk *clk;
+ unsigned long rate;
+ struct device_node *pri_node;
+ struct device_node *sec_node;
+
+ base = of_io_request_and_map(node, 0, "integrator-timer");
+ if (!base)
+ return;
+
+ clk = of_clk_get(node, 0);
+ if (IS_ERR(clk)) {
+ pr_err("No clock for %s\n", node->name);
+ return;
+ }
+ clk_prepare_enable(clk);
+ rate = clk_get_rate(clk);
+ writel(0, base + TIMER_CTRL);
+
+ err = of_property_read_string(of_aliases,
+ "arm,timer-primary", &path);
+ if (WARN_ON(err))
+ return;
+ pri_node = of_find_node_by_path(path);
+ err = of_property_read_string(of_aliases,
+ "arm,timer-secondary", &path);
+ if (WARN_ON(err))
+ return;
+ sec_node = of_find_node_by_path(path);
+
+ if (node == pri_node) {
+ /* The primary timer lacks IRQ, use as clocksource */
+ integrator_clocksource_init(rate, base);
+ return;
+ }
+
+ if (node == sec_node) {
+ /* The secondary timer will drive the clock event */
+ irq = irq_of_parse_and_map(node, 0);
+ integrator_clockevent_init(rate, base, irq);
+ return;
+ }
+
+ pr_info("Timer @%p unused\n", base);
+ clk_disable_unprepare(clk);
+}
+
+CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer",
+ integrator_ap_timer_init_of);
diff --git a/drivers/soc/versatile/Kconfig b/drivers/soc/versatile/Kconfig
index bf5ee9c85330..a928a7fc6be4 100644
--- a/drivers/soc/versatile/Kconfig
+++ b/drivers/soc/versatile/Kconfig
@@ -1,6 +1,15 @@
#
# ARM Versatile SoC drivers
#
+config SOC_INTEGRATOR_CM
+ bool "SoC bus device for the ARM Integrator platform core modules"
+ depends on ARCH_INTEGRATOR
+ select SOC_BUS
+ help
+ Include support for the SoC bus on the ARM Integrator platform
+ core modules providing some sysfs information about the ASIC
+ variant.
+
config SOC_REALVIEW
bool "SoC bus device for the ARM RealView platforms"
depends on ARCH_REALVIEW
diff --git a/drivers/soc/versatile/Makefile b/drivers/soc/versatile/Makefile
index ad547435648e..cf612fe3a659 100644
--- a/drivers/soc/versatile/Makefile
+++ b/drivers/soc/versatile/Makefile
@@ -1 +1,2 @@
+obj-$(CONFIG_SOC_INTEGRATOR_CM) += soc-integrator.o
obj-$(CONFIG_SOC_REALVIEW) += soc-realview.o
diff --git a/drivers/soc/versatile/soc-integrator.c b/drivers/soc/versatile/soc-integrator.c
new file mode 100644
index 000000000000..ccaa53739ab4
--- /dev/null
+++ b/drivers/soc/versatile/soc-integrator.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * 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 <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+
+#define INTEGRATOR_HDR_ID_OFFSET 0x00
+
+static u32 integrator_coreid;
+
+static const struct of_device_id integrator_cm_match[] = {
+ { .compatible = "arm,core-module-integrator", },
+};
+
+static const char *integrator_arch_str(u32 id)
+{
+ switch ((id >> 16) & 0xff) {
+ case 0x00:
+ return "ASB little-endian";
+ case 0x01:
+ return "AHB little-endian";
+ case 0x03:
+ return "AHB-Lite system bus, bi-endian";
+ case 0x04:
+ return "AHB";
+ case 0x08:
+ return "AHB system bus, ASB processor bus";