Browse Source

Merge tag 'sunxi-cleanup-for-3.10' of git://github.com/mripard/linux into next/cleanup

From Maxime Ripard:
Cleanups for Allwinner sunXi architecture:
  - Remove sunxi.dtsi
  - Switch to clocksource/irqchip device tree handlers
  - Cleanup the watchdog code

* tag 'sunxi-cleanup-for-3.10' of git://github.com/mripard/linux:
  ARM: sunxi: Rework the restart code
  irqchip: sunxi: Rename sunxi to sun4i
  irqchip: sunxi: Make use of the IRQCHIP_DECLARE macro
  clocksource: sunxi: Rename sunxi to sun4i
  clocksource: sunxi: make use of CLKSRC_OF
  clocksource: sunxi: Cleanup the timer code
  clocksource: make CLOCKSOURCE_OF_DECLARE type safe

Signed-off-by: Olof Johansson <olof@lixom.net>

Add/change conflict in drivers/clocksource/Makefile resolved.
Olof Johansson 12 years ago
parent
commit
b9d5868e34

+ 2 - 2
Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-ic.txt → Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt

@@ -2,7 +2,7 @@ Allwinner Sunxi Interrupt Controller
 
 Required properties:
 
-- compatible : should be "allwinner,sunxi-ic"
+- compatible : should be "allwinner,sun4i-ic"
 - reg : Specifies base physical address and size of the registers.
 - interrupt-controller : Identifies the node as an interrupt controller
 - #interrupt-cells : Specifies the number of cells needed to encode an
@@ -97,7 +97,7 @@ The interrupt sources are as follows:
 Example:
 
 intc: interrupt-controller {
-	compatible = "allwinner,sunxi-ic";
+	compatible = "allwinner,sun4i-ic";
 	reg = <0x01c20400 0x400>;
 	interrupt-controller;
 	#interrupt-cells = <2>;

+ 2 - 2
Documentation/devicetree/bindings/timer/allwinner,sunxi-timer.txt → Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt

@@ -2,7 +2,7 @@ Allwinner A1X SoCs Timer Controller
 
 Required properties:
 
-- compatible : should be "allwinner,sunxi-timer"
+- compatible : should be "allwinner,sun4i-timer"
 - reg : Specifies base physical address and size of the registers.
 - interrupts : The interrupt of the first timer
 - clocks: phandle to the source clock (usually a 24 MHz fixed clock)
@@ -10,7 +10,7 @@ Required properties:
 Example:
 
 timer {
-	compatible = "allwinner,sunxi-timer";
+	compatible = "allwinner,sun4i-timer";
 	reg = <0x01c20c00 0x400>;
 	interrupts = <22>;
 	clocks = <&osc>;

+ 3 - 3
Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt → Documentation/devicetree/bindings/watchdog/sun4i-wdt.txt

@@ -1,13 +1,13 @@
-Allwinner sunXi Watchdog timer
+Allwinner sun4i Watchdog timer
 
 Required properties:
 
-- compatible : should be "allwinner,sunxi-wdt"
+- compatible : should be "allwinner,sun4i-wdt"
 - reg : Specifies base physical address and size of the registers.
 
 Example:
 
 wdt: watchdog@01c20c90 {
-	compatible = "allwinner,sunxi-wdt";
+	compatible = "allwinner,sun4i-wdt";
 	reg = <0x01c20c90 0x10>;
 };

+ 3 - 2
arch/arm/mach-sunxi/Kconfig

@@ -1,10 +1,11 @@
 config ARCH_SUNXI
 	bool "Allwinner A1X SOCs" if ARCH_MULTI_V7
 	select CLKSRC_MMIO
+	select CLKSRC_OF
 	select COMMON_CLK
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_IRQ_CHIP
 	select PINCTRL
 	select SPARSE_IRQ
-	select SUNXI_TIMER
-	select PINCTRL_SUNXI
+	select SUN4I_TIMER
+	select PINCTRL_SUNXI

+ 46 - 28
arch/arm/mach-sunxi/sunxi.c

@@ -10,63 +10,77 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include <linux/clocksource.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/irqchip.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/io.h>
-#include <linux/sunxi_timer.h>
 
-#include <linux/irqchip/sunxi.h>
+#include <linux/clk/sunxi.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/system_misc.h>
 
 #include "sunxi.h"
 
-#define WATCHDOG_CTRL_REG	0x00
-#define WATCHDOG_CTRL_RESTART		(1 << 0)
-#define WATCHDOG_MODE_REG	0x04
-#define WATCHDOG_MODE_ENABLE		(1 << 0)
-#define WATCHDOG_MODE_RESET_ENABLE	(1 << 1)
+#define SUN4I_WATCHDOG_CTRL_REG		0x00
+#define SUN4I_WATCHDOG_CTRL_RESTART		(1 << 0)
+#define SUN4I_WATCHDOG_MODE_REG		0x04
+#define SUN4I_WATCHDOG_MODE_ENABLE		(1 << 0)
+#define SUN4I_WATCHDOG_MODE_RESET_ENABLE	(1 << 1)
 
 static void __iomem *wdt_base;
 
-static void sunxi_setup_restart(void)
-{
-	struct device_node *np = of_find_compatible_node(NULL, NULL,
-						"allwinner,sunxi-wdt");
-	if (WARN(!np, "unable to setup watchdog restart"))
-		return;
-
-	wdt_base = of_iomap(np, 0);
-	WARN(!wdt_base, "failed to map watchdog base address");
-}
-
-static void sunxi_restart(char mode, const char *cmd)
+static void sun4i_restart(char mode, const char *cmd)
 {
 	if (!wdt_base)
 		return;
 
 	/* Enable timer and set reset bit in the watchdog */
-	writel(WATCHDOG_MODE_ENABLE | WATCHDOG_MODE_RESET_ENABLE,
-		wdt_base + WATCHDOG_MODE_REG);
+	writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE,
+	       wdt_base + SUN4I_WATCHDOG_MODE_REG);
 
 	/*
 	 * Restart the watchdog. The default (and lowest) interval
 	 * value for the watchdog is 0.5s.
 	 */
-	writel(WATCHDOG_CTRL_RESTART, wdt_base + WATCHDOG_CTRL_REG);
+	writel(SUN4I_WATCHDOG_CTRL_RESTART, wdt_base + SUN4I_WATCHDOG_CTRL_REG);
 
 	while (1) {
 		mdelay(5);
-		writel(WATCHDOG_MODE_ENABLE | WATCHDOG_MODE_RESET_ENABLE,
-			wdt_base + WATCHDOG_MODE_REG);
+		writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE,
+		       wdt_base + SUN4I_WATCHDOG_MODE_REG);
 	}
 }
 
