diff options
-rw-r--r-- | arch/arm/mach-realview/realview_eb.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-realview/realview_pb1176.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-realview/realview_pb11mp.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-realview/realview_pba8.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-realview/realview_pbx.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/include/mach/gpio.h | 3 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpio/devres.c | 90 | ||||
-rw-r--r-- | drivers/gpio/gpio-pl061.c | 200 | ||||
-rw-r--r-- | drivers/gpio/gpio-sa1100.c | 6 | ||||
-rw-r--r-- | drivers/gpio/gpio-tegra.c | 9 | ||||
-rw-r--r-- | include/asm-generic/gpio.h | 4 | ||||
-rw-r--r-- | include/linux/amba/pl061.h | 2 |
14 files changed, 214 insertions, 118 deletions
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index 0069561464f9..e62962117763 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c | |||
@@ -117,17 +117,14 @@ static void __init realview_eb_map_io(void) | |||
117 | 117 | ||
118 | static struct pl061_platform_data gpio0_plat_data = { | 118 | static struct pl061_platform_data gpio0_plat_data = { |
119 | .gpio_base = 0, | 119 | .gpio_base = 0, |
120 | .irq_base = -1, | ||
121 | }; | 120 | }; |
122 | 121 | ||
123 | static struct pl061_platform_data gpio1_plat_data = { | 122 | static struct pl061_platform_data gpio1_plat_data = { |
124 | .gpio_base = 8, | 123 | .gpio_base = 8, |
125 | .irq_base = -1, | ||
126 | }; | 124 | }; |
127 | 125 | ||
128 | static struct pl061_platform_data gpio2_plat_data = { | 126 | static struct pl061_platform_data gpio2_plat_data = { |
129 | .gpio_base = 16, | 127 | .gpio_base = 16, |
130 | .irq_base = -1, | ||
131 | }; | 128 | }; |
132 | 129 | ||
133 | static struct pl022_ssp_controller ssp0_plat_data = { | 130 | static struct pl022_ssp_controller ssp0_plat_data = { |
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c index 8fe395568a47..e4abe94fb11a 100644 --- a/arch/arm/mach-realview/realview_pb1176.c +++ b/arch/arm/mach-realview/realview_pb1176.c | |||
@@ -113,17 +113,14 @@ static void __init realview_pb1176_map_io(void) | |||
113 | 113 | ||
114 | static struct pl061_platform_data gpio0_plat_data = { | 114 | static struct pl061_platform_data gpio0_plat_data = { |
115 | .gpio_base = 0, | 115 | .gpio_base = 0, |
116 | .irq_base = -1, | ||
117 | }; | 116 | }; |
118 | 117 | ||
119 | static struct pl061_platform_data gpio1_plat_data = { | 118 | static struct pl061_platform_data gpio1_plat_data = { |
120 | .gpio_base = 8, | 119 | .gpio_base = 8, |
121 | .irq_base = -1, | ||
122 | }; | 120 | }; |
123 | 121 | ||
124 | static struct pl061_platform_data gpio2_plat_data = { | 122 | static struct pl061_platform_data gpio2_plat_data = { |
125 | .gpio_base = 16, | 123 | .gpio_base = 16, |
126 | .irq_base = -1, | ||
127 | }; | 124 | }; |
128 | 125 | ||
129 | static struct pl022_ssp_controller ssp0_plat_data = { | 126 | static struct pl022_ssp_controller ssp0_plat_data = { |
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c index 34a26011bb89..127a3fd42ab1 100644 --- a/arch/arm/mach-realview/realview_pb11mp.c +++ b/arch/arm/mach-realview/realview_pb11mp.c | |||
@@ -112,17 +112,14 @@ static void __init realview_pb11mp_map_io(void) | |||
112 | 112 | ||
113 | static struct pl061_platform_data gpio0_plat_data = { | 113 | static struct pl061_platform_data gpio0_plat_data = { |
114 | .gpio_base = 0, | 114 | .gpio_base = 0, |
115 | .irq_base = -1, | ||
116 | }; | 115 | }; |
117 | 116 | ||
118 | static struct pl061_platform_data gpio1_plat_data = { | 117 | static struct pl061_platform_data gpio1_plat_data = { |
119 | .gpio_base = 8, | 118 | .gpio_base = 8, |
120 | .irq_base = -1, | ||
121 | }; | 119 | }; |
122 | 120 | ||
123 | static struct pl061_platform_data gpio2_plat_data = { | 121 | static struct pl061_platform_data gpio2_plat_data = { |
124 | .gpio_base = 16, | 122 | .gpio_base = 16, |
125 | .irq_base = -1, | ||
126 | }; | 123 | }; |
127 | 124 | ||
128 | static struct pl022_ssp_controller ssp0_plat_data = { | 125 | static struct pl022_ssp_controller ssp0_plat_data = { |
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c index d26a6def1d65..25b2e59296f8 100644 --- a/arch/arm/mach-realview/realview_pba8.c +++ b/arch/arm/mach-realview/realview_pba8.c | |||
@@ -102,17 +102,14 @@ static void __init realview_pba8_map_io(void) | |||
102 | 102 | ||
103 | static struct pl061_platform_data gpio0_plat_data = { | 103 | static struct pl061_platform_data gpio0_plat_data = { |
104 | .gpio_base = 0, | 104 | .gpio_base = 0, |
105 | .irq_base = -1, | ||
106 | }; | 105 | }; |
107 | 106 | ||
108 | static struct pl061_platform_data gpio1_plat_data = { | 107 | static struct pl061_platform_data gpio1_plat_data = { |
109 | .gpio_base = 8, | 108 | .gpio_base = 8, |
110 | .irq_base = -1, | ||
111 | }; | 109 | }; |
112 | 110 | ||
113 | static struct pl061_platform_data gpio2_plat_data = { | 111 | static struct pl061_platform_data gpio2_plat_data = { |
114 | .gpio_base = 16, | 112 | .gpio_base = 16, |
115 | .irq_base = -1, | ||
116 | }; | 113 | }; |
117 | 114 | ||
118 | static struct pl022_ssp_controller ssp0_plat_data = { | 115 | static struct pl022_ssp_controller ssp0_plat_data = { |
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c index a250fb4124bf..ac715645b860 100644 --- a/arch/arm/mach-realview/realview_pbx.c +++ b/arch/arm/mach-realview/realview_pbx.c | |||
@@ -124,17 +124,14 @@ static void __init realview_pbx_map_io(void) | |||
124 | 124 | ||
125 | static struct pl061_platform_data gpio0_plat_data = { | 125 | static struct pl061_platform_data gpio0_plat_data = { |
126 | .gpio_base = 0, | 126 | .gpio_base = 0, |
127 | .irq_base = -1, | ||
128 | }; | 127 | }; |
129 | 128 | ||
130 | static struct pl061_platform_data gpio1_plat_data = { | 129 | static struct pl061_platform_data gpio1_plat_data = { |
131 | .gpio_base = 8, | 130 | .gpio_base = 8, |
132 | .irq_base = -1, | ||
133 | }; | 131 | }; |
134 | 132 | ||
135 | static struct pl061_platform_data gpio2_plat_data = { | 133 | static struct pl061_platform_data gpio2_plat_data = { |
136 | .gpio_base = 16, | 134 | .gpio_base = 16, |
137 | .irq_base = -1, | ||
138 | }; | 135 | }; |
139 | 136 | ||
140 | static struct pl022_ssp_controller ssp0_plat_data = { | 137 | static struct pl022_ssp_controller ssp0_plat_data = { |
diff --git a/arch/arm/mach-sa1100/include/mach/gpio.h b/arch/arm/mach-sa1100/include/mach/gpio.h index 703631887c94..a38fc4f54241 100644 --- a/arch/arm/mach-sa1100/include/mach/gpio.h +++ b/arch/arm/mach-sa1100/include/mach/gpio.h | |||
@@ -51,7 +51,4 @@ static inline void gpio_set_value(unsigned gpio, int value) | |||
51 | 51 | ||
52 | #define gpio_cansleep __gpio_cansleep | 52 | #define gpio_cansleep __gpio_cansleep |
53 | 53 | ||
54 | #define gpio_to_irq(gpio) ((gpio < 11) ? (IRQ_GPIO0 + gpio) : \ | ||
55 | (IRQ_GPIO11 - 11 + gpio)) | ||
56 | |||
57 | #endif | 54 | #endif |
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 573532f7553e..37c4bd1cacd5 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -138,6 +138,7 @@ config GPIO_MXS | |||
138 | config GPIO_PL061 | 138 | config GPIO_PL061 |
139 | bool "PrimeCell PL061 GPIO support" | 139 | bool "PrimeCell PL061 GPIO support" |
140 | depends on ARM_AMBA | 140 | depends on ARM_AMBA |
141 | select GENERIC_IRQ_CHIP | ||
141 | help | 142 | help |
142 | Say yes here to support the PrimeCell PL061 GPIO device | 143 | Say yes here to support the PrimeCell PL061 GPIO device |
143 | 144 | ||
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 62e641e79e8f..fa10df604c01 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG | 3 | ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG |
4 | 4 | ||
5 | obj-$(CONFIG_GPIOLIB) += gpiolib.o | 5 | obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o |
6 | 6 | ||
7 | # Device drivers. Generally keep list sorted alphabetically | 7 | # Device drivers. Generally keep list sorted alphabetically |
8 | obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o | 8 | obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o |
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c new file mode 100644 index 000000000000..3dd29399cef5 --- /dev/null +++ b/drivers/gpio/devres.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * drivers/gpio/devres.c - managed gpio resources | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 | ||
6 | * as published by the Free Software Foundation. | ||
7 | * | ||
8 | * You should have received a copy of the GNU General Public License | ||
9 | * along with this program; if not, write to the Free Software | ||
10 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
11 | * | ||
12 | * This file is based on kernel/irq/devres.c | ||
13 | * | ||
14 | * Copyright (c) 2011 John Crispin <blogic@openwrt.org> | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/gpio.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/gfp.h> | ||
21 | |||
22 | static void devm_gpio_release(struct device *dev, void *res) | ||
23 | { | ||
24 | unsigned *gpio = res; | ||
25 | |||
26 | gpio_free(*gpio); | ||
27 | } | ||
28 | |||
29 | static int devm_gpio_match(struct device *dev, void *res, void *data) | ||
30 | { | ||
31 | unsigned *this = res, *gpio = data; | ||
32 | |||
33 | return *this == *gpio; | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * devm_gpio_request - request a gpio for a managed device | ||
38 | * @dev: device to request the gpio for | ||
39 | * @gpio: gpio to allocate | ||
40 | * @label: the name of the requested gpio | ||
41 | * | ||
42 | * Except for the extra @dev argument, this function takes the | ||
43 | * same arguments and performs the same function as | ||
44 | * gpio_request(). GPIOs requested with this function will be | ||
45 | * automatically freed on driver detach. | ||
46 | * | ||
47 | * If an GPIO allocated with this function needs to be freed | ||
48 | * separately, devm_gpio_free() must be used. | ||
49 | */ | ||
50 | |||
51 | int devm_gpio_request(struct device *dev, unsigned gpio, const char *label) | ||
52 | { | ||
53 | unsigned *dr; | ||
54 | int rc; | ||
55 | |||
56 | dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL); | ||
57 | if (!dr) | ||
58 | return -ENOMEM; | ||
59 | |||
60 | rc = gpio_request(gpio, label); | ||
61 | if (rc) { | ||
62 | devres_free(dr); | ||
63 | return rc; | ||
64 | } | ||
65 | |||
66 | *dr = gpio; | ||
67 | devres_add(dev, dr); | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | EXPORT_SYMBOL(devm_gpio_request); | ||
72 | |||
73 | /** | ||
74 | * devm_gpio_free - free an interrupt | ||
75 | * @dev: device to free gpio for | ||
76 | * @gpio: gpio to free | ||
77 | * | ||
78 | * Except for the extra @dev argument, this function takes the | ||
79 | * same arguments and performs the same function as gpio_free(). | ||
80 | * This function instead of gpio_free() should be used to manually | ||
81 | * free GPIOs allocated with devm_gpio_request(). | ||
82 | */ | ||
83 | void devm_gpio_free(struct device *dev, unsigned int gpio) | ||
84 | { | ||
85 | |||
86 | WARN_ON(devres_destroy(dev, devm_gpio_release, devm_gpio_match, | ||
87 | &gpio)); | ||
88 | gpio_free(gpio); | ||
89 | } | ||
90 | EXPORT_SYMBOL(devm_gpio_free); | ||
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 8f79c03049f3..77c9cc70fa77 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/spinlock.h> | 12 | #include <linux/spinlock.h> |
13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/list.h> | ||
16 | #include <linux/io.h> | 15 | #include <linux/io.h> |
17 | #include <linux/ioport.h> | 16 | #include <linux/ioport.h> |
18 | #include <linux/irq.h> | 17 | #include <linux/irq.h> |
@@ -23,6 +22,8 @@ | |||
23 | #include <linux/amba/bus.h> | 22 | #include <linux/amba/bus.h> |
24 | #include <linux/amba/pl061.h> | 23 | #include <linux/amba/pl061.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/pm.h> | ||
26 | #include <asm/mach/irq.h> | ||
26 | 27 | ||
27 | #define GPIODIR 0x400 | 28 | #define GPIODIR 0x400 |
28 | #define GPIOIS 0x404 | 29 | #define GPIOIS 0x404 |
@@ -35,25 +36,33 @@ | |||
35 | 36 | ||
36 | #define PL061_GPIO_NR 8 | 37 | #define PL061_GPIO_NR 8 |
37 | 38 | ||
38 | struct pl061_gpio { | 39 | #ifdef CONFIG_PM |
39 | /* We use a list of pl061_gpio structs for each trigger IRQ in the main | 40 | struct pl061_context_save_regs { |
40 | * interrupts controller of the system. We need this to support systems | 41 | u8 gpio_data; |
41 | * in which more that one PL061s are connected to the same IRQ. The ISR | 42 | u8 gpio_dir; |
42 | * interates through this list to find the source of the interrupt. | 43 | u8 gpio_is; |
43 | */ | 44 | u8 gpio_ibe; |
44 | struct list_head list; | 45 | u8 gpio_iev; |
46 | u8 gpio_ie; | ||
47 | }; | ||
48 | #endif | ||
45 | 49 | ||
50 | struct pl061_gpio { | ||
46 | /* Each of the two spinlocks protects a different set of hardware | 51 | /* Each of the two spinlocks protects a different set of hardware |
47 | * regiters and data structurs. This decouples the code of the IRQ from | 52 | * regiters and data structurs. This decouples the code of the IRQ from |
48 | * the GPIO code. This also makes the case of a GPIO routine call from | 53 | * the GPIO code. This also makes the case of a GPIO routine call from |
49 | * the IRQ code simpler. | 54 | * the IRQ code simpler. |
50 | */ | 55 | */ |
51 | spinlock_t lock; /* GPIO registers */ | 56 | spinlock_t lock; /* GPIO registers */ |
52 | spinlock_t irq_lock; /* IRQ registers */ | ||
53 | 57 | ||
54 | void __iomem *base; | 58 | void __iomem *base; |
55 | unsigned irq_base; | 59 | int irq_base; |
60 | struct irq_chip_generic *irq_gc; | ||
56 | struct gpio_chip gc; | 61 | struct gpio_chip gc; |
62 | |||
63 | #ifdef CONFIG_PM | ||
64 | struct pl061_context_save_regs csave_regs; | ||
65 | #endif | ||
57 | }; | 66 | }; |
58 | 67 | ||
59 | static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) | 68 | static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) |
@@ -118,46 +127,16 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) | |||
118 | { | 127 | { |
119 | struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); | 128 | struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); |
120 | 129 | ||
121 | if (chip->irq_base == NO_IRQ) | 130 | if (chip->irq_base <= 0) |
122 | return -EINVAL; | 131 | return -EINVAL; |
123 | 132 | ||
124 | return chip->irq_base + offset; | 133 | return chip->irq_base + offset; |
125 | } | 134 | } |
126 | 135 | ||
127 | /* | ||
128 | * PL061 GPIO IRQ | ||
129 | */ | ||
130 | static void pl061_irq_disable(struct irq_data *d) | ||
131 | { | ||
132 | struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); | ||
133 | int offset = d->irq - chip->irq_base; | ||
134 | unsigned long flags; | ||
135 | u8 gpioie; | ||
136 | |||
137 | spin_lock_irqsave(&chip->irq_lock, flags); | ||
138 | gpioie = readb(chip->base + GPIOIE); | ||
139 | gpioie &= ~(1 << offset); | ||
140 | writeb(gpioie, chip->base + GPIOIE); | ||
141 | spin_unlock_irqrestore(&chip->irq_lock, flags); | ||
142 | } | ||
143 | |||
144 | static void pl061_irq_enable(struct irq_data *d) | ||
145 | { | ||
146 | struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); | ||
147 | int offset = d->irq - chip->irq_base; | ||
148 | unsigned long flags; | ||
149 | u8 gpioie; | ||
150 | |||
151 | spin_lock_irqsave(&chip->irq_lock, flags); | ||
152 | gpioie = readb(chip->base + GPIOIE); | ||
153 | gpioie |= 1 << offset; | ||
154 | writeb(gpioie, chip->base + GPIOIE); | ||
155 | spin_unlock_irqrestore(&chip->irq_lock, flags); | ||
156 | } | ||
157 | |||
158 | static int pl061_irq_type(struct irq_data *d, unsigned trigger) | 136 | static int pl061_irq_type(struct irq_data *d, unsigned trigger) |
159 | { | 137 | { |
160 | struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); | 138 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); |
139 | struct pl061_gpio *chip = gc->private; | ||
161 | int offset = d->irq - chip->irq_base; | 140 | int offset = d->irq - chip->irq_base; |
162 | unsigned long flags; | 141 | unsigned long flags; |
163 | u8 gpiois, gpioibe, gpioiev; | 142 | u8 gpiois, gpioibe, gpioiev; |
@@ -165,7 +144,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) | |||
165 | if (offset < 0 || offset >= PL061_GPIO_NR) | 144 | if (offset < 0 || offset >= PL061_GPIO_NR) |
166 | return -EINVAL; | 145 | return -EINVAL; |
167 | 146 | ||
168 | spin_lock_irqsave(&chip->irq_lock, flags); | 147 | raw_spin_lock_irqsave(&gc->lock, flags); |
169 | 148 | ||
170 | gpioiev = readb(chip->base + GPIOIEV); | 149 | gpioiev = readb(chip->base + GPIOIEV); |
171 | 150 | ||
@@ -194,49 +173,54 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) | |||
194 | 173 | ||
195 | writeb(gpioiev, chip->base + GPIOIEV); | 174 | writeb(gpioiev, chip->base + GPIOIEV); |
196 | 175 | ||
197 | spin_unlock_irqrestore(&chip->irq_lock, flags); | 176 | raw_spin_unlock_irqrestore(&gc->lock, flags); |
198 | 177 | ||
199 | return 0; | 178 | return 0; |
200 | } | 179 | } |
201 | 180 | ||
202 | static struct irq_chip pl061_irqchip = { | ||
203 | .name = "GPIO", | ||
204 | .irq_enable = pl061_irq_enable, | ||
205 | .irq_disable = pl061_irq_disable, | ||
206 | .irq_set_type = pl061_irq_type, | ||
207 | }; | ||
208 | |||
209 | static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) | 181 | static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) |
210 | { | 182 | { |
211 | struct list_head *chip_list = irq_get_handler_data(irq); | 183 | unsigned long pending; |
212 | struct list_head *ptr; | 184 | int offset; |
213 | struct pl061_gpio *chip; | 185 | struct pl061_gpio *chip = irq_desc_get_handler_data(desc); |
214 | 186 | struct irq_chip *irqchip = irq_desc_get_chip(desc); | |
215 | desc->irq_data.chip->irq_ack(&desc->irq_data); | ||
216 | list_for_each(ptr, chip_list) { | ||
217 | unsigned long pending; | ||
218 | int offset; | ||
219 | 187 | ||
220 | chip = list_entry(ptr, struct pl061_gpio, list); | 188 | chained_irq_enter(irqchip, desc); |
221 | pending = readb(chip->base + GPIOMIS); | ||
222 | writeb(pending, chip->base + GPIOIC); | ||
223 | |||
224 | if (pending == 0) | ||
225 | continue; | ||
226 | 189 | ||
190 | pending = readb(chip->base + GPIOMIS); | ||
191 | writeb(pending, chip->base + GPIOIC); | ||
192 | if (pending) { | ||
227 | for_each_set_bit(offset, &pending, PL061_GPIO_NR) | 193 | for_each_set_bit(offset, &pending, PL061_GPIO_NR) |
228 | generic_handle_irq(pl061_to_irq(&chip->gc, offset)); | 194 | generic_handle_irq(pl061_to_irq(&chip->gc, offset)); |
229 | } | 195 | } |
230 | desc->irq_data.chip->irq_unmask(&desc->irq_data); | 196 | |
197 | chained_irq_exit(irqchip, desc); | ||
198 | } | ||
199 | |||
200 | static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base) | ||
201 | { | ||
202 | struct irq_chip_type *ct; | ||
203 | |||
204 | chip->irq_gc = irq_alloc_generic_chip("gpio-pl061", 1, irq_base, | ||
205 | chip->base, handle_simple_irq); | ||
206 | chip->irq_gc->private = chip; | ||
207 | |||
208 | ct = chip->irq_gc->chip_types; | ||
209 | ct->chip.irq_mask = irq_gc_mask_clr_bit; | ||
210 | ct->chip.irq_unmask = irq_gc_mask_set_bit; | ||
211 | ct->chip.irq_set_type = pl061_irq_type; | ||
212 | ct->chip.irq_set_wake = irq_gc_set_wake; | ||
213 | ct->regs.mask = GPIOIE; | ||
214 | |||
215 | irq_setup_generic_chip(chip->irq_gc, IRQ_MSK(PL061_GPIO_NR), | ||
216 | IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); | ||
231 | } | 217 | } |
232 | 218 | ||
233 | static int pl061_probe(struct amba_device *dev, const struct amba_id *id) | 219 | static int pl061_probe(struct amba_device *dev, const struct amba_id *id) |
234 | { | 220 | { |
235 | struct pl061_platform_data *pdata; | 221 | struct pl061_platform_data *pdata; |
236 | struct pl061_gpio *chip; | 222 | struct pl061_gpio *chip; |
237 | struct list_head *chip_list; | ||
238 | int ret, irq, i; | 223 | int ret, irq, i; |
239 | static DECLARE_BITMAP(init_irq, NR_IRQS); | ||
240 | 224 | ||
241 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 225 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
242 | if (chip == NULL) | 226 | if (chip == NULL) |
@@ -248,7 +232,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) | |||
248 | chip->irq_base = pdata->irq_base; | 232 | chip->irq_base = pdata->irq_base; |
249 | } else if (dev->dev.of_node) { | 233 | } else if (dev->dev.of_node) { |
250 | chip->gc.base = -1; | 234 | chip->gc.base = -1; |
251 | chip->irq_base = NO_IRQ; | 235 | chip->irq_base = 0; |
252 | } else { | 236 | } else { |
253 | ret = -ENODEV; | 237 | ret = -ENODEV; |
254 | goto free_mem; | 238 | goto free_mem; |
@@ -267,8 +251,6 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) | |||
267 | } | 251 | } |
268 | 252 | ||
269 | spin_lock_init(&chip->lock); | 253 | spin_lock_init(&chip->lock); |
270 | spin_lock_init(&chip->irq_lock); | ||
271 | INIT_LIST_HEAD(&chip->list); | ||
272 | 254 | ||
273 | chip->gc.direction_input = pl061_direction_input; | 255 | chip->gc.direction_input = pl061_direction_input; |
274 | chip->gc.direction_output = pl061_direction_output; | 256 | chip->gc.direction_output = pl061_direction_output; |
@@ -288,9 +270,11 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) | |||
288 | * irq_chip support | 270 | * irq_chip support |
289 | */ | 271 | */ |
290 | 272 | ||
291 | if (chip->irq_base == NO_IRQ) | 273 | if (chip->irq_base <= 0) |
292 | return 0; | 274 | return 0; |
293 | 275 | ||
276 | pl061_init_gc(chip, chip->irq_base); | ||
277 | |||
294 | writeb(0, chip->base + GPIOIE); /* disable irqs */ | 278 | writeb(0, chip->base + GPIOIE); /* disable irqs */ |
295 | irq = dev->irq[0]; | 279 | irq = dev->irq[0]; |
296 | if (irq < 0) { | 280 | if (irq < 0) { |
@@ -298,18 +282,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) | |||
298 | goto iounmap; | 282 | goto iounmap; |
299 | } | 283 | } |
300 | irq_set_chained_handler(irq, pl061_irq_handler); | 284 | irq_set_chained_handler(irq, pl061_irq_handler); |
301 | if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */ | 285 | irq_set_handler_data(irq, chip); |
302 | chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL); | ||
303 | if (chip_list == NULL) { | ||
304 | clear_bit(irq, init_irq); | ||
305 | ret = -ENOMEM; | ||
306 | goto iounmap; | ||
307 | } | ||
308 | INIT_LIST_HEAD(chip_list); | ||
309 | irq_set_handler_data(irq, chip_list); | ||
310 | } else | ||
311 | chip_list = irq_get_handler_data(irq); | ||
312 | list_add(&chip->list, chip_list); | ||
313 | 286 | ||
314 | for (i = 0; i < PL061_GPIO_NR; i++) { | 287 | for (i = 0; i < PL061_GPIO_NR; i++) { |
315 | if (pdata) { | 288 | if (pdata) { |
@@ -319,13 +292,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) | |||
319 | else | 292 | else |
320 | pl061_direction_input(&chip->gc, i); | 293 | pl061_direction_input(&chip->gc, i); |
321 | } | 294 | } |
322 | |||
323 | irq_set_chip_and_handler(i + chip->irq_base, &pl061_irqchip, | ||
324 | handle_simple_irq); | ||
325 | set_irq_flags(i+chip->irq_base, IRQF_VALID); | ||
326 | irq_set_chip_data(i + chip->irq_base, chip); | ||
327 | } | 295 | } |
328 | 296 | ||
297 | amba_set_drvdata(dev, chip); | ||
298 | |||
329 | return 0; | 299 | return 0; |
330 | 300 | ||
331 | iounmap: | 301 | iounmap: |
@@ -338,6 +308,53 @@ free_mem: | |||
338 | return ret; | 308 | return ret; |
339 | } | 309 | } |
340 | 310 | ||
311 | #ifdef CONFIG_PM | ||
312 | static int pl061_suspend(struct device *dev) | ||
313 | { | ||
314 | struct pl061_gpio *chip = dev_get_drvdata(dev); | ||
315 | int offset; | ||
316 | |||
317 | chip->csave_regs.gpio_data = 0; | ||
318 | chip->csave_regs.gpio_dir = readb(chip->base + GPIODIR); | ||
319 | chip->csave_regs.gpio_is = readb(chip->base + GPIOIS); | ||
320 | chip->csave_regs.gpio_ibe = readb(chip->base + GPIOIBE); | ||
321 | chip->csave_regs.gpio_iev = readb(chip->base + GPIOIEV); | ||
322 | chip->csave_regs.gpio_ie = readb(chip->base + GPIOIE); | ||
323 | |||
324 | for (offset = 0; offset < PL061_GPIO_NR; offset++) { | ||
325 | if (chip->csave_regs.gpio_dir & (1 << offset)) | ||
326 | chip->csave_regs.gpio_data |= | ||
327 | pl061_get_value(&chip->gc, offset) << offset; | ||
328 | } | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int pl061_resume(struct device *dev) | ||
334 | { | ||
335 | struct pl061_gpio *chip = dev_get_drvdata(dev); | ||
336 | int offset; | ||
337 | |||
338 | for (offset = 0; offset < PL061_GPIO_NR; offset++) { | ||
339 | if (chip->csave_regs.gpio_dir & (1 << offset)) | ||
340 | pl061_direction_output(&chip->gc, offset, | ||
341 | chip->csave_regs.gpio_data & | ||
342 | (1 << offset)); | ||
343 | else | ||
344 | pl061_direction_input(&chip->gc, offset); | ||
345 | } | ||
346 | |||
347 | writeb(chip->csave_regs.gpio_is, chip->base + GPIOIS); | ||
348 | writeb(chip->csave_regs.gpio_ibe, chip->base + GPIOIBE); | ||
349 | writeb(chip->csave_regs.gpio_iev, chip->base + GPIOIEV); | ||
350 | writeb(chip->csave_regs.gpio_ie, chip->base + GPIOIE); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume); | ||
356 | #endif | ||
357 | |||
341 | static struct amba_id pl061_ids[] = { | 358 | static struct amba_id pl061_ids[] = { |
342 | { | 359 | { |
343 | .id = 0x00041061, | 360 | .id = 0x00041061, |
@@ -351,6 +368,9 @@ MODULE_DEVICE_TABLE(amba, pl061_ids); | |||
351 | static struct amba_driver pl061_gpio_driver = { | 368 | static struct amba_driver pl061_gpio_driver = { |
352 | .drv = { | 369 | .drv = { |
353 | .name = "pl061_gpio", | 370 | .name = "pl061_gpio", |
371 | #ifdef CONFIG_PM | ||
372 | .pm = &pl061_dev_pm_ops, | ||
373 | #endif | ||
354 | }, | 374 | }, |
355 | .id_table = pl061_ids, | 375 | .id_table = pl061_ids, |
356 | .probe = pl061_probe, | 376 | .probe = pl061_probe, |
diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index b6c1f6d80649..7eecf69362ee 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c | |||
@@ -47,12 +47,18 @@ static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int | |||
47 | return 0; | 47 | return 0; |
48 | } | 48 | } |
49 | 49 | ||
50 | static int sa1100_to_irq(struct gpio_chip *chip, unsigned offset) | ||
51 | { | ||
52 | return offset < 11 ? (IRQ_GPIO0 + offset) : (IRQ_GPIO11 - 11 + offset); | ||
53 | } | ||
54 | |||
50 | static struct gpio_chip sa1100_gpio_chip = { | 55 | static struct gpio_chip sa1100_gpio_chip = { |
51 | .label = "gpio", | 56 | .label = "gpio", |
52 | .direction_input = sa1100_direction_input, | 57 | .direction_input = sa1100_direction_input, |
53 | .direction_output = sa1100_direction_output, | 58 | .direction_output = sa1100_direction_output, |
54 | .set = sa1100_gpio_set, | 59 | .set = sa1100_gpio_set, |
55 | .get = sa1100_gpio_get, | 60 | .get = sa1100_gpio_get, |
61 | .to_irq = sa1100_to_irq, | ||
56 | .base = 0, | 62 | .base = 0, |
57 | .ngpio = GPIO_MAX + 1, | 63 | .ngpio = GPIO_MAX + 1, |
58 | }; | 64 | }; |
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 61044c889f7f..bdc293791590 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c | |||
@@ -361,14 +361,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) | |||
361 | return -ENODEV; | 361 | return -ENODEV; |
362 | } | 362 | } |
363 | 363 | ||
364 | if (!devm_request_mem_region(&pdev->dev, res->start, | 364 | regs = devm_request_and_ioremap(&pdev->dev, res); |
365 | resource_size(res), | ||
366 | dev_name(&pdev->dev))) { | ||
367 | dev_err(&pdev->dev, "Couldn't request MEM resource\n"); | ||
368 | return -ENODEV; | ||
369 | } | ||
370 | |||
371 | regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); | ||
372 | if (!regs) { | 365 | if (!regs) { |
373 | dev_err(&pdev->dev, "Couldn't ioremap regs\n"); | 366 | dev_err(&pdev->dev, "Couldn't ioremap regs\n"); |
374 | return -ENODEV; | 367 | return -ENODEV; |
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index d466c8d8826d..1ff4e221cb4d 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h | |||
@@ -177,6 +177,10 @@ extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *labe | |||
177 | extern int gpio_request_array(const struct gpio *array, size_t num); | 177 | extern int gpio_request_array(const struct gpio *array, size_t num); |
178 | extern void gpio_free_array(const struct gpio *array, size_t num); | 178 | extern void gpio_free_array(const struct gpio *array, size_t num); |
179 | 179 | ||
180 | /* bindings for managed devices that want to request gpios */ | ||
181 | int devm_gpio_request(struct device *dev, unsigned gpio, const char *label); | ||
182 | void devm_gpio_free(struct device *dev, unsigned int gpio); | ||
183 | |||
180 | #ifdef CONFIG_GPIO_SYSFS | 184 | #ifdef CONFIG_GPIO_SYSFS |
181 | 185 | ||
182 | /* | 186 | /* |
diff --git a/include/linux/amba/pl061.h b/include/linux/amba/pl061.h index 2412af944f1f..fb83c0453489 100644 --- a/include/linux/amba/pl061.h +++ b/include/linux/amba/pl061.h | |||
@@ -7,7 +7,7 @@ struct pl061_platform_data { | |||
7 | unsigned gpio_base; | 7 | unsigned gpio_base; |
8 | 8 | ||
9 | /* number of the first IRQ. | 9 | /* number of the first IRQ. |
10 | * If the IRQ functionality in not desired this must be set to NO_IRQ. | 10 | * If the IRQ functionality in not desired this must be set to 0. |
11 | */ | 11 | */ |
12 | unsigned irq_base; | 12 | unsigned irq_base; |
13 | 13 | ||