[PATCH v3 0/8] bcma/ssb/BCM47XX: add GPIO driver to ssb/bcma

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH v3 0/8] bcma/ssb/BCM47XX: add GPIO driver to ssb/bcma

Hauke Mehrtens-2
This is a complete rewrote of the original patch "MIPS: BCM47xx: use
gpiolib"
Instead of providing the GPIO driver in the arch code it is now moved
into ssb and bcma and could also be used by other systems. The GPIO
functions in drivers/ssb/embedded.c are still used by arch/mips/bcm47xx
/wgt634u.c, but I am planing to write some code for baord detection and
a driver for LED and the buttons, after that wgt634u.c could be removed.

This is based on mips/master tree.

v3:
 * make BCMA_DRIVER_GPIO and SSB_DRIVER_GPIO selectable in Kconfig
 * return -ENOTSUPP if the gpio driver is not activated
 * handle error -ENOTSUPP with debug message
 * do not lock *_gpio_in()
 * add comment above chip->base = 0

v2:
 * fix compile problem in ssb: add GPIO driver

Hauke Mehrtens (8):
  bcma: add locking around GPIO register accesses
  bcma: add bcma_chipco_gpio_pull{up,down}
  bcma: add comment to bcma_chipco_gpio_control
  bcma: add GPIO driver
  ssb: add ssb_chipco_gpio_pull{up,down}
  ssb: add locking around gpio register accesses
  ssb: add GPIO driver
  MIPS: BCM47XX: remove GPIO driver

 arch/mips/Kconfig                           |    2 +-
 arch/mips/bcm47xx/Kconfig                   |    2 +
 arch/mips/bcm47xx/Makefile                  |    2 +-
 arch/mips/bcm47xx/gpio.c                    |  102 ----------------
 arch/mips/include/asm/mach-bcm47xx/gpio.h   |  154 ++---------------------
 drivers/bcma/Kconfig                        |    9 ++
 drivers/bcma/Makefile                       |    1 +
 drivers/bcma/bcma_private.h                 |   10 ++
 drivers/bcma/driver_chipcommon.c            |   81 +++++++++++-
 drivers/bcma/driver_gpio.c                  |   98 +++++++++++++++
 drivers/bcma/main.c                         |    5 +
 drivers/ssb/Kconfig                         |    9 ++
 drivers/ssb/Makefile                        |    1 +
 drivers/ssb/driver_chipcommon.c             |   78 +++++++++++-
 drivers/ssb/driver_extif.c                  |   43 ++++++-
 drivers/ssb/driver_gpio.c                   |  176 +++++++++++++++++++++++++++
 drivers/ssb/main.c                          |    7 ++
 drivers/ssb/ssb_private.h                   |   17 +++
 include/linux/bcma/bcma_driver_chipcommon.h |   10 ++
 include/linux/ssb/ssb.h                     |    4 +
 include/linux/ssb/ssb_driver_chipcommon.h   |    3 +
 include/linux/ssb/ssb_driver_extif.h        |    1 +
 22 files changed, 551 insertions(+), 264 deletions(-)
 delete mode 100644 arch/mips/bcm47xx/gpio.c
 create mode 100644 drivers/bcma/driver_gpio.c
 create mode 100644 drivers/ssb/driver_gpio.c

--
1.7.10.4


Reply | Threaded
Open this post in threaded view
|

[PATCH v3 1/8] bcma: add locking around GPIO register accesses

Hauke Mehrtens-2
The GPIOs are access through some registers in the chip common core.
We need locking around these GPIO accesses, all GPIOs are accessed
through the same registers and parallel writes will cause problems.

Signed-off-by: Hauke Mehrtens <[hidden email]>
---
 drivers/bcma/driver_chipcommon.c            |   47 ++++++++++++++++++++++++---
 include/linux/bcma/bcma_driver_chipcommon.h |    3 ++
 2 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index a4c3ebc..c9b63d9 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -30,6 +30,8 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
  if (cc->setup_done)
  return;
 
+ spin_lock_init(&cc->gpio_lock);
+
  if (cc->core->id.rev >= 11)
  cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
  cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
@@ -84,28 +86,63 @@ u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask)
 
 u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
- return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
+ unsigned long flags;
+ u32 res;
+
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
 }
 
 u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
- return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
+ unsigned long flags;
+ u32 res;
+
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
 }
 
 u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
- return bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
+ unsigned long flags;
+ u32 res;
+
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
 }
 EXPORT_SYMBOL_GPL(bcma_chipco_gpio_control);
 
 u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
- return bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
+ unsigned long flags;
+ u32 res;
+
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
 }
 
 u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