+static struct of_device_id sunxi_restart_ids[] = {
+	{ .compatible = "allwinner,sun4i-wdt", .data = sun4i_restart },
+	{ /*sentinel*/ }
+};
+
+static void sunxi_setup_restart(void)
+{
+	const struct of_device_id *of_id;
+	struct device_node *np;
+
+	np = of_find_matching_node(NULL, sunxi_restart_ids);
+	if (WARN(!np, "unable to setup watchdog restart"))
+		return;
+
+	wdt_base = of_iomap(np, 0);
+	WARN(!wdt_base, "failed to map watchdog base address");
+
+	of_id = of_match_node(sunxi_restart_ids, np);
+	WARN(!of_id, "restart function not available");
+
+	arm_pm_restart = of_id->data;
+}
+
 static struct map_desc sunxi_io_desc[] __initdata = {
 	{
 		.virtual	= (unsigned long) SUNXI_REGS_VIRT_BASE,
@@ -81,6 +95,12 @@ void __init sunxi_map_io(void)
 	iotable_init(sunxi_io_desc, ARRAY_SIZE(sunxi_io_desc));
 }
 
+static void __init sunxi_timer_init(void)
+{
+	sunxi_init_clocks();
+	clocksource_of_init();
+}
+
 static void __init sunxi_dt_init(void)
 {
 	sunxi_setup_restart();
@@ -97,9 +117,7 @@ static const char * const sunxi_board_dt_compat[] = {
 DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)")
 	.init_machine	= sunxi_dt_init,
 	.map_io		= sunxi_map_io,
-	.init_irq	= sunxi_init_irq,
-	.handle_irq	= sunxi_handle_irq,
-	.restart	= sunxi_restart,
-	.init_time	= &sunxi_timer_init,
+	.init_irq	= irqchip_init,
+	.init_time	= sunxi_timer_init,
 	.dt_compat	= sunxi_board_dt_compat,
 MACHINE_END

+ 1 - 1
drivers/clocksource/Kconfig

@@ -25,7 +25,7 @@ config DW_APB_TIMER_OF
 config ARMADA_370_XP_TIMER
 	bool
 
-config SUNXI_TIMER
+config SUN4I_TIMER
 	bool
 
 config VT8500_TIMER

+ 1 - 1
drivers/clocksource/Makefile

@@ -17,7 +17,7 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU)	+= clksrc-dbx500-prcmu.o
 obj-$(CONFIG_ARMADA_370_XP_TIMER)	+= time-armada-370-xp.o
 obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o
 obj-$(CONFIG_ARCH_MXS)		+= mxs_timer.o
-obj-$(CONFIG_SUNXI_TIMER)	+= sunxi_timer.o
+obj-$(CONFIG_SUN4I_TIMER)	+= sun4i_timer.o
 obj-$(CONFIG_ARCH_TEGRA)	+= tegra20_timer.o
 obj-$(CONFIG_VT8500_TIMER)	+= vt8500_timer.o
 

+ 2 - 1
drivers/clocksource/clksrc-of.c

@@ -16,6 +16,7 @@
 
 #include <linux/init.h>
 #include <linux/of.h>
+#include <linux/clocksource.h>
 
 extern struct of_device_id __clksrc_of_table[];
 
@@ -26,7 +27,7 @@ void __init clocksource_of_init(void)
 {
 	struct device_node *np;
 	const struct of_device_id *match;
-	void (*init_func)(struct device_node *);
+	clocksource_of_init_fn init_func;
 
 	for_each_matching_node_and_match(np, __clksrc_of_table, &match) {
 		init_func = match->data;

+ 41 - 53
drivers/clocksource/sunxi_timer.c → drivers/clocksource/sun4i_timer.c

@@ -22,66 +22,64 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
-#include <linux/sunxi_timer.h>
-#include <linux/clk/sunxi.h>
 
-#define TIMER_CTL_REG		0x00
-#define TIMER_CTL_ENABLE		(1 << 0)
+#define TIMER_IRQ_EN_REG	0x00
+#define TIMER_IRQ_EN(val)		(1 << val)
 #define TIMER_IRQ_ST_REG	0x04
-#define TIMER0_CTL_REG		0x10
-#define TIMER0_CTL_ENABLE		(1 << 0)
-#define TIMER0_CTL_AUTORELOAD		(1 << 1)
-#define TIMER0_CTL_ONESHOT		(1 << 7)
-#define TIMER0_INTVAL_REG	0x14
-#define TIMER0_CNTVAL_REG	0x18
+#define TIMER_CTL_REG(val)	(0x10 * val + 0x10)
+#define TIMER_CTL_ENABLE		(1 << 0)
+#define TIMER_CTL_AUTORELOAD		(1 << 1)
+#define TIMER_CTL_ONESHOT		(1 << 7)
+#define TIMER_INTVAL_REG(val)	(0x10 * val + 0x14)
+#define TIMER_CNTVAL_REG(val)	(0x10 * val + 0x18)
 
 #define TIMER_SCAL		16
 
 static void __iomem *timer_base;
 
-static void sunxi_clkevt_mode(enum clock_event_mode mode,
+static void sun4i_clkevt_mode(enum clock_event_mode mode,
 			      struct clock_event_device *clk)
 {
-	u32 u = readl(timer_base + TIMER0_CTL_REG);
+	u32 u = readl(timer_base + TIMER_CTL_REG(0));
 
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
-		u &= ~(TIMER0_CTL_ONESHOT);
-		writel(u | TIMER0_CTL_ENABLE, timer_base + TIMER0_CTL_REG);
+		u &= ~(TIMER_CTL_ONESHOT);
+		writel(u | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0));
 		break;
 
 	case CLOCK_EVT_MODE_ONESHOT:
-		writel(u | TIMER0_CTL_ONESHOT, timer_base + TIMER0_CTL_REG);
+		writel(u | TIMER_CTL_ONESHOT, timer_base + TIMER_CTL_REG(0));
 		break;
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
 	default:
-		writel(u & ~(TIMER0_CTL_ENABLE), timer_base + TIMER0_CTL_REG);
+		writel(u & ~(TIMER_CTL_ENABLE), timer_base + TIMER_CTL_REG(0));
 		break;
 	}
 }
 
-static int sunxi_clkevt_next_event(unsigned long evt,
+static int sun4i_clkevt_next_event(unsigned long evt,
 				   struct clock_event_device *unused)
 {
-	u32 u = readl(timer_base + TIMER0_CTL_REG);
-	writel(evt, timer_base + TIMER0_CNTVAL_REG);
-	writel(u | TIMER0_CTL_ENABLE | TIMER0_CTL_AUTORELOAD,
-	       timer_base + TIMER0_CTL_REG);
+	u32 u = readl(timer_base + TIMER_CTL_REG(0));
+	writel(evt, timer_base + TIMER_CNTVAL_REG(0));
+	writel(u | TIMER_CTL_ENABLE | TIMER_CTL_AUTORELOAD,
+	       timer_base + TIMER_CTL_REG(0));
 
 	return 0;
 }
 
-static struct clock_event_device sunxi_clockevent = {
-	.name = "sunxi_tick",
+static struct clock_event_device sun4i_clockevent = {
+	.name = "sun4i_tick",
 	.rating = 300,
 	.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-	.set_mode = sunxi_clkevt_mode,
-	.set_next_event = sunxi_clkevt_next_event,
+	.set_mode = sun4i_clkevt_mode,
+	.set_next_event = sun4i_clkevt_next_event,
 };
 
 
-static irqreturn_t sunxi_timer_interrupt(int irq, void *dev_id)
+static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id)
 {
 	struct clock_event_device *evt = (struct clock_event_device *)dev_id;
 
@@ -91,30 +89,20 @@ static irqreturn_t sunxi_timer_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static struct irqaction sunxi_timer_irq = {
-	.name = "sunxi_timer0",
+static struct irqaction sun4i_timer_irq = {
+	.name = "sun4i_timer0",
 	.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-	.handler = sunxi_timer_interrupt,
-	.dev_id = &sunxi_clockevent,
-};
-
-static struct of_device_id sunxi_timer_dt_ids[] = {
-	{ .compatible = "allwinner,sunxi-timer" },
-	{ }
+	.handler = sun4i_timer_interrupt,
+	.dev_id = &sun4i_clockevent,
 };
 
-void __init sunxi_timer_init(void)
+static void __init sun4i_timer_init(struct device_node *node)
 {
-	struct device_node *node;
 	unsigned long rate = 0;
 	struct clk *clk;
 	int ret, irq;
 	u32 val;
 
-	node = of_find_matching_node(NULL, sunxi_timer_dt_ids);
-	if (!node)
-		panic("No sunxi timer node");
-
 	timer_base = of_iomap(node, 0);
 	if (!timer_base)
 		panic("Can't map registers");
@@ -123,8 +111,6 @@ void __init sunxi_timer_init(void)
 	if (irq <= 0)
 		panic("Can't parse IRQ");
 
-	sunxi_init_clocks();
-
 	clk = of_clk_get(node, 0);
 	if (IS_ERR(clk))
 		panic("Can't get timer clock");
@@ -132,29 +118,31 @@ void __init sunxi_timer_init(void)
 	rate = clk_get_rate(clk);
 
 	writel(rate / (TIMER_SCAL * HZ),
-	       timer_base + TIMER0_INTVAL_REG);
+	       timer_base + TIMER_INTVAL_REG(0));
 
 	/* set clock source to HOSC, 16 pre-division */
-	val = readl(timer_base + TIMER0_CTL_REG);
+	val = readl(timer_base + TIMER_CTL_REG(0));
 	val &= ~(0x07 << 4);
 	val &= ~(0x03 << 2);
 	val |= (4 << 4) | (1 << 2);
-	writel(val, timer_base + TIMER0_CTL_REG);
+	writel(val, timer_base + TIMER_CTL_REG(0));
 
 	/* set mode to auto reload */
-	val = readl(timer_base + TIMER0_CTL_REG);
-	writel(val | TIMER0_CTL_AUTORELOAD, timer_base + TIMER0_CTL_REG);
+	val = readl(timer_base + TIMER_CTL_REG(0));
+	writel(val | TIMER_CTL_AUTORELOAD, timer_base + TIMER_CTL_REG(0));
 
-	ret = setup_irq(irq, &sunxi_timer_irq);
+	ret = setup_irq(irq, &sun4i_timer_irq);
 	if (ret)
 		pr_warn("failed to setup irq %d\n", irq);
 
 	/* Enable timer0 interrupt */
-	val = readl(timer_base + TIMER_CTL_REG);
-	writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG);
+	val = readl(timer_base + TIMER_IRQ_EN_REG);
+	writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG);
 
-	sunxi_clockevent.cpumask = cpumask_of(0);
+	sun4i_clockevent.cpumask = cpumask_of(0);
 
-	clockevents_config_and_register(&sunxi_clockevent, rate / TIMER_SCAL,
+	clockevents_config_and_register(&sun4i_clockevent, rate / TIMER_SCAL,
 					0x1, 0xff);
 }
+CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer",
+		       sun4i_timer_init);

+ 1 - 1
drivers/clocksource/vt8500_timer.c

@@ -165,4 +165,4 @@ static void __init vt8500_timer_init(struct device_node *np)
 					4, 0xf0000000);
 }
 
-CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init)
+CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init);

+ 1 - 1
drivers/irqchip/Makefile

@@ -5,7 +5,7 @@ obj-$(CONFIG_ARCH_EXYNOS)		+= exynos-combiner.o
 obj-$(CONFIG_ARCH_MXS)			+= irq-mxs.o
 obj-$(CONFIG_METAG)			+= irq-metag-ext.o
 obj-$(CONFIG_METAG_PERFCOUNTER_IRQS)	+= irq-metag.o
-obj-$(CONFIG_ARCH_SUNXI)		+= irq-sunxi.o
+obj-$(CONFIG_ARCH_SUNXI)		+= irq-sun4i.o
 obj-$(CONFIG_ARCH_SPEAR3XX)		+= spear-shirq.o
 obj-$(CONFIG_ARM_GIC)			+= irq-gic.o
 obj-$(CONFIG_ARM_VIC)			+= irq-vic.o

+ 149 - 0
drivers/irqchip/irq-sun4i.c

@@ -0,0 +1,149 @@
+/*
+ * Allwinner A1X SoCs IRQ chip driver.
+ *
+ * Copyright (C) 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * Based on code from
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Benn Huang <benn@allwinnertech.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
+
+#include "irqchip.h"
+
+#define SUN4I_IRQ_VECTOR_REG		0x00
+#define SUN4I_IRQ_PROTECTION_REG	0x08
+#define SUN4I_IRQ_NMI_CTRL_REG		0x0c
+#define SUN4I_IRQ_PENDING_REG(x)	(0x10 + 0x4 * x)
+#define SUN4I_IRQ_FIQ_PENDING_REG(x)	(0x20 + 0x4 * x)
+#define SUN4I_IRQ_ENABLE_REG(x)		(0x40 + 0x4 * x)
+#define SUN4I_IRQ_MASK_REG(x)		(0x50 + 0x4 * x)
+
+static void __iomem *sun4i_irq_base;
+static struct irq_domain *sun4i_irq_domain;
+
+static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs);
+
+void sun4i_irq_ack(struct irq_data *irqd)
+{
+	unsigned int irq = irqd_to_hwirq(irqd);
+	unsigned int irq_off = irq % 32;
+	int reg = irq / 32;
+	u32 val;
+
+	val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
+	writel(val | (1 << irq_off),
+	       sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
+}
+
+static void sun4i_irq_mask(struct irq_data *irqd)
+{
+	unsigned int irq = irqd_to_hwirq(irqd);
+	unsigned int irq_off = irq % 32;
+	int reg = irq / 32;
+	u32 val;
+
+	val = readl(sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg));
+	writel(val & ~(1 << irq_off),
+	       sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg));
+}
+
+static void sun4i_irq_unmask(struct irq_data *irqd)
+{
+	unsigned int irq = irqd_to_hwirq(irqd);
+	unsigned int irq_off = irq % 32;
+	int reg = irq / 32;
+	u32 val;
+
+	val = readl(sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg));
+	writel(val | (1 << irq_off),
+	       sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg));
+}
+
+static struct irq_chip sun4i_irq_chip = {
+	.name		= "sun4i_irq",
+	.irq_ack	= sun4i_irq_ack,
+	.irq_mask	= sun4i_irq_mask,
+	.irq_unmask	= sun4i_irq_unmask,
+};
+
+static int sun4i_irq_map(struct irq_domain *d, unsigned int virq,
+			 irq_hw_number_t hw)
+{
+	irq_set_chip_and_handler(virq, &sun4i_irq_chip,
+				 handle_level_irq);
+	set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+
+	return 0;
+}
+
+static struct irq_domain_ops sun4i_irq_ops = {
+	.map = sun4i_irq_map,
+	.xlate = irq_domain_xlate_onecell,
+};
+
+static int __init sun4i_of_init(struct device_node *node,
+				struct device_node *parent)
+{
+	sun4i_irq_base = of_iomap(node, 0);
+	if (!sun4i_irq_base)
+		panic("%s: unable to map IC registers\n",
+			node->full_name);
+
+	/* Disable all interrupts */
+	writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(0));
+	writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1));
+	writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2));
+
+	/* Mask all the interrupts */
+	writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0));
+	writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1));
+	writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2));
+
+	/* Clear all the pending interrupts */
+	writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0));
+	writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(1));
+	writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(2));
+
+	/* Enable protection mode */
+	writel(0x01, sun4i_irq_base + SUN4I_IRQ_PROTECTION_REG);
+
+	/* Configure the external interrupt source type */
+	writel(0x00, sun4i_irq_base + SUN4I_IRQ_NMI_CTRL_REG);
+
+	sun4i_irq_domain = irq_domain_add_linear(node, 3 * 32,
+						 &sun4i_irq_ops, NULL);
+	if (!sun4i_irq_domain)
+		panic("%s: unable to create IRQ domain\n", node->full_name);
+
+	set_handle_irq(sun4i_handle_irq);
+
+	return 0;
+}
+IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-ic", sun4i_of_init);
+
+static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
+{
+	u32 irq, hwirq;
+
+	hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
+	while (hwirq != 0) {
+		irq = irq_find_mapping(sun4i_irq_domain, hwirq);
+		handle_IRQ(irq, regs);
+		hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
+	}
+}

