diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-30 17:20:32 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-30 17:20:32 -0800 |
commit | cdfc83075fb76369a31e6c187d0cebcab9f8b9c8 (patch) | |
tree | 33d1cdca3e2cb610451ed30943189f55652bac4c /drivers/bcma | |
parent | 04a24ae45d018e177db7e4ae2d03a70f79149782 (diff) | |
parent | b26a21c1eacdb7daf22a304fa857413df2650cfe (diff) | |
download | linux-stable-cdfc83075fb76369a31e6c187d0cebcab9f8b9c8.tar.gz linux-stable-cdfc83075fb76369a31e6c187d0cebcab9f8b9c8.tar.bz2 linux-stable-cdfc83075fb76369a31e6c187d0cebcab9f8b9c8.zip |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle:
"The most notable new addition inside this pull request is the support
for MIPS's latest and greatest core called "inter/proAptiv". The
patch series describes this core as follows.
"The interAptiv is a power-efficient multi-core microprocessor
for use in system-on-chip (SoC) applications. The interAptiv combines
a multi-threading pipeline with a coherence manager to deliver improved
computational throughput and power efficiency. The interAptiv can
contain one to four MIPS32R3 interAptiv cores, system level
coherence manager with L2 cache, optional coherent I/O port,
and optional floating point unit."
The platform specific patches touch all 3 Broadcom families. It adds
support for the new Broadcom/Netlogix XLP9xx Soc, building a common
BCM63XX SMP kernel for all BCM63XX SoCs regardless of core type/count
and full gpio button/led descriptions for BCM47xx.
The rest of the series are cleanups and bug fixes that are MIPS
generic and consist largely of changes that Imgtec/MIPS had published
in their linux-mti-3.10.git stable tree. Random other cleanups and
patches preparing code to be merged in 3.15"
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (139 commits)
mips: select ARCH_MIGHT_HAVE_PC_SERIO
mips: delete non-required instances of include <linux/init.h>
MIPS: KVM: remove shadow_tlb code
MIPS: KVM: use common EHINV aware UNIQUE_ENTRYHI
mips/ide: flush dcache also if icache does not snoop dcache
MIPS: BCM47XX: fix position of cpu_wait disabling
MIPS: BCM63XX: select correct MIPS_L1_CACHE_SHIFT value
MIPS: update MIPS_L1_CACHE_SHIFT based on MIPS_L1_CACHE_SHIFT_<N>
MIPS: introduce MIPS_L1_CACHE_SHIFT_<N>
MIPS: ZBOOT: gather string functions into string.c
arch/mips/pci: don't check resource with devm_ioremap_resource
arch/mips/lantiq/xway: don't check resource with devm_ioremap_resource
bcma: gpio: don't cast u32 to unsigned long
ssb: gpio: add own IRQ domain
MIPS: BCM47XX: fix sparse warnings in board.c
MIPS: BCM47XX: add board detection for Linksys WRT54GS V1
MIPS: BCM47XX: fix detection for some boards
MIPS: BCM47XX: Enable buttons support on SSB
MIPS: BCM47XX: Convert WNDR4500 to new syntax
MIPS: BCM47XX: Use "timer" trigger for status LEDs
...
Diffstat (limited to 'drivers/bcma')
-rw-r--r-- | drivers/bcma/Kconfig | 1 | ||||
-rw-r--r-- | drivers/bcma/driver_gpio.c | 137 |
2 files changed, 136 insertions, 2 deletions
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index 7c081b38ef3e..0ee48be23837 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -75,6 +75,7 @@ config BCMA_DRIVER_GMAC_CMN config BCMA_DRIVER_GPIO bool "BCMA GPIO driver" depends on BCMA && GPIOLIB + select IRQ_DOMAIN if BCMA_HOST_SOC help Driver to provide access to the GPIO pins of the bcma bus. diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c index 45f0996a3752..25f9887a35d0 100644 --- a/drivers/bcma/driver_gpio.c +++ b/drivers/bcma/driver_gpio.c @@ -9,6 +9,9 @@ */ #include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/irqdomain.h> #include <linux/export.h> #include <linux/bcma/bcma.h> @@ -73,19 +76,136 @@ static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio) bcma_chipco_gpio_pullup(cc, 1 << gpio, 0); } +#if IS_BUILTIN(CONFIG_BCMA_HOST_SOC) static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) { struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip); if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) - return bcma_core_irq(cc->core); + return irq_find_mapping(cc->irq_domain, gpio); else return -EINVAL; } +static void bcma_gpio_irq_unmask(struct irq_data *d) +{ + struct bcma_drv_cc *cc = irq_data_get_irq_chip_data(d); + int gpio = irqd_to_hwirq(d); + u32 val = bcma_chipco_gpio_in(cc, BIT(gpio)); + + bcma_chipco_gpio_polarity(cc, BIT(gpio), val); + bcma_chipco_gpio_intmask(cc, BIT(gpio), BIT(gpio)); +} + +static void bcma_gpio_irq_mask(struct irq_data *d) +{ + struct bcma_drv_cc *cc = irq_data_get_irq_chip_data(d); + int gpio = irqd_to_hwirq(d); + + bcma_chipco_gpio_intmask(cc, BIT(gpio), 0); +} + +static struct irq_chip bcma_gpio_irq_chip = { + .name = "BCMA-GPIO", + .irq_mask = bcma_gpio_irq_mask, + .irq_unmask = bcma_gpio_irq_unmask, +}; + +static irqreturn_t bcma_gpio_irq_handler(int irq, void *dev_id) +{ + struct bcma_drv_cc *cc = dev_id; + u32 val = bcma_cc_read32(cc, BCMA_CC_GPIOIN); + u32 mask = bcma_cc_read32(cc, BCMA_CC_GPIOIRQ); + u32 pol = bcma_cc_read32(cc, BCMA_CC_GPIOPOL); + unsigned long irqs = (val ^ pol) & mask; + int gpio; + + if (!irqs) + return IRQ_NONE; + + for_each_set_bit(gpio, &irqs, cc->gpio.ngpio) + generic_handle_irq(bcma_gpio_to_irq(&cc->gpio, gpio)); + bcma_chipco_gpio_polarity(cc, irqs, val & irqs); + + return IRQ_HANDLED; +} + +static int bcma_gpio_irq_domain_init(struct bcma_drv_cc *cc) +{ + struct gpio_chip *chip = &cc->gpio; + int gpio, hwirq, err; + + if (cc->core->bus->hosttype != BCMA_HOSTTYPE_SOC) + return 0; + + cc->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, + &irq_domain_simple_ops, cc); + if (!cc->irq_domain) { + err = -ENODEV; + goto err_irq_domain; + } + for (gpio = 0; gpio < chip->ngpio; gpio++) { + int irq = irq_create_mapping(cc->irq_domain, gpio); + + irq_set_chip_data(irq, cc); + irq_set_chip_and_handler(irq, &bcma_gpio_irq_chip, + handle_simple_irq); + } + + hwirq = bcma_core_irq(cc->core); + err = request_irq(hwirq, bcma_gpio_irq_handler, IRQF_SHARED, "gpio", + cc); + if (err) + goto err_req_irq; + + bcma_chipco_gpio_intmask(cc, ~0, 0); + bcma_cc_set32(cc, BCMA_CC_IRQMASK, BCMA_CC_IRQ_GPIO); + + return 0; + +err_req_irq: + for (gpio = 0; gpio < chip->ngpio; gpio++) { + int irq = irq_find_mapping(cc->irq_domain, gpio); + + irq_dispose_mapping(irq); + } + irq_domain_remove(cc->irq_domain); +err_irq_domain: + return err; +} + +static void bcma_gpio_irq_domain_exit(struct bcma_drv_cc *cc) +{ + struct gpio_chip *chip = &cc->gpio; + int gpio; + + if (cc->core->bus->hosttype != BCMA_HOSTTYPE_SOC) + return; + + bcma_cc_mask32(cc, BCMA_CC_IRQMASK, ~BCMA_CC_IRQ_GPIO); + free_irq(bcma_core_irq(cc->core), cc); + for (gpio = 0; gpio < chip->ngpio; gpio++) { + int irq = irq_find_mapping(cc->irq_domain, gpio); + + irq_dispose_mapping(irq); + } + irq_domain_remove(cc->irq_domain); +} +#else +static int bcma_gpio_irq_domain_init(struct bcma_drv_cc *cc) +{ + return 0; +} + +static void bcma_gpio_irq_domain_exit(struct bcma_drv_cc *cc) +{ +} +#endif + int bcma_gpio_init(struct bcma_drv_cc *cc) { struct gpio_chip *chip = &cc->gpio; + int err; chip->label = "bcma_gpio"; chip->owner = THIS_MODULE; @@ -95,7 +215,9 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) chip->set = bcma_gpio_set_value; chip->direction_input = bcma_gpio_direction_input; chip->direction_output = bcma_gpio_direction_output; +#if IS_BUILTIN(CONFIG_BCMA_HOST_SOC) chip->to_irq = bcma_gpio_to_irq; +#endif chip->ngpio = 16; /* There is just one SoC in one device and its GPIO addresses should be * deterministic to address them more easily. The other buses could get @@ -105,10 +227,21 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) else chip->base = -1; - return gpiochip_add(chip); + err = bcma_gpio_irq_domain_init(cc); + if (err) + return err; + + err = gpiochip_add(chip); + if (err) { + bcma_gpio_irq_domain_exit(cc); + return err; + } + + return 0; } int bcma_gpio_unregister(struct bcma_drv_cc *cc) { + bcma_gpio_irq_domain_exit(cc); return gpiochip_remove(&cc->gpio); } |