- return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
+ unsigned long flags;
+ u32 res;
+
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
 }
 
 #ifdef CONFIG_BCMA_DRIVER_MIPS
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 1cf1749..a085d98 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -567,6 +567,9 @@ struct bcma_drv_cc {
  int nr_serial_ports;
  struct bcma_serial_port serial_ports[4];
 #endif /* CONFIG_BCMA_DRIVER_MIPS */
+
+ /* Lock for GPIO register access. */
+ spinlock_t gpio_lock;
 };
 
 /* Register access */
--
1.7.10.4


Reply | Threaded
Open this post in threaded view
|

[PATCH v3 2/8] bcma: add bcma_chipco_gpio_pull{up,down}

Hauke Mehrtens-2
In reply to this post by Hauke Mehrtens-2
Add functions to access the GPIO registers for pullup and pulldown.
These are needed for handling gpio registration.

Signed-off-by: Hauke Mehrtens <[hidden email]>
---
 drivers/bcma/driver_chipcommon.c            |   30 +++++++++++++++++++++++++++
 include/linux/bcma/bcma_driver_chipcommon.h |    2 ++
 2 files changed, 32 insertions(+)

diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index c9b63d9..0945383 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -145,6 +145,36 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
  return res;
 }
 
+u32 bcma_chipco_gpio_pullup(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ unsigned long flags;
+ u32 res;
+
+ if (cc->core->id.rev < 20)
+ return 0;
+
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPULLUP, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
+}
+
+u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ unsigned long flags;
+ u32 res;
+
+ if (cc->core->id.rev < 20)
+ return 0;
+
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPULLDOWN, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
+}
+
 #ifdef CONFIG_BCMA_DRIVER_MIPS
 void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
 {
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index a085d98..2567026 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -606,6 +606,8 @@ u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value);
 u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value);
 u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value);
 u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value);
+u32 bcma_chipco_gpio_pullup(struct bcma_drv_cc *cc, u32 mask, u32 value);
+u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value);
 
 /* PMU support */
 extern void bcma_pmu_init(struct bcma_drv_cc *cc);
--
1.7.10.4


Reply | Threaded
Open this post in threaded view
|

[PATCH v3s 3/8] bcma: add comment to bcma_chipco_gpio_control

Hauke Mehrtens-2
In reply to this post by Hauke Mehrtens-2
Add description to the function.

Signed-off-by: Hauke Mehrtens <[hidden email]>
---
 drivers/bcma/driver_chipcommon.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 0945383..994fce6 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -108,6 +108,10 @@ u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
  return res;
 }
 
+/*
+ * If the bit is set to 0, chipcommon controlls this GPIO,
+ * if the bit is set to 1, it is used by some part of the chip and not our code.
+ */
 u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
 {
  unsigned long flags;
--
1.7.10.4


Reply | Threaded
Open this post in threaded view
|

[PATCH v3 4/8] bcma: add GPIO driver

Hauke Mehrtens-2
In reply to this post by Hauke Mehrtens-2
Register a GPIO driver to access the GPIOs provided by the chip.
The GPIOs of the SoC should always start at 0 and the other GPIOs could
start at a random position. There is just one SoC in a system and when
they start at 0 the number is predictable.

Signed-off-by: Hauke Mehrtens <[hidden email]>
---
 drivers/bcma/Kconfig                        |    9 +++
 drivers/bcma/Makefile                       |    1 +
 drivers/bcma/bcma_private.h                 |   10 +++
 drivers/bcma/driver_gpio.c                  |   98 +++++++++++++++++++++++++++
 drivers/bcma/main.c                         |    5 ++
 include/linux/bcma/bcma_driver_chipcommon.h |    5 ++
 6 files changed, 128 insertions(+)
 create mode 100644 drivers/bcma/driver_gpio.c

diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index a533af2..d7b56a8 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -65,6 +65,15 @@ config BCMA_DRIVER_GMAC_CMN
 
   If unsure, say N
 
+config BCMA_DRIVER_GPIO
+ bool "BCMA GPIO driver"
+ depends on BCMA
+ select GPIOLIB
+ help
+  Driver to provide access to the GPIO pins of the bcma bus.
+
+  If unsure, say N
+
 config BCMA_DEBUG
  bool "BCMA debugging"
  depends on BCMA
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index 8ad42d4..734b32f 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -6,6 +6,7 @@ bcma-y += driver_pci.o
 bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
 bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
 bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o
+bcma-$(CONFIG_BCMA_DRIVER_GPIO) += driver_gpio.o
 bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
 bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o
 obj-$(CONFIG_BCMA) += bcma.o
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 169fc58..8cd80bf 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -89,4 +89,14 @@ bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
 void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
 #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
 
+#ifdef CONFIG_BCMA_DRIVER_GPIO
+/* driver_gpio.c */
+int bcma_gpio_init(struct bcma_drv_cc *cc);
+#else
+static inline int bcma_gpio_init(struct bcma_drv_cc *cc)
+{
+ return -ENOTSUPP;
+}
+#endif /* CONFIG_BCMA_DRIVER_GPIO */
+
 #endif
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c
new file mode 100644
index 0000000..9a6f585
--- /dev/null
+++ b/drivers/bcma/driver_gpio.c
@@ -0,0 +1,98 @@
+/*
+ * Broadcom specific AMBA
+ * GPIO driver
+ *
+ * Copyright 2011, Broadcom Corporation
+ * Copyright 2012, Hauke Mehrtens <[hidden email]>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/gpio.h>
+#include <linux/export.h>
+#include <linux/bcma/bcma.h>
+
+#include "bcma_private.h"
+
+static inline struct bcma_drv_cc *bcma_gpio_get_cc(struct gpio_chip *chip)
+{
+ return container_of(chip, struct bcma_drv_cc, gpio);
+}
+
+static int bcma_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+
+ return !!bcma_chipco_gpio_in(cc, 1 << gpio);
+}
+
+static void bcma_gpio_set_value(struct gpio_chip *chip, unsigned gpio,
+ int value)
+{
+ struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+
+ bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0);
+}
+
+static int bcma_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+
+ bcma_chipco_gpio_outen(cc, 1 << gpio, 0);
+ return 0;
+}
+
+static int bcma_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
+      int value)
+{
+ struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+
+ bcma_chipco_gpio_outen(cc, 1 << gpio, 1 << gpio);
+ bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0);
+ return 0;
+}
+
+static int bcma_gpio_request(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+
+ bcma_chipco_gpio_control(cc, 1 << gpio, 0);
+ /* clear pulldown */
+ bcma_chipco_gpio_pulldown(cc, 1 << gpio, 0);
+ /* Set pullup */
+ bcma_chipco_gpio_pullup(cc, 1 << gpio, 1 << gpio);
+
+ return 0;
+}
+
+static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+
+ /* clear pullup */
+ bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
+}
+
+int bcma_gpio_init(struct bcma_drv_cc *cc)
+{
+ struct gpio_chip *chip = &cc->gpio;
+
+ chip->label = "bcma_gpio";
+ chip->owner = THIS_MODULE;
+ chip->request = bcma_gpio_request;
+ chip->free = bcma_gpio_free;
+ chip->get = bcma_gpio_get_value;
+ chip->set = bcma_gpio_set_value;
+ chip->direction_input = bcma_gpio_direction_input;
+ chip->direction_output = bcma_gpio_direction_output;
+ 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
+ * a random base number. */
+ if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
+ chip->base = 0;
+ else
+ chip->base = -1;
+
+ return gpiochip_add(chip);
+}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index d865470..478ba01 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -152,6 +152,11 @@ static int bcma_register_cores(struct bcma_bus *bus)
  bcma_err(bus, "Error registering NAND flash\n");
  }
 #endif
+ err = bcma_gpio_init(&bus->drv_cc);
+ if (err == -ENOTSUPP)
+ bcma_debug(bus, "GPIO driver not activated\n");
+ else if (err)
+ bcma_err(bus, "Error registering GPIO driver: %i\n", err);
 
  return 0;
 }
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 2567026..7d662a9 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -1,6 +1,8 @@
 #ifndef LINUX_BCMA_DRIVER_CC_H_
 #define LINUX_BCMA_DRIVER_CC_H_
 
+#include <linux/gpio.h>
+
 /** ChipCommon core registers. **/
 #define BCMA_CC_ID 0x0000
 #define  BCMA_CC_ID_ID 0x0000FFFF
@@ -570,6 +572,9 @@ struct bcma_drv_cc {
 
  /* Lock for GPIO register access. */
  spinlock_t gpio_lock;
+#ifdef CONFIG_BCMA_DRIVER_GPIO
+ struct gpio_chip gpio;
+#endif
 };
 
 /* Register access */
--
1.7.10.4


Reply | Threaded
Open this post in threaded view
|

[PATCH v3 5/8] ssb: add ssb_chipco_gpio_pull{up,down}

Hauke Mehrtens-2
In reply to this post by Hauke Mehrtens-2
Add functions to access the GPIO registers for pullup and pulldown.
These are needed for handling gpio registration.

Signed-off-by: Hauke Mehrtens <[hidden email]>
---
 drivers/ssb/driver_chipcommon.c           |   16 ++++++++++++++++
 include/linux/ssb/ssb_driver_chipcommon.h |    2 ++
 2 files changed, 18 insertions(+)

diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index e9d2ca1..4df4926 100644
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -442,6 +442,22 @@ u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value)
  return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value);
 }
 
+u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value)
+{
+ if (cc->dev->id.revision < 20)
+ return 0xffffffff;
+
+ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value);
+}
+
+u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value)
+{
+ if (cc->dev->id.revision < 20)
+ return 0xffffffff;
+
+ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value);
+}
+
 #ifdef CONFIG_SSB_SERIAL
 int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
    struct ssb_serial_port *ports)
diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h
index c2b02a5..c8d07c9 100644
--- a/include/linux/ssb/ssb_driver_chipcommon.h
+++ b/include/linux/ssb/ssb_driver_chipcommon.h
@@ -644,6 +644,8 @@ u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value);
 u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value);
 u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value);
 u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value);
+u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value);
+u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value);
 
 #ifdef CONFIG_SSB_SERIAL
 extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
--
1.7.10.4


Reply | Threaded
Open this post in threaded view
|

[PATCH v3 6/8] ssb: add locking around gpio register accesses

Hauke Mehrtens-2
In reply to this post by Hauke Mehrtens-2
The GPIOs are access through some registers in the chip common core or
over extif. We need locking around these GPIO accesses, all GPIOs are
accessed through the same registers and parallel writes will cause
problems.

Signed-off-by: Hauke Mehrtens <[hidden email]>
---
 drivers/ssb/driver_chipcommon.c           |   66 ++++++++++++++++++++++++++---
 drivers/ssb/driver_extif.c                |   43 +++++++++++++++++--
 drivers/ssb/main.c                        |    1 +
 drivers/ssb/ssb_private.h                 |    8 ++++
 include/linux/ssb/ssb_driver_chipcommon.h |    1 +
 include/linux/ssb/ssb_driver_extif.h      |    1 +
 6 files changed, 109 insertions(+), 11 deletions(-)

diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index 4df4926..24e02bb 100644
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -284,6 +284,9 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
 {
  if (!cc->dev)
  return; /* We don't have a ChipCommon */
+
+ spin_lock_init(&cc->gpio_lock);
+
  if (cc->dev->id.revision >= 11)
  cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
  ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
@@ -418,44 +421,93 @@ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask)
 
 u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
 {
- return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
 }
 
 u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
 {
- return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
 }
 
 u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value)
 {
- return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
 }
 EXPORT_SYMBOL(ssb_chipco_gpio_control);
 
 u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value)
 {
- return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value);
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
 }
 
 u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value)
 {
- return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value);
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
 }
 
 u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value)
 {
+ unsigned long flags;
+ u32 res = 0;
+
  if (cc->dev->id.revision < 20)
  return 0xffffffff;
 
- return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value);
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
 }
 
 u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value)
 {
+ unsigned long flags;
+ u32 res = 0;
+
  if (cc->dev->id.revision < 20)
  return 0xffffffff;
 
- return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value);
+ spin_lock_irqsave(&cc->gpio_lock, flags);
+ res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value);
+ spin_unlock_irqrestore(&cc->gpio_lock, flags);
+
+ return res;
 }
 
 #ifdef CONFIG_SSB_SERIAL
diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c
index dc47f30..e1d0bb8 100644
--- a/drivers/ssb/driver_extif.c
+++ b/drivers/ssb/driver_extif.c
@@ -118,6 +118,13 @@ void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
  extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks);
 }
 
+void ssb_extif_init(struct ssb_extif *extif)
+{
+ if (!extif->dev)
+ return; /* We don't have a Extif core */
+ spin_lock_init(&extif->gpio_lock);
+}
+
 u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
 {
  return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
@@ -125,22 +132,50 @@ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
 
 u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
 {
- return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&extif->gpio_lock, flags);
+ res = extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
    mask, value);
+ spin_unlock_irqrestore(&extif->gpio_lock, flags);
+
+ return res;
 }
 
 u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
 {
- return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&extif->gpio_lock, flags);
+ res = extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
    mask, value);
+ spin_unlock_irqrestore(&extif->gpio_lock, flags);
+
+ return res;
 }
 
 u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value)
 {
- return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value);
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&extif->gpio_lock, flags);
+ res = extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value);
+ spin_unlock_irqrestore(&extif->gpio_lock, flags);
+
+ return res;
 }
 
 u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value)
 {
- return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value);
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&extif->gpio_lock, flags);
+ res = extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value);
+ spin_unlock_irqrestore(&extif->gpio_lock, flags);
+
+ return res;
 }
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index df0f145..6fe2d10 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -796,6 +796,7 @@ static int __devinit ssb_bus_register(struct ssb_bus *bus,
  if (err)
  goto err_pcmcia_exit;
  ssb_chipcommon_init(&bus->chipco);
+ ssb_extif_init(&bus->extif);
  ssb_mipscore_init(&bus->mipscore);
  err = ssb_fetch_invariants(bus, get_invariants);
  if (err) {
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
index a305550..d6a1ba9 100644
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -211,4 +211,12 @@ static inline void b43_pci_ssb_bridge_exit(void)
 extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc);
 extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc);
 