+ 0 - 151
drivers/irqchip/irq-sunxi.c

@@ -1,151 +0,0 @@
-/*
- * Allwinner A1X SoCs IRQ chip driver.
- *
- * Copyright (C) 2012 Maxime Ripard
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * Based on code from
- * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
- * Benn Huang <benn@allwinnertech.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-
-#include <linux/irqchip/sunxi.h>
-
-#define SUNXI_IRQ_VECTOR_REG		0x00
-#define SUNXI_IRQ_PROTECTION_REG	0x08
-#define SUNXI_IRQ_NMI_CTRL_REG		0x0c
-#define SUNXI_IRQ_PENDING_REG(x)	(0x10 + 0x4 * x)
-#define SUNXI_IRQ_FIQ_PENDING_REG(x)	(0x20 + 0x4 * x)
-#define SUNXI_IRQ_ENABLE_REG(x)		(0x40 + 0x4 * x)
-#define SUNXI_IRQ_MASK_REG(x)		(0x50 + 0x4 * x)
-
-static void __iomem *sunxi_irq_base;
-static struct irq_domain *sunxi_irq_domain;
-
-void sunxi_irq_ack(struct irq_data *irqd)
-{
-	unsigned int irq = irqd_to_hwirq(irqd);
-	unsigned int irq_off = irq % 32;
-	int reg = irq / 32;
-	u32 val;
-
-	val = readl(sunxi_irq_base + SUNXI_IRQ_PENDING_REG(reg));
-	writel(val | (1 << irq_off),
-	       sunxi_irq_base + SUNXI_IRQ_PENDING_REG(reg));
-}
-
-static void sunxi_irq_mask(struct irq_data *irqd)
-{
-	unsigned int irq = irqd_to_hwirq(irqd);
-	unsigned int irq_off = irq % 32;
-	int reg = irq / 32;
-	u32 val;
-
-	val = readl(sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
-	writel(val & ~(1 << irq_off),
-	       sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
-}
-
-static void sunxi_irq_unmask(struct irq_data *irqd)
-{
-	unsigned int irq = irqd_to_hwirq(irqd);
-	unsigned int irq_off = irq % 32;
-	int reg = irq / 32;
-	u32 val;
-
-	val = readl(sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
-	writel(val | (1 << irq_off),
-	       sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
-}
-
-static struct irq_chip sunxi_irq_chip = {
-	.name		= "sunxi_irq",
-	.irq_ack	= sunxi_irq_ack,
-	.irq_mask	= sunxi_irq_mask,
-	.irq_unmask	= sunxi_irq_unmask,
-};
-
-static int sunxi_irq_map(struct irq_domain *d, unsigned int virq,
-			 irq_hw_number_t hw)
-{
-	irq_set_chip_and_handler(virq, &sunxi_irq_chip,
-				 handle_level_irq);
-	set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
-
-	return 0;
-}
-
-static struct irq_domain_ops sunxi_irq_ops = {
-	.map = sunxi_irq_map,
-	.xlate = irq_domain_xlate_onecell,
-};
-
-static int __init sunxi_of_init(struct device_node *node,
-				struct device_node *parent)
-{
-	sunxi_irq_base = of_iomap(node, 0);
-	if (!sunxi_irq_base)
-		panic("%s: unable to map IC registers\n",
-			node->full_name);
-
-	/* Disable all interrupts */
-	writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(0));
-	writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(1));
-	writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(2));
-
-	/* Mask all the interrupts */
-	writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(0));
-	writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(1));
-	writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(2));
-
-	/* Clear all the pending interrupts */
-	writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(0));
-	writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(1));
-	writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(2));
-
-	/* Enable protection mode */
-	writel(0x01, sunxi_irq_base + SUNXI_IRQ_PROTECTION_REG);
-
-	/* Configure the external interrupt source type */
-	writel(0x00, sunxi_irq_base + SUNXI_IRQ_NMI_CTRL_REG);
-
-	sunxi_irq_domain = irq_domain_add_linear(node, 3 * 32,
-						 &sunxi_irq_ops, NULL);
-	if (!sunxi_irq_domain)
-		panic("%s: unable to create IRQ domain\n", node->full_name);
-
-	return 0;
-}
-
-static struct of_device_id sunxi_irq_dt_ids[] __initconst = {
-	{ .compatible = "allwinner,sunxi-ic", .data = sunxi_of_init },
-	{ }
-};
-
-void __init sunxi_init_irq(void)
-{
-	of_irq_init(sunxi_irq_dt_ids);
-}
-
-asmlinkage void __exception_irq_entry sunxi_handle_irq(struct pt_regs *regs)
-{
-	u32 irq, hwirq;
-
-	hwirq = readl(sunxi_irq_base + SUNXI_IRQ_VECTOR_REG) >> 2;
-	while (hwirq != 0) {
-		irq = irq_find_mapping(sunxi_irq_domain, hwirq);
-		handle_IRQ(irq, regs);
-		hwirq = readl(sunxi_irq_base + SUNXI_IRQ_VECTOR_REG) >> 2;
-	}
-}

