aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/boot/dts/emev2-kzm9d.dts26
-rw-r--r--arch/arm/boot/dts/emev2.dtsi63
-rw-r--r--arch/arm/mach-shmobile/Kconfig11
-rw-r--r--arch/arm/mach-shmobile/Makefile3
-rw-r--r--arch/arm/mach-shmobile/board-kzm9d.c85
-rw-r--r--arch/arm/mach-shmobile/clock-emev2.c249
-rw-r--r--arch/arm/mach-shmobile/include/mach/emev2.h19
-rw-r--r--arch/arm/mach-shmobile/platsmp.c18
-rw-r--r--arch/arm/mach-shmobile/setup-emev2.c452
-rw-r--r--arch/arm/mach-shmobile/smp-emev2.c97
-rw-r--r--drivers/gpio/Kconfig6
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-em.c418
-rw-r--r--include/linux/platform_data/gpio-em.h10
14 files changed, 1458 insertions, 0 deletions
diff --git a/arch/arm/boot/dts/emev2-kzm9d.dts b/arch/arm/boot/dts/emev2-kzm9d.dts
new file mode 100644
index 00000000000..297e3baba71
--- /dev/null
+++ b/arch/arm/boot/dts/emev2-kzm9d.dts
@@ -0,0 +1,26 @@
1/*
2 * Device Tree Source for the KZM9D board
3 *
4 * Copyright (C) 2012 Renesas Solutions Corp.
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 */
10/dts-v1/;
11
12/include/ "emev2.dtsi"
13
14/ {
15 model = "EMEV2 KZM9D Board";
16 compatible = "renesas,kzm9d", "renesas,emev2";
17
18 memory {
19 device_type = "memory";
20 reg = <0x40000000 0x8000000>;
21 };
22
23 chosen {
24 bootargs = "console=ttyS1,115200n81";
25 };
26};
diff --git a/arch/arm/boot/dts/emev2.dtsi b/arch/arm/boot/dts/emev2.dtsi
new file mode 100644
index 00000000000..eb504a6c0f4
--- /dev/null
+++ b/arch/arm/boot/dts/emev2.dtsi
@@ -0,0 +1,63 @@
1/*
2 * Device Tree Source for the EMEV2 SoC
3 *
4 * Copyright (C) 2012 Renesas Solutions Corp.
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 */
10
11/include/ "skeleton.dtsi"
12
13/ {
14 compatible = "renesas,emev2";
15 interrupt-parent = <&gic>;
16
17 cpus {
18 cpu@0 {
19 compatible = "arm,cortex-a9";
20 };
21 cpu@1 {
22 compatible = "arm,cortex-a9";
23 };
24 };
25
26 gic: interrupt-controller@e0020000 {
27 compatible = "arm,cortex-a9-gic";
28 interrupt-controller;
29 #interrupt-cells = <3>;
30 reg = <0xe0028000 0x1000>,
31 <0xe0020000 0x0100>;
32 };
33
34 sti@e0180000 {
35 compatible = "renesas,em-sti";
36 reg = <0xe0180000 0x54>;
37 interrupts = <0 125 0>;
38 };
39
40 uart@e1020000 {
41 compatible = "renesas,em-uart";
42 reg = <0xe1020000 0x38>;
43 interrupts = <0 8 0>;
44 };
45
46 uart@e1030000 {
47 compatible = "renesas,em-uart";
48 reg = <0xe1030000 0x38>;
49 interrupts = <0 9 0>;
50 };
51
52 uart@e1040000 {
53 compatible = "renesas,em-uart";
54 reg = <0xe1040000 0x38>;
55 interrupts = <0 10 0>;
56 };
57
58 uart@e1050000 {
59 compatible = "renesas,em-uart";
60 reg = <0xe1050000 0x38>;
61 interrupts = <0 11 0>;
62 };
63};
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 34560cab45d..7dcf08ee979 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -41,6 +41,12 @@ config ARCH_R8A7779
41 select ARM_GIC 41 select ARM_GIC
42 select ARCH_WANT_OPTIONAL_GPIOLIB 42 select ARCH_WANT_OPTIONAL_GPIOLIB
43 43
44config ARCH_EMEV2
45 bool "Emma Mobile EV2"
46 select CPU_V7
47 select ARM_GIC
48 select ARCH_WANT_OPTIONAL_GPIOLIB
49
44comment "SH-Mobile Board Type" 50comment "SH-Mobile Board Type"
45 51
46config MACH_G3EVM 52config MACH_G3EVM
@@ -98,6 +104,11 @@ config MACH_MARZEN
98 depends on ARCH_R8A7779 104 depends on ARCH_R8A7779
99 select ARCH_REQUIRE_GPIOLIB 105 select ARCH_REQUIRE_GPIOLIB
100 106
107config MACH_KZM9D
108 bool "KZM9D board"
109 depends on ARCH_EMEV2
110 select USE_OF
111
101comment "SH-Mobile System Configuration" 112comment "SH-Mobile System Configuration"
102 113
103config CPU_HAS_INTEVT 114config CPU_HAS_INTEVT
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index e7c2590b75d..c795335931c 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -12,12 +12,14 @@ obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o
12obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o 12obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o
13obj-$(CONFIG_ARCH_R8A7740) += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o 13obj-$(CONFIG_ARCH_R8A7740) += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o
14obj-$(CONFIG_ARCH_R8A7779) += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o 14obj-$(CONFIG_ARCH_R8A7779) += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o
15obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o clock-emev2.o
15 16
16# SMP objects 17# SMP objects
17smp-y := platsmp.o headsmp.o 18smp-y := platsmp.o headsmp.o
18smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o 19smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o
19smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o 20smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o
20smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o 21smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o
22smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o
21 23
22# Pinmux setup 24# Pinmux setup
23pfc-y := 25pfc-y :=
@@ -49,6 +51,7 @@ obj-$(CONFIG_MACH_MACKEREL) += board-mackerel.o
49obj-$(CONFIG_MACH_KOTA2) += board-kota2.o 51obj-$(CONFIG_MACH_KOTA2) += board-kota2.o
50obj-$(CONFIG_MACH_BONITO) += board-bonito.o 52obj-$(CONFIG_MACH_BONITO) += board-bonito.o
51obj-$(CONFIG_MACH_MARZEN) += board-marzen.o 53obj-$(CONFIG_MACH_MARZEN) += board-marzen.o
54obj-$(CONFIG_MACH_KZM9D) += board-kzm9d.o
52 55
53# Framework support 56# Framework support
54obj-$(CONFIG_SMP) += $(smp-y) 57obj-$(CONFIG_SMP) += $(smp-y)
diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c
new file mode 100644
index 00000000000..7bc5e7d39f9
--- /dev/null
+++ b/arch/arm/mach-shmobile/board-kzm9d.c
@@ -0,0 +1,85 @@
1/*
2 * kzm9d board support
3 *
4 * Copyright (C) 2012 Renesas Solutions Corp.
5 * Copyright (C) 2012 Magnus Damm
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
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 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/interrupt.h>
23#include <linux/platform_device.h>
24#include <linux/smsc911x.h>
25#include <mach/common.h>
26#include <mach/emev2.h>
27#include <asm/mach-types.h>
28#include <asm/mach/arch.h>
29#include <asm/hardware/gic.h>
30
31/* Ether */
32static struct resource smsc911x_resources[] = {
33 [0] = {
34 .start = 0x20000000,
35 .end = 0x2000ffff,
36 .flags = IORESOURCE_MEM,
37 },
38 [1] = {
39 .start = EMEV2_GPIO_IRQ(1),
40 .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
41 },
42};
43
44static struct smsc911x_platform_config smsc911x_platdata = {
45 .flags = SMSC911X_USE_32BIT,
46 .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
47 .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
48};
49
50static struct platform_device smsc91x_device = {
51 .name = "smsc911x",
52 .id = 0,
53 .dev = {
54 .platform_data = &smsc911x_platdata,
55 },
56 .num_resources = ARRAY_SIZE(smsc911x_resources),
57 .resource = smsc911x_resources,
58};
59
60static struct platform_device *kzm9d_devices[] __initdata = {
61 &smsc91x_device,
62};
63
64void __init kzm9d_add_standard_devices(void)
65{
66 emev2_add_standard_devices();
67
68 platform_add_devices(kzm9d_devices, ARRAY_SIZE(kzm9d_devices));
69}
70
71static const char *kzm9d_boards_compat_dt[] __initdata = {
72 "renesas,kzm9d",
73 NULL,
74};
75
76DT_MACHINE_START(KZM9D_DT, "kzm9d")
77 .map_io = emev2_map_io,
78 .init_early = emev2_add_early_devices,
79 .nr_irqs = NR_IRQS_LEGACY,
80 .init_irq = emev2_init_irq,
81 .handle_irq = gic_handle_irq,
82 .init_machine = kzm9d_add_standard_devices,
83 .timer = &shmobile_timer,
84 .dt_compat = kzm9d_boards_compat_dt,
85MACHINE_END
diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c
new file mode 100644
index 00000000000..4710f1847bb
--- /dev/null
+++ b/arch/arm/mach-shmobile/clock-emev2.c
@@ -0,0 +1,249 @@
1/*
2 * Emma Mobile EV2 clock framework support
3 *
4 * Copyright (C) 2012 Magnus Damm
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; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#include <linux/init.h>
20#include <linux/kernel.h>
21#include <linux/io.h>
22#include <linux/sh_clk.h>
23#include <linux/clkdev.h>
24#include <mach/common.h>
25
26#define EMEV2_SMU_BASE 0xe0110000
27
28/* EMEV2 SMU registers */
29#define USIAU0_RSTCTRL 0x094
30#define USIBU1_RSTCTRL 0x0ac
31#define USIBU2_RSTCTRL 0x0b0
32#define USIBU3_RSTCTRL 0x0b4
33#define STI_RSTCTRL 0x124
34#define USIAU0GCLKCTRL 0x4a0
35#define USIBU1GCLKCTRL 0x4b8
36#define USIBU2GCLKCTRL 0x4bc
37#define USIBU3GCLKCTRL 0x04c0
38#define STIGCLKCTRL 0x528
39#define USIAU0SCLKDIV 0x61c
40#define USIB2SCLKDIV 0x65c
41#define USIB3SCLKDIV 0x660
42#define STI_CLKSEL 0x688
43#define SMU_GENERAL_REG0 0x7c0
44
45/* not pretty, but hey */
46static void __iomem *smu_base;
47
48static void emev2_smu_write(unsigned long value, int offs)
49{
50 BUG_ON(!smu_base || (offs >= PAGE_SIZE));
51 iowrite32(value, smu_base + offs);
52}
53
54void emev2_set_boot_vector(unsigned long value)
55{
56 emev2_smu_write(value, SMU_GENERAL_REG0);
57}
58
59static struct clk_mapping smu_mapping = {
60 .phys = EMEV2_SMU_BASE,
61 .len = PAGE_SIZE,
62};
63
64/* Fixed 32 KHz root clock from C32K pin */
65static struct clk c32k_clk = {
66 .rate = 32768,
67 .mapping = &smu_mapping,
68};
69
70/* PLL3 multiplies C32K with 7000 */
71static unsigned long pll3_recalc(struct clk *clk)
72{
73 return clk->parent->rate * 7000;
74}
75
76static struct sh_clk_ops pll3_clk_ops = {
77 .recalc = pll3_recalc,
78};
79
80static struct clk pll3_clk = {
81 .ops = &pll3_clk_ops,
82 .parent = &c32k_clk,
83};
84
85static struct clk *main_clks[] = {
86 &c32k_clk,
87 &pll3_clk,
88};
89
90enum { SCLKDIV_USIAU0, SCLKDIV_USIBU2, SCLKDIV_USIBU1, SCLKDIV_USIBU3,
91 SCLKDIV_NR };
92
93#define SCLKDIV(_reg, _shift) \
94{ \
95 .parent = &pll3_clk, \
96 .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \
97 .enable_bit = _shift, \
98}
99
100static struct clk sclkdiv_clks[SCLKDIV_NR] = {
101 [SCLKDIV_USIAU0] = SCLKDIV(USIAU0SCLKDIV, 0),
102 [SCLKDIV_USIBU2] = SCLKDIV(USIB2SCLKDIV, 16),
103 [SCLKDIV_USIBU1] = SCLKDIV(USIB2SCLKDIV, 0),
104 [SCLKDIV_USIBU3] = SCLKDIV(USIB3SCLKDIV, 0),
105};
106
107enum { GCLK_USIAU0_SCLK, GCLK_USIBU1_SCLK, GCLK_USIBU2_SCLK, GCLK_USIBU3_SCLK,
108 GCLK_STI_SCLK,
109 GCLK_NR };
110
111#define GCLK_SCLK(_parent, _reg) \
112{ \
113 .parent = _parent, \
114 .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \
115 .enable_bit = 1, /* SCLK_GCC */ \
116}
117
118static struct clk gclk_clks[GCLK_NR] = {
119 [GCLK_USIAU0_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIAU0],
120 USIAU0GCLKCTRL),
121 [GCLK_USIBU1_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU1],
122 USIBU1GCLKCTRL),
123 [GCLK_USIBU2_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU2],
124 USIBU2GCLKCTRL),
125 [GCLK_USIBU3_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU3],
126 USIBU3GCLKCTRL),
127 [GCLK_STI_SCLK] = GCLK_SCLK(&c32k_clk, STIGCLKCTRL),
128};
129
130static int emev2_gclk_enable(struct clk *clk)
131{
132 iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
133 clk->mapped_reg);
134 return 0;
135}
136
137static void emev2_gclk_disable(struct clk *clk)
138{
139 iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
140 clk->mapped_reg);
141}
142
143static struct sh_clk_ops emev2_gclk_clk_ops = {
144 .enable = emev2_gclk_enable,
145 .disable = emev2_gclk_disable,
146 .recalc = followparent_recalc,
147};
148
149static int __init emev2_gclk_register(struct clk *clks, int nr)
150{
151 struct clk *clkp;
152 int ret = 0;
153 int k;
154
155 for (k = 0; !ret && (k < nr); k++) {
156 clkp = clks + k;
157 clkp->ops = &emev2_gclk_clk_ops;
158 ret |= clk_register(clkp);
159 }
160
161 return ret;
162}
163
164static unsigned long emev2_sclkdiv_recalc(struct clk *clk)
165{
166 unsigned int sclk_div;
167
168 sclk_div = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0xff;
169
170 return clk->parent->rate / (sclk_div + 1);
171}
172
173static struct sh_clk_ops emev2_sclkdiv_clk_ops = {
174 .recalc = emev2_sclkdiv_recalc,
175};
176
177static int __init emev2_sclkdiv_register(struct clk *clks, int nr)
178{
179 struct clk *clkp;
180 int ret = 0;
181 int k;
182
183 for (k = 0; !ret && (k < nr); k++) {
184 clkp = clks + k;
185 clkp->ops = &emev2_sclkdiv_clk_ops;
186 ret |= clk_register(clkp);
187 }
188
189 return ret;
190}
191
192static struct clk_lookup lookups[] = {
193 CLKDEV_DEV_ID("serial8250-em.0", &gclk_clks[GCLK_USIAU0_SCLK]),
194 CLKDEV_DEV_ID("e1020000.uart", &gclk_clks[GCLK_USIAU0_SCLK]),
195 CLKDEV_DEV_ID("serial8250-em.1", &gclk_clks[GCLK_USIBU1_SCLK]),
196 CLKDEV_DEV_ID("e1030000.uart", &gclk_clks[GCLK_USIBU1_SCLK]),
197 CLKDEV_DEV_ID("serial8250-em.2", &gclk_clks[GCLK_USIBU2_SCLK]),
198 CLKDEV_DEV_ID("e1040000.uart", &gclk_clks[GCLK_USIBU2_SCLK]),
199 CLKDEV_DEV_ID("serial8250-em.3", &gclk_clks[GCLK_USIBU3_SCLK]),
200 CLKDEV_DEV_ID("e1050000.uart", &gclk_clks[GCLK_USIBU3_SCLK]),
201 CLKDEV_DEV_ID("em_sti.0", &gclk_clks[GCLK_STI_SCLK]),
202 CLKDEV_DEV_ID("e0180000.sti", &gclk_clks[GCLK_STI_SCLK]),
203};
204
205void __init emev2_clock_init(void)
206{
207 int k, ret = 0;
208 static int is_setup;
209
210 /* yuck, this is ugly as hell, but the non-smp case of clocks
211 * code is now designed to rely on ioremap() instead of static
212 * entity maps. in the case of smp we need access to the SMU
213 * register earlier than ioremap() is actually working without
214 * any static maps. to enable SMP in ugly but with dynamic
215 * mappings we have to call emev2_clock_init() from different
216 * places depending on UP and SMP...
217 */
218 if (is_setup++)
219 return;
220
221 smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE);
222 BUG_ON(!smu_base);
223
224 /* setup STI timer to run on 37.768 kHz and deassert reset */
225 emev2_smu_write(0, STI_CLKSEL);
226 emev2_smu_write(1, STI_RSTCTRL);
227
228 /* deassert reset for UART0->UART3 */
229 emev2_smu_write(2, USIAU0_RSTCTRL);
230 emev2_smu_write(2, USIBU1_RSTCTRL);
231 emev2_smu_write(2, USIBU2_RSTCTRL);
232 emev2_smu_write(2, USIBU3_RSTCTRL);
233
234 for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
235 ret = clk_register(main_clks[k]);
236
237 if (!ret)
238 ret = emev2_sclkdiv_register(sclkdiv_clks, SCLKDIV_NR);
239
240 if (!ret)
241 ret = emev2_gclk_register(gclk_clks, GCLK_NR);
242
243 clkdev_add_table(lookups, ARRAY_SIZE(lookups));
244
245 if (!ret)
246 shmobile_clk_init();
247 else
248 panic("failed to setup emev2 clocks\n");
249}
diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h
new file mode 100644
index 00000000000..e6b0c1bf4b7
--- /dev/null
+++ b/arch/arm/mach-shmobile/include/mach/emev2.h
@@ -0,0 +1,19 @@
1#ifndef __ASM_EMEV2_H__
2#define __ASM_EMEV2_H__
3
4extern void emev2_map_io(void);
5extern void emev2_init_irq(void);
6extern void emev2_add_early_devices(void);
7extern void emev2_add_standard_devices(void);
8extern void emev2_clock_init(void);
9extern void emev2_set_boot_vector(unsigned long value);
10extern unsigned int emev2_get_core_count(void);
11extern int emev2_platform_cpu_kill(unsigned int cpu);
12extern void emev2_secondary_init(unsigned int cpu);
13extern int emev2_boot_secondary(unsigned int cpu);
14extern void emev2_smp_prepare_cpus(void);
15
16#define EMEV2_GPIO_BASE 200
17#define EMEV2_GPIO_IRQ(n) (EMEV2_GPIO_BASE + (n))
18
19#endif /* __ASM_EMEV2_H__ */
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c
index 45fa3924c6a..7006cdc8b8c 100644
--- a/arch/arm/mach-shmobile/platsmp.c
+++ b/arch/arm/mach-shmobile/platsmp.c
@@ -16,12 +16,15 @@
16#include <linux/device.h> 16#include <linux/device.h>
17#include <linux/smp.h> 17#include <linux/smp.h>
18#include <linux/io.h> 18#include <linux/io.h>
19#include <linux/of.h>
19#include <asm/hardware/gic.h> 20#include <asm/hardware/gic.h>
20#include <asm/mach-types.h> 21#include <asm/mach-types.h>
21#include <mach/common.h> 22#include <mach/common.h>
23#include <mach/emev2.h>
22 24
23#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2()) 25#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2())
24#define is_r8a7779() machine_is_marzen() 26#define is_r8a7779() machine_is_marzen()
27#define is_emev2() of_machine_is_compatible("renesas,emev2")
25 28
26static unsigned int __init shmobile_smp_get_core_count(void) 29static unsigned int __init shmobile_smp_get_core_count(void)
27{ 30{
@@ -31,6 +34,9 @@ static unsigned int __init shmobile_smp_get_core_count(void)
31 if (is_r8a7779()) 34 if (is_r8a7779())
32 return r8a7779_get_core_count(); 35 return r8a7779_get_core_count();
33 36
37 if (is_emev2())
38 return emev2_get_core_count();
39
34 return 1; 40 return 1;
35} 41}
36 42
@@ -41,6 +47,9 @@ static void __init shmobile_smp_prepare_cpus(void)
41 47
42 if (is_r8a7779()) 48 if (is_r8a7779())
43 r8a7779_smp_prepare_cpus(); 49 r8a7779_smp_prepare_cpus();
50
51 if (is_emev2())
52 emev2_smp_prepare_cpus();
44} 53}
45 54
46int shmobile_platform_cpu_kill(unsigned int cpu) 55int shmobile_platform_cpu_kill(unsigned int cpu)
@@ -48,6 +57,9 @@ int shmobile_platform_cpu_kill(unsigned int cpu)
48 if (is_r8a7779()) 57 if (is_r8a7779())
49 return r8a7779_platform_cpu_kill(cpu); 58 return r8a7779_platform_cpu_kill(cpu);
50 59
60 if (is_emev2())
61 return emev2_platform_cpu_kill(cpu);
62
51 return 1; 63 return 1;
52} 64}
53 65
@@ -60,6 +72,9 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
60 72
61 if (is_r8a7779()) 73 if (is_r8a7779())
62 r8a7779_secondary_init(cpu); 74 r8a7779_secondary_init(cpu);
75
76 if (is_emev2())
77 emev2_secondary_init(cpu);
63} 78}
64 79
65int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) 80int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -70,6 +85,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
70 if (is_r8a7779()) 85 if (is_r8a7779())
71 return r8a7779_boot_secondary(cpu); 86 return r8a7779_boot_secondary(cpu);
72 87
88 if (is_emev2())
89 return emev2_boot_secondary(cpu);
90
73 return -ENOSYS; 91 return -ENOSYS;
74} 92}
75 93
diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c
new file mode 100644
index 00000000000..dae9aa68bb0
--- /dev/null
+++ b/arch/arm/mach-shmobile/setup-emev2.c
@@ -0,0 +1,452 @@
1/*
2 * Emma Mobile EV2 processor support
3 *
4 * Copyright (C) 2012 Magnus Damm
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; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23#include <linux/platform_device.h>
24#include <linux/platform_data/gpio-em.h>
25#include <linux/of_platform.h>
26#include <linux/delay.h>
27#include <linux/input.h>
28#include <linux/io.h>
29#include <linux/of_irq.h>
30#include <mach/hardware.h>
31#include <mach/common.h>
32#include <mach/emev2.h>
33#include <mach/irqs.h>
34#include <asm/mach-types.h>
35#include <asm/mach/arch.h>
36#include <asm/mach/map.h>
37#include <asm/mach/time.h>
38#include <asm/hardware/gic.h>
39
40static struct map_desc emev2_io_desc[] __initdata = {
41#ifdef CONFIG_SMP
42 /* 128K entity map for 0xe0100000 (SMU) */
43 {
44 .virtual = 0xe0100000,
45 .pfn = __phys_to_pfn(0xe0100000),
46 .length = SZ_128K,
47 .type = MT_DEVICE
48 },
49 /* 2M mapping for SCU + L2 controller */
50 {
51 .virtual = 0xf0000000,
52 .pfn = __phys_to_pfn(0x1e000000),
53 .length = SZ_2M,
54 .type = MT_DEVICE
55 },
56#endif
57};
58
59void __init emev2_map_io(void)
60{
61 iotable_init(emev2_io_desc, ARRAY_SIZE(emev2_io_desc));
62}
63
64/* UART */
65static struct resource uart0_resources[] = {
66 [0] = {
67 .start = 0xe1020000,
68 .end = 0xe1020037,
69 .flags = IORESOURCE_MEM,
70 },
71 [1] = {
72 .start = 40,
73 .flags = IORESOURCE_IRQ,
74 }
75};
76
77static struct platform_device uart0_device = {
78 .name = "serial8250-em",
79 .id = 0,
80 .num_resources = ARRAY_SIZE(uart0_resources),
81 .resource = uart0_resources,
82};
83
84static struct resource uart1_resources[] = {
85 [0] = {
86 .start = 0xe1030000,
87 .end = 0xe1030037,
88 .flags = IORESOURCE_MEM,
89 },
90 [1] = {
91 .start = 41,
92 .flags = IORESOURCE_IRQ,
93 }
94};
95
96static struct platform_device uart1_device = {
97 .name = "serial8250-em",
98 .id = 1,
99 .num_resources = ARRAY_SIZE(uart1_resources),
100 .resource = uart1_resources,
101};
102
103static struct resource uart2_resources[] = {
104 [0] = {
105 .start = 0xe1040000,
106 .end = 0xe1040037,
107 .flags = IORESOURCE_MEM,
108 },
109 [1] = {
110 .start = 42,
111 .flags = IORESOURCE_IRQ,
112 }
113};
114
115static struct platform_device uart2_device = {
116 .name = "serial8250-em",
117 .id = 2,
118 .num_resources = ARRAY_SIZE(uart2_resources),
119 .resource = uart2_resources,
120};
121
122static struct resource uart3_resources[] = {
123 [0] = {
124 .start = 0xe1050000,
125 .end = 0xe1050037,
126 .flags = IORESOURCE_MEM,
127 },
128 [1] = {
129 .start = 43,
130 .flags = IORESOURCE_IRQ,
131 }
132};
133
134static struct platform_device uart3_device = {
135 .name = "serial8250-em",
136 .id = 3,
137 .num_resources = ARRAY_SIZE(uart3_resources),
138 .resource = uart3_resources,
139};
140
141/* STI */
142static struct resource sti_resources[] = {
143 [0] = {
144 .name = "STI",
145 .start = 0xe0180000,
146 .end = 0xe0180053,
147 .flags = IORESOURCE_MEM,
148 },
149 [1] = {
150 .start = 157,
151 .flags = IORESOURCE_IRQ,
152 },
153};
154
155static struct platform_device sti_device = {
156 .name = "em_sti",
157 .id = 0,
158 .resource = sti_resources,
159 .num_resources = ARRAY_SIZE(sti_resources),
160};
161
162
163/* GIO */
164static struct gpio_em_config gio0_config = {
165 .gpio_base = 0,
166 .irq_base = EMEV2_GPIO_IRQ(0),
167 .number_of_pins = 32,
168};
169
170static struct resource gio0_resources[] = {
171 [0] = {
172 .name = "GIO_000",
173 .start = 0xe0050000,
174 .end = 0xe005002b,
175 .flags = IORESOURCE_MEM,
176 },
177 [1] = {
178 .name = "GIO_000",
179 .start = 0xe0050040,
180 .end = 0xe005005f,
181 .flags = IORESOURCE_MEM,
182 },
183 [2] = {
184 .start = 99,
185 .flags = IORESOURCE_IRQ,
186 },
187 [3] = {
188 .start = 100,
189 .flags = IORESOURCE_IRQ,
190 },
191};
192
193static struct platform_device gio0_device = {
194 .name = "em_gio",
195 .id = 0,
196 .resource = gio0_resources,
197 .num_resources = ARRAY_SIZE(gio0_resources),
198 .dev = {
199 .platform_data = &gio0_config,
200 },
201};
202
203static struct gpio_em_config gio1_config = {
204 .gpio_base = 32,
205 .irq_base = EMEV2_GPIO_IRQ(32),
206 .number_of_pins = 32,
207};
208
209static struct resource gio1_resources[] = {
210 [0] = {
211 .name = "GIO_032",
212 .start = 0xe0050080,
213 .end = 0xe00500ab,
214 .flags = IORESOURCE_MEM,
215 },
216 [1] = {
217 .name = "GIO_032",
218 .start = 0xe00500c0,
219 .end = 0xe00500df,
220 .flags = IORESOURCE_MEM,
221 },
222 [2] = {
223 .start = 101,
224 .flags = IORESOURCE_IRQ,
225 },
226 [3] = {
227 .start = 102,
228 .flags = IORESOURCE_IRQ,
229 },
230};
231
232static struct platform_device gio1_device = {
233 .name = "em_gio",
234 .id = 1,
235 .resource = gio1_resources,
236 .num_resources = ARRAY_SIZE(gio1_resources),
237 .dev = {
238 .platform_data = &gio1_config,
239 },
240};
241
242static struct gpio_em_config gio2_config = {
243 .gpio_base = 64,
244 .irq_base = EMEV2_GPIO_IRQ(64),
245 .number_of_pins = 32,
246};
247
248static struct resource gio2_resources[] = {
249 [0] = {
250 .name = "GIO_064",
251 .start = 0xe0050100,
252 .end = 0xe005012b,
253 .flags = IORESOURCE_MEM,
254 },
255 [1] = {
256 .name = "GIO_064",
257 .start = 0xe0050140,
258 .end = 0xe005015f,
259 .flags = IORESOURCE_MEM,
260 },
261 [2] = {
262 .start = 103,
263 .flags = IORESOURCE_IRQ,
264 },
265 [3] = {
266 .start = 104,
267 .flags = IORESOURCE_IRQ,
268 },
269};
270
271static struct platform_device gio2_device = {
272 .name = "em_gio",
273 .id = 2,
274 .resource = gio2_resources,
275 .num_resources = ARRAY_SIZE(gio2_resources),
276 .dev = {
277 .platform_data = &gio2_config,
278 },
279};
280
281static struct gpio_em_config gio3_config = {
282 .gpio_base = 96,
283 .irq_base = EMEV2_GPIO_IRQ(96),
284 .number_of_pins = 32,
285};
286
287static struct resource gio3_resources[] = {
288 [0] = {
289 .name = "GIO_096",
290 .start = 0xe0050100,
291 .end = 0xe005012b,
292 .flags = IORESOURCE_MEM,
293 },
294 [1] = {
295 .name = "GIO_096",
296 .start = 0xe0050140,
297 .end = 0xe005015f,
298 .flags = IORESOURCE_MEM,
299 },
300 [2] = {
301 .start = 105,
302 .flags = IORESOURCE_IRQ,
303 },
304 [3] = {
305 .start = 106,
306 .flags = IORESOURCE_IRQ,
307 },
308};
309
310static struct platform_device gio3_device = {
311 .name = "em_gio",
312 .id = 3,
313 .resource = gio3_resources,
314 .num_resources = ARRAY_SIZE(gio3_resources),
315 .dev = {
316 .platform_data = &gio3_config,
317 },
318};
319
320static struct gpio_em_config gio4_config = {
321 .gpio_base = 128,
322 .irq_base = EMEV2_GPIO_IRQ(128),
323 .number_of_pins = 31,
324};
325
326static struct resource gio4_resources[] = {
327 [0] = {
328 .name = "GIO_128",
329 .start = 0xe0050200,
330 .end = 0xe005022b,
331 .flags = IORESOURCE_MEM,
332 },
333 [1] = {
334 .name = "GIO_128",
335 .start = 0xe0050240,
336 .end = 0xe005025f,
337 .flags = IORESOURCE_MEM,
338 },
339 [2] = {
340 .start = 107,
341 .flags = IORESOURCE_IRQ,
342 },
343 [3] = {
344 .start = 108,
345 .flags = IORESOURCE_IRQ,
346 },
347};
348
349static struct platform_device gio4_device = {
350 .name = "em_gio",
351 .id = 4,
352 .resource = gio4_resources,
353 .num_resources = ARRAY_SIZE(gio4_resources),
354 .dev = {
355 .platform_data = &gio4_config,
356 },
357};
358
359static struct platform_device *emev2_early_devices[] __initdata = {
360 &uart0_device,
361 &uart1_device,
362 &uart2_device,
363 &uart3_device,
364};
365
366static struct platform_device *emev2_late_devices[] __initdata = {
367 &sti_device,
368 &gio0_device,
369 &gio1_device,
370 &gio2_device,
371 &gio3_device,
372 &gio4_device,
373};
374
375void __init emev2_add_standard_devices(void)
376{
377 emev2_clock_init();
378
379 platform_add_devices(emev2_early_devices,
380 ARRAY_SIZE(emev2_early_devices));
381
382 platform_add_devices(emev2_late_devices,
383 ARRAY_SIZE(emev2_late_devices));
384}
385
386void __init emev2_init_delay(void)
387{
388 shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */
389}
390
391void __init emev2_add_early_devices(void)
392{
393 emev2_init_delay();
394
395 early_platform_add_devices(emev2_early_devices,
396 ARRAY_SIZE(emev2_early_devices));
397
398 /* setup early console here as well */
399 shmobile_setup_console();
400}
401
402void __init emev2_init_irq(void)
403{
404 void __iomem *gic_dist_base;
405 void __iomem *gic_cpu_base;
406
407 /* Static mappings, never released */
408 gic_dist_base = ioremap(0xe0028000, PAGE_SIZE);
409 gic_cpu_base = ioremap(0xe0020000, PAGE_SIZE);
410 BUG_ON(!gic_dist_base || !gic_cpu_base);
411
412 /* Use GIC to handle interrupts */
413 gic_init(0, 29, gic_dist_base, gic_cpu_base);
414}
415
416#ifdef CONFIG_USE_OF
417static const struct of_dev_auxdata emev2_auxdata_lookup[] __initconst = {
418 { }
419};
420
421void __init emev2_add_standard_devices_dt(void)
422{
423 of_platform_populate(NULL, of_default_bus_match_table,
424 emev2_auxdata_lookup, NULL);
425}
426
427static const struct of_device_id emev2_dt_irq_match[] = {
428 { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
429 {},
430};
431
432static const char *emev2_boards_compat_dt[] __initdata = {
433 "renesas,emev2",
434 NULL,
435};
436
437void __init emev2_init_irq_dt(void)
438{
439 of_irq_init(emev2_dt_irq_match);
440}
441
442DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)")
443 .init_early = emev2_init_delay,
444 .nr_irqs = NR_IRQS_LEGACY,
445 .init_irq = emev2_init_irq_dt,
446 .handle_irq = gic_handle_irq,
447 .init_machine = emev2_add_standard_devices_dt,
448 .timer = &shmobile_timer,
449 .dt_compat = emev2_boards_compat_dt,
450MACHINE_END
451
452#endif /* CONFIG_USE_OF */
diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c
new file mode 100644
index 00000000000..6a35c4a31e6
--- /dev/null
+++ b/arch/arm/mach-shmobile/smp-emev2.c
@@ -0,0 +1,97 @@
1/*
2 * SMP support for Emma Mobile EV2
3 *
4 * Copyright (C) 2012 Renesas Solutions Corp.
5 * Copyright (C) 2012 Magnus Damm
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
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 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20#include <linux/kernel.h>
21#include <linux/init.h>
22#include <linux/smp.h>
23#include <linux/spinlock.h>
24#include <linux/io.h>
25#include <linux/delay.h>
26#include <mach/common.h>
27#include <mach/emev2.h>
28#include <asm/smp_plat.h>
29#include <asm/smp_scu.h>
30#include <asm/hardware/gic.h>
31#include <asm/cacheflush.h>
32
33#define EMEV2_SCU_BASE 0x1e000000
34
35static DEFINE_SPINLOCK(scu_lock);
36static void __iomem *scu_base;
37
38static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
39{
40 unsigned long tmp;
41
42 /* we assume this code is running on a different cpu
43 * than the one that is changing coherency setting */
44 spin_lock(&scu_lock);
45 tmp = readl(scu_base + 8);
46 tmp &= ~clr;
47 tmp |= set;
48 writel(tmp, scu_base + 8);
49 spin_unlock(&scu_lock);
50
51}
52
53unsigned int __init emev2_get_core_count(void)
54{
55 if (!scu_base) {
56 scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE);
57 emev2_clock_init(); /* need ioremapped SMU */
58 }
59
60 WARN_ON_ONCE(!scu_base);
61
62 return scu_base ? scu_get_core_count(scu_base) : 1;
63}
64
65int emev2_platform_cpu_kill(unsigned int cpu)
66{
67 return 0; /* not supported yet */
68}
69
70void __cpuinit emev2_secondary_init(unsigned int cpu)
71{
72 gic_secondary_init(0);
73}
74
75int __cpuinit emev2_boot_secondary(unsigned int cpu)
76{
77 cpu = cpu_logical_map(cpu);
78
79 /* enable cache coherency */
80 modify_scu_cpu_psr(0, 3 << (cpu * 8));
81
82 /* Tell ROM loader about our vector (in headsmp.S) */
83 emev2_set_boot_vector(__pa(shmobile_secondary_vector));
84
85 gic_raise_softirq(cpumask_of(cpu), 1);
86 return 0;
87}
88
89void __init emev2_smp_prepare_cpus(void)
90{
91 int cpu = cpu_logical_map(0);
92
93 scu_enable(scu_base);
94
95 /* enable cache coherency on CPU0 */
96 modify_scu_cpu_psr(0, 3 << (cpu * 8));
97}
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e03653d6935..eb80ba30045 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -91,6 +91,12 @@ config GPIO_IT8761E
91 help 91 help
92 Say yes here to support GPIO functionality of IT8761E super I/O chip. 92 Say yes here to support GPIO functionality of IT8761E super I/O chip.
93 93
94config GPIO_EM
95 tristate "Emma Mobile GPIO"
96 depends on ARM
97 help
98 Say yes here to support GPIO on Renesas Emma Mobile SoCs.
99
94config GPIO_EP93XX 100config GPIO_EP93XX
95 def_bool y 101 def_bool y
96 depends on ARCH_EP93XX 102 depends on ARCH_EP93XX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 007f54bd008..3f1f829260b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
15obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o 15obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
16obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o 16obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
17obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o 17obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
18obj-$(CONFIG_GPIO_EM) += gpio-em.o
18obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o 19obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
19obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o 20obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
20obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o 21obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
new file mode 100644
index 00000000000..150d9768811
--- /dev/null
+++ b/drivers/gpio/gpio-em.c
@@ -0,0 +1,418 @@
1/*
2 * Emma Mobile GPIO Support - GIO
3 *
4 * Copyright (C) 2012 Magnus Damm
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
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include <linux/init.h>
21#include <linux/platform_device.h>
22#include <linux/spinlock.h>
23#include <linux/interrupt.h>
24#include <linux/ioport.h>
25#include <linux/io.h>
26#include <linux/irq.h>
27#include <linux/irqdomain.h>
28#include <linux/bitops.h>
29#include <linux/err.h>
30#include <linux/gpio.h>
31#include <linux/slab.h>
32#include <linux/module.h>
33#include <linux/platform_data/gpio-em.h>
34
35struct em_gio_priv {
36 void __iomem *base0;
37 void __iomem *base1;
38 unsigned int irq_base;
39 spinlock_t sense_lock;
40 struct platform_device *pdev;
41 struct gpio_chip gpio_chip;
42 struct irq_chip irq_chip;
43 struct irq_domain *irq_domain;
44};
45
46#define GIO_E1 0x00
47#define GIO_E0 0x04
48#define GIO_EM 0x04
49#define GIO_OL 0x08
50#define GIO_OH 0x0c
51#define GIO_I 0x10
52#define GIO_IIA 0x14
53#define GIO_IEN 0x18
54#define GIO_IDS 0x1c
55#define GIO_IIM 0x1c
56#define GIO_RAW 0x20
57#define GIO_MST 0x24
58#define GIO_IIR 0x28
59
60#define GIO_IDT0 0x40
61#define GIO_IDT1 0x44
62#define GIO_IDT2 0x48
63#define GIO_IDT3 0x4c
64#define GIO_RAWBL 0x50
65#define GIO_RAWBH 0x54
66#define GIO_IRBL 0x58
67#define GIO_IRBH 0x5c
68
69#define GIO_IDT(n) (GIO_IDT0 + ((n) * 4))
70
71static inline unsigned long em_gio_read(struct em_gio_priv *p, int offs)
72{
73 if (offs < GIO_IDT0)
74 return ioread32(p->base0 + offs);
75 else
76 return ioread32(p->base1 + (offs - GIO_IDT0));
77}
78
79static inline void em_gio_write(struct em_gio_priv *p, int offs,
80 unsigned long value)
81{
82 if (offs < GIO_IDT0)
83 iowrite32(value, p->base0 + offs);
84 else
85 iowrite32(value, p->base1 + (offs - GIO_IDT0));
86}
87
88static inline struct em_gio_priv *irq_to_priv(struct irq_data *d)
89{
90 struct irq_chip *chip = irq_data_get_irq_chip(d);
91 return container_of(chip, struct em_gio_priv, irq_chip);
92}
93
94static void em_gio_irq_disable(struct irq_data *d)
95{
96 struct em_gio_priv *p = irq_to_priv(d);
97
98 em_gio_write(p, GIO_IDS, BIT(irqd_to_hwirq(d)));
99}
100
101static void em_gio_irq_enable(struct irq_data *d)
102{
103 struct em_gio_priv *p = irq_to_priv(d);
104
105 em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
106}
107
108#define GIO_ASYNC(x) (x + 8)
109
110static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
111 [IRQ_TYPE_EDGE_RISING] = GIO_ASYNC(0x00),
112 [IRQ_TYPE_EDGE_FALLING] = GIO_ASYNC(0x01),
113 [IRQ_TYPE_LEVEL_HIGH] = GIO_ASYNC(0x02),
114 [IRQ_TYPE_LEVEL_LOW] = GIO_ASYNC(0x03),
115 [IRQ_TYPE_EDGE_BOTH] = GIO_ASYNC(0x04),
116};
117
118static int em_gio_irq_set_type(struct irq_data *d, unsigned int type)
119{
120 unsigned char value = em_gio_sense_table[type & IRQ_TYPE_SENSE_MASK];
121 struct em_gio_priv *p = irq_to_priv(d);
122 unsigned int reg, offset, shift;
123 unsigned long flags;
124 unsigned long tmp;
125
126 if (!value)
127 return -EINVAL;
128
129 offset = irqd_to_hwirq(d);
130
131 pr_debug("gio: sense irq = %d, mode = %d\n", offset, value);
132
133 /* 8 x 4 bit fields in 4 IDT registers */
134 reg = GIO_IDT(offset >> 3);
135 shift = (offset & 0x07) << 4;
136
137 spin_lock_irqsave(&p->sense_lock, flags);
138
139 /* disable the interrupt in IIA */
140 tmp = em_gio_read(p, GIO_IIA);
141 tmp &= ~BIT(offset);
142 em_gio_write(p, GIO_IIA, tmp);
143
144 /* change the sense setting in IDT */
145 tmp = em_gio_read(p, reg);
146 tmp &= ~(0xf << shift);
147 tmp |= value << shift;
148 em_gio_write(p, reg, tmp);
149
150 /* clear pending interrupts */
151 em_gio_write(p, GIO_IIR, BIT(offset));
152
153 /* enable the interrupt in IIA */
154 tmp = em_gio_read(p, GIO_IIA);
155 tmp |= BIT(offset);
156 em_gio_write(p, GIO_IIA, tmp);
157
158 spin_unlock_irqrestore(&p->sense_lock, flags);
159
160 return 0;
161}
162
163static irqreturn_t em_gio_irq_handler(int irq, void *dev_id)
164{
165 struct em_gio_priv *p = dev_id;
166 unsigned long pending;
167 unsigned int offset, irqs_handled = 0;
168
169 while ((pending = em_gio_read(p, GIO_MST))) {
170 offset = __ffs(pending);
171 em_gio_write(p, GIO_IIR, BIT(offset));
172 generic_handle_irq(irq_find_mapping(p->irq_domain, offset));
173 irqs_handled++;
174 }
175
176 return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
177}
178
179static inline struct em_gio_priv *gpio_to_priv(struct gpio_chip *chip)
180{
181 return container_of(chip, struct em_gio_priv, gpio_chip);
182}
183
184static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset)
185{
186 em_gio_write(gpio_to_priv(chip), GIO_E0, BIT(offset));
187 return 0;
188}
189
190static int em_gio_get(struct gpio_chip *chip, unsigned offset)
191{
192 return (int)(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset));
193}
194
195static void __em_gio_set(struct gpio_chip *chip, unsigned int reg,
196 unsigned shift, int value)
197{
198 /* upper 16 bits contains mask and lower 16 actual value */
199 em_gio_write(gpio_to_priv(chip), reg,
200 (1 << (shift + 16)) | (value << shift));
201}
202
203static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value)
204{
205 /* output is split into two registers */
206 if (offset < 16)
207 __em_gio_set(chip, GIO_OL, offset, value);
208 else
209 __em_gio_set(chip, GIO_OH, offset - 16, value);
210}
211
212static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset,
213 int value)
214{
215 /* write GPIO value to output before selecting output mode of pin */
216 em_gio_set(chip, offset, value);
217 em_gio_write(gpio_to_priv(chip), GIO_E1, BIT(offset));
218 return 0;
219}
220
221static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset)
222{
223 return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset);
224}
225
226static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq,
227 irq_hw_number_t hw)
228{
229 struct em_gio_priv *p = h->host_data;
230
231 pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq);
232
233 irq_set_chip_data(virq, h->host_data);
234 irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
235 set_irq_flags(virq, IRQF_VALID); /* kill me now */
236 return 0;
237}
238
239static struct irq_domain_ops em_gio_irq_domain_ops = {
240 .map = em_gio_irq_domain_map,
241};
242
243static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p)
244{
245 struct platform_device *pdev = p->pdev;
246 struct gpio_em_config *pdata = pdev->dev.platform_data;
247
248 p->irq_base = irq_alloc_descs(pdata->irq_base, 0,
249 pdata->number_of_pins, numa_node_id());
250 if (IS_ERR_VALUE(p->irq_base)) {
251 dev_err(&pdev->dev, "cannot get irq_desc\n");
252 return -ENXIO;
253 }
254 pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n",
255 pdata->gpio_base, pdata->number_of_pins, p->irq_base);
256
257 p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
258 pdata->number_of_pins,
259 p->irq_base, 0,
260 &em_gio_irq_domain_ops, p);
261 if (!p->irq_domain) {
262 irq_free_descs(p->irq_base, pdata->number_of_pins);
263 return -ENXIO;
264 }
265
266 return 0;
267}
268
269static void __devexit em_gio_irq_domain_cleanup(struct em_gio_priv *p)
270{
271 struct gpio_em_config *pdata = p->pdev->dev.platform_data;
272
273 irq_free_descs(p->irq_base, pdata->number_of_pins);
274 /* FIXME: irq domain wants to be freed! */
275}
276
277static int __devinit em_gio_probe(struct platform_device *pdev)
278{
279 struct gpio_em_config *pdata = pdev->dev.platform_data;
280 struct em_gio_priv *p;
281 struct resource *io[2], *irq[2];
282 struct gpio_chip *gpio_chip;
283 struct irq_chip *irq_chip;
284 const char *name = dev_name(&pdev->dev);
285 int ret;
286
287 p = kzalloc(sizeof(*p), GFP_KERNEL);
288 if (!p) {
289 dev_err(&pdev->dev, "failed to allocate driver data\n");
290 ret = -ENOMEM;
291 goto err0;
292 }
293
294 p->pdev = pdev;
295 platform_set_drvdata(pdev, p);
296 spin_lock_init(&p->sense_lock);
297
298 io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0);
299 io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1);
300 irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
301 irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
302
303 if (!io[0] || !io[1] || !irq[0] || !irq[1] || !pdata) {
304 dev_err(&pdev->dev, "missing IRQ, IOMEM or configuration\n");
305 ret = -EINVAL;
306 goto err1;
307 }
308
309 p->base0 = ioremap_nocache(io[0]->start, resource_size(io[0]));
310 if (!p->base0) {
311 dev_err(&pdev->dev, "failed to remap low I/O memory\n");
312 ret = -ENXIO;
313 goto err1;
314 }
315
316 p->base1 = ioremap_nocache(io[1]->start, resource_size(io[1]));
317 if (!p->base1) {
318 dev_err(&pdev->dev, "failed to remap high I/O memory\n");
319 ret = -ENXIO;
320 goto err2;
321 }
322
323 gpio_chip = &p->gpio_chip;
324 gpio_chip->direction_input = em_gio_direction_input;
325 gpio_chip->get = em_gio_get;
326 gpio_chip->direction_output = em_gio_direction_output;
327 gpio_chip->set = em_gio_set;
328 gpio_chip->to_irq = em_gio_to_irq;
329 gpio_chip->label = name;
330 gpio_chip->owner = THIS_MODULE;
331 gpio_chip->base = pdata->gpio_base;
332 gpio_chip->ngpio = pdata->number_of_pins;
333
334 irq_chip = &p->irq_chip;
335 irq_chip->name = name;
336 irq_chip->irq_mask = em_gio_irq_disable;
337 irq_chip->irq_unmask = em_gio_irq_enable;
338 irq_chip->irq_enable = em_gio_irq_enable;
339 irq_chip->irq_disable = em_gio_irq_disable;
340 irq_chip->irq_set_type = em_gio_irq_set_type;
341 irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
342
343 ret = em_gio_irq_domain_init(p);
344 if (ret) {
345 dev_err(&pdev->dev, "cannot initialize irq domain\n");
346 goto err3;
347 }
348
349 if (request_irq(irq[0]->start, em_gio_irq_handler, 0, name, p)) {
350 dev_err(&pdev->dev, "failed to request low IRQ\n");
351 ret = -ENOENT;
352 goto err4;
353 }
354
355 if (request_irq(irq[1]->start, em_gio_irq_handler, 0, name, p)) {
356 dev_err(&pdev->dev, "failed to request high IRQ\n");
357 ret = -ENOENT;
358 goto err5;
359 }
360
361 ret = gpiochip_add(gpio_chip);
362 if (ret) {
363 dev_err(&pdev->dev, "failed to add GPIO controller\n");
364 goto err6;
365 }
366 return 0;
367
368err6:
369 free_irq(irq[1]->start, pdev);
370err5:
371 free_irq(irq[0]->start, pdev);
372err4:
373 em_gio_irq_domain_cleanup(p);
374err3:
375 iounmap(p->base1);
376err2:
377 iounmap(p->base0);
378err1:
379 kfree(p);
380err0:
381 return ret;
382}
383
384static int __devexit em_gio_remove(struct platform_device *pdev)
385{
386 struct em_gio_priv *p = platform_get_drvdata(pdev);
387 struct resource *irq[2];
388 int ret;
389
390 ret = gpiochip_remove(&p->gpio_chip);
391 if (ret)
392 return ret;
393
394 irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
395 irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
396
397 free_irq(irq[1]->start, pdev);
398 free_irq(irq[0]->start, pdev);
399 em_gio_irq_domain_cleanup(p);
400 iounmap(p->base1);
401 iounmap(p->base0);
402 kfree(p);
403 return 0;
404}
405
406static struct platform_driver em_gio_device_driver = {
407 .probe = em_gio_probe,
408 .remove = __devexit_p(em_gio_remove),
409 .driver = {
410 .name = "em_gio",
411 }
412};
413
414module_platform_driver(em_gio_device_driver);
415
416MODULE_AUTHOR("Magnus Damm");
417MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver");
418MODULE_LICENSE("GPL v2");
diff --git a/include/linux/platform_data/gpio-em.h b/include/linux/platform_data/gpio-em.h
new file mode 100644
index 00000000000..573edfb046c
--- /dev/null
+++ b/include/linux/platform_data/gpio-em.h
@@ -0,0 +1,10 @@
1#ifndef __GPIO_EM_H__
2#define __GPIO_EM_H__
3
4struct gpio_em_config {
5 unsigned int gpio_base;
6 unsigned int irq_base;
7 unsigned int number_of_pins;
8};
9
10#endif /* __GPIO_EM_H__ */