+#ifdef CONFIG_SSB_DRIVER_EXTIF
+extern void ssb_extif_init(struct ssb_extif *extif);
+#else
+static inline void ssb_extif_init(struct ssb_extif *extif)
+{
+}
+#endif
+
 #endif /* LINUX_SSB_PRIVATE_H_ */
diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h
index c8d07c9..30b6943 100644
--- a/include/linux/ssb/ssb_driver_chipcommon.h
+++ b/include/linux/ssb/ssb_driver_chipcommon.h
@@ -590,6 +590,7 @@ struct ssb_chipcommon {
  u32 status;
  /* Fast Powerup Delay constant */
  u16 fast_pwrup_delay;
+ spinlock_t gpio_lock;
  struct ssb_chipcommon_pmu pmu;
 };
 
diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h
index 91161f0..bd23068 100644
--- a/include/linux/ssb/ssb_driver_extif.h
+++ b/include/linux/ssb/ssb_driver_extif.h
@@ -158,6 +158,7 @@
 
 struct ssb_extif {
  struct ssb_device *dev;
+ spinlock_t gpio_lock;
 };
 
 static inline bool ssb_extif_available(struct ssb_extif *extif)
--
1.7.10.4


Reply | Threaded
Open this post in threaded view
|

[PATCH v3 7/8] ssb: add GPIO driver

Hauke Mehrtens-2
In reply to this post by Hauke Mehrtens-2
Register a GPIO driver to access the GPIOs provided by the chip.
The GPIOs of the SoC should always start at 0 and the other GPIOs could
start at a random position. There is just one SoC in a system and when
they start at 0 the number is predictable.

Signed-off-by: Hauke Mehrtens <[hidden email]>
---
 drivers/ssb/Kconfig       |    9 +++
 drivers/ssb/Makefile      |    1 +
 drivers/ssb/driver_gpio.c |  176 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/ssb/main.c        |    6 ++
 drivers/ssb/ssb_private.h |    9 +++
 include/linux/ssb/ssb.h   |    4 ++
 6 files changed, 205 insertions(+)
 create mode 100644 drivers/ssb/driver_gpio.c

diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
index 42cdaa9..ff3c8a2 100644
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -160,4 +160,13 @@ config SSB_DRIVER_GIGE
 
   If unsure, say N
 
+config SSB_DRIVER_GPIO
+ bool "SSB GPIO driver"
+ depends on SSB
+ select GPIOLIB
+ help
+  Driver to provide access to the GPIO pins on the bus.
+
+  If unsure, say N
+
 endmenu
diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile
index 656e58b..9159ba7 100644
--- a/drivers/ssb/Makefile
+++ b/drivers/ssb/Makefile
@@ -15,6 +15,7 @@ ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o
 ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o
 ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o
 ssb-$(CONFIG_SSB_DRIVER_GIGE) += driver_gige.o
+ssb-$(CONFIG_SSB_DRIVER_GPIO) += driver_gpio.o
 
 # b43 pci-ssb-bridge driver
 # Not strictly a part of SSB, but kept here for convenience
diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c
new file mode 100644
index 0000000..97ac0a3
--- /dev/null
+++ b/drivers/ssb/driver_gpio.c
@@ -0,0 +1,176 @@
+/*
+ * Sonics Silicon Backplane
+ * GPIO driver
+ *
+ * Copyright 2011, Broadcom Corporation
+ * Copyright 2012, Hauke Mehrtens <[hidden email]>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/gpio.h>
+#include <linux/export.h>
+#include <linux/ssb/ssb.h>
+
+#include "ssb_private.h"
+
+static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip)
+{
+ return container_of(chip, struct ssb_bus, gpio);
+}
+
+static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+ return !!ssb_chipco_gpio_in(&bus->chipco, 1 << gpio);
+}
+
+static void ssb_gpio_chipco_set_value(struct gpio_chip *chip, unsigned gpio,
+      int value)
+{
+ struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+ ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0);
+}
+
+static int ssb_gpio_chipco_direction_input(struct gpio_chip *chip,
+   unsigned gpio)
+{
+ struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+ ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 0);
+ return 0;
+}
+
+static int ssb_gpio_chipco_direction_output(struct gpio_chip *chip,
+    unsigned gpio, int value)
+{
+ struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+ ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 1 << gpio);
+ ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0);
+ return 0;
+}
+
+static int ssb_gpio_chipco_request(struct gpio_chip *chip, unsigned gpio)
+{
+ struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+ ssb_chipco_gpio_control(&bus->chipco, 1 << gpio, 0);
+ /* clear pulldown */
+ ssb_chipco_gpio_pulldown(&bus->chipco, 1 << gpio, 0);
+ /* Set pullup */
+ ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 1 << gpio);
+
+ return 0;
+}
+
+static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned gpio)
+{
+ struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+ /* clear pullup */
+ ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0);
+}
+
+static int ssb_gpio_chipco_init(struct ssb_bus *bus)
+{
+ struct gpio_chip *chip = &bus->gpio;
+
+ chip->label = "ssb_chipco_gpio";
+ chip->owner = THIS_MODULE;
+ chip->request = ssb_gpio_chipco_request;
+ chip->free = ssb_gpio_chipco_free;
+ chip->get = ssb_gpio_chipco_get_value;
+ chip->set = ssb_gpio_chipco_set_value;
+ chip->direction_input = ssb_gpio_chipco_direction_input;
+ chip->direction_output = ssb_gpio_chipco_direction_output;
+ 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
+ * a random base number. */
+ if (bus->bustype == SSB_BUSTYPE_SSB)
+ chip->base = 0;
+ else
+ chip->base = -1;
+
+ return gpiochip_add(chip);
+}
+
+#ifdef CONFIG_SSB_DRIVER_EXTIF
+
+static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+ return !!ssb_extif_gpio_in(&bus->extif, 1 << gpio);
+}
+
+static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned gpio,
+     int value)
+{
+ struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+ ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0);
+}
+
+static int ssb_gpio_extif_direction_input(struct gpio_chip *chip,
+  unsigned gpio)
+{
+ struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+ ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 0);
+ return 0;
+}
+
+static int ssb_gpio_extif_direction_output(struct gpio_chip *chip,
+   unsigned gpio, int value)
+{
+ struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+ ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 1 << gpio);
+ ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0);
+ return 0;
+}
+
+static int ssb_gpio_extif_init(struct ssb_bus *bus)
+{
+ struct gpio_chip *chip = &bus->gpio;
+
+ chip->label = "ssb_extif_gpio";
+ chip->owner = THIS_MODULE;
+ chip->get = ssb_gpio_extif_get_value;
+ chip->set = ssb_gpio_extif_set_value;
+ chip->direction_input = ssb_gpio_extif_direction_input;
+ chip->direction_output = ssb_gpio_extif_direction_output;
+ chip->ngpio = 5;
+ /* 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
+ * a random base number. */
+ if (bus->bustype == SSB_BUSTYPE_SSB)
+ chip->base = 0;
+ else
+ chip->base = -1;
+
+ return gpiochip_add(chip);
+}
+
+#else
+static int ssb_gpio_extif_init(struct ssb_bus *bus)
+{
+ return -ENOTSUPP;
+}
+#endif
+
+int ssb_gpio_init(struct ssb_bus *bus)
+{
+ if (ssb_chipco_available(&bus->chipco))
+ return ssb_gpio_chipco_init(bus);
+ else if (ssb_extif_available(&bus->extif))
+ return ssb_gpio_extif_init(bus);
+ else
+ SSB_WARN_ON(1);
+
+ return -1;
+}
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 6fe2d10..87f0ddf 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -798,6 +798,12 @@ static int __devinit ssb_bus_register(struct ssb_bus *bus,
  ssb_chipcommon_init(&bus->chipco);
  ssb_extif_init(&bus->extif);
  ssb_mipscore_init(&bus->mipscore);
+ err = ssb_gpio_init(bus);
+ if (err == -ENOTSUPP)
+ ssb_dprintk(KERN_DEBUG PFX "GPIO driver not activated\n");
+ else if (err)
+ ssb_dprintk(KERN_ERR PFX
+   "Error registering GPIO driver: %i\n", err);
  err = ssb_fetch_invariants(bus, get_invariants);
  if (err) {
  ssb_bus_may_powerdown(bus);
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
index d6a1ba9..463b76a2 100644
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -219,4 +219,13 @@ static inline void ssb_extif_init(struct ssb_extif *extif)
 }
 #endif
 
+#ifdef CONFIG_SSB_DRIVER_GPIO
+extern int ssb_gpio_init(struct ssb_bus *bus);
+#else /* CONFIG_SSB_DRIVER_GPIO */
+static inline int ssb_gpio_init(struct ssb_bus *bus)
+{
+ return -ENOTSUPP;
+}
+#endif /* CONFIG_SSB_DRIVER_GPIO */
+
 #endif /* LINUX_SSB_PRIVATE_H_ */
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index bb674c0..3862a5b 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -6,6 +6,7 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <linux/pci.h>
+#include <linux/gpio.h>
 #include <linux/mod_devicetable.h>
 #include <linux/dma-mapping.h>
 
@@ -433,6 +434,9 @@ struct ssb_bus {
  /* Lock for GPIO register access. */
  spinlock_t gpio_lock;
 #endif /* EMBEDDED */
+#ifdef CONFIG_SSB_DRIVER_GPIO
+ struct gpio_chip gpio;
+#endif /* DRIVER_GPIO */
 
  /* Internal-only stuff follows. Do not touch. */
  struct list_head list;
--
1.7.10.4


Reply | Threaded
Open this post in threaded view
|

[PATCH v3 8/8] MIPS: BCM47XX: remove GPIO driver

Hauke Mehrtens-2
In reply to this post by Hauke Mehrtens-2
Instated of providing an own GPIO driver use the one provided by ssb and
bcma.

Acked-by: Florian Fainelli <[hidden email]>
Signed-off-by: Hauke Mehrtens <[hidden email]>
---
 arch/mips/Kconfig                         |    2 +-
 arch/mips/bcm47xx/Kconfig                 |    2 +
 arch/mips/bcm47xx/Makefile                |    2 +-
 arch/mips/bcm47xx/gpio.c                  |  102 -------------------
 arch/mips/include/asm/mach-bcm47xx/gpio.h |  154 ++---------------------------
 5 files changed, 12 insertions(+), 250 deletions(-)
 delete mode 100644 arch/mips/bcm47xx/gpio.c

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index dba9390..abc8b69 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -105,6 +105,7 @@ config ATH79
 
 config BCM47XX
  bool "Broadcom BCM47XX based boards"
+ select ARCH_WANT_OPTIONAL_GPIOLIB
  select CEVT_R4K
  select CSRC_R4K
  select DMA_NONCOHERENT
@@ -112,7 +113,6 @@ config BCM47XX
  select IRQ_CPU
  select SYS_SUPPORTS_32BIT_KERNEL
  select SYS_SUPPORTS_LITTLE_ENDIAN
- select GENERIC_GPIO
  select SYS_HAS_EARLY_PRINTK
  select CFE
  help
diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
index b311be4..d7af29f 100644
--- a/arch/mips/bcm47xx/Kconfig
+++ b/arch/mips/bcm47xx/Kconfig
@@ -9,6 +9,7 @@ config BCM47XX_SSB
  select SSB_EMBEDDED
  select SSB_B43_PCI_BRIDGE if PCI
  select SSB_PCICORE_HOSTMODE if PCI
+ select SSB_DRIVER_GPIO
  default y
  help
  Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support.
@@ -23,6 +24,7 @@ config BCM47XX_BCMA
  select BCMA_DRIVER_MIPS
  select BCMA_HOST_PCI if PCI
  select BCMA_DRIVER_PCI_HOSTMODE if PCI
+ select BCMA_DRIVER_GPIO
  default y
  help
  Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile
index 4389de1..1a3567f 100644
--- a/arch/mips/bcm47xx/Makefile
+++ b/arch/mips/bcm47xx/Makefile
@@ -3,5 +3,5 @@
 # under Linux.
 #
 
-obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o sprom.o
+obj-y += irq.o nvram.o prom.o serial.o setup.o time.o sprom.o
 obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
deleted file mode 100644
index 5ebdf62..0000000
--- a/arch/mips/bcm47xx/gpio.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2007 Aurelien Jarno <[hidden email]>
- */
-
-#include <linux/export.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>
-
-#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)
-{
- 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;
-#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 0;
-#endif
- }
- return -EINVAL;
-}
-EXPORT_SYMBOL(gpio_request);
-
-void gpio_free(unsigned gpio)
-{
- 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;
-
- if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
-    ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
- return;
-
- clear_bit(gpio, gpio_in_use);
- return;
-#endif
-#ifdef CONFIG_BCM47XX_BCMA
- case BCM47XX_BUS_TYPE_BCMA:
- if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
- return;
-
- clear_bit(gpio, gpio_in_use);
- return;
-#endif
- }
-}
-EXPORT_SYMBOL(gpio_free);
-
-int gpio_to_irq(unsigned gpio)
-{
- switch (bcm47xx_bus_type) {
-#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
- return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
- else if (ssb_extif_available(&bcm47xx_bus.ssb.extif))
- return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
- else
- return -EINVAL;
-#endif
-#ifdef CONFIG_BCM47XX_BCMA
- case BCM47XX_BUS_TYPE_BCMA:
- return bcma_core_mips_irq(bcm47xx_bus.bcma.bus.drv_cc.core) + 2;
-#endif
- }
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(gpio_to_irq);
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 2ef17e8..90daefa 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -1,155 +1,17 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2007 Aurelien Jarno <[hidden email]>
- */
+#ifndef __ASM_MIPS_MACH_BCM47XX_GPIO_H
+#define __ASM_MIPS_MACH_BCM47XX_GPIO_H
 
-#ifndef __BCM47XX_GPIO_H
-#define __BCM47XX_GPIO_H
+#include <asm-generic/gpio.h>
 
-#include <linux/ssb/ssb_embedded.h>
-#include <linux/bcma/bcma.h>
-#include <asm/mach-bcm47xx/bcm47xx.h>
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
 
-#define BCM47XX_EXTIF_GPIO_LINES 5
-#define BCM47XX_CHIPCO_GPIO_LINES 16
+#define gpio_cansleep __gpio_cansleep
+#define gpio_to_irq __gpio_to_irq
 
-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)
+static inline int irq_to_gpio(unsigned int irq)
 {
- 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);
-}
-
-
-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;
-}
-
-static inline int gpio_direction_output(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;
-}
-
-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;
-}
-
-
-#endif /* __BCM47XX_GPIO_H */
--
1.7.10.4


Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v3 0/8] bcma/ssb/BCM47XX: add GPIO driver to ssb/bcma