+ 9 - 2
include/linux/clocksource.h

@@ -332,16 +332,23 @@ extern int clocksource_mmio_init(void __iomem *, const char *,
 
 extern int clocksource_i8253_init(void);
 
+struct device_node;
+typedef void(*clocksource_of_init_fn)(struct device_node *);
 #ifdef CONFIG_CLKSRC_OF
 extern void clocksource_of_init(void);
 
 #define CLOCKSOURCE_OF_DECLARE(name, compat, fn)			\
 	static const struct of_device_id __clksrc_of_table_##name	\
 		__used __section(__clksrc_of_table)			\
-		 = { .compatible = compat, .data = fn };
+		 = { .compatible = compat,				\
+		     .data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn }
 #else
 static inline void clocksource_of_init(void) {}
-#define CLOCKSOURCE_OF_DECLARE(name, compat, fn)
+#define CLOCKSOURCE_OF_DECLARE(name, compat, fn)			\
+	static const struct of_device_id __clksrc_of_table_##name	\
+		__attribute__((unused))					\
+		 = { .compatible = compat,				\
+		     .data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn }
 #endif
 
 #endif /* _LINUX_CLOCKSOURCE_H */

+ 0 - 27
include/linux/irqchip/sunxi.h

@@ -1,27 +0,0 @@
-/*
- * Copyright 2012 Maxime Ripard
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * 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.
- */
-
-#ifndef __LINUX_IRQCHIP_SUNXI_H
-#define __LINUX_IRQCHIP_SUNXI_H
-
-#include <asm/exception.h>
-
-extern void sunxi_init_irq(void);
-
-extern asmlinkage void __exception_irq_entry sunxi_handle_irq(
-	struct pt_regs *regs);
-
-#endif

+ 0 - 24
include/linux/sunxi_timer.h

@@ -1,24 +0,0 @@
-/*
- * Copyright 2012 Maxime Ripard
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * 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.
- */
-
-#ifndef __SUNXI_TIMER_H
-#define __SUNXI_TIMER_H
-
-#include <asm/mach/time.h>
-
-void sunxi_timer_init(void);
-
-#endif