1 From 37dc57c2400b2998868a5c103756f36b8dc53a17 Mon Sep 17 00:00:00 2001
2 From: Rafa? Mi?ecki <zajec5@gmail.com>
3 Date: Thu, 12 Dec 2013 13:46:03 +0100
4 Subject: [PATCH 088/110] bcma: gpio: add own IRQ domain
6 Input GPIO changes can generate interrupts, but we need kind of ACK for
7 them by changing IRQ polarity. This is required to stop hardware from
8 keep generating interrupts and generate another one on the next GPIO
10 This code allows using GPIOs with standard interrupts and add for
11 example GPIO buttons support.
13 Signed-off-by: Rafa? Mi?ecki <zajec5@gmail.com>
14 Acked-by: Hauke Mehrtens <hauke@hauke-m.de>
15 Acked-by: John Crispin <blogic@openwrt.org>
16 Patchwork: http://patchwork.linux-mips.org/patch/6216/
18 drivers/bcma/Kconfig | 1 +
19 drivers/bcma/driver_gpio.c | 135 ++++++++++++++++++++++++++-
20 include/linux/bcma/bcma_driver_chipcommon.h | 1 +
21 3 files changed, 134 insertions(+), 3 deletions(-)
23 --- a/drivers/bcma/Kconfig
24 +++ b/drivers/bcma/Kconfig
25 @@ -76,6 +76,7 @@ config BCMA_DRIVER_GMAC_CMN
26 config BCMA_DRIVER_GPIO
27 bool "BCMA GPIO driver"
28 depends on BCMA && GPIOLIB
29 + select IRQ_DOMAIN if BCMA_HOST_SOC
31 Driver to provide access to the GPIO pins of the bcma bus.
33 --- a/drivers/bcma/driver_gpio.c
34 +++ b/drivers/bcma/driver_gpio.c
38 #include <linux/gpio.h>
39 +#include <linux/irq.h>
40 +#include <linux/interrupt.h>
41 +#include <linux/irqdomain.h>
42 #include <linux/export.h>
43 #include <linux/bcma/bcma.h>
45 @@ -73,19 +76,133 @@ static void bcma_gpio_free(struct gpio_c
46 bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
49 +#if IS_BUILTIN(CONFIG_BCMA_HOST_SOC)
50 static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
52 struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
54 if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
55 - return bcma_core_irq(cc->core);
56 + return irq_find_mapping(cc->irq_domain, gpio);
61 +static void bcma_gpio_irq_unmask(struct irq_data *d)
63 + struct bcma_drv_cc *cc = irq_data_get_irq_chip_data(d);
64 + int gpio = irqd_to_hwirq(d);
66 + bcma_chipco_gpio_intmask(cc, BIT(gpio), BIT(gpio));
69 +static void bcma_gpio_irq_mask(struct irq_data *d)
71 + struct bcma_drv_cc *cc = irq_data_get_irq_chip_data(d);
72 + int gpio = irqd_to_hwirq(d);
74 + bcma_chipco_gpio_intmask(cc, BIT(gpio), 0);
77 +static struct irq_chip bcma_gpio_irq_chip = {
78 + .name = "BCMA-GPIO",
79 + .irq_mask = bcma_gpio_irq_mask,
80 + .irq_unmask = bcma_gpio_irq_unmask,
83 +static irqreturn_t bcma_gpio_irq_handler(int irq, void *dev_id)
85 + struct bcma_drv_cc *cc = dev_id;
86 + u32 val = bcma_cc_read32(cc, BCMA_CC_GPIOIN);
87 + u32 mask = bcma_cc_read32(cc, BCMA_CC_GPIOIRQ);
88 + u32 pol = bcma_cc_read32(cc, BCMA_CC_GPIOPOL);
89 + u32 irqs = (val ^ pol) & mask;
95 + for_each_set_bit(gpio, (unsigned long *)&irqs, cc->gpio.ngpio)
96 + generic_handle_irq(bcma_gpio_to_irq(&cc->gpio, gpio));
97 + bcma_chipco_gpio_polarity(cc, irqs, val & irqs);
102 +static int bcma_gpio_irq_domain_init(struct bcma_drv_cc *cc)
104 + struct gpio_chip *chip = &cc->gpio;
105 + int gpio, hwirq, err;
107 + if (cc->core->bus->hosttype != BCMA_HOSTTYPE_SOC)
110 + cc->irq_domain = irq_domain_add_linear(NULL, chip->ngpio,
111 + &irq_domain_simple_ops, cc);
112 + if (!cc->irq_domain) {
114 + goto err_irq_domain;
116 + for (gpio = 0; gpio < chip->ngpio; gpio++) {
117 + int irq = irq_create_mapping(cc->irq_domain, gpio);
119 + irq_set_chip_data(irq, cc);
120 + irq_set_chip_and_handler(irq, &bcma_gpio_irq_chip,
121 + handle_simple_irq);
124 + hwirq = bcma_core_irq(cc->core);
125 + err = request_irq(hwirq, bcma_gpio_irq_handler, IRQF_SHARED, "gpio",
130 + bcma_cc_set32(cc, BCMA_CC_IRQMASK, BCMA_CC_IRQ_GPIO);
135 + for (gpio = 0; gpio < chip->ngpio; gpio++) {
136 + int irq = irq_find_mapping(cc->irq_domain, gpio);
138 + irq_dispose_mapping(irq);
140 + irq_domain_remove(cc->irq_domain);
145 +static void bcma_gpio_irq_domain_exit(struct bcma_drv_cc *cc)
147 + struct gpio_chip *chip = &cc->gpio;
150 + if (cc->core->bus->hosttype != BCMA_HOSTTYPE_SOC)
153 + bcma_cc_mask32(cc, BCMA_CC_IRQMASK, ~BCMA_CC_IRQ_GPIO);
154 + free_irq(bcma_core_irq(cc->core), cc);
155 + for (gpio = 0; gpio < chip->ngpio; gpio++) {
156 + int irq = irq_find_mapping(cc->irq_domain, gpio);
158 + irq_dispose_mapping(irq);
160 + irq_domain_remove(cc->irq_domain);
163 +static int bcma_gpio_irq_domain_init(struct bcma_drv_cc *cc)
168 +static void bcma_gpio_irq_domain_exit(struct bcma_drv_cc *cc)
173 int bcma_gpio_init(struct bcma_drv_cc *cc)
175 struct gpio_chip *chip = &cc->gpio;
178 chip->label = "bcma_gpio";
179 chip->owner = THIS_MODULE;
180 @@ -95,7 +212,8 @@ int bcma_gpio_init(struct bcma_drv_cc *c
181 chip->set = bcma_gpio_set_value;
182 chip->direction_input = bcma_gpio_direction_input;
183 chip->direction_output = bcma_gpio_direction_output;
184 - chip->to_irq = bcma_gpio_to_irq;
185 + if (IS_BUILTIN(CONFIG_BCMA_HOST_SOC))
186 + chip->to_irq = bcma_gpio_to_irq;
188 /* There is just one SoC in one device and its GPIO addresses should be
189 * deterministic to address them more easily. The other buses could get
190 @@ -105,10 +223,21 @@ int bcma_gpio_init(struct bcma_drv_cc *c
194 - return gpiochip_add(chip);
195 + err = bcma_gpio_irq_domain_init(cc);
199 + err = gpiochip_add(chip);
201 + bcma_gpio_irq_domain_exit(cc);
208 int bcma_gpio_unregister(struct bcma_drv_cc *cc)
210 + bcma_gpio_irq_domain_exit(cc);
211 return gpiochip_remove(&cc->gpio);
213 --- a/include/linux/bcma/bcma_driver_chipcommon.h
214 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
215 @@ -640,6 +640,7 @@ struct bcma_drv_cc {
216 spinlock_t gpio_lock;
217 #ifdef CONFIG_BCMA_DRIVER_GPIO
218 struct gpio_chip gpio;
219 + struct irq_domain *irq_domain;