diff options
Diffstat (limited to 'target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch')
-rw-r--r-- | target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch | 490 |
1 files changed, 490 insertions, 0 deletions
diff --git a/target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch b/target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch new file mode 100644 index 0000000000..4aa2e46d77 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch @@ -0,0 +1,490 @@ +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -92,6 +92,7 @@ config ATH79 + + config BCM47XX + bool "Broadcom BCM47XX based boards" ++ select ARCH_REQUIRE_GPIOLIB + select BOOT_RAW + select CEVT_R4K + select CSRC_R4K +@@ -100,7 +101,6 @@ config BCM47XX + select IRQ_CPU + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN +- select GENERIC_GPIO + select CFE + help + Support for BCM47XX based boards +--- a/arch/mips/bcm47xx/gpio.c ++++ b/arch/mips/bcm47xx/gpio.c +@@ -4,81 +4,198 @@ + * for more details. + * + * Copyright (C) 2007 Aurelien Jarno <aurelien@aurel32.net> ++ * Copyright (C) 2012 Hauke Mehrtens <hauke@hauke-m.de> ++ * ++ * Parts of this file are based on Atheros AR71XX/AR724X/AR913X GPIO + */ + + #include <linux/export.h> ++#include <linux/gpio.h> + #include <linux/ssb/ssb.h> +-#include <linux/ssb/ssb_driver_chipcommon.h> +-#include <linux/ssb/ssb_driver_extif.h> +-#include <asm/mach-bcm47xx/bcm47xx.h> +-#include <asm/mach-bcm47xx/gpio.h> ++#include <linux/ssb/ssb_embedded.h> ++#include <linux/bcma/bcma.h> ++#include <linux/bcma/bcma_driver_gpio.h> ++ ++#include <bcm47xx.h> + +-#if (BCM47XX_CHIPCO_GPIO_LINES > BCM47XX_EXTIF_GPIO_LINES) +-static DECLARE_BITMAP(gpio_in_use, BCM47XX_CHIPCO_GPIO_LINES); +-#else +-static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES); +-#endif + +-int gpio_request(unsigned gpio, const char *tag) ++static unsigned long bcm47xx_gpio_count; ++ ++/* low level BCM47xx gpio api */ ++u32 bcm47xx_gpio_in(u32 mask) + { + switch (bcm47xx_bus_type) { + #ifdef CONFIG_BCM47XX_SSB + case BCM47XX_BUS_TYPE_SSB: +- if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) && +- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES)) +- return -EINVAL; +- +- if (ssb_extif_available(&bcm47xx_bus.ssb.extif) && +- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES)) +- return -EINVAL; ++ return ssb_gpio_in(&bcm47xx_bus.ssb, mask); ++#endif ++#ifdef CONFIG_BCM47XX_BCMA ++ case BCM47XX_BUS_TYPE_BCMA: ++ return bcma_gpio_in(&bcm47xx_bus.bcma.bus, mask); ++#endif ++ } ++ return -EINVAL; ++} ++EXPORT_SYMBOL(bcm47xx_gpio_in); + +- if (test_and_set_bit(gpio, gpio_in_use)) +- return -EBUSY; ++u32 bcm47xx_gpio_out(u32 mask, u32 value) ++{ ++ switch (bcm47xx_bus_type) { ++#ifdef CONFIG_BCM47XX_SSB ++ case BCM47XX_BUS_TYPE_SSB: ++ return ssb_gpio_out(&bcm47xx_bus.ssb, mask, value); ++#endif ++#ifdef CONFIG_BCM47XX_BCMA ++ case BCM47XX_BUS_TYPE_BCMA: ++ return bcma_gpio_out(&bcm47xx_bus.bcma.bus, mask, value); ++#endif ++ } ++ return -EINVAL; ++} ++EXPORT_SYMBOL(bcm47xx_gpio_out); + +- return 0; ++u32 bcm47xx_gpio_outen(u32 mask, u32 value) ++{ ++ switch (bcm47xx_bus_type) { ++#ifdef CONFIG_BCM47XX_SSB ++ case BCM47XX_BUS_TYPE_SSB: ++ return ssb_gpio_outen(&bcm47xx_bus.ssb, mask, value); + #endif + #ifdef CONFIG_BCM47XX_BCMA + case BCM47XX_BUS_TYPE_BCMA: +- if (gpio >= BCM47XX_CHIPCO_GPIO_LINES) +- return -EINVAL; ++ return bcma_gpio_outen(&bcm47xx_bus.bcma.bus, mask, value); ++#endif ++ } ++ return -EINVAL; ++} ++EXPORT_SYMBOL(bcm47xx_gpio_outen); + +- if (test_and_set_bit(gpio, gpio_in_use)) +- return -EBUSY; ++u32 bcm47xx_gpio_control(u32 mask, u32 value) ++{ ++ switch (bcm47xx_bus_type) { ++#ifdef CONFIG_BCM47XX_SSB ++ case BCM47XX_BUS_TYPE_SSB: ++ return ssb_gpio_control(&bcm47xx_bus.ssb, mask, value); ++#endif ++#ifdef CONFIG_BCM47XX_BCMA ++ case BCM47XX_BUS_TYPE_BCMA: ++ return bcma_gpio_control(&bcm47xx_bus.bcma.bus, mask, value); ++#endif ++ } ++ return -EINVAL; ++} ++EXPORT_SYMBOL(bcm47xx_gpio_control); + +- return 0; ++u32 bcm47xx_gpio_intmask(u32 mask, u32 value) ++{ ++ switch (bcm47xx_bus_type) { ++#ifdef CONFIG_BCM47XX_SSB ++ case BCM47XX_BUS_TYPE_SSB: ++ return ssb_gpio_intmask(&bcm47xx_bus.ssb, mask, value); ++#endif ++#ifdef CONFIG_BCM47XX_BCMA ++ case BCM47XX_BUS_TYPE_BCMA: ++ return bcma_gpio_intmask(&bcm47xx_bus.bcma.bus, mask, value); + #endif + } + return -EINVAL; + } +-EXPORT_SYMBOL(gpio_request); ++EXPORT_SYMBOL(bcm47xx_gpio_intmask); + +-void gpio_free(unsigned gpio) ++u32 bcm47xx_gpio_polarity(u32 mask, u32 value) + { + switch (bcm47xx_bus_type) { + #ifdef CONFIG_BCM47XX_SSB + case BCM47XX_BUS_TYPE_SSB: +- if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) && +- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES)) +- return; ++ return ssb_gpio_polarity(&bcm47xx_bus.ssb, mask, value); ++#endif ++#ifdef CONFIG_BCM47XX_BCMA ++ case BCM47XX_BUS_TYPE_BCMA: ++ return bcma_gpio_polarity(&bcm47xx_bus.bcma.bus, mask, value); ++#endif ++ } ++ return -EINVAL; ++} ++EXPORT_SYMBOL(bcm47xx_gpio_polarity); ++ ++ ++ ++static int bcm47xx_gpio_get_value(struct gpio_chip *chip, unsigned gpio) ++{ ++ return bcm47xx_gpio_in(1 << gpio); ++} ++ ++static void bcm47xx_gpio_set_value(struct gpio_chip *chip, ++ unsigned gpio, int value) ++{ ++ bcm47xx_gpio_out(1 << gpio, value ? 1 << gpio : 0); ++} ++ ++static int bcm47xx_gpio_direction_input(struct gpio_chip *chip, ++ unsigned gpio) ++{ ++ bcm47xx_gpio_outen(1 << gpio, 0); ++ return 0; ++} ++ ++static int bcm47xx_gpio_direction_output(struct gpio_chip *chip, ++ unsigned gpio, int value) ++{ ++ /* first set the gpio out value */ ++ bcm47xx_gpio_out(1 << gpio, value ? 1 << gpio : 0); ++ /* then set the gpio mode */ ++ bcm47xx_gpio_outen(1 << gpio, 1 << gpio); ++ return 0; ++} ++ ++static struct gpio_chip bcm47xx_gpio_chip = { ++ .label = "bcm47xx", ++ .get = bcm47xx_gpio_get_value, ++ .set = bcm47xx_gpio_set_value, ++ .direction_input = bcm47xx_gpio_direction_input, ++ .direction_output = bcm47xx_gpio_direction_output, ++ .base = 0, ++}; + +- if (ssb_extif_available(&bcm47xx_bus.ssb.extif) && +- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES)) +- return; ++void __init bcm47xx_gpio_init(void) ++{ ++ int err; + +- clear_bit(gpio, gpio_in_use); +- return; ++ switch (bcm47xx_bus_type) { ++#ifdef CONFIG_BCM47XX_SSB ++ case BCM47XX_BUS_TYPE_SSB: ++ bcm47xx_gpio_count = ssb_gpio_count(&bcm47xx_bus.ssb); + #endif + #ifdef CONFIG_BCM47XX_BCMA + case BCM47XX_BUS_TYPE_BCMA: +- if (gpio >= BCM47XX_CHIPCO_GPIO_LINES) +- return; +- +- clear_bit(gpio, gpio_in_use); +- return; ++ bcm47xx_gpio_count = bcma_gpio_count(&bcm47xx_bus.bcma.bus); + #endif + } ++ ++ bcm47xx_gpio_chip.ngpio = bcm47xx_gpio_count; ++ ++ err = gpiochip_add(&bcm47xx_gpio_chip); ++ if (err) ++ panic("cannot add BCM47xx GPIO chip, error=%d", err); + } +-EXPORT_SYMBOL(gpio_free); ++ ++int gpio_get_value(unsigned gpio) ++{ ++ if (gpio < bcm47xx_gpio_count) ++ return bcm47xx_gpio_in(1 << gpio); ++ ++ return __gpio_get_value(gpio); ++} ++EXPORT_SYMBOL(gpio_get_value); ++ ++void gpio_set_value(unsigned gpio, int value) ++{ ++ if (gpio < bcm47xx_gpio_count) ++ bcm47xx_gpio_out(1 << gpio, value ? 1 << gpio : 0); ++ else ++ __gpio_set_value(gpio, value); ++} ++EXPORT_SYMBOL(gpio_set_value); + + int gpio_to_irq(unsigned gpio) + { +@@ -99,4 +216,11 @@ int gpio_to_irq(unsigned gpio) + } + return -EINVAL; + } +-EXPORT_SYMBOL_GPL(gpio_to_irq); ++EXPORT_SYMBOL(gpio_to_irq); ++ ++int irq_to_gpio(unsigned irq) ++{ ++ /* FIXME */ ++ return -EINVAL; ++} ++EXPORT_SYMBOL(irq_to_gpio); +--- a/arch/mips/bcm47xx/setup.c ++++ b/arch/mips/bcm47xx/setup.c +@@ -344,6 +344,8 @@ void __init plat_mem_setup(void) + _machine_restart = bcm47xx_machine_restart; + _machine_halt = bcm47xx_machine_halt; + pm_power_off = bcm47xx_machine_halt; ++ ++ bcm47xx_gpio_init(); + } + + static int __init bcm47xx_register_bus_complete(void) +--- a/arch/mips/bcm47xx/wgt634u.c ++++ b/arch/mips/bcm47xx/wgt634u.c +@@ -133,6 +133,7 @@ static int __init wgt634u_init(void) + * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx. + */ + u8 *et0mac; ++ int err; + + if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB) + return -ENODEV; +@@ -146,6 +147,12 @@ static int __init wgt634u_init(void) + + printk(KERN_INFO "WGT634U machine detected.\n"); + ++ err = gpio_request(WGT634U_GPIO_RESET, "reset-buton"); ++ if (err) { ++ printk(KERN_INFO "Can not register gpio fir reset button\n"); ++ return 0; ++ } ++ + if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET), + gpio_interrupt, IRQF_SHARED, + "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) { +--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h ++++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h +@@ -56,4 +56,6 @@ void bcm47xx_fill_bcma_boardinfo(struct + const char *prefix); + #endif + ++void bcm47xx_gpio_init(void); ++ + #endif /* __ASM_BCM47XX_H */ +--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h ++++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h +@@ -4,152 +4,39 @@ + * for more details. + * + * Copyright (C) 2007 Aurelien Jarno <aurelien@aurel32.net> ++ * Copyright (C) 2012 Hauke Mehrtens <hauke@hauke-m.de> + */ + + #ifndef __BCM47XX_GPIO_H + #define __BCM47XX_GPIO_H + +-#include <linux/ssb/ssb_embedded.h> +-#include <linux/bcma/bcma.h> +-#include <asm/mach-bcm47xx/bcm47xx.h> +- +-#define BCM47XX_EXTIF_GPIO_LINES 5 +-#define BCM47XX_CHIPCO_GPIO_LINES 16 +- +-extern int gpio_request(unsigned gpio, const char *label); +-extern void gpio_free(unsigned gpio); +-extern int gpio_to_irq(unsigned gpio); ++#define ARCH_NR_GPIOS 64 ++#include <asm-generic/gpio.h> + +-static inline int gpio_get_value(unsigned gpio) +-{ +- switch (bcm47xx_bus_type) { +-#ifdef CONFIG_BCM47XX_SSB +- case BCM47XX_BUS_TYPE_SSB: +- return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio); +-#endif +-#ifdef CONFIG_BCM47XX_BCMA +- case BCM47XX_BUS_TYPE_BCMA: +- return bcma_chipco_gpio_in(&bcm47xx_bus.bcma.bus.drv_cc, +- 1 << gpio); +-#endif +- } +- return -EINVAL; +-} +- +-#define gpio_get_value_cansleep gpio_get_value +- +-static inline void gpio_set_value(unsigned gpio, int value) +-{ +- switch (bcm47xx_bus_type) { +-#ifdef CONFIG_BCM47XX_SSB +- case BCM47XX_BUS_TYPE_SSB: +- ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio, +- value ? 1 << gpio : 0); +- return; +-#endif +-#ifdef CONFIG_BCM47XX_BCMA +- case BCM47XX_BUS_TYPE_BCMA: +- bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio, +- value ? 1 << gpio : 0); +- return; +-#endif +- } +-} +- +-#define gpio_set_value_cansleep gpio_set_value +- +-static inline int gpio_cansleep(unsigned gpio) +-{ +- return 0; +-} ++/* low level BCM47xx gpio api */ ++u32 bcm47xx_gpio_in(u32 mask); ++u32 bcm47xx_gpio_out(u32 mask, u32 value); ++u32 bcm47xx_gpio_outen(u32 mask, u32 value); ++u32 bcm47xx_gpio_control(u32 mask, u32 value); ++u32 bcm47xx_gpio_intmask(u32 mask, u32 value); ++u32 bcm47xx_gpio_polarity(u32 mask, u32 value); + +-static inline int gpio_is_valid(unsigned gpio) +-{ +- return gpio < (BCM47XX_EXTIF_GPIO_LINES + BCM47XX_CHIPCO_GPIO_LINES); +-} ++int gpio_to_irq(unsigned gpio); ++int irq_to_gpio(unsigned irq); ++int gpio_get_value(unsigned gpio); ++void gpio_set_value(unsigned gpio, int value); + +- +-static inline int gpio_direction_input(unsigned gpio) ++static inline void gpio_intmask(unsigned gpio, int value) + { +- switch (bcm47xx_bus_type) { +-#ifdef CONFIG_BCM47XX_SSB +- case BCM47XX_BUS_TYPE_SSB: +- ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0); +- return 0; +-#endif +-#ifdef CONFIG_BCM47XX_BCMA +- case BCM47XX_BUS_TYPE_BCMA: +- bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio, +- 0); +- return 0; +-#endif +- } +- return -EINVAL; ++ bcm47xx_gpio_intmask(1 << gpio, value ? 1 << gpio : 0); + } + +-static inline int gpio_direction_output(unsigned gpio, int value) ++static inline void gpio_polarity(unsigned gpio, int value) + { +- switch (bcm47xx_bus_type) { +-#ifdef CONFIG_BCM47XX_SSB +- case BCM47XX_BUS_TYPE_SSB: +- /* first set the gpio out value */ +- ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio, +- value ? 1 << gpio : 0); +- /* then set the gpio mode */ +- ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio); +- return 0; +-#endif +-#ifdef CONFIG_BCM47XX_BCMA +- case BCM47XX_BUS_TYPE_BCMA: +- /* first set the gpio out value */ +- bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio, +- value ? 1 << gpio : 0); +- /* then set the gpio mode */ +- bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio, +- 1 << gpio); +- return 0; +-#endif +- } +- return -EINVAL; ++ bcm47xx_gpio_polarity(1 << gpio, value ? 1 << gpio : 0); + } + +-static inline int gpio_intmask(unsigned gpio, int value) +-{ +- switch (bcm47xx_bus_type) { +-#ifdef CONFIG_BCM47XX_SSB +- case BCM47XX_BUS_TYPE_SSB: +- ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio, +- value ? 1 << gpio : 0); +- return 0; +-#endif +-#ifdef CONFIG_BCM47XX_BCMA +- case BCM47XX_BUS_TYPE_BCMA: +- bcma_chipco_gpio_intmask(&bcm47xx_bus.bcma.bus.drv_cc, +- 1 << gpio, value ? 1 << gpio : 0); +- return 0; +-#endif +- } +- return -EINVAL; +-} +- +-static inline int gpio_polarity(unsigned gpio, int value) +-{ +- switch (bcm47xx_bus_type) { +-#ifdef CONFIG_BCM47XX_SSB +- case BCM47XX_BUS_TYPE_SSB: +- ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio, +- value ? 1 << gpio : 0); +- return 0; +-#endif +-#ifdef CONFIG_BCM47XX_BCMA +- case BCM47XX_BUS_TYPE_BCMA: +- bcma_chipco_gpio_polarity(&bcm47xx_bus.bcma.bus.drv_cc, +- 1 << gpio, value ? 1 << gpio : 0); +- return 0; +-#endif +- } +- return -EINVAL; +-} + ++#define gpio_cansleep __gpio_cansleep + + #endif /* __BCM47XX_GPIO_H */ |