Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'emev2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/renesas into next/soc

* 'emev2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/renesas:
mach-shmobile: Use DT_MACHINE for KZM9D V3
mach-shmobile: Emma Mobile EV2 DT support V3
mach-shmobile: KZM9D board Ethernet support V3
mach-shmobile: Emma Mobile EV2 GPIO support V3
mach-shmobile: Emma Mobile EV2 SMP support V3
mach-shmobile: KZM9D board support V3
mach-shmobile: Emma Mobile EV2 SoC base support V3
gpio: Emma Mobile GPIO driver V2

+1458
+26
arch/arm/boot/dts/emev2-kzm9d.dts
··· 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 + };
+63
arch/arm/boot/dts/emev2.dtsi
··· 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 + };
+11
arch/arm/mach-shmobile/Kconfig
··· 41 41 select ARM_GIC 42 42 select ARCH_WANT_OPTIONAL_GPIOLIB 43 43 44 + config ARCH_EMEV2 45 + bool "Emma Mobile EV2" 46 + select CPU_V7 47 + select ARM_GIC 48 + select ARCH_WANT_OPTIONAL_GPIOLIB 49 + 44 50 comment "SH-Mobile Board Type" 45 51 46 52 config MACH_G3EVM ··· 103 97 bool "MARZEN board" 104 98 depends on ARCH_R8A7779 105 99 select ARCH_REQUIRE_GPIOLIB 100 + 101 + config MACH_KZM9D 102 + bool "KZM9D board" 103 + depends on ARCH_EMEV2 104 + select USE_OF 106 105 107 106 comment "SH-Mobile System Configuration" 108 107
+3
arch/arm/mach-shmobile/Makefile
··· 12 12 obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o 13 13 obj-$(CONFIG_ARCH_R8A7740) += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o 14 14 obj-$(CONFIG_ARCH_R8A7779) += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o 15 + obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o clock-emev2.o 15 16 16 17 # SMP objects 17 18 smp-y := platsmp.o headsmp.o 18 19 smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o 19 20 smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o 20 21 smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o 22 + smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o 21 23 22 24 # Pinmux setup 23 25 pfc-y := ··· 51 49 obj-$(CONFIG_MACH_KOTA2) += board-kota2.o 52 50 obj-$(CONFIG_MACH_BONITO) += board-bonito.o 53 51 obj-$(CONFIG_MACH_MARZEN) += board-marzen.o 52 + obj-$(CONFIG_MACH_KZM9D) += board-kzm9d.o 54 53 55 54 # Framework support 56 55 obj-$(CONFIG_SMP) += $(smp-y)
+85
arch/arm/mach-shmobile/board-kzm9d.c
··· 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 */ 32 + static 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 + 44 + static 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 + 50 + static 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 + 60 + static struct platform_device *kzm9d_devices[] __initdata = { 61 + &smsc91x_device, 62 + }; 63 + 64 + void __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 + 71 + static const char *kzm9d_boards_compat_dt[] __initdata = { 72 + "renesas,kzm9d", 73 + NULL, 74 + }; 75 + 76 + DT_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, 85 + MACHINE_END
+249
arch/arm/mach-shmobile/clock-emev2.c
··· 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 */ 46 + static void __iomem *smu_base; 47 + 48 + static 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 + 54 + void emev2_set_boot_vector(unsigned long value) 55 + { 56 + emev2_smu_write(value, SMU_GENERAL_REG0); 57 + } 58 + 59 + static 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 */ 65 + static struct clk c32k_clk = { 66 + .rate = 32768, 67 + .mapping = &smu_mapping, 68 + }; 69 + 70 + /* PLL3 multiplies C32K with 7000 */ 71 + static unsigned long pll3_recalc(struct clk *clk) 72 + { 73 + return clk->parent->rate * 7000; 74 + } 75 + 76 + static struct sh_clk_ops pll3_clk_ops = { 77 + .recalc = pll3_recalc, 78 + }; 79 + 80 + static struct clk pll3_clk = { 81 + .ops = &pll3_clk_ops, 82 + .parent = &c32k_clk, 83 + }; 84 + 85 + static struct clk *main_clks[] = { 86 + &c32k_clk, 87 + &pll3_clk, 88 + }; 89 + 90 + enum { 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 + 100 + static 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 + 107 + enum { 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 + 118 + static 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 + 130 + static 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 + 137 + static void emev2_gclk_disable(struct clk *clk) 138 + { 139 + iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit), 140 + clk->mapped_reg); 141 + } 142 + 143 + static struct sh_clk_ops emev2_gclk_clk_ops = { 144 + .enable = emev2_gclk_enable, 145 + .disable = emev2_gclk_disable, 146 + .recalc = followparent_recalc, 147 + }; 148 + 149 + static 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 + 164 + static 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 + 173 + static struct sh_clk_ops emev2_sclkdiv_clk_ops = { 174 + .recalc = emev2_sclkdiv_recalc, 175 + }; 176 + 177 + static 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 + 192 + static 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 + 205 + void __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 + }
+19
arch/arm/mach-shmobile/include/mach/emev2.h
··· 1 + #ifndef __ASM_EMEV2_H__ 2 + #define __ASM_EMEV2_H__ 3 + 4 + extern void emev2_map_io(void); 5 + extern void emev2_init_irq(void); 6 + extern void emev2_add_early_devices(void); 7 + extern void emev2_add_standard_devices(void); 8 + extern void emev2_clock_init(void); 9 + extern void emev2_set_boot_vector(unsigned long value); 10 + extern unsigned int emev2_get_core_count(void); 11 + extern int emev2_platform_cpu_kill(unsigned int cpu); 12 + extern void emev2_secondary_init(unsigned int cpu); 13 + extern int emev2_boot_secondary(unsigned int cpu); 14 + extern 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__ */
+18
arch/arm/mach-shmobile/platsmp.c
··· 16 16 #include <linux/device.h> 17 17 #include <linux/smp.h> 18 18 #include <linux/io.h> 19 + #include <linux/of.h> 19 20 #include <asm/hardware/gic.h> 20 21 #include <asm/mach-types.h> 21 22 #include <mach/common.h> 23 + #include <mach/emev2.h> 22 24 23 25 #define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2()) 24 26 #define is_r8a7779() machine_is_marzen() 27 + #define is_emev2() of_machine_is_compatible("renesas,emev2") 25 28 26 29 static unsigned int __init shmobile_smp_get_core_count(void) 27 30 { ··· 33 30 34 31 if (is_r8a7779()) 35 32 return r8a7779_get_core_count(); 33 + 34 + if (is_emev2()) 35 + return emev2_get_core_count(); 36 36 37 37 return 1; 38 38 } ··· 47 41 48 42 if (is_r8a7779()) 49 43 r8a7779_smp_prepare_cpus(); 44 + 45 + if (is_emev2()) 46 + emev2_smp_prepare_cpus(); 50 47 } 51 48 52 49 int shmobile_platform_cpu_kill(unsigned int cpu) 53 50 { 54 51 if (is_r8a7779()) 55 52 return r8a7779_platform_cpu_kill(cpu); 53 + 54 + if (is_emev2()) 55 + return emev2_platform_cpu_kill(cpu); 56 56 57 57 return 1; 58 58 } ··· 72 60 73 61 if (is_r8a7779()) 74 62 r8a7779_secondary_init(cpu); 63 + 64 + if (is_emev2()) 65 + emev2_secondary_init(cpu); 75 66 } 76 67 77 68 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) ··· 84 69 85 70 if (is_r8a7779()) 86 71 return r8a7779_boot_secondary(cpu); 72 + 73 + if (is_emev2()) 74 + return emev2_boot_secondary(cpu); 87 75 88 76 return -ENOSYS; 89 77 }
+452
arch/arm/mach-shmobile/setup-emev2.c
··· 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 + 40 + static 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 + 59 + void __init emev2_map_io(void) 60 + { 61 + iotable_init(emev2_io_desc, ARRAY_SIZE(emev2_io_desc)); 62 + } 63 + 64 + /* UART */ 65 + static 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 + 77 + static 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 + 84 + static 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 + 96 + static 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 + 103 + static 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 + 115 + static 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 + 122 + static 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 + 134 + static 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 */ 142 + static 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 + 155 + static 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 */ 164 + static struct gpio_em_config gio0_config = { 165 + .gpio_base = 0, 166 + .irq_base = EMEV2_GPIO_IRQ(0), 167 + .number_of_pins = 32, 168 + }; 169 + 170 + static 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 + 193 + static 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 + 203 + static struct gpio_em_config gio1_config = { 204 + .gpio_base = 32, 205 + .irq_base = EMEV2_GPIO_IRQ(32), 206 + .number_of_pins = 32, 207 + }; 208 + 209 + static 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 + 232 + static 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 + 242 + static struct gpio_em_config gio2_config = { 243 + .gpio_base = 64, 244 + .irq_base = EMEV2_GPIO_IRQ(64), 245 + .number_of_pins = 32, 246 + }; 247 + 248 + static 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 + 271 + static 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 + 281 + static struct gpio_em_config gio3_config = { 282 + .gpio_base = 96, 283 + .irq_base = EMEV2_GPIO_IRQ(96), 284 + .number_of_pins = 32, 285 + }; 286 + 287 + static 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 + 310 + static 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 + 320 + static struct gpio_em_config gio4_config = { 321 + .gpio_base = 128, 322 + .irq_base = EMEV2_GPIO_IRQ(128), 323 + .number_of_pins = 31, 324 + }; 325 + 326 + static 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 + 349 + static 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 + 359 + static struct platform_device *emev2_early_devices[] __initdata = { 360 + &uart0_device, 361 + &uart1_device, 362 + &uart2_device, 363 + &uart3_device, 364 + }; 365 + 366 + static 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 + 375 + void __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 + 386 + void __init emev2_init_delay(void) 387 + { 388 + shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */ 389 + } 390 + 391 + void __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 + 402 + void __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 417 + static const struct of_dev_auxdata emev2_auxdata_lookup[] __initconst = { 418 + { } 419 + }; 420 + 421 + void __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 + 427 + static const struct of_device_id emev2_dt_irq_match[] = { 428 + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, 429 + {}, 430 + }; 431 + 432 + static const char *emev2_boards_compat_dt[] __initdata = { 433 + "renesas,emev2", 434 + NULL, 435 + }; 436 + 437 + void __init emev2_init_irq_dt(void) 438 + { 439 + of_irq_init(emev2_dt_irq_match); 440 + } 441 + 442 + DT_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, 450 + MACHINE_END 451 + 452 + #endif /* CONFIG_USE_OF */
+97
arch/arm/mach-shmobile/smp-emev2.c
··· 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 + 35 + static DEFINE_SPINLOCK(scu_lock); 36 + static void __iomem *scu_base; 37 + 38 + static 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 + 53 + unsigned 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 + 65 + int emev2_platform_cpu_kill(unsigned int cpu) 66 + { 67 + return 0; /* not supported yet */ 68 + } 69 + 70 + void __cpuinit emev2_secondary_init(unsigned int cpu) 71 + { 72 + gic_secondary_init(0); 73 + } 74 + 75 + int __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 + 89 + void __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 + }
+6
drivers/gpio/Kconfig
··· 91 91 help 92 92 Say yes here to support GPIO functionality of IT8761E super I/O chip. 93 93 94 + config 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 + 94 100 config GPIO_EP93XX 95 101 def_bool y 96 102 depends on ARCH_EP93XX
+1
drivers/gpio/Makefile
··· 15 15 obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o 16 16 obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o 17 17 obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o 18 + obj-$(CONFIG_GPIO_EM) += gpio-em.o 18 19 obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o 19 20 obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o 20 21 obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
+418
drivers/gpio/gpio-em.c
··· 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 + 35 + struct 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 + 71 + static 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 + 79 + static 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 + 88 + static 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 + 94 + static 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 + 101 + static 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 + 110 + static 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 + 118 + static 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 + 163 + static 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 + 179 + static 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 + 184 + static 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 + 190 + static 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 + 195 + static 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 + 203 + static 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 + 212 + static 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 + 221 + static 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 + 226 + static 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 + 239 + static struct irq_domain_ops em_gio_irq_domain_ops = { 240 + .map = em_gio_irq_domain_map, 241 + }; 242 + 243 + static 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 + 269 + static 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 + 277 + static 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 + 368 + err6: 369 + free_irq(irq[1]->start, pdev); 370 + err5: 371 + free_irq(irq[0]->start, pdev); 372 + err4: 373 + em_gio_irq_domain_cleanup(p); 374 + err3: 375 + iounmap(p->base1); 376 + err2: 377 + iounmap(p->base0); 378 + err1: 379 + kfree(p); 380 + err0: 381 + return ret; 382 + } 383 + 384 + static 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 + 406 + static 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 + 414 + module_platform_driver(em_gio_device_driver); 415 + 416 + MODULE_AUTHOR("Magnus Damm"); 417 + MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver"); 418 + MODULE_LICENSE("GPL v2");
+10
include/linux/platform_data/gpio-em.h
··· 1 + #ifndef __GPIO_EM_H__ 2 + #define __GPIO_EM_H__ 3 + 4 + struct 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__ */