diff options
author | Tony Lindgren <tony@atomide.com> | 2010-05-20 14:37:23 -0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2010-05-20 14:37:23 -0400 |
commit | f6304f5804f228b6c2fea9e3dfac25c5b2db9b38 (patch) | |
tree | 362b9b6a3bd32b868e5917a32d448ac75c5854df /arch/arm/mach-nomadik | |
parent | 4fa73a1bf89ebea4eba8a9982b5f64d266d8b5e9 (diff) | |
parent | 6daa642d9b8ec762b3c5641cd5e5fa855a5405bf (diff) |
Merge branch 'omap4-i2c-init' into omap-for-linus
Diffstat (limited to 'arch/arm/mach-nomadik')
-rw-r--r-- | arch/arm/mach-nomadik/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-nomadik/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-nomadik/board-nhk8815.c | 10 | ||||
-rw-r--r-- | arch/arm/mach-nomadik/clock.c | 38 | ||||
-rw-r--r-- | arch/arm/mach-nomadik/clock.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-nomadik/cpu-8815.c | 83 | ||||
-rw-r--r-- | arch/arm/mach-nomadik/gpio.c | 397 | ||||
-rw-r--r-- | arch/arm/mach-nomadik/include/mach/gpio.h | 67 |
8 files changed, 81 insertions, 518 deletions
diff --git a/arch/arm/mach-nomadik/Kconfig b/arch/arm/mach-nomadik/Kconfig index 3c5e0f522e9c..71f3ea623974 100644 --- a/arch/arm/mach-nomadik/Kconfig +++ b/arch/arm/mach-nomadik/Kconfig | |||
@@ -6,6 +6,7 @@ config MACH_NOMADIK_8815NHK | |||
6 | bool "ST 8815 Nomadik Hardware Kit (evaluation board)" | 6 | bool "ST 8815 Nomadik Hardware Kit (evaluation board)" |
7 | select NOMADIK_8815 | 7 | select NOMADIK_8815 |
8 | select HAS_MTU | 8 | select HAS_MTU |
9 | select NOMADIK_GPIO | ||
9 | 10 | ||
10 | endmenu | 11 | endmenu |
11 | 12 | ||
diff --git a/arch/arm/mach-nomadik/Makefile b/arch/arm/mach-nomadik/Makefile index 36f67fb207d2..a6bbd1a7b4e7 100644 --- a/arch/arm/mach-nomadik/Makefile +++ b/arch/arm/mach-nomadik/Makefile | |||
@@ -7,7 +7,7 @@ | |||
7 | 7 | ||
8 | # Object file lists. | 8 | # Object file lists. |
9 | 9 | ||
10 | obj-y += clock.o gpio.o | 10 | obj-y += clock.o |
11 | 11 | ||
12 | # Cpu revision | 12 | # Cpu revision |
13 | obj-$(CONFIG_NOMADIK_8815) += cpu-8815.o | 13 | obj-$(CONFIG_NOMADIK_8815) += cpu-8815.o |
diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c index ab3712c86d2b..841d459ad59d 100644 --- a/arch/arm/mach-nomadik/board-nhk8815.c +++ b/arch/arm/mach-nomadik/board-nhk8815.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include <mach/setup.h> | 32 | #include <mach/setup.h> |
33 | #include <mach/nand.h> | 33 | #include <mach/nand.h> |
34 | #include <mach/fsmc.h> | 34 | #include <mach/fsmc.h> |
35 | #include "clock.h" | ||
36 | 35 | ||
37 | /* Initial value for SRC control register: all timers use MXTAL/8 source */ | 36 | /* Initial value for SRC control register: all timers use MXTAL/8 source */ |
38 | #define SRC_CR_INIT_MASK 0x00007fff | 37 | #define SRC_CR_INIT_MASK 0x00007fff |
@@ -202,11 +201,6 @@ static struct amba_device *amba_devs[] __initdata = { | |||
202 | &uart1_device, | 201 | &uart1_device, |
203 | }; | 202 | }; |
204 | 203 | ||
205 | /* We have a fixed clock alone, by now */ | ||
206 | static struct clk nhk8815_clk_48 = { | ||
207 | .rate = 48*1000*1000, | ||
208 | }; | ||
209 | |||
210 | static struct resource nhk8815_eth_resources[] = { | 204 | static struct resource nhk8815_eth_resources[] = { |
211 | { | 205 | { |
212 | .name = "smc91x-regs", | 206 | .name = "smc91x-regs", |
@@ -276,10 +270,8 @@ static void __init nhk8815_platform_init(void) | |||
276 | platform_add_devices(nhk8815_platform_devices, | 270 | platform_add_devices(nhk8815_platform_devices, |
277 | ARRAY_SIZE(nhk8815_platform_devices)); | 271 | ARRAY_SIZE(nhk8815_platform_devices)); |
278 | 272 | ||
279 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { | 273 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) |
280 | nmdk_clk_create(&nhk8815_clk_48, amba_devs[i]->dev.init_name); | ||
281 | amba_device_register(amba_devs[i], &iomem_resource); | 274 | amba_device_register(amba_devs[i], &iomem_resource); |
282 | } | ||
283 | } | 275 | } |
284 | 276 | ||
285 | MACHINE_START(NOMADIK, "NHK8815") | 277 | MACHINE_START(NOMADIK, "NHK8815") |
diff --git a/arch/arm/mach-nomadik/clock.c b/arch/arm/mach-nomadik/clock.c index 9f92502a0083..60f5bee09f2e 100644 --- a/arch/arm/mach-nomadik/clock.c +++ b/arch/arm/mach-nomadik/clock.c | |||
@@ -32,14 +32,36 @@ void clk_disable(struct clk *clk) | |||
32 | } | 32 | } |
33 | EXPORT_SYMBOL(clk_disable); | 33 | EXPORT_SYMBOL(clk_disable); |
34 | 34 | ||
35 | /* Create a clock structure with the given name */ | 35 | /* We have a fixed clock alone, for now */ |
36 | int nmdk_clk_create(struct clk *clk, const char *dev_id) | 36 | static struct clk clk_48 = { |
37 | { | 37 | .rate = 48 * 1000 * 1000, |
38 | struct clk_lookup *clkdev; | 38 | }; |
39 | |||
40 | /* | ||
41 | * Catch-all default clock to satisfy drivers using the clk API. We don't | ||
42 | * model the actual hardware clocks yet. | ||
43 | */ | ||
44 | static struct clk clk_default; | ||
39 | 45 | ||
40 | clkdev = clkdev_alloc(clk, NULL, dev_id); | 46 | #define CLK(_clk, dev) \ |
41 | if (!clkdev) | 47 | { \ |
42 | return -ENOMEM; | 48 | .clk = _clk, \ |
43 | clkdev_add(clkdev); | 49 | .dev_id = dev, \ |
50 | } | ||
51 | |||
52 | static struct clk_lookup lookups[] = { | ||
53 | CLK(&clk_48, "uart0"), | ||
54 | CLK(&clk_48, "uart1"), | ||
55 | CLK(&clk_default, "gpio.0"), | ||
56 | CLK(&clk_default, "gpio.1"), | ||
57 | CLK(&clk_default, "gpio.2"), | ||
58 | CLK(&clk_default, "gpio.3"), | ||
59 | }; | ||
60 | |||
61 | static int __init clk_init(void) | ||
62 | { | ||
63 | clkdev_add_table(lookups, ARRAY_SIZE(lookups)); | ||
44 | return 0; | 64 | return 0; |
45 | } | 65 | } |
66 | |||
67 | arch_initcall(clk_init); | ||
diff --git a/arch/arm/mach-nomadik/clock.h b/arch/arm/mach-nomadik/clock.h index 235faec7f627..5563985a2cc7 100644 --- a/arch/arm/mach-nomadik/clock.h +++ b/arch/arm/mach-nomadik/clock.h | |||
@@ -11,4 +11,3 @@ | |||
11 | struct clk { | 11 | struct clk { |
12 | unsigned long rate; | 12 | unsigned long rate; |
13 | }; | 13 | }; |
14 | extern int nmdk_clk_create(struct clk *clk, const char *dev_id); | ||
diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c index 9bf33b30a025..91c3c901b469 100644 --- a/arch/arm/mach-nomadik/cpu-8815.c +++ b/arch/arm/mach-nomadik/cpu-8815.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
22 | #include <linux/amba/bus.h> | 22 | #include <linux/amba/bus.h> |
23 | #include <linux/platform_device.h> | ||
23 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
24 | 25 | ||
25 | #include <mach/hardware.h> | 26 | #include <mach/hardware.h> |
@@ -30,60 +31,66 @@ | |||
30 | #include <asm/cacheflush.h> | 31 | #include <asm/cacheflush.h> |
31 | #include <asm/hardware/cache-l2x0.h> | 32 | #include <asm/hardware/cache-l2x0.h> |
32 | 33 | ||
34 | #define __MEM_4K_RESOURCE(x) \ | ||
35 | .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM} | ||
36 | |||
33 | /* The 8815 has 4 GPIO blocks, let's register them immediately */ | 37 | /* The 8815 has 4 GPIO blocks, let's register them immediately */ |
38 | |||
39 | #define GPIO_RESOURCE(block) \ | ||
40 | { \ | ||
41 | .start = NOMADIK_GPIO##block##_BASE, \ | ||
42 | .end = NOMADIK_GPIO##block##_BASE + SZ_4K - 1, \ | ||
43 | .flags = IORESOURCE_MEM, \ | ||
44 | }, \ | ||
45 | { \ | ||
46 | .start = IRQ_GPIO##block, \ | ||
47 | .end = IRQ_GPIO##block, \ | ||
48 | .flags = IORESOURCE_IRQ, \ | ||
49 | } | ||
50 | |||
51 | #define GPIO_DEVICE(block) \ | ||
52 | { \ | ||
53 | .name = "gpio", \ | ||
54 | .id = block, \ | ||
55 | .num_resources = 2, \ | ||
56 | .resource = &cpu8815_gpio_resources[block * 2], \ | ||
57 | .dev = { \ | ||
58 | .platform_data = &cpu8815_gpio[block], \ | ||
59 | }, \ | ||
60 | } | ||
61 | |||
34 | static struct nmk_gpio_platform_data cpu8815_gpio[] = { | 62 | static struct nmk_gpio_platform_data cpu8815_gpio[] = { |
35 | { | 63 | { |
36 | .name = "GPIO-0-31", | 64 | .name = "GPIO-0-31", |
37 | .first_gpio = 0, | 65 | .first_gpio = 0, |
38 | .first_irq = NOMADIK_GPIO_TO_IRQ(0), | 66 | .first_irq = NOMADIK_GPIO_TO_IRQ(0), |
39 | .parent_irq = IRQ_GPIO0, | ||
40 | }, { | 67 | }, { |
41 | .name = "GPIO-32-63", | 68 | .name = "GPIO-32-63", |
42 | .first_gpio = 32, | 69 | .first_gpio = 32, |
43 | .first_irq = NOMADIK_GPIO_TO_IRQ(32), | 70 | .first_irq = NOMADIK_GPIO_TO_IRQ(32), |
44 | .parent_irq = IRQ_GPIO1, | ||
45 | }, { | 71 | }, { |
46 | .name = "GPIO-64-95", | 72 | .name = "GPIO-64-95", |
47 | .first_gpio = 64, | 73 | .first_gpio = 64, |
48 | .first_irq = NOMADIK_GPIO_TO_IRQ(64), | 74 | .first_irq = NOMADIK_GPIO_TO_IRQ(64), |
49 | .parent_irq = IRQ_GPIO2, | ||
50 | }, { | 75 | }, { |
51 | .name = "GPIO-96-127", /* 124..127 not routed to pin */ | 76 | .name = "GPIO-96-127", /* 124..127 not routed to pin */ |
52 | .first_gpio = 96, | 77 | .first_gpio = 96, |
53 | .first_irq = NOMADIK_GPIO_TO_IRQ(96), | 78 | .first_irq = NOMADIK_GPIO_TO_IRQ(96), |
54 | .parent_irq = IRQ_GPIO3, | ||
55 | } | 79 | } |
56 | }; | 80 | }; |
57 | 81 | ||
58 | #define __MEM_4K_RESOURCE(x) \ | 82 | static struct resource cpu8815_gpio_resources[] = { |
59 | .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM} | 83 | GPIO_RESOURCE(0), |
84 | GPIO_RESOURCE(1), | ||
85 | GPIO_RESOURCE(2), | ||
86 | GPIO_RESOURCE(3), | ||
87 | }; | ||
60 | 88 | ||
61 | static struct amba_device cpu8815_amba_gpio[] = { | 89 | static struct platform_device cpu8815_platform_gpio[] = { |
62 | { | 90 | GPIO_DEVICE(0), |
63 | .dev = { | 91 | GPIO_DEVICE(1), |
64 | .init_name = "gpio0", | 92 | GPIO_DEVICE(2), |
65 | .platform_data = cpu8815_gpio + 0, | 93 | GPIO_DEVICE(3), |
66 | }, | ||
67 | __MEM_4K_RESOURCE(NOMADIK_GPIO0_BASE), | ||
68 | }, { | ||
69 | .dev = { | ||
70 | .init_name = "gpio1", | ||
71 | .platform_data = cpu8815_gpio + 1, | ||
72 | }, | ||
73 | __MEM_4K_RESOURCE(NOMADIK_GPIO1_BASE), | ||
74 | }, { | ||
75 | .dev = { | ||
76 | .init_name = "gpio2", | ||
77 | .platform_data = cpu8815_gpio + 2, | ||
78 | }, | ||
79 | __MEM_4K_RESOURCE(NOMADIK_GPIO2_BASE), | ||
80 | }, { | ||
81 | .dev = { | ||
82 | .init_name = "gpio3", | ||
83 | .platform_data = cpu8815_gpio + 3, | ||
84 | }, | ||
85 | __MEM_4K_RESOURCE(NOMADIK_GPIO3_BASE), | ||
86 | }, | ||
87 | }; | 94 | }; |
88 | 95 | ||
89 | static struct amba_device cpu8815_amba_rng = { | 96 | static struct amba_device cpu8815_amba_rng = { |
@@ -93,11 +100,14 @@ static struct amba_device cpu8815_amba_rng = { | |||
93 | __MEM_4K_RESOURCE(NOMADIK_RNG_BASE), | 100 | __MEM_4K_RESOURCE(NOMADIK_RNG_BASE), |
94 | }; | 101 | }; |
95 | 102 | ||
103 | static struct platform_device *platform_devs[] __initdata = { | ||
104 | cpu8815_platform_gpio + 0, | ||
105 | cpu8815_platform_gpio + 1, | ||
106 | cpu8815_platform_gpio + 2, | ||
107 | cpu8815_platform_gpio + 3, | ||
108 | }; | ||
109 | |||
96 | static struct amba_device *amba_devs[] __initdata = { | 110 | static struct amba_device *amba_devs[] __initdata = { |
97 | cpu8815_amba_gpio + 0, | ||
98 | cpu8815_amba_gpio + 1, | ||
99 | cpu8815_amba_gpio + 2, | ||
100 | cpu8815_amba_gpio + 3, | ||
101 | &cpu8815_amba_rng | 111 | &cpu8815_amba_rng |
102 | }; | 112 | }; |
103 | 113 | ||
@@ -105,6 +115,7 @@ static int __init cpu8815_init(void) | |||
105 | { | 115 | { |
106 | int i; | 116 | int i; |
107 | 117 | ||
118 | platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); | ||
108 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) | 119 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) |
109 | amba_device_register(amba_devs[i], &iomem_resource); | 120 | amba_device_register(amba_devs[i], &iomem_resource); |
110 | return 0; | 121 | return 0; |
diff --git a/arch/arm/mach-nomadik/gpio.c b/arch/arm/mach-nomadik/gpio.c deleted file mode 100644 index 66b1c91ccc74..000000000000 --- a/arch/arm/mach-nomadik/gpio.c +++ /dev/null | |||
@@ -1,397 +0,0 @@ | |||
1 | /* | ||
2 | * Generic GPIO driver for logic cells found in the Nomadik SoC | ||
3 | * | ||
4 | * Copyright (C) 2008,2009 STMicroelectronics | ||
5 | * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> | ||
6 | * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/amba/bus.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/gpio.h> | ||
19 | #include <linux/spinlock.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/irq.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | #include <mach/hardware.h> | ||
25 | #include <mach/gpio.h> | ||
26 | |||
27 | /* | ||
28 | * The GPIO module in the Nomadik family of Systems-on-Chip is an | ||
29 | * AMBA device, managing 32 pins and alternate functions. The logic block | ||
30 | * is currently only used in the Nomadik. | ||
31 | * | ||
32 | * Symbols in this file are called "nmk_gpio" for "nomadik gpio" | ||
33 | */ | ||
34 | |||
35 | #define NMK_GPIO_PER_CHIP 32 | ||
36 | struct nmk_gpio_chip { | ||
37 | struct gpio_chip chip; | ||
38 | void __iomem *addr; | ||
39 | unsigned int parent_irq; | ||
40 | spinlock_t *lock; | ||
41 | /* Keep track of configured edges */ | ||
42 | u32 edge_rising; | ||
43 | u32 edge_falling; | ||
44 | }; | ||
45 | |||
46 | /* Mode functions */ | ||
47 | int nmk_gpio_set_mode(int gpio, int gpio_mode) | ||
48 | { | ||
49 | struct nmk_gpio_chip *nmk_chip; | ||
50 | unsigned long flags; | ||
51 | u32 afunc, bfunc, bit; | ||
52 | |||
53 | nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio)); | ||
54 | if (!nmk_chip) | ||
55 | return -EINVAL; | ||
56 | |||
57 | bit = 1 << (gpio - nmk_chip->chip.base); | ||
58 | |||
59 | spin_lock_irqsave(&nmk_chip->lock, flags); | ||
60 | afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit; | ||
61 | bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit; | ||
62 | if (gpio_mode & NMK_GPIO_ALT_A) | ||
63 | afunc |= bit; | ||
64 | if (gpio_mode & NMK_GPIO_ALT_B) | ||
65 | bfunc |= bit; | ||
66 | writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA); | ||
67 | writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB); | ||
68 | spin_unlock_irqrestore(&nmk_chip->lock, flags); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | EXPORT_SYMBOL(nmk_gpio_set_mode); | ||
73 | |||
74 | int nmk_gpio_get_mode(int gpio) | ||
75 | { | ||
76 | struct nmk_gpio_chip *nmk_chip; | ||
77 | u32 afunc, bfunc, bit; | ||
78 | |||
79 | nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio)); | ||
80 | if (!nmk_chip) | ||
81 | return -EINVAL; | ||
82 | |||
83 | bit = 1 << (gpio - nmk_chip->chip.base); | ||
84 | |||
85 | afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & bit; | ||
86 | bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & bit; | ||
87 | |||
88 | return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0); | ||
89 | } | ||
90 | EXPORT_SYMBOL(nmk_gpio_get_mode); | ||
91 | |||
92 | |||
93 | /* IRQ functions */ | ||
94 | static inline int nmk_gpio_get_bitmask(int gpio) | ||
95 | { | ||
96 | return 1 << (gpio % 32); | ||
97 | } | ||
98 | |||
99 | static void nmk_gpio_irq_ack(unsigned int irq) | ||
100 | { | ||
101 | int gpio; | ||
102 | struct nmk_gpio_chip *nmk_chip; | ||
103 | |||
104 | gpio = NOMADIK_IRQ_TO_GPIO(irq); | ||
105 | nmk_chip = get_irq_chip_data(irq); | ||
106 | if (!nmk_chip) | ||
107 | return; | ||
108 | writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC); | ||
109 | } | ||
110 | |||
111 | static void nmk_gpio_irq_mask(unsigned int irq) | ||
112 | { | ||
113 | int gpio; | ||
114 | struct nmk_gpio_chip *nmk_chip; | ||
115 | unsigned long flags; | ||
116 | u32 bitmask, reg; | ||
117 | |||
118 | gpio = NOMADIK_IRQ_TO_GPIO(irq); | ||
119 | nmk_chip = get_irq_chip_data(irq); | ||
120 | bitmask = nmk_gpio_get_bitmask(gpio); | ||
121 | if (!nmk_chip) | ||
122 | return; | ||
123 | |||
124 | /* we must individually clear the two edges */ | ||
125 | spin_lock_irqsave(&nmk_chip->lock, flags); | ||
126 | if (nmk_chip->edge_rising & bitmask) { | ||
127 | reg = readl(nmk_chip->addr + NMK_GPIO_RWIMSC); | ||
128 | reg &= ~bitmask; | ||
129 | writel(reg, nmk_chip->addr + NMK_GPIO_RWIMSC); | ||
130 | } | ||
131 | if (nmk_chip->edge_falling & bitmask) { | ||
132 | reg = readl(nmk_chip->addr + NMK_GPIO_FWIMSC); | ||
133 | reg &= ~bitmask; | ||
134 | writel(reg, nmk_chip->addr + NMK_GPIO_FWIMSC); | ||
135 | } | ||
136 | spin_unlock_irqrestore(&nmk_chip->lock, flags); | ||
137 | }; | ||
138 | |||
139 | static void nmk_gpio_irq_unmask(unsigned int irq) | ||
140 | { | ||
141 | int gpio; | ||
142 | struct nmk_gpio_chip *nmk_chip; | ||
143 | unsigned long flags; | ||
144 | u32 bitmask, reg; | ||
145 | |||
146 | gpio = NOMADIK_IRQ_TO_GPIO(irq); | ||
147 | nmk_chip = get_irq_chip_data(irq); | ||
148 | bitmask = nmk_gpio_get_bitmask(gpio); | ||
149 | if (!nmk_chip) | ||
150 | return; | ||
151 | |||
152 | /* we must individually set the two edges */ | ||
153 | spin_lock_irqsave(&nmk_chip->lock, flags); | ||
154 | if (nmk_chip->edge_rising & bitmask) { | ||
155 | reg = readl(nmk_chip->addr + NMK_GPIO_RWIMSC); | ||
156 | reg |= bitmask; | ||
157 | writel(reg, nmk_chip->addr + NMK_GPIO_RWIMSC); | ||
158 | } | ||
159 | if (nmk_chip->edge_falling & bitmask) { | ||
160 | reg = readl(nmk_chip->addr + NMK_GPIO_FWIMSC); | ||
161 | reg |= bitmask; | ||
162 | writel(reg, nmk_chip->addr + NMK_GPIO_FWIMSC); | ||
163 | } | ||
164 | spin_unlock_irqrestore(&nmk_chip->lock, flags); | ||
165 | } | ||
166 | |||
167 | static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type) | ||
168 | { | ||
169 | int gpio; | ||
170 | struct nmk_gpio_chip *nmk_chip; | ||
171 | unsigned long flags; | ||
172 | u32 bitmask; | ||
173 | |||
174 | gpio = NOMADIK_IRQ_TO_GPIO(irq); | ||
175 | nmk_chip = get_irq_chip_data(irq); | ||
176 | bitmask = nmk_gpio_get_bitmask(gpio); | ||
177 | if (!nmk_chip) | ||
178 | return -EINVAL; | ||
179 | |||
180 | if (type & IRQ_TYPE_LEVEL_HIGH) | ||
181 | return -EINVAL; | ||
182 | if (type & IRQ_TYPE_LEVEL_LOW) | ||
183 | return -EINVAL; | ||
184 | |||
185 | spin_lock_irqsave(&nmk_chip->lock, flags); | ||
186 | |||
187 | nmk_chip->edge_rising &= ~bitmask; | ||
188 | if (type & IRQ_TYPE_EDGE_RISING) | ||
189 | nmk_chip->edge_rising |= bitmask; | ||
190 | writel(nmk_chip->edge_rising, nmk_chip->addr + NMK_GPIO_RIMSC); | ||
191 | |||
192 | nmk_chip->edge_falling &= ~bitmask; | ||
193 | if (type & IRQ_TYPE_EDGE_FALLING) | ||
194 | nmk_chip->edge_falling |= bitmask; | ||
195 | writel(nmk_chip->edge_falling, nmk_chip->addr + NMK_GPIO_FIMSC); | ||
196 | |||
197 | spin_unlock_irqrestore(&nmk_chip->lock, flags); | ||
198 | |||
199 | nmk_gpio_irq_unmask(irq); | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static struct irq_chip nmk_gpio_irq_chip = { | ||
205 | .name = "Nomadik-GPIO", | ||
206 | .ack = nmk_gpio_irq_ack, | ||
207 | .mask = nmk_gpio_irq_mask, | ||
208 | .unmask = nmk_gpio_irq_unmask, | ||
209 | .set_type = nmk_gpio_irq_set_type, | ||
210 | }; | ||
211 | |||
212 | static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
213 | { | ||
214 | struct nmk_gpio_chip *nmk_chip; | ||
215 | struct irq_chip *host_chip; | ||
216 | unsigned int gpio_irq; | ||
217 | u32 pending; | ||
218 | unsigned int first_irq; | ||
219 | |||
220 | nmk_chip = get_irq_data(irq); | ||
221 | first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base); | ||
222 | while ( (pending = readl(nmk_chip->addr + NMK_GPIO_IS)) ) { | ||
223 | gpio_irq = first_irq + __ffs(pending); | ||
224 | generic_handle_irq(gpio_irq); | ||
225 | } | ||
226 | if (0) {/* don't ack parent irq, as ack == disable */ | ||
227 | host_chip = get_irq_chip(irq); | ||
228 | host_chip->ack(irq); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip) | ||
233 | { | ||
234 | unsigned int first_irq; | ||
235 | int i; | ||
236 | |||
237 | first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base); | ||
238 | for (i = first_irq; i < first_irq + NMK_GPIO_PER_CHIP; i++) { | ||
239 | set_irq_chip(i, &nmk_gpio_irq_chip); | ||
240 | set_irq_handler(i, handle_edge_irq); | ||
241 | set_irq_flags(i, IRQF_VALID); | ||
242 | set_irq_chip_data(i, nmk_chip); | ||
243 | } | ||
244 | set_irq_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler); | ||
245 | set_irq_data(nmk_chip->parent_irq, nmk_chip); | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* I/O Functions */ | ||
250 | static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset) | ||
251 | { | ||
252 | struct nmk_gpio_chip *nmk_chip = | ||
253 | container_of(chip, struct nmk_gpio_chip, chip); | ||
254 | |||
255 | writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset, | ||
260 | int val) | ||
261 | { | ||
262 | struct nmk_gpio_chip *nmk_chip = | ||
263 | container_of(chip, struct nmk_gpio_chip, chip); | ||
264 | |||
265 | writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS); | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset) | ||
270 | { | ||
271 | struct nmk_gpio_chip *nmk_chip = | ||
272 | container_of(chip, struct nmk_gpio_chip, chip); | ||
273 | u32 bit = 1 << offset; | ||
274 | |||
275 | return (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0; | ||
276 | } | ||
277 | |||
278 | static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset, | ||
279 | int val) | ||
280 | { | ||
281 | struct nmk_gpio_chip *nmk_chip = | ||
282 | container_of(chip, struct nmk_gpio_chip, chip); | ||
283 | u32 bit = 1 << offset; | ||
284 | |||
285 | if (val) | ||
286 | writel(bit, nmk_chip->addr + NMK_GPIO_DATS); | ||
287 | else | ||
288 | writel(bit, nmk_chip->addr + NMK_GPIO_DATC); | ||
289 | } | ||
290 | |||
291 | /* This structure is replicated for each GPIO block allocated at probe time */ | ||
292 | static struct gpio_chip nmk_gpio_template = { | ||
293 | .direction_input = nmk_gpio_make_input, | ||
294 | .get = nmk_gpio_get_input, | ||
295 | .direction_output = nmk_gpio_make_output, | ||
296 | .set = nmk_gpio_set_output, | ||
297 | .ngpio = NMK_GPIO_PER_CHIP, | ||
298 | .can_sleep = 0, | ||
299 | }; | ||
300 | |||
301 | static int __init nmk_gpio_probe(struct amba_device *dev, struct amba_id *id) | ||
302 | { | ||
303 | struct nmk_gpio_platform_data *pdata; | ||
304 | struct nmk_gpio_chip *nmk_chip; | ||
305 | struct gpio_chip *chip; | ||
306 | int ret; | ||
307 | |||
308 | pdata = dev->dev.platform_data; | ||
309 | ret = amba_request_regions(dev, pdata->name); | ||
310 | if (ret) | ||
311 | return ret; | ||
312 | |||
313 | nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL); | ||
314 | if (!nmk_chip) { | ||
315 | ret = -ENOMEM; | ||
316 | goto out_amba; | ||
317 | } | ||
318 | /* | ||
319 | * The virt address in nmk_chip->addr is in the nomadik register space, | ||
320 | * so we can simply convert the resource address, without remapping | ||
321 | */ | ||
322 | nmk_chip->addr = io_p2v(dev->res.start); | ||
323 | nmk_chip->chip = nmk_gpio_template; | ||
324 | nmk_chip->parent_irq = pdata->parent_irq; | ||
325 | |||
326 | chip = &nmk_chip->chip; | ||
327 | chip->base = pdata->first_gpio; | ||
328 | chip->label = pdata->name; | ||
329 | chip->dev = &dev->dev; | ||
330 | chip->owner = THIS_MODULE; | ||
331 | |||
332 | ret = gpiochip_add(&nmk_chip->chip); | ||
333 | if (ret) | ||
334 | goto out_free; | ||
335 | |||
336 | amba_set_drvdata(dev, nmk_chip); | ||
337 | |||
338 | nmk_gpio_init_irq(nmk_chip); | ||
339 | |||
340 | dev_info(&dev->dev, "Bits %i-%i at address %p\n", | ||
341 | nmk_chip->chip.base, nmk_chip->chip.base+31, nmk_chip->addr); | ||
342 | return 0; | ||
343 | |||
344 | out_free: | ||
345 | kfree(nmk_chip); | ||
346 | out_amba: | ||
347 | amba_release_regions(dev); | ||
348 | dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret, | ||
349 | pdata->first_gpio, pdata->first_gpio+31); | ||
350 | return ret; | ||
351 | } | ||
352 | |||
353 | static int nmk_gpio_remove(struct amba_device *dev) | ||
354 | { | ||
355 | struct nmk_gpio_chip *nmk_chip; | ||
356 | |||
357 | nmk_chip = amba_get_drvdata(dev); | ||
358 | gpiochip_remove(&nmk_chip->chip); | ||
359 | kfree(nmk_chip); | ||
360 | amba_release_regions(dev); | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | |||
365 | /* We have 0x1f080060 and 0x1f180060, accept both using the mask */ | ||
366 | static struct amba_id nmk_gpio_ids[] = { | ||
367 | { | ||
368 | .id = 0x1f080060, | ||
369 | .mask = 0xffefffff, | ||
370 | }, | ||
371 | {0, 0}, | ||
372 | }; | ||
373 | |||
374 | static struct amba_driver nmk_gpio_driver = { | ||
375 | .drv = { | ||
376 | .owner = THIS_MODULE, | ||
377 | .name = "gpio", | ||
378 | }, | ||
379 | .probe = nmk_gpio_probe, | ||
380 | .remove = nmk_gpio_remove, | ||
381 | .suspend = NULL, /* to be done */ | ||
382 | .resume = NULL, | ||
383 | .id_table = nmk_gpio_ids, | ||
384 | }; | ||
385 | |||
386 | static int __init nmk_gpio_init(void) | ||
387 | { | ||
388 | return amba_driver_register(&nmk_gpio_driver); | ||
389 | } | ||
390 | |||
391 | arch_initcall(nmk_gpio_init); | ||
392 | |||
393 | MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini"); | ||
394 | MODULE_DESCRIPTION("Nomadik GPIO Driver"); | ||
395 | MODULE_LICENSE("GPL"); | ||
396 | |||
397 | |||
diff --git a/arch/arm/mach-nomadik/include/mach/gpio.h b/arch/arm/mach-nomadik/include/mach/gpio.h index 61577c9f9a7d..7a81a0420343 100644 --- a/arch/arm/mach-nomadik/include/mach/gpio.h +++ b/arch/arm/mach-nomadik/include/mach/gpio.h | |||
@@ -1,71 +1,6 @@ | |||
1 | /* | ||
2 | * Structures and registers for GPIO access in the Nomadik SoC | ||
3 | * | ||
4 | * Copyright (C) 2008 STMicroelectronics | ||
5 | * Author: Prafulla WADASKAR <prafulla.wadaskar@st.com> | ||
6 | * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef __ASM_ARCH_GPIO_H | 1 | #ifndef __ASM_ARCH_GPIO_H |
13 | #define __ASM_ARCH_GPIO_H | 2 | #define __ASM_ARCH_GPIO_H |
14 | 3 | ||
15 | #include <asm-generic/gpio.h> | 4 | #include <plat/gpio.h> |
16 | |||
17 | /* | ||
18 | * These currently cause a function call to happen, they may be optimized | ||
19 | * if needed by adding cpu-specific defines to identify blocks | ||
20 | * (see mach-pxa/include/mach/gpio.h as an example using GPLR etc) | ||
21 | */ | ||
22 | #define gpio_get_value __gpio_get_value | ||
23 | #define gpio_set_value __gpio_set_value | ||
24 | #define gpio_cansleep __gpio_cansleep | ||
25 | #define gpio_to_irq __gpio_to_irq | ||
26 | |||
27 | /* | ||
28 | * "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving | ||
29 | * the "gpio" namespace for generic and cross-machine functions | ||
30 | */ | ||
31 | |||
32 | /* Register in the logic block */ | ||
33 | #define NMK_GPIO_DAT 0x00 | ||
34 | #define NMK_GPIO_DATS 0x04 | ||
35 | #define NMK_GPIO_DATC 0x08 | ||
36 | #define NMK_GPIO_PDIS 0x0c | ||
37 | #define NMK_GPIO_DIR 0x10 | ||
38 | #define NMK_GPIO_DIRS 0x14 | ||
39 | #define NMK_GPIO_DIRC 0x18 | ||
40 | #define NMK_GPIO_SLPC 0x1c | ||
41 | #define NMK_GPIO_AFSLA 0x20 | ||
42 | #define NMK_GPIO_AFSLB 0x24 | ||
43 | |||
44 | #define NMK_GPIO_RIMSC 0x40 | ||
45 | #define NMK_GPIO_FIMSC 0x44 | ||
46 | #define NMK_GPIO_IS 0x48 | ||
47 | #define NMK_GPIO_IC 0x4c | ||
48 | #define NMK_GPIO_RWIMSC 0x50 | ||
49 | #define NMK_GPIO_FWIMSC 0x54 | ||
50 | #define NMK_GPIO_WKS 0x58 | ||
51 | |||
52 | /* Alternate functions: function C is set in hw by setting both A and B */ | ||
53 | #define NMK_GPIO_ALT_GPIO 0 | ||
54 | #define NMK_GPIO_ALT_A 1 | ||
55 | #define NMK_GPIO_ALT_B 2 | ||
56 | #define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B) | ||
57 | |||
58 | extern int nmk_gpio_set_mode(int gpio, int gpio_mode); | ||
59 | extern int nmk_gpio_get_mode(int gpio); | ||
60 | |||
61 | /* | ||
62 | * Platform data to register a block: only the initial gpio/irq number. | ||
63 | */ | ||
64 | struct nmk_gpio_platform_data { | ||
65 | char *name; | ||
66 | int first_gpio; | ||
67 | int first_irq; | ||
68 | int parent_irq; | ||
69 | }; | ||
70 | 5 | ||
71 | #endif /* __ASM_ARCH_GPIO_H */ | 6 | #endif /* __ASM_ARCH_GPIO_H */ |