diff options
-rw-r--r-- | arch/arm/mach-s5pc100/gpiolib.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-s5pv210/gpiolib.c | 1 | ||||
-rw-r--r-- | arch/arm/plat-s5p/irq-gpioint.c | 68 | ||||
-rw-r--r-- | arch/arm/plat-samsung/include/plat/gpio-cfg.h | 16 |
4 files changed, 76 insertions, 10 deletions
diff --git a/arch/arm/mach-s5pc100/gpiolib.c b/arch/arm/mach-s5pc100/gpiolib.c index 20856eb7dd51..2842394b28b5 100644 --- a/arch/arm/mach-s5pc100/gpiolib.c +++ b/arch/arm/mach-s5pc100/gpiolib.c | |||
@@ -348,6 +348,7 @@ static __init int s5pc100_gpiolib_init(void) | |||
348 | } | 348 | } |
349 | 349 | ||
350 | samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, nr_chips); | 350 | samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, nr_chips); |
351 | s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); | ||
351 | 352 | ||
352 | return 0; | 353 | return 0; |
353 | } | 354 | } |
diff --git a/arch/arm/mach-s5pv210/gpiolib.c b/arch/arm/mach-s5pv210/gpiolib.c index ab673effd767..1ba20a703e05 100644 --- a/arch/arm/mach-s5pv210/gpiolib.c +++ b/arch/arm/mach-s5pv210/gpiolib.c | |||
@@ -281,6 +281,7 @@ static __init int s5pv210_gpiolib_init(void) | |||
281 | } | 281 | } |
282 | 282 | ||
283 | samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips); | 283 | samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips); |
284 | s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); | ||
284 | 285 | ||
285 | return 0; | 286 | return 0; |
286 | } | 287 | } |
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c index 79a7b1c5a57e..cd87d3256e03 100644 --- a/arch/arm/plat-s5p/irq-gpioint.c +++ b/arch/arm/plat-s5p/irq-gpioint.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/irq.h> | 17 | #include <linux/irq.h> |
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/gpio.h> | 19 | #include <linux/gpio.h> |
20 | #include <linux/slab.h> | ||
20 | 21 | ||
21 | #include <mach/map.h> | 22 | #include <mach/map.h> |
22 | #include <plat/gpio-core.h> | 23 | #include <plat/gpio-core.h> |
@@ -29,7 +30,16 @@ | |||
29 | #define PEND_OFFSET 0xA00 | 30 | #define PEND_OFFSET 0xA00 |
30 | #define REG_OFFSET(x) ((x) << 2) | 31 | #define REG_OFFSET(x) ((x) << 2) |
31 | 32 | ||
32 | static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR]; | 33 | struct s5p_gpioint_bank { |
34 | struct list_head list; | ||
35 | int start; | ||
36 | int nr_groups; | ||
37 | int irq; | ||
38 | struct s3c_gpio_chip **chips; | ||
39 | void (*handler)(unsigned int, struct irq_desc *); | ||
40 | }; | ||
41 | |||
42 | LIST_HEAD(banks); | ||
33 | 43 | ||
34 | static int s5p_gpioint_get_offset(struct irq_data *data) | 44 | static int s5p_gpioint_get_offset(struct irq_data *data) |
35 | { | 45 | { |
@@ -139,11 +149,12 @@ static struct irq_chip s5p_gpioint = { | |||
139 | 149 | ||
140 | static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) | 150 | static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) |
141 | { | 151 | { |
152 | struct s5p_gpioint_bank *bank = get_irq_data(irq); | ||
142 | int group, pend_offset, mask_offset; | 153 | int group, pend_offset, mask_offset; |
143 | unsigned int pend, mask; | 154 | unsigned int pend, mask; |
144 | 155 | ||
145 | for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) { | 156 | for (group = 0; group < bank->nr_groups; group++) { |
146 | struct s3c_gpio_chip *chip = irq_chips[group]; | 157 | struct s3c_gpio_chip *chip = bank->chips[group]; |
147 | if (!chip) | 158 | if (!chip) |
148 | continue; | 159 | continue; |
149 | 160 | ||
@@ -168,23 +179,44 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) | |||
168 | static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) | 179 | static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) |
169 | { | 180 | { |
170 | static int used_gpioint_groups = 0; | 181 | static int used_gpioint_groups = 0; |
171 | static bool handler_registered = 0; | ||
172 | int irq, group = chip->group; | 182 | int irq, group = chip->group; |
173 | int i; | 183 | int i; |
184 | struct s5p_gpioint_bank *bank = NULL; | ||
174 | 185 | ||
175 | if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT) | 186 | if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT) |
176 | return -ENOMEM; | 187 | return -ENOMEM; |
177 | 188 | ||
189 | list_for_each_entry(bank, &banks, list) { | ||
190 | if (group >= bank->start && | ||
191 | group < bank->start + bank->nr_groups) | ||
192 | break; | ||
193 | } | ||
194 | if (!bank) | ||
195 | return -EINVAL; | ||
196 | |||
197 | if (!bank->handler) { | ||
198 | bank->chips = kzalloc(sizeof(struct s3c_gpio_chip *) * | ||
199 | bank->nr_groups, GFP_KERNEL); | ||
200 | if (!bank->chips) | ||
201 | return -ENOMEM; | ||
202 | |||
203 | set_irq_chained_handler(bank->irq, s5p_gpioint_handler); | ||
204 | set_irq_data(bank->irq, bank); | ||
205 | bank->handler = s5p_gpioint_handler; | ||
206 | printk(KERN_INFO "Registered chained gpio int handler for interrupt %d.\n", | ||
207 | bank->irq); | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * chained GPIO irq has been sucessfully registered, allocate new gpio | ||
212 | * int group and assign irq nubmers | ||
213 | */ | ||
214 | |||
178 | chip->irq_base = S5P_GPIOINT_BASE + | 215 | chip->irq_base = S5P_GPIOINT_BASE + |
179 | used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE; | 216 | used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE; |
180 | used_gpioint_groups++; | 217 | used_gpioint_groups++; |
181 | 218 | ||
182 | if (!handler_registered) { | 219 | bank->chips[group - bank->start] = chip; |
183 | set_irq_chained_handler(IRQ_GPIOINT, s5p_gpioint_handler); | ||
184 | handler_registered = 1; | ||
185 | } | ||
186 | |||
187 | irq_chips[group] = chip; | ||
188 | for (i = 0; i < chip->chip.ngpio; i++) { | 220 | for (i = 0; i < chip->chip.ngpio; i++) { |
189 | irq = chip->irq_base + i; | 221 | irq = chip->irq_base + i; |
190 | set_irq_chip(irq, &s5p_gpioint); | 222 | set_irq_chip(irq, &s5p_gpioint); |
@@ -221,3 +253,19 @@ int __init s5p_register_gpio_interrupt(int pin) | |||
221 | } | 253 | } |
222 | return ret; | 254 | return ret; |
223 | } | 255 | } |
256 | |||
257 | int __init s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups) | ||
258 | { | ||
259 | struct s5p_gpioint_bank *bank; | ||
260 | |||
261 | bank = kzalloc(sizeof(*bank), GFP_KERNEL); | ||
262 | if (!bank) | ||
263 | return -ENOMEM; | ||
264 | |||
265 | bank->start = start; | ||
266 | bank->nr_groups = nr_groups; | ||
267 | bank->irq = chain_irq; | ||
268 | |||
269 | list_add_tail(&bank->list, &banks); | ||
270 | return 0; | ||
271 | } | ||
diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h index e4b5cf126fa9..5e04fa6eda74 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h | |||
@@ -225,4 +225,20 @@ extern int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr); | |||
225 | */ | 225 | */ |
226 | extern int s5p_register_gpio_interrupt(int pin); | 226 | extern int s5p_register_gpio_interrupt(int pin); |
227 | 227 | ||
228 | /** s5p_register_gpioint_bank() - add gpio bank for further gpio interrupt | ||
229 | * registration (see s5p_register_gpio_interrupt function) | ||
230 | * @chain_irq: chained irq number for the gpio int handler for this bank | ||
231 | * @start: start gpio group number of this bank | ||
232 | * @nr_groups: number of gpio groups handled by this bank | ||
233 | * | ||
234 | * This functions registers initial information about gpio banks that | ||
235 | * can be later used by the s5p_register_gpio_interrupt() function to | ||
236 | * enable support for gpio interrupt for particular gpio group. | ||
237 | */ | ||
238 | #ifdef CONFIG_S5P_GPIO_INT | ||
239 | extern int s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups); | ||
240 | #else | ||
241 | #define s5p_register_gpioint_bank(chain_irq, start, nr_groups) do { } while (0) | ||
242 | #endif | ||
243 | |||
228 | #endif /* __PLAT_GPIO_CFG_H */ | 244 | #endif /* __PLAT_GPIO_CFG_H */ |