Rafał Miłecki-2
In reply to this post by Hauke Mehrtens-2
2012/11/21 Hauke Mehrtens <[hidden email]>:
> This is a complete rewrote of the original patch "MIPS: BCM47xx: use
> gpiolib"
> Instead of providing the GPIO driver in the arch code it is now moved
> into ssb and bcma and could also be used by other systems. The GPIO
> functions in drivers/ssb/embedded.c are still used by arch/mips/bcm47xx
> /wgt634u.c, but I am planing to write some code for baord detection and
> a driver for LED and the buttons, after that wgt634u.c could be removed.
>
> This is based on mips/master tree.

Is this patches supposed to appear in
http://git.kernel.org/?p=linux/kernel/git/ralf/linux.git;a=summary
? Just so I can know where to look for it.

--
Rafał

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v3 0/8] bcma/ssb/BCM47XX: add GPIO driver to ssb/bcma

Hauke Mehrtens-2
On 11/30/2012 02:11 PM, Rafał Miłecki wrote:

> 2012/11/21 Hauke Mehrtens <[hidden email]>:
>> This is a complete rewrote of the original patch "MIPS: BCM47xx: use
>> gpiolib"
>> Instead of providing the GPIO driver in the arch code it is now moved
>> into ssb and bcma and could also be used by other systems. The GPIO
>> functions in drivers/ssb/embedded.c are still used by arch/mips/bcm47xx
>> /wgt634u.c, but I am planing to write some code for baord detection and
>> a driver for LED and the buttons, after that wgt634u.c could be removed.
>>
>> This is based on mips/master tree.
>
> Is this patches supposed to appear in
> http://git.kernel.org/?p=linux/kernel/git/ralf/linux.git;a=summary
> ? Just so I can know where to look for it.
>
Hi Rafał,

