aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch
diff options
context:
space:
mode:
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.patch493
1 files changed, 493 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 000000000..2f62728d6
--- /dev/null
+++ b/target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch
@@ -0,0 +1,493 @@
+--- 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 <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 <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;
+-
+- 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 <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);
+-
+-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 <asm-generic/gpio.h>
+
++/* 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 */