--- 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 @@ -101,7 +102,6 @@ config BCM47XX select NO_EXCEPT_FILL 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,83 +4,154 @@ * for more details. * * Copyright (C) 2007 Aurelien Jarno + * Copyright (C) 2012 Hauke Mehrtens + * + * Parts of this file are based on Atheros AR71XX/AR724X/AR913X GPIO */ #include +#include #include -#include -#include -#include -#include +#include +#include + +#include -#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; - - if (test_and_set_bit(gpio, gpio_in_use)) - return -EBUSY; - - return 0; + return ssb_gpio_in(&bcm47xx_bus.ssb, mask); #endif #ifdef CONFIG_BCM47XX_BCMA case BCM47XX_BUS_TYPE_BCMA: - if (gpio >= BCM47XX_CHIPCO_GPIO_LINES) - return -EINVAL; - - if (test_and_set_bit(gpio, gpio_in_use)) - return -EBUSY; + return bcma_chipco_gpio_in(&bcm47xx_bus.bcma.bus.drv_cc, mask); +#endif + } + return -EINVAL; +} +EXPORT_SYMBOL(bcm47xx_gpio_in); - return 0; +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_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, mask, + value); #endif } return -EINVAL; } -EXPORT_SYMBOL(gpio_request); +EXPORT_SYMBOL(bcm47xx_gpio_out); -void gpio_free(unsigned gpio) +u32 bcm47xx_gpio_outen(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_outen(&bcm47xx_bus.ssb, mask, value); +#endif +#ifdef CONFIG_BCM47XX_BCMA + case BCM47XX_BUS_TYPE_BCMA: + return bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, + mask, value); +#endif + } + return -EINVAL; +} +EXPORT_SYMBOL(bcm47xx_gpio_outen); - if (ssb_extif_available(&bcm47xx_bus.ssb.extif) && - ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES)) - return; +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_chipco_gpio_control(&bcm47xx_bus.bcma.bus.drv_cc, + mask, value); +#endif + } + return -EINVAL; +} +EXPORT_SYMBOL(bcm47xx_gpio_control); - clear_bit(gpio, gpio_in_use); - return; +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: - if (gpio >= BCM47XX_CHIPCO_GPIO_LINES) - return; + return bcma_chipco_gpio_intmask(&bcm47xx_bus.bcma.bus.drv_cc, + mask, value); +#endif + } + return -EINVAL; +} +EXPORT_SYMBOL(bcm47xx_gpio_intmask); - clear_bit(gpio, gpio_in_use); - return; +u32 bcm47xx_gpio_polarity(u32 mask, u32 value) +{ + switch (bcm47xx_bus_type) { +#ifdef CONFIG_BCM47XX_SSB + case BCM47XX_BUS_TYPE_SSB: + return ssb_gpio_polarity(&bcm47xx_bus.ssb, mask, value); +#endif +#ifdef CONFIG_BCM47XX_BCMA + case BCM47XX_BUS_TYPE_BCMA: + return bcma_chipco_gpio_polarity(&bcm47xx_bus.bcma.bus.drv_cc, + 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; } -EXPORT_SYMBOL(gpio_free); -int gpio_to_irq(unsigned gpio) +static int bcm47xx_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) { switch (bcm47xx_bus_type) { #ifdef CONFIG_BCM47XX_SSB @@ -99,4 +170,55 @@ int gpio_to_irq(unsigned gpio) } return -EINVAL; } -EXPORT_SYMBOL_GPL(gpio_to_irq); + +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, + .to_irq = bcm47xx_gpio_to_irq, + .base = 0, +}; + +void __init bcm47xx_gpio_init(void) +{ + int err; + + switch (bcm47xx_bus_type) { +#ifdef CONFIG_BCM47XX_SSB + case BCM47XX_BUS_TYPE_SSB: + bcm47xx_gpio_count = ssb_gpio_count(&bcm47xx_bus.ssb); + break; +#endif +#ifdef CONFIG_BCM47XX_BCMA + case BCM47XX_BUS_TYPE_BCMA: + bcm47xx_gpio_count = bcma_chipco_gpio_count(); + break; +#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); +} + +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); --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -346,6 +346,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 for reset button\n"); + return 0; + } + if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET), gpio_interrupt, IRQF_SHARED, "WGT634U GPIO", ccore)) { --- 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,42 @@ * for more details. * * Copyright (C) 2007 Aurelien Jarno + * Copyright (C) 2012 Hauke Mehrtens */ #ifndef __BCM47XX_GPIO_H #define __BCM47XX_GPIO_H -#include -#include -#include - -#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); - -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; -} - -static inline int gpio_is_valid(unsigned gpio) -{ - return gpio < (BCM47XX_EXTIF_GPIO_LINES + BCM47XX_CHIPCO_GPIO_LINES); -} +#define ARCH_NR_GPIOS 64 +#include +/* 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_direction_input(unsigned gpio) -{ - 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; -} +int gpio_get_value(unsigned gpio); +void gpio_set_value(unsigned gpio, int value); -static inline int gpio_direction_output(unsigned gpio, int value) +static inline void gpio_intmask(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_intmask(1 << gpio, value ? 1 << gpio : 0); } -static inline int gpio_intmask(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: - 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; + bcm47xx_gpio_polarity(1 << gpio, value ? 1 << gpio : 0); } -static inline int gpio_polarity(unsigned gpio, int value) +static inline int irq_to_gpio(int gpio) { - 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 +#define gpio_to_irq __gpio_to_irq #endif /* __BCM47XX_GPIO_H */