It is in a mips tree at [0] and it is also in linux-next.

Hauke

[0]: http://git.linux-mips.org/?p=ralf/upstream-sfr.git;a=summary


Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v3 0/8] bcma/ssb/BCM47XX: add GPIO driver to ssb/bcma

Rafał Miłecki-2
2012/11/30 Hauke Mehrtens <[hidden email]>:

> On 11/30/2012 02:11 PM, Rafał Miłecki wrote:
>> 2012/11/21 Hauke Mehrtens <[hidden email]>:
>>> This is a complete rewrote of the original patch "MIPS: BCM47xx: use
>>> gpiolib"
>>> Instead of providing the GPIO driver in the arch code it is now moved
>>> into ssb and bcma and could also be used by other systems. The GPIO
>>> functions in drivers/ssb/embedded.c are still used by arch/mips/bcm47xx
>>> /wgt634u.c, but I am planing to write some code for baord detection and
>>> a driver for LED and the buttons, after that wgt634u.c could be removed.
>>>
>>> This is based on mips/master tree.
>>
>> Is this patches supposed to appear in
>> http://git.kernel.org/?p=linux/kernel/git/ralf/linux.git;a=summary
>> ? Just so I can know where to look for it.
>>
> Hi Rafał,
>
> It is in a mips tree at [0] and it is also in linux-next.
>
> Hauke
>
> [0]: http://git.linux-mips.org/?p=ralf/upstream-sfr.git;a=summary

Thanks for pointing as well as for your work!

--
Rafał