aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2013-04-11 06:39:00 -0400
committerOlof Johansson <olof@lixom.net>2013-04-11 06:39:00 -0400
commitb9d5868e342a9802db7b299be511ac547ff1034d (patch)
tree49c8fe5467b817bcaf2afa6468c2e362f50e4770
parent83c15f4c05757b3c5fe1551a474458fd16d27bae (diff)
parentbc34b5f27cd33f4213bc5c8df0099dd11408d29d (diff)
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.
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt (renamed from Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-ic.txt)4
-rw-r--r--Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt (renamed from Documentation/devicetree/bindings/timer/allwinner,sunxi-timer.txt)4
-rw-r--r--Documentation/devicetree/bindings/watchdog/sun4i-wdt.txt (renamed from Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt)6
-rw-r--r--arch/arm/mach-sunxi/Kconfig5
-rw-r--r--arch/arm/mach-sunxi/sunxi.c74
-rw-r--r--drivers/clocksource/Kconfig2
-rw-r--r--drivers/clocksource/Makefile2
-rw-r--r--drivers/clocksource/clksrc-of.c3
-rw-r--r--drivers/clocksource/sun4i_timer.c (renamed from drivers/clocksource/sunxi_timer.c)94
-rw-r--r--drivers/clocksource/vt8500_timer.c2
-rw-r--r--drivers/irqchip/Makefile2
-rw-r--r--drivers/irqchip/irq-sun4i.c149
-rw-r--r--drivers/irqchip/irq-sunxi.c151
-rw-r--r--include/linux/clocksource.h11
-rw-r--r--include/linux/irqchip/sunxi.h27
-rw-r--r--include/linux/sunxi_timer.h24
16 files changed, 261 insertions, 299 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt
index 7f9fb85f5456..e7f4dc14eff2 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-ic.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt
@@ -2,7 +2,7 @@ Allwinner Sunxi Interrupt Controller
2 2
3Required properties: 3Required properties:
4 4
5- compatible : should be "allwinner,sunxi-ic" 5- compatible : should be "allwinner,sun4i-ic"
6- reg : Specifies base physical address and size of the registers. 6- reg : Specifies base physical address and size of the registers.
7- interrupt-controller : Identifies the node as an interrupt controller 7- interrupt-controller : Identifies the node as an interrupt controller
8- #interrupt-cells : Specifies the number of cells needed to encode an 8- #interrupt-cells : Specifies the number of cells needed to encode an
@@ -97,7 +97,7 @@ The interrupt sources are as follows:
97Example: 97Example:
98 98
99intc: interrupt-controller { 99intc: interrupt-controller {
100 compatible = "allwinner,sunxi-ic"; 100 compatible = "allwinner,sun4i-ic";
101 reg = <0x01c20400 0x400>; 101 reg = <0x01c20400 0x400>;
102 interrupt-controller; 102 interrupt-controller;
103 #interrupt-cells = <2>; 103 #interrupt-cells = <2>;
diff --git a/Documentation/devicetree/bindings/timer/allwinner,sunxi-timer.txt b/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt
index 0c7b64e95a61..48aeb7884ed3 100644
--- a/Documentation/devicetree/bindings/timer/allwinner,sunxi-timer.txt
+++ b/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt
@@ -2,7 +2,7 @@ Allwinner A1X SoCs Timer Controller
2 2
3Required properties: 3Required properties:
4 4
5- compatible : should be "allwinner,sunxi-timer" 5- compatible : should be "allwinner,sun4i-timer"
6- reg : Specifies base physical address and size of the registers. 6- reg : Specifies base physical address and size of the registers.
7- interrupts : The interrupt of the first timer 7- interrupts : The interrupt of the first timer
8- clocks: phandle to the source clock (usually a 24 MHz fixed clock) 8- clocks: phandle to the source clock (usually a 24 MHz fixed clock)
@@ -10,7 +10,7 @@ Required properties:
10Example: 10Example:
11 11
12timer { 12timer {
13 compatible = "allwinner,sunxi-timer"; 13 compatible = "allwinner,sun4i-timer";
14 reg = <0x01c20c00 0x400>; 14 reg = <0x01c20c00 0x400>;
15 interrupts = <22>; 15 interrupts = <22>;
16 clocks = <&osc>; 16 clocks = <&osc>;
diff --git a/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt b/Documentation/devicetree/bindings/watchdog/sun4i-wdt.txt
index 0b2717775600..ecd650adff31 100644
--- a/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/sun4i-wdt.txt
@@ -1,13 +1,13 @@
1Allwinner sunXi Watchdog timer 1Allwinner sun4i Watchdog timer
2 2
3Required properties: 3Required properties:
4 4
5- compatible : should be "allwinner,sunxi-wdt" 5- compatible : should be "allwinner,sun4i-wdt"
6- reg : Specifies base physical address and size of the registers. 6- reg : Specifies base physical address and size of the registers.
7 7
8Example: 8Example:
9 9
10wdt: watchdog@01c20c90 { 10wdt: watchdog@01c20c90 {
11 compatible = "allwinner,sunxi-wdt"; 11 compatible = "allwinner,sun4i-wdt";
12 reg = <0x01c20c90 0x10>; 12 reg = <0x01c20c90 0x10>;
13}; 13};
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 8709a39bd34c..d259c782d742 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -1,10 +1,11 @@
1config ARCH_SUNXI 1config ARCH_SUNXI
2 bool "Allwinner A1X SOCs" if ARCH_MULTI_V7 2 bool "Allwinner A1X SOCs" if ARCH_MULTI_V7
3 select CLKSRC_MMIO 3 select CLKSRC_MMIO
4 select CLKSRC_OF
4 select COMMON_CLK 5 select COMMON_CLK
5 select GENERIC_CLOCKEVENTS 6 select GENERIC_CLOCKEVENTS
6 select GENERIC_IRQ_CHIP 7 select GENERIC_IRQ_CHIP
7 select PINCTRL 8 select PINCTRL
8 select SPARSE_IRQ 9 select SPARSE_IRQ
9 select SUNXI_TIMER 10 select SUN4I_TIMER
10 select PINCTRL_SUNXI \ No newline at end of file 11 select PINCTRL_SUNXI
diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
index 23afb732cb40..706ce35396b8 100644
--- a/arch/arm/mach-sunxi/sunxi.c
+++ b/arch/arm/mach-sunxi/sunxi.c
@@ -10,63 +10,77 @@
10 * warranty of any kind, whether express or implied. 10 * warranty of any kind, whether express or implied.
11 */ 11 */
12 12
13#include <linux/clocksource.h>
13#include <linux/delay.h> 14#include <linux/delay.h>
14#include <linux/kernel.h> 15#include <linux/kernel.h>
15#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/irqchip.h>
16#include <linux/of_address.h> 18#include <linux/of_address.h>
17#include <linux/of_irq.h> 19#include <linux/of_irq.h>
18#include <linux/of_platform.h> 20#include <linux/of_platform.h>
19#include <linux/io.h> 21#include <linux/io.h>
20#include <linux/sunxi_timer.h>
21 22
22#include <linux/irqchip/sunxi.h> 23#include <linux/clk/sunxi.h>
23 24
24#include <asm/mach/arch.h> 25#include <asm/mach/arch.h>
25#include <asm/mach/map.h> 26#include <asm/mach/map.h>
27#include <asm/system_misc.h>
26 28
27#include "sunxi.h" 29#include "sunxi.h"
28 30
29#define WATCHDOG_CTRL_REG 0x00 31#define SUN4I_WATCHDOG_CTRL_REG 0x00
30#define WATCHDOG_CTRL_RESTART (1 << 0) 32#define SUN4I_WATCHDOG_CTRL_RESTART (1 << 0)
31#define WATCHDOG_MODE_REG 0x04 33#define SUN4I_WATCHDOG_MODE_REG 0x04
32#define WATCHDOG_MODE_ENABLE (1 << 0) 34#define SUN4I_WATCHDOG_MODE_ENABLE (1 << 0)
33#define WATCHDOG_MODE_RESET_ENABLE (1 << 1) 35#define SUN4I_WATCHDOG_MODE_RESET_ENABLE (1 << 1)
34 36
35static void __iomem *wdt_base; 37static void __iomem *wdt_base;
36 38
37static void sunxi_setup_restart(void) 39static void sun4i_restart(char mode, const char *cmd)
38{
39 struct device_node *np = of_find_compatible_node(NULL, NULL,
40 "allwinner,sunxi-wdt");
41 if (WARN(!np, "unable to setup watchdog restart"))
42 return;
43
44 wdt_base = of_iomap(np, 0);
45 WARN(!wdt_base, "failed to map watchdog base address");
46}
47
48static void sunxi_restart(char mode, const char *cmd)
49{ 40{
50 if (!wdt_base) 41 if (!wdt_base)
51 return; 42 return;
52 43
53 /* Enable timer and set reset bit in the watchdog */ 44 /* Enable timer and set reset bit in the watchdog */
54 writel(WATCHDOG_MODE_ENABLE | WATCHDOG_MODE_RESET_ENABLE, 45 writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE,
55 wdt_base + WATCHDOG_MODE_REG); 46 wdt_base + SUN4I_WATCHDOG_MODE_REG);
56 47
57 /* 48 /*
58 * Restart the watchdog. The default (and lowest) interval 49 * Restart the watchdog. The default (and lowest) interval
59 * value for the watchdog is 0.5s. 50 * value for the watchdog is 0.5s.
60 */ 51 */
61 writel(WATCHDOG_CTRL_RESTART, wdt_base + WATCHDOG_CTRL_REG); 52 writel(SUN4I_WATCHDOG_CTRL_RESTART, wdt_base + SUN4I_WATCHDOG_CTRL_REG);
62 53
63 while (1) { 54 while (1) {
64 mdelay(5); 55 mdelay(5);
65 writel(WATCHDOG_MODE_ENABLE | WATCHDOG_MODE_RESET_ENABLE, 56 writel(SUN4I_WATCHDOG_MODE_ENABLE | SUN4I_WATCHDOG_MODE_RESET_ENABLE,
66 wdt_base + WATCHDOG_MODE_REG); 57 wdt_base + SUN4I_WATCHDOG_MODE_REG);
67 } 58 }
68} 59}
69 60
61static struct of_device_id sunxi_restart_ids[] = {
62 { .compatible = "allwinner,sun4i-wdt", .data = sun4i_restart },
63 { /*sentinel*/ }
64};
65
66static void sunxi_setup_restart(void)
67{
68 const struct of_device_id *of_id;
69 struct device_node *np;
70
71 np = of_find_matching_node(NULL, sunxi_restart_ids);
72 if (WARN(!np, "unable to setup watchdog restart"))
73 return;
74
75 wdt_base = of_iomap(np, 0);
76 WARN(!wdt_base, "failed to map watchdog base address");
77
78 of_id = of_match_node(sunxi_restart_ids, np);
79 WARN(!of_id, "restart function not available");
80
81 arm_pm_restart = of_id->data;
82}
83
70static struct map_desc sunxi_io_desc[] __initdata = { 84static struct map_desc sunxi_io_desc[] __initdata = {
71 { 85 {
72 .virtual = (unsigned long) SUNXI_REGS_VIRT_BASE, 86 .virtual = (unsigned long) SUNXI_REGS_VIRT_BASE,
@@ -81,6 +95,12 @@ void __init sunxi_map_io(void)
81 iotable_init(sunxi_io_desc, ARRAY_SIZE(sunxi_io_desc)); 95 iotable_init(sunxi_io_desc, ARRAY_SIZE(sunxi_io_desc));
82} 96}
83 97
98static void __init sunxi_timer_init(void)
99{
100 sunxi_init_clocks();
101 clocksource_of_init();
102}
103
84static void __init sunxi_dt_init(void) 104static void __init sunxi_dt_init(void)
85{ 105{
86 sunxi_setup_restart(); 106 sunxi_setup_restart();
@@ -97,9 +117,7 @@ static const char * const sunxi_board_dt_compat[] = {
97DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)") 117DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)")
98 .init_machine = sunxi_dt_init, 118 .init_machine = sunxi_dt_init,
99 .map_io = sunxi_map_io, 119 .map_io = sunxi_map_io,
100 .init_irq = sunxi_init_irq, 120 .init_irq = irqchip_init,
101 .handle_irq = sunxi_handle_irq, 121 .init_time = sunxi_timer_init,
102 .restart = sunxi_restart,
103 .init_time = &sunxi_timer_init,
104 .dt_compat = sunxi_board_dt_compat, 122 .dt_compat = sunxi_board_dt_compat,
105MACHINE_END 123MACHINE_END
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index e507ab7df60b..9002185a0a1a 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -25,7 +25,7 @@ config DW_APB_TIMER_OF
25config ARMADA_370_XP_TIMER 25config ARMADA_370_XP_TIMER
26 bool 26 bool
27 27
28config SUNXI_TIMER 28config SUN4I_TIMER
29 bool 29 bool
30 30
31config VT8500_TIMER 31config VT8500_TIMER
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 89c5adc498b3..98f220a7a92c 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -17,7 +17,7 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
17obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o 17obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
18obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o 18obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
19obj-$(CONFIG_ARCH_MXS) += mxs_timer.o 19obj-$(CONFIG_ARCH_MXS) += mxs_timer.o
20obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o 20obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o
21obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o 21obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o
22obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o 22obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o
23 23
diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c
index 3ef11fba781c..37f5325bec95 100644
--- a/drivers/clocksource/clksrc-of.c
+++ b/drivers/clocksource/clksrc-of.c
@@ -16,6 +16,7 @@
16 16
17#include <linux/init.h> 17#include <linux/init.h>
18#include <linux/of.h> 18#include <linux/of.h>
19#include <linux/clocksource.h>
19 20
20extern struct of_device_id __clksrc_of_table[]; 21extern struct of_device_id __clksrc_of_table[];
21 22
@@ -26,7 +27,7 @@ void __init clocksource_of_init(void)
26{ 27{
27 struct device_node *np; 28 struct device_node *np;
28 const struct of_device_id *match; 29 const struct of_device_id *match;
29 void (*init_func)(struct device_node *); 30 clocksource_of_init_fn init_func;
30 31
31 for_each_matching_node_and_match(np, __clksrc_of_table, &match) { 32 for_each_matching_node_and_match(np, __clksrc_of_table, &match) {
32 init_func = match->data; 33 init_func = match->data;
diff --git a/drivers/clocksource/sunxi_timer.c b/drivers/clocksource/sun4i_timer.c
index 0ce85e29769b..d4674e78ef35 100644
--- a/drivers/clocksource/sunxi_timer.c
+++ b/drivers/clocksource/sun4i_timer.c
@@ -22,66 +22,64 @@
22#include <linux/of.h> 22#include <linux/of.h>
23#include <linux/of_address.h> 23#include <linux/of_address.h>
24#include <linux/of_irq.h> 24#include <linux/of_irq.h>
25#include <linux/sunxi_timer.h>
26#include <linux/clk/sunxi.h>
27 25
28#define TIMER_CTL_REG 0x00 26#define TIMER_IRQ_EN_REG 0x00
29#define TIMER_CTL_ENABLE (1 << 0) 27#define TIMER_IRQ_EN(val) (1 << val)
30#define TIMER_IRQ_ST_REG 0x04 28#define TIMER_IRQ_ST_REG 0x04
31#define TIMER0_CTL_REG 0x10 29#define TIMER_CTL_REG(val) (0x10 * val + 0x10)
32#define TIMER0_CTL_ENABLE (1 << 0) 30#define TIMER_CTL_ENABLE (1 << 0)
33#define TIMER0_CTL_AUTORELOAD (1 << 1) 31#define TIMER_CTL_AUTORELOAD (1 << 1)
34#define TIMER0_CTL_ONESHOT (1 << 7) 32#define TIMER_CTL_ONESHOT (1 << 7)
35#define TIMER0_INTVAL_REG 0x14 33#define TIMER_INTVAL_REG(val) (0x10 * val + 0x14)
36#define TIMER0_CNTVAL_REG 0x18 34#define TIMER_CNTVAL_REG(val) (0x10 * val + 0x18)
37 35
38#define TIMER_SCAL 16 36#define TIMER_SCAL 16
39 37
40static void __iomem *timer_base; 38static void __iomem *timer_base;
41 39
42static void sunxi_clkevt_mode(enum clock_event_mode mode, 40static void sun4i_clkevt_mode(enum clock_event_mode mode,
43 struct clock_event_device *clk) 41 struct clock_event_device *clk)
44{ 42{
45 u32 u = readl(timer_base + TIMER0_CTL_REG); 43 u32 u = readl(timer_base + TIMER_CTL_REG(0));
46 44
47 switch (mode) { 45 switch (mode) {
48 case CLOCK_EVT_MODE_PERIODIC: 46 case CLOCK_EVT_MODE_PERIODIC:
49 u &= ~(TIMER0_CTL_ONESHOT); 47 u &= ~(TIMER_CTL_ONESHOT);
50 writel(u | TIMER0_CTL_ENABLE, timer_base + TIMER0_CTL_REG); 48 writel(u | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0));
51 break; 49 break;
52 50
53 case CLOCK_EVT_MODE_ONESHOT: 51 case CLOCK_EVT_MODE_ONESHOT:
54 writel(u | TIMER0_CTL_ONESHOT, timer_base + TIMER0_CTL_REG); 52 writel(u | TIMER_CTL_ONESHOT, timer_base + TIMER_CTL_REG(0));
55 break; 53 break;
56 case CLOCK_EVT_MODE_UNUSED: 54 case CLOCK_EVT_MODE_UNUSED:
57 case CLOCK_EVT_MODE_SHUTDOWN: 55 case CLOCK_EVT_MODE_SHUTDOWN:
58 default: 56 default:
59 writel(u & ~(TIMER0_CTL_ENABLE), timer_base + TIMER0_CTL_REG); 57 writel(u & ~(TIMER_CTL_ENABLE), timer_base + TIMER_CTL_REG(0));
60 break; 58 break;
61 } 59 }
62} 60}
63 61
64static int sunxi_clkevt_next_event(unsigned long evt, 62static int sun4i_clkevt_next_event(unsigned long evt,
65 struct clock_event_device *unused) 63 struct clock_event_device *unused)
66{ 64{
67 u32 u = readl(timer_base + TIMER0_CTL_REG); 65 u32 u = readl(timer_base + TIMER_CTL_REG(0));
68 writel(evt, timer_base + TIMER0_CNTVAL_REG); 66 writel(evt, timer_base + TIMER_CNTVAL_REG(0));
69 writel(u | TIMER0_CTL_ENABLE | TIMER0_CTL_AUTORELOAD, 67 writel(u | TIMER_CTL_ENABLE | TIMER_CTL_AUTORELOAD,
70 timer_base + TIMER0_CTL_REG); 68 timer_base + TIMER_CTL_REG(0));
71 69
72 return 0; 70 return 0;
73} 71}
74 72
75static struct clock_event_device sunxi_clockevent = { 73static struct clock_event_device sun4i_clockevent = {
76 .name = "sunxi_tick", 74 .name = "sun4i_tick",
77 .rating = 300, 75 .rating = 300,
78 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 76 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
79 .set_mode = sunxi_clkevt_mode, 77 .set_mode = sun4i_clkevt_mode,
80 .set_next_event = sunxi_clkevt_next_event, 78 .set_next_event = sun4i_clkevt_next_event,
81}; 79};
82 80
83 81
84static irqreturn_t sunxi_timer_interrupt(int irq, void *dev_id) 82static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id)
85{ 83{
86 struct clock_event_device *evt = (struct clock_event_device *)dev_id; 84 struct clock_event_device *evt = (struct clock_event_device *)dev_id;
87 85
@@ -91,30 +89,20 @@ static irqreturn_t sunxi_timer_interrupt(int irq, void *dev_id)
91 return IRQ_HANDLED; 89 return IRQ_HANDLED;
92} 90}
93 91
94static struct irqaction sunxi_timer_irq = { 92static struct irqaction sun4i_timer_irq = {
95 .name = "sunxi_timer0", 93 .name = "sun4i_timer0",
96 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 94 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
97 .handler = sunxi_timer_interrupt, 95 .handler = sun4i_timer_interrupt,
98 .dev_id = &sunxi_clockevent, 96 .dev_id = &sun4i_clockevent,
99};
100
101static struct of_device_id sunxi_timer_dt_ids[] = {
102 { .compatible = "allwinner,sunxi-timer" },
103 { }
104}; 97};
105 98
106void __init sunxi_timer_init(void) 99static void __init sun4i_timer_init(struct device_node *node)
107{ 100{
108 struct device_node *node;
109 unsigned long rate = 0; 101 unsigned long rate = 0;
110 struct clk *clk; 102 struct clk *clk;
111 int ret, irq; 103 int ret, irq;
112 u32 val; 104 u32 val;
113 105
114 node = of_find_matching_node(NULL, sunxi_timer_dt_ids);
115 if (!node)
116 panic("No sunxi timer node");
117
118 timer_base = of_iomap(node, 0); 106 timer_base = of_iomap(node, 0);
119 if (!timer_base) 107 if (!timer_base)
120 panic("Can't map registers"); 108 panic("Can't map registers");
@@ -123,8 +111,6 @@ void __init sunxi_timer_init(void)
123 if (irq <= 0) 111 if (irq <= 0)
124 panic("Can't parse IRQ"); 112 panic("Can't parse IRQ");
125 113
126 sunxi_init_clocks();
127
128 clk = of_clk_get(node, 0); 114 clk = of_clk_get(node, 0);
129 if (IS_ERR(clk)) 115 if (IS_ERR(clk))
130 panic("Can't get timer clock"); 116 panic("Can't get timer clock");
@@ -132,29 +118,31 @@ void __init sunxi_timer_init(void)
132 rate = clk_get_rate(clk); 118 rate = clk_get_rate(clk);
133 119
134 writel(rate / (TIMER_SCAL * HZ), 120 writel(rate / (TIMER_SCAL * HZ),
135 timer_base + TIMER0_INTVAL_REG); 121 timer_base + TIMER_INTVAL_REG(0));
136 122
137 /* set clock source to HOSC, 16 pre-division */ 123 /* set clock source to HOSC, 16 pre-division */
138 val = readl(timer_base + TIMER0_CTL_REG); 124 val = readl(timer_base + TIMER_CTL_REG(0));
139 val &= ~(0x07 << 4); 125 val &= ~(0x07 << 4);
140 val &= ~(0x03 << 2); 126 val &= ~(0x03 << 2);
141 val |= (4 << 4) | (1 << 2); 127 val |= (4 << 4) | (1 << 2);
142 writel(val, timer_base + TIMER0_CTL_REG); 128 writel(val, timer_base + TIMER_CTL_REG(0));
143 129
144 /* set mode to auto reload */ 130 /* set mode to auto reload */
145 val = readl(timer_base + TIMER0_CTL_REG); 131 val = readl(timer_base + TIMER_CTL_REG(0));
146 writel(val | TIMER0_CTL_AUTORELOAD, timer_base + TIMER0_CTL_REG); 132 writel(val | TIMER_CTL_AUTORELOAD, timer_base + TIMER_CTL_REG(0));
147 133
148 ret = setup_irq(irq, &sunxi_timer_irq); 134 ret = setup_irq(irq, &sun4i_timer_irq);
149 if (ret) 135 if (ret)
150 pr_warn("failed to setup irq %d\n", irq); 136 pr_warn("failed to setup irq %d\n", irq);
151 137
152 /* Enable timer0 interrupt */ 138 /* Enable timer0 interrupt */
153 val = readl(timer_base + TIMER_CTL_REG); 139 val = readl(timer_base + TIMER_IRQ_EN_REG);
154 writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG); 140 writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG);
155 141
156 sunxi_clockevent.cpumask = cpumask_of(0); 142 sun4i_clockevent.cpumask = cpumask_of(0);
157 143
158 clockevents_config_and_register(&sunxi_clockevent, rate / TIMER_SCAL, 144 clockevents_config_and_register(&sun4i_clockevent, rate / TIMER_SCAL,
159 0x1, 0xff); 145 0x1, 0xff);
160} 146}
147CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer",
148 sun4i_timer_init);
diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c
index 242255285597..64f553f04fa4 100644
--- a/drivers/clocksource/vt8500_timer.c
+++ b/drivers/clocksource/vt8500_timer.c
@@ -165,4 +165,4 @@ static void __init vt8500_timer_init(struct device_node *np)
165 4, 0xf0000000); 165 4, 0xf0000000);
166} 166}
167 167
168CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init) 168CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init);
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 9d8f4f1c6e39..d5e119ca9425 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o
5obj-$(CONFIG_ARCH_MXS) += irq-mxs.o 5obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
6obj-$(CONFIG_METAG) += irq-metag-ext.o 6obj-$(CONFIG_METAG) += irq-metag-ext.o
7obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o 7obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
8obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi.o 8obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
9obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o 9obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
10obj-$(CONFIG_ARM_GIC) += irq-gic.o 10obj-$(CONFIG_ARM_GIC) += irq-gic.o
11obj-$(CONFIG_ARM_VIC) += irq-vic.o 11obj-$(CONFIG_ARM_VIC) += irq-vic.o
diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
new file mode 100644
index 000000000000..b66d4ae06898
--- /dev/null
+++ b/drivers/irqchip/irq-sun4i.c
@@ -0,0 +1,149 @@
1/*
2 * Allwinner A1X SoCs IRQ chip driver.
3 *
4 * Copyright (C) 2012 Maxime Ripard
5 *
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
7 *
8 * Based on code from
9 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
10 * Benn Huang <benn@allwinnertech.com>
11 *
12 * This file is licensed under the terms of the GNU General Public
13 * License version 2. This program is licensed "as is" without any
14 * warranty of any kind, whether express or implied.
15 */
16
17#include <linux/io.h>
18#include <linux/irq.h>
19#include <linux/of.h>
20#include <linux/of_address.h>
21#include <linux/of_irq.h>
22
23#include <asm/exception.h>
24#include <asm/mach/irq.h>
25
26#include "irqchip.h"
27
28#define SUN4I_IRQ_VECTOR_REG 0x00
29#define SUN4I_IRQ_PROTECTION_REG 0x08
30#define SUN4I_IRQ_NMI_CTRL_REG 0x0c
31#define SUN4I_IRQ_PENDING_REG(x) (0x10 + 0x4 * x)
32#define SUN4I_IRQ_FIQ_PENDING_REG(x) (0x20 + 0x4 * x)
33#define SUN4I_IRQ_ENABLE_REG(x) (0x40 + 0x4 * x)
34#define SUN4I_IRQ_MASK_REG(x) (0x50 + 0x4 * x)
35
36static void __iomem *sun4i_irq_base;
37static struct irq_domain *sun4i_irq_domain;
38
39static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs);
40
41void sun4i_irq_ack(struct irq_data *irqd)
42{
43 unsigned int irq = irqd_to_hwirq(irqd);
44 unsigned int irq_off = irq % 32;
45 int reg = irq / 32;
46 u32 val;
47
48 val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
49 writel(val | (1 << irq_off),
50 sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
51}
52
53static void sun4i_irq_mask(struct irq_data *irqd)
54{
55 unsigned int irq = irqd_to_hwirq(irqd);
56 unsigned int irq_off = irq % 32;
57 int reg = irq / 32;
58 u32 val;
59
60 val = readl(sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg));
61 writel(val & ~(1 << irq_off),
62 sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg));
63}
64
65static void sun4i_irq_unmask(struct irq_data *irqd)
66{
67 unsigned int irq = irqd_to_hwirq(irqd);
68 unsigned int irq_off = irq % 32;
69 int reg = irq / 32;
70 u32 val;
71
72 val = readl(sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg));
73 writel(val | (1 << irq_off),
74 sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg));
75}
76
77static struct irq_chip sun4i_irq_chip = {
78 .name = "sun4i_irq",
79 .irq_ack = sun4i_irq_ack,
80 .irq_mask = sun4i_irq_mask,
81 .irq_unmask = sun4i_irq_unmask,
82};
83
84static int sun4i_irq_map(struct irq_domain *d, unsigned int virq,
85 irq_hw_number_t hw)
86{
87 irq_set_chip_and_handler(virq, &sun4i_irq_chip,
88 handle_level_irq);
89 set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
90
91 return 0;
92}
93
94static struct irq_domain_ops sun4i_irq_ops = {
95 .map = sun4i_irq_map,
96 .xlate = irq_domain_xlate_onecell,
97};
98
99static int __init sun4i_of_init(struct device_node *node,
100 struct device_node *parent)
101{
102 sun4i_irq_base = of_iomap(node, 0);
103 if (!sun4i_irq_base)
104 panic("%s: unable to map IC registers\n",
105 node->full_name);
106
107 /* Disable all interrupts */
108 writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(0));
109 writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1));
110 writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2));
111
112 /* Mask all the interrupts */
113 writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0));
114 writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1));
115 writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2));
116
117 /* Clear all the pending interrupts */
118 writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0));
119 writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(1));
120 writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(2));
121
122 /* Enable protection mode */
123 writel(0x01, sun4i_irq_base + SUN4I_IRQ_PROTECTION_REG);
124
125 /* Configure the external interrupt source type */
126 writel(0x00, sun4i_irq_base + SUN4I_IRQ_NMI_CTRL_REG);
127
128 sun4i_irq_domain = irq_domain_add_linear(node, 3 * 32,
129 &sun4i_irq_ops, NULL);
130 if (!sun4i_irq_domain)
131 panic("%s: unable to create IRQ domain\n", node->full_name);
132
133 set_handle_irq(sun4i_handle_irq);
134
135 return 0;
136}
137IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-ic", sun4i_of_init);
138
139static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
140{
141 u32 irq, hwirq;
142
143 hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
144 while (hwirq != 0) {
145 irq = irq_find_mapping(sun4i_irq_domain, hwirq);
146 handle_IRQ(irq, regs);
147 hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
148 }
149}
diff --git a/drivers/irqchip/irq-sunxi.c b/drivers/irqchip/irq-sunxi.c
deleted file mode 100644
index 10974fa42653..000000000000
--- a/drivers/irqchip/irq-sunxi.c
+++ /dev/null
@@ -1,151 +0,0 @@
1/*
2 * Allwinner A1X SoCs IRQ chip driver.
3 *
4 * Copyright (C) 2012 Maxime Ripard
5 *
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
7 *
8 * Based on code from
9 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
10 * Benn Huang <benn@allwinnertech.com>
11 *
12 * This file is licensed under the terms of the GNU General Public
13 * License version 2. This program is licensed "as is" without any
14 * warranty of any kind, whether express or implied.
15 */
16
17#include <linux/io.h>
18#include <linux/irq.h>
19#include <linux/of.h>
20#include <linux/of_address.h>
21#include <linux/of_irq.h>
22
23#include <linux/irqchip/sunxi.h>
24
25#define SUNXI_IRQ_VECTOR_REG 0x00
26#define SUNXI_IRQ_PROTECTION_REG 0x08
27#define SUNXI_IRQ_NMI_CTRL_REG 0x0c
28#define SUNXI_IRQ_PENDING_REG(x) (0x10 + 0x4 * x)
29#define SUNXI_IRQ_FIQ_PENDING_REG(x) (0x20 + 0x4 * x)
30#define SUNXI_IRQ_ENABLE_REG(x) (0x40 + 0x4 * x)
31#define SUNXI_IRQ_MASK_REG(x) (0x50 + 0x4 * x)
32
33static void __iomem *sunxi_irq_base;
34static struct irq_domain *sunxi_irq_domain;
35
36void sunxi_irq_ack(struct irq_data *irqd)
37{
38 unsigned int irq = irqd_to_hwirq(irqd);
39 unsigned int irq_off = irq % 32;
40 int reg = irq / 32;
41 u32 val;
42
43 val = readl(sunxi_irq_base + SUNXI_IRQ_PENDING_REG(reg));
44 writel(val | (1 << irq_off),
45 sunxi_irq_base + SUNXI_IRQ_PENDING_REG(reg));
46}
47
48static void sunxi_irq_mask(struct irq_data *irqd)
49{
50 unsigned int irq = irqd_to_hwirq(irqd);
51 unsigned int irq_off = irq % 32;
52 int reg = irq / 32;
53 u32 val;
54
55 val = readl(sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
56 writel(val & ~(1 << irq_off),
57 sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
58}
59
60static void sunxi_irq_unmask(struct irq_data *irqd)
61{
62 unsigned int irq = irqd_to_hwirq(irqd);
63 unsigned int irq_off = irq % 32;
64 int reg = irq / 32;
65 u32 val;
66
67 val = readl(sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
68 writel(val | (1 << irq_off),
69 sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg));
70}
71
72static struct irq_chip sunxi_irq_chip = {
73 .name = "sunxi_irq",
74 .irq_ack = sunxi_irq_ack,
75 .irq_mask = sunxi_irq_mask,
76 .irq_unmask = sunxi_irq_unmask,
77};
78
79static int sunxi_irq_map(struct irq_domain *d, unsigned int virq,
80 irq_hw_number_t hw)
81{
82 irq_set_chip_and_handler(virq, &sunxi_irq_chip,
83 handle_level_irq);
84 set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
85
86 return 0;
87}
88
89static struct irq_domain_ops sunxi_irq_ops = {
90 .map = sunxi_irq_map,
91 .xlate = irq_domain_xlate_onecell,
92};
93
94static int __init sunxi_of_init(struct device_node *node,
95 struct device_node *parent)
96{
97 sunxi_irq_base = of_iomap(node, 0);
98 if (!sunxi_irq_base)
99 panic("%s: unable to map IC registers\n",
100 node->full_name);
101
102 /* Disable all interrupts */
103 writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(0));
104 writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(1));
105 writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(2));
106
107 /* Mask all the interrupts */
108 writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(0));
109 writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(1));
110 writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(2));
111
112 /* Clear all the pending interrupts */
113 writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(0));
114 writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(1));
115 writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(2));
116
117 /* Enable protection mode */
118 writel(0x01, sunxi_irq_base + SUNXI_IRQ_PROTECTION_REG);
119
120 /* Configure the external interrupt source type */
121 writel(0x00, sunxi_irq_base + SUNXI_IRQ_NMI_CTRL_REG);
122
123 sunxi_irq_domain = irq_domain_add_linear(node, 3 * 32,
124 &sunxi_irq_ops, NULL);
125 if (!sunxi_irq_domain)
126 panic("%s: unable to create IRQ domain\n", node->full_name);
127
128 return 0;
129}
130
131static struct of_device_id sunxi_irq_dt_ids[] __initconst = {
132 { .compatible = "allwinner,sunxi-ic", .data = sunxi_of_init },
133 { }
134};
135
136void __init sunxi_init_irq(void)
137{
138 of_irq_init(sunxi_irq_dt_ids);
139}
140
141asmlinkage void __exception_irq_entry sunxi_handle_irq(struct pt_regs *regs)
142{
143 u32 irq, hwirq;
144
145 hwirq = readl(sunxi_irq_base + SUNXI_IRQ_VECTOR_REG) >> 2;
146 while (hwirq != 0) {
147 irq = irq_find_mapping(sunxi_irq_domain, hwirq);
148 handle_IRQ(irq, regs);
149 hwirq = readl(sunxi_irq_base + SUNXI_IRQ_VECTOR_REG) >> 2;
150 }
151}
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 08ed5e19d8c6..192d6d1771ee 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -332,16 +332,23 @@ extern int clocksource_mmio_init(void __iomem *, const char *,
332 332
333extern int clocksource_i8253_init(void); 333extern int clocksource_i8253_init(void);
334 334
335struct device_node;
336typedef void(*clocksource_of_init_fn)(struct device_node *);
335#ifdef CONFIG_CLKSRC_OF 337#ifdef CONFIG_CLKSRC_OF
336extern void clocksource_of_init(void); 338extern void clocksource_of_init(void);
337 339
338#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ 340#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \
339 static const struct of_device_id __clksrc_of_table_##name \ 341 static const struct of_device_id __clksrc_of_table_##name \
340 __used __section(__clksrc_of_table) \ 342 __used __section(__clksrc_of_table) \
341 = { .compatible = compat, .data = fn }; 343 = { .compatible = compat, \
344 .data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn }
342#else 345#else
343static inline void clocksource_of_init(void) {} 346static inline void clocksource_of_init(void) {}
344#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) 347#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \
348 static const struct of_device_id __clksrc_of_table_##name \
349 __attribute__((unused)) \
350 = { .compatible = compat, \
351 .data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn }
345#endif 352#endif
346 353
347#endif /* _LINUX_CLOCKSOURCE_H */ 354#endif /* _LINUX_CLOCKSOURCE_H */
diff --git a/include/linux/irqchip/sunxi.h b/include/linux/irqchip/sunxi.h
deleted file mode 100644
index 1fe2c2260e2b..000000000000
--- a/include/linux/irqchip/sunxi.h
+++ /dev/null
@@ -1,27 +0,0 @@
1/*
2 * Copyright 2012 Maxime Ripard
3 *
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#ifndef __LINUX_IRQCHIP_SUNXI_H
18#define __LINUX_IRQCHIP_SUNXI_H
19
20#include <asm/exception.h>
21
22extern void sunxi_init_irq(void);
23
24extern asmlinkage void __exception_irq_entry sunxi_handle_irq(
25 struct pt_regs *regs);
26
27#endif
diff --git a/include/linux/sunxi_timer.h b/include/linux/sunxi_timer.h
deleted file mode 100644
index 18081787e5f3..000000000000
--- a/include/linux/sunxi_timer.h
+++ /dev/null
@@ -1,24 +0,0 @@
1/*
2 * Copyright 2012 Maxime Ripard
3 *
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#ifndef __SUNXI_TIMER_H
18#define __SUNXI_TIMER_H
19
20#include <asm/mach/time.h>
21
22void sunxi_timer_init(void);
23
24#endif