Re: [RFC][PATCH another try] MIPS: BCM47XX: Prepare support for GPIO buttons

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 28/11/13 16:14, Rafał Miłecki wrote:
So far this adds support for one Netgear model only, but it's designed
and ready to add many more device. We could hopefully import database
from OpenWrt.

Signed-off-by: Rafał Miłecki<zajec5@xxxxxxxxx>

Hi Rafał,

i spoke to hauke earlier today. we are fighting bloat and the INPUT based button drivers are part of what we consider bloat. we have been movin all targets to the gpio-button-hotplug module in oder to drop the dependency on the rather cumbersome input subsystem.

currently the gpio-button-hotplug module uses polled gpios. However i have a semi finished patch that adds irq support. i will revamp it and push it in the very near future.

as 47xx will need to use the same button driver as all other platforms i am afraid that this patch gets a nak and we will need to rebase the functionality ontop of the module once irq support was added.

Sorry for the bad news, but its in the interest of debloatation.

	John


---
This is another try to implement GPIO buttons support. Instead of
re-implementing most of the gpio_keys code, I decided to modify
gpio_keys a bit. A proper patch was posted to the linux-input:
[PATCH] Input: gpio_keys - add ack_irq callback for HW that needs ACK
http://www.mail-archive.com/linux-input@xxxxxxxxxxxxxxx/msg07071.html

This is just a RFC, we have to see if the above patch will be accepted
by linux-input guys first.
---
  arch/mips/bcm47xx/Kconfig           |    6 ++
  arch/mips/bcm47xx/Makefile          |    2 +-
  arch/mips/bcm47xx/bcm47xx_private.h |    3 +
  arch/mips/bcm47xx/buttons.c         |  152 +++++++++++++++++++++++++++++++++++
  arch/mips/bcm47xx/setup.c           |    1 +
  5 files changed, 163 insertions(+), 1 deletion(-)
  create mode 100644 arch/mips/bcm47xx/buttons.c

diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
index 09fc922..28b7d4b 100644
--- a/arch/mips/bcm47xx/Kconfig
+++ b/arch/mips/bcm47xx/Kconfig
@@ -11,6 +11,9 @@ config BCM47XX_SSB
  	select SSB_PCICORE_HOSTMODE if PCI
  	select SSB_DRIVER_GPIO
  	select GPIOLIB
+	select INPUT
+	select INPUT_KEYBOARD
+	select KEYBOARD_GPIO
  	select LEDS_GPIO_REGISTER
  	default y
  	help
@@ -28,6 +31,9 @@ config BCM47XX_BCMA
  	select BCMA_DRIVER_PCI_HOSTMODE if PCI
  	select BCMA_DRIVER_GPIO
  	select GPIOLIB
+	select INPUT
+	select INPUT_KEYBOARD
+	select KEYBOARD_GPIO
  	select LEDS_GPIO_REGISTER
  	default y
  	help
diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile
index 84e9aed..006a05e 100644
--- a/arch/mips/bcm47xx/Makefile
+++ b/arch/mips/bcm47xx/Makefile
@@ -4,5 +4,5 @@
  #

  obj-y				+= irq.o nvram.o prom.o serial.o setup.o time.o sprom.o
-obj-y				+= board.o leds.o
+obj-y				+= board.o buttons.o leds.o
  obj-$(CONFIG_BCM47XX_SSB)	+= wgt634u.o
diff --git a/arch/mips/bcm47xx/bcm47xx_private.h b/arch/mips/bcm47xx/bcm47xx_private.h
index 1a1e600..5c94ace 100644
--- a/arch/mips/bcm47xx/bcm47xx_private.h
+++ b/arch/mips/bcm47xx/bcm47xx_private.h
@@ -3,6 +3,9 @@

  #include<linux/kernel.h>

+/* buttons.c */
+int __init bcm47xx_buttons_register(void);
+
  /* leds.c */
  void __init bcm47xx_leds_register(void);

diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c
new file mode 100644
index 0000000..bec9f61
--- /dev/null
+++ b/arch/mips/bcm47xx/buttons.c
@@ -0,0 +1,152 @@
+#include "bcm47xx_private.h"
+
+#include<linux/input.h>
+#include<linux/gpio_keys.h>
+#include<linux/interrupt.h>
+#include<linux/ssb/ssb_embedded.h>
+#include<bcm47xx_board.h>
+#include<bcm47xx.h>
+
+struct input_dev *input;
+
+/**************************************************
+ * Database
+ **************************************************/
+
+static struct gpio_keys_button
+bcm47xx_buttons_netgear_wndr4500_v1[] = {
+	{
+		.code		= KEY_WPS_BUTTON,
+		.gpio		= 4,
+		.active_low	= 1,
+	},
+	{
+		.code		= KEY_RFKILL,
+		.gpio		= 5,
+		.active_low	= 1,
+	},
+	{
+		.code		= KEY_RESTART,
+		.gpio		= 6,
+		.active_low	= 1,
+	},
+};
+
+/**************************************************
+ * Handlers
+ **************************************************/
+
+static void bcm47xx_buttons_gpio_polarity(u32 mask, u32 value)
+{
+	switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb_gpio_polarity(&bcm47xx_bus.ssb, mask, value);
+		return;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_chipco_gpio_polarity(&bcm47xx_bus.bcma.bus.drv_cc, mask,
+					  value);
+		return;
+#endif
+	}
+	WARN_ON(1);
+}
+
+static void bcm47xx_buttons_irq(const struct gpio_keys_button *button)
+{
+	int gpio = button->gpio;
+	u32 val = __gpio_get_value(gpio);
+
+	/*
+	 * As soon as button state changes, adjust interrupt polarity.
+	 * This prevents hardware from keep generating interrupts for
+	 * the current state.
+	 */
+	bcm47xx_buttons_gpio_polarity(BIT(gpio), val ? BIT(gpio) : 0);
+}
+
+/**************************************************
+ * Init
+ **************************************************/
+
+static struct gpio_keys_platform_data bcm47xx_button_pdata;
+
+static struct platform_device bcm47xx_buttons_gpio_keys = {
+	.name = "gpio-keys",
+	.dev = {
+		.platform_data =&bcm47xx_button_pdata,
+	}
+};
+
+#define bcm47xx_set_bdata(dev_buttons) do {				\
+	bcm47xx_button_pdata.buttons = dev_buttons;			\
+	bcm47xx_button_pdata.nbuttons = ARRAY_SIZE(dev_buttons);	\
+} while (0)
+
+int __init bcm47xx_buttons_register(void)
+{
+#ifdef CONFIG_BCM47XX_SSB
+	struct ssb_bus *ssb;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+	struct bcma_drv_cc *bcma_cc;
+#endif
+	enum bcm47xx_board board = bcm47xx_board_get();
+	u32 gpio_mask = 0;
+	int i, err;
+
+	switch (board) {
+	case BCM47XX_BOARD_NETGEAR_WNDR4500V1:
+		bcm47xx_set_bdata(bcm47xx_buttons_netgear_wndr4500_v1);
+		break;
+	default:
+		pr_debug("No buttons configuration found for this device\n");
+		return -ENOTSUPP;
+	}
+
+	for (i = 0; i<  bcm47xx_button_pdata.nbuttons; i++)
+		bcm47xx_button_pdata.buttons[i].ack_irq = bcm47xx_buttons_irq;
+
+	err = platform_device_register(&bcm47xx_buttons_gpio_keys);
+	if (err) {
+		pr_err("Failed to register platform device: %d\n", err);
+		return err;
+	}
+
+	for (i = 0; i<  bcm47xx_button_pdata.nbuttons; i++) {
+		struct gpio_keys_button *button =
+			&bcm47xx_button_pdata.buttons[i];
+		int gpio = button->gpio;
+		int val = __gpio_get_value(gpio);
+
+		bcm47xx_buttons_gpio_polarity(BIT(gpio), val ? BIT(gpio) : 0);
+		gpio_mask |= BIT(gpio);
+	}
+
+	/*
+	 * Set a list of GPIOs that should generate interrupts and enable GPIO
+	 * interrupts in the ChipCommon core.
+	 */
+	switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+	case BCM47XX_BUS_TYPE_SSB:
+		ssb =&bcm47xx_bus.ssb;
+		ssb_gpio_intmask(ssb, gpio_mask, gpio_mask);
+		if (&ssb->chipco)
+			chipco_set32(&ssb->chipco, SSB_CHIPCO_IRQMASK,
+				     SSB_CHIPCO_IRQ_GPIO);
+		break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+	case BCM47XX_BUS_TYPE_BCMA:
+		bcma_cc =&bcm47xx_bus.bcma.bus.drv_cc;
+		bcma_chipco_gpio_intmask(bcma_cc, gpio_mask, gpio_mask);
+		bcma_cc_set32(bcma_cc, BCMA_CC_IRQMASK, BCMA_CC_IRQ_GPIO);
+		break;
+#endif
+	}
+
+	return 0;
+}
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 7e61c0b..a791124 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -242,6 +242,7 @@ static int __init bcm47xx_register_bus_complete(void)
  #endif
  	}

+	bcm47xx_buttons_register();
  	bcm47xx_leds_register();

  	return 0;



[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux