From 2cfd943fe9074c3bfd1c293222d7de381e2f1576 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@openwrt.org>
Date: Mon, 7 Mar 2016 09:20:22 +0000
Subject: mac80211: rework gpio chip/button support to build on platforms
 without CONFIG_GPIOLIB

Signed-off-by: Felix Fietkau <nbd@openwrt.org>

SVN-Revision: 48938
---
 .../patches/548-ath9k_enable_gpio_chip.patch       | 235 ++++++++++++++++++++
 .../patches/549-ath9k_enable_gpio_buttons.patch    | 148 +++++++++++++
 .../patches/549-ath9k_enable_gpio_chip.patch       | 243 ---------------------
 .../patches/550-ath9k_enable_gpio_buttons.patch    | 169 --------------
 4 files changed, 383 insertions(+), 412 deletions(-)
 create mode 100644 package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
 create mode 100644 package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
 delete mode 100644 package/kernel/mac80211/patches/549-ath9k_enable_gpio_chip.patch
 delete mode 100644 package/kernel/mac80211/patches/550-ath9k_enable_gpio_buttons.patch

diff --git a/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch b/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
new file mode 100644
index 0000000000..f91d85c6f8
--- /dev/null
+++ b/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
@@ -0,0 +1,235 @@
+From: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+Date: Sun, 31 Jan 2016 21:01:31 +0100
+Subject: [PATCH v4 4/8] mac80211: ath9k: enable access to GPIO
+
+Enable access to GPIO chip and its pins for Atheros AR92xx
+wireless devices. For now AR9285 and AR9287 are supported.
+
+Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -24,6 +24,7 @@
+ #include <linux/completion.h>
+ #include <linux/time.h>
+ #include <linux/hw_random.h>
++#include <linux/gpio/driver.h>
+ 
+ #include "common.h"
+ #include "debug.h"
+@@ -963,6 +964,14 @@ struct ath_led {
+ 	struct led_classdev cdev;
+ };
+ 
++#ifdef CONFIG_GPIOLIB
++struct ath9k_gpio_chip {
++	struct ath_softc *sc;
++	char label[32];
++	struct gpio_chip gchip;
++};
++#endif
++
+ struct ath_softc {
+ 	struct ieee80211_hw *hw;
+ 	struct device *dev;
+@@ -1017,6 +1026,9 @@ struct ath_softc {
+ #ifdef CPTCFG_MAC80211_LEDS
+ 	const char *led_default_trigger;
+ 	struct list_head leds;
++#ifdef CONFIG_GPIOLIB
++	struct ath9k_gpio_chip *gpiochip;
++#endif
+ #endif
+ 
+ #ifdef CPTCFG_ATH9K_DEBUGFS
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -16,12 +16,138 @@
+ 
+ #include "ath9k.h"
+ #include <linux/ath9k_platform.h>
++#include <linux/gpio.h>
++
++#ifdef CPTCFG_MAC80211_LEDS
++
++#ifdef CONFIG_GPIOLIB
++
++/***************/
++/*  GPIO Chip  */
++/***************/
++
++/* gpio_chip handler : set GPIO to input */
++static int ath9k_gpio_pin_cfg_input(struct gpio_chip *chip, unsigned offset)
++{
++	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
++						  gchip);
++
++	ath9k_hw_cfg_gpio_input(gc->sc->sc_ah, offset);
++
++	return 0;
++}
++
++/* gpio_chip handler : set GPIO to output */
++static int ath9k_gpio_pin_cfg_output(struct gpio_chip *chip, unsigned offset,
++				     int value)
++{
++	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
++						  gchip);
++
++	ath9k_hw_cfg_output(gc->sc->sc_ah, offset,
++			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
++	ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value);
++
++	return 0;
++}
++
++/* gpio_chip handler : query GPIO direction (0=out, 1=in) */
++static int ath9k_gpio_pin_get_dir(struct gpio_chip *chip, unsigned offset)
++{
++	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
++						  gchip);
++	struct ath_hw *ah = gc->sc->sc_ah;
++
++	return !((REG_READ(ah, AR_GPIO_OE_OUT) >> (offset * 2)) & 3);
++}
++
++/* gpio_chip handler : get GPIO pin value */
++static int ath9k_gpio_pin_get(struct gpio_chip *chip, unsigned offset)
++{
++	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
++						  gchip);
++
++	return ath9k_hw_gpio_get(gc->sc->sc_ah, offset);
++}
++
++/* gpio_chip handler : set GPIO pin to value */
++static void ath9k_gpio_pin_set(struct gpio_chip *chip, unsigned offset,
++			       int value)
++{
++	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
++						  gchip);
++
++	ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value);
++}
++
++/* register GPIO chip */
++static void ath9k_register_gpio_chip(struct ath_softc *sc)
++{
++	struct ath9k_gpio_chip *gc;
++	u16 ng;
++
++	/* for now only AR9285 and AR9287 are recognized */
++	if (AR_SREV_9287(sc->sc_ah))
++		ng = AR9287_NUM_GPIO;
++	else if (AR_SREV_9285(sc->sc_ah))
++		ng = AR9285_NUM_GPIO;
++	else
++		return;
++
++	gc = kzalloc(sizeof(struct ath9k_gpio_chip), GFP_KERNEL);
++	if (!gc)
++		return;
++
++	snprintf(gc->label, sizeof(gc->label), "ath9k-%s",
++		 wiphy_name(sc->hw->wiphy));
++	gc->gchip.label = gc->label;
++	gc->gchip.base = -1;	/* determine base automatically */
++	gc->gchip.ngpio = ng;
++	gc->gchip.direction_input = ath9k_gpio_pin_cfg_input;
++	gc->gchip.direction_output = ath9k_gpio_pin_cfg_output;
++	gc->gchip.get_direction = ath9k_gpio_pin_get_dir;
++	gc->gchip.get = ath9k_gpio_pin_get;
++	gc->gchip.set = ath9k_gpio_pin_set;
++	gc->gchip.owner = THIS_MODULE;
++
++	if (gpiochip_add(&gc->gchip)) {
++		kfree(gc);
++		return;
++	}
++
++	sc->gpiochip = gc;
++	gc->sc = sc;
++}
++
++/* remove GPIO chip */
++static void ath9k_unregister_gpio_chip(struct ath_softc *sc)
++{
++	struct ath9k_gpio_chip *gc = sc->gpiochip;
++
++	if (!gc)
++		return;
++
++	gpiochip_remove(&gc->gchip);
++	kfree(gc);
++	sc->gpiochip = NULL;
++}
++
++#else /* CONFIG_GPIOLIB */
++
++static inline void ath9k_register_gpio_chip(struct ath_softc *sc)
++{
++}
++
++static inline void ath9k_unregister_gpio_chip(struct ath_softc *sc)
++{
++}
++
++#endif /* CONFIG_GPIOLIB */
+ 
+ /********************************/
+ /*	 LED functions		*/
+ /********************************/
+ 
+-#ifdef CPTCFG_MAC80211_LEDS
+ static void ath_led_brightness(struct led_classdev *led_cdev,
+ 			       enum led_brightness brightness)
+ {
+@@ -60,6 +186,12 @@ static int ath_add_led(struct ath_softc
+ 	else
+ 		ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
+ 
++#ifdef CONFIG_GPIOLIB
++	/* If there is GPIO chip configured, reserve LED pin */
++	if (sc->gpiochip)
++		gpio_request(sc->gpiochip->gchip.base + gpio->gpio, gpio->name);
++#endif
++
+ 	return 0;
+ }
+ 
+@@ -116,11 +248,17 @@ void ath_deinit_leds(struct ath_softc *s
+ 
+ 	while (!list_empty(&sc->leds)) {
+ 		led = list_first_entry(&sc->leds, struct ath_led, list);
++#ifdef CONFIG_GPIOLIB
++		/* If there is GPIO chip configured, free LED pin */
++		if (sc->gpiochip)
++			gpio_free(sc->gpiochip->gchip.base + led->gpio->gpio);
++#endif
+ 		list_del(&led->list);
+ 		ath_led_brightness(&led->cdev, LED_OFF);
+ 		led_classdev_unregister(&led->cdev);
+ 		kfree(led);
+ 	}
++	ath9k_unregister_gpio_chip(sc);
+ }
+ 
+ void ath_init_leds(struct ath_softc *sc)
+@@ -135,6 +273,8 @@ void ath_init_leds(struct ath_softc *sc)
+ 	if (AR_SREV_9100(sc->sc_ah))
+ 		return;
+ 
++	ath9k_register_gpio_chip(sc);
++
+ 	if (pdata && pdata->led_name)
+ 		strncpy(led_name, pdata->led_name, sizeof(led_name));
+ 	else
+@@ -186,6 +326,7 @@ void ath_fill_led_pin(struct ath_softc *
+ 	/* LED off, active low */
+ 	ath9k_hw_set_gpio(ah, ah->led_pin, (ah->config.led_active_high) ? 0 : 1);
+ }
++
+ #endif
+ 
+ /*******************/
diff --git a/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch b/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
new file mode 100644
index 0000000000..05274065c7
--- /dev/null
+++ b/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
@@ -0,0 +1,148 @@
+From: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+Subject: [PATCH v5 5/8] mac80211: ath9k: enable GPIO buttons
+
+Enable platform-defined GPIO button support for ath9k device.
+Key poller is activated for attached platform buttons.
+Requires ath9k GPIO chip access.
+
+Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -1028,6 +1028,7 @@ struct ath_softc {
+ 	struct list_head leds;
+ #ifdef CONFIG_GPIOLIB
+ 	struct ath9k_gpio_chip *gpiochip;
++	struct platform_device *btnpdev;	/* gpio-keys-polled */
+ #endif
+ #endif
+ 
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -17,6 +17,8 @@
+ #include "ath9k.h"
+ #include <linux/ath9k_platform.h>
+ #include <linux/gpio.h>
++#include <linux/platform_device.h>
++#include <linux/gpio_keys.h>
+ 
+ #ifdef CPTCFG_MAC80211_LEDS
+ 
+@@ -132,6 +134,63 @@ static void ath9k_unregister_gpio_chip(s
+ 	sc->gpiochip = NULL;
+ }
+ 
++/******************/
++/*  GPIO Buttons  */
++/******************/
++
++/* add GPIO buttons */
++static void ath9k_init_buttons(struct ath_softc *sc)
++{
++	struct ath9k_platform_data *pdata = sc->dev->platform_data;
++	struct platform_device *pdev;
++	struct gpio_keys_platform_data gkpdata;
++	struct gpio_keys_button *bt;
++	int i;
++
++	if (!sc->gpiochip)
++		return;
++
++	if (!pdata || !pdata->btns || !pdata->num_btns)
++		return;
++
++	bt = devm_kmemdup(sc->dev, pdata->btns,
++			  pdata->num_btns * sizeof(struct gpio_keys_button),
++			  GFP_KERNEL);
++	if (!bt)
++		return;
++
++	for (i = 0; i < pdata->num_btns; i++) {
++		ath9k_hw_cfg_gpio_input(sc->sc_ah, pdata->btns[i].gpio);
++		bt[i].gpio = sc->gpiochip->gchip.base + pdata->btns[i].gpio;
++	}
++
++	memset(&gkpdata, 0, sizeof(struct gpio_keys_platform_data));
++	gkpdata.buttons = bt;
++	gkpdata.nbuttons = pdata->num_btns;
++	gkpdata.poll_interval = pdata->btn_poll_interval;
++
++	pdev = platform_device_register_data(sc->dev, "gpio-keys-polled",
++					     PLATFORM_DEVID_AUTO, &gkpdata,
++					     sizeof(gkpdata));
++	if (!IS_ERR_OR_NULL(pdev))
++		sc->btnpdev = pdev;
++	else {
++		sc->btnpdev = NULL;
++		devm_kfree(sc->dev, bt);
++	}
++}
++
++/* remove GPIO buttons */
++static void ath9k_deinit_buttons(struct ath_softc *sc)
++{
++	if (!sc->gpiochip || !sc->btnpdev)
++		return;
++
++	platform_device_unregister(sc->btnpdev);
++
++	sc->btnpdev = NULL;
++}
++
+ #else /* CONFIG_GPIOLIB */
+ 
+ static inline void ath9k_register_gpio_chip(struct ath_softc *sc)
+@@ -142,6 +201,14 @@ static inline void ath9k_unregister_gpio
+ {
+ }
+ 
++static inline void ath9k_init_buttons(struct ath_softc *sc)
++{
++}
++
++static inline void ath9k_deinit_buttons(struct ath_softc *sc)
++{
++}
++
+ #endif /* CONFIG_GPIOLIB */
+ 
+ /********************************/
+@@ -246,6 +313,7 @@ void ath_deinit_leds(struct ath_softc *s
+ {
+ 	struct ath_led *led;
+ 
++	ath9k_deinit_buttons(sc);
+ 	while (!list_empty(&sc->leds)) {
+ 		led = list_first_entry(&sc->leds, struct ath_led, list);
+ #ifdef CONFIG_GPIOLIB
+@@ -274,6 +342,7 @@ void ath_init_leds(struct ath_softc *sc)
+ 		return;
+ 
+ 	ath9k_register_gpio_chip(sc);
++	ath9k_init_buttons(sc);
+ 
+ 	if (pdata && pdata->led_name)
+ 		strncpy(led_name, pdata->led_name, sizeof(led_name));
+@@ -289,7 +358,7 @@ void ath_init_leds(struct ath_softc *sc)
+ 	ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger,
+ 			    !sc->sc_ah->config.led_active_high);
+ 
+-	if (!pdata)
++	if (!pdata || !pdata->leds || !pdata->num_leds)
+ 		return;
+ 
+ 	for (i = 0; i < pdata->num_leds; i++)
+--- a/include/linux/ath9k_platform.h
++++ b/include/linux/ath9k_platform.h
+@@ -46,6 +46,10 @@ struct ath9k_platform_data {
+ 	int num_leds;
+ 	const struct gpio_led *leds;
+ 	const char *led_name;
++
++	unsigned num_btns;
++	const struct gpio_keys_button *btns;
++	unsigned btn_poll_interval;
+ };
+ 
+ #endif /* _LINUX_ATH9K_PLATFORM_H */
diff --git a/package/kernel/mac80211/patches/549-ath9k_enable_gpio_chip.patch b/package/kernel/mac80211/patches/549-ath9k_enable_gpio_chip.patch
deleted file mode 100644
index 55bb991183..0000000000
--- a/package/kernel/mac80211/patches/549-ath9k_enable_gpio_chip.patch
+++ /dev/null
@@ -1,243 +0,0 @@
-From: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
-Date: Sun, 31 Jan 2016 21:01:31 +0100
-Subject: [PATCH v4 4/8] mac80211: ath9k: enable access to GPIO
-
-Enable access to GPIO chip and its pins for Atheros AR92xx
-wireless devices. For now AR9285 and AR9287 are supported.
-
-Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
----
- ath9k.h |   23 ++++++++++++
- gpio.c  |  121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- init.c  |    2 +
- 3 files changed, 146 insertions(+)
-
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -24,6 +24,7 @@
- #include <linux/completion.h>
- #include <linux/time.h>
- #include <linux/hw_random.h>
-+#include <linux/gpio/driver.h>
- 
- #include "common.h"
- #include "debug.h"
-@@ -817,6 +818,13 @@ void ath_fill_led_pin(struct ath_softc *
- int ath_create_gpio_led(struct ath_softc *sc, int gpio, const char *name,
-                         const char *trigger, bool active_low);
- 
-+/***************/
-+/*  GPIO Chip  */
-+/***************/
-+
-+void ath9k_register_gpio_chip(struct ath_softc *sc);
-+void ath9k_unregister_gpio_chip(struct ath_softc *sc);
-+
- #else
- static inline void ath_init_leds(struct ath_softc *sc)
- {
-@@ -828,6 +836,14 @@ static inline void ath_deinit_leds(struc
- static inline void ath_fill_led_pin(struct ath_softc *sc)
- {
- }
-+
-+static inline void ath9k_register_gpio_chip(struct ath_softc *sc)
-+{
-+}
-+
-+static inline void ath9k_unregister_gpio_chip(struct ath_softc *sc)
-+{
-+}
- #endif
- 
- /************************/
-@@ -963,6 +979,12 @@ struct ath_led {
- 	struct led_classdev cdev;
- };
- 
-+struct ath9k_gpio_chip {
-+	struct ath_softc *sc;
-+	char label[32];
-+	struct gpio_chip gchip;
-+};
-+
- struct ath_softc {
- 	struct ieee80211_hw *hw;
- 	struct device *dev;
-@@ -1017,6 +1039,7 @@ struct ath_softc {
- #ifdef CPTCFG_MAC80211_LEDS
- 	const char *led_default_trigger;
- 	struct list_head leds;
-+	struct ath9k_gpio_chip *gpiochip;
- #endif
- 
- #ifdef CPTCFG_ATH9K_DEBUGFS
---- a/drivers/net/wireless/ath/ath9k/gpio.c
-+++ b/drivers/net/wireless/ath/ath9k/gpio.c
-@@ -22,6 +22,9 @@
- /********************************/
- 
- #ifdef CPTCFG_MAC80211_LEDS
-+
-+#include <asm-generic/gpio.h>
-+
- static void ath_led_brightness(struct led_classdev *led_cdev,
- 			       enum led_brightness brightness)
- {
-@@ -60,6 +63,10 @@ static int ath_add_led(struct ath_softc
- 	else
- 		ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
- 
-+	/* If there is GPIO chip configured, reserve LED pin */
-+	if (sc->gpiochip)
-+		gpio_request(sc->gpiochip->gchip.base + gpio->gpio, gpio->name);
-+
- 	return 0;
- }
- 
-@@ -116,6 +123,9 @@ void ath_deinit_leds(struct ath_softc *s
- 
- 	while (!list_empty(&sc->leds)) {
- 		led = list_first_entry(&sc->leds, struct ath_led, list);
-+		/* If there is GPIO chip configured, free LED pin */
-+		if (sc->gpiochip)
-+			gpio_free(sc->gpiochip->gchip.base + led->gpio->gpio);
- 		list_del(&led->list);
- 		ath_led_brightness(&led->cdev, LED_OFF);
- 		led_classdev_unregister(&led->cdev);
-@@ -186,6 +196,117 @@ void ath_fill_led_pin(struct ath_softc *
- 	/* LED off, active low */
- 	ath9k_hw_set_gpio(ah, ah->led_pin, (ah->config.led_active_high) ? 0 : 1);
- }
-+
-+/***************/
-+/*  GPIO Chip  */
-+/***************/
-+
-+/* gpio_chip handler : set GPIO to input */
-+static int ath9k_gpio_pin_cfg_input(struct gpio_chip *chip, unsigned offset)
-+{
-+	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
-+						  gchip);
-+
-+	ath9k_hw_cfg_gpio_input(gc->sc->sc_ah, offset);
-+
-+	return 0;
-+}
-+
-+/* gpio_chip handler : set GPIO to output */
-+static int ath9k_gpio_pin_cfg_output(struct gpio_chip *chip, unsigned offset,
-+				     int value)
-+{
-+	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
-+						  gchip);
-+
-+	ath9k_hw_cfg_output(gc->sc->sc_ah, offset,
-+			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-+	ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value);
-+
-+	return 0;
-+}
-+
-+/* gpio_chip handler : query GPIO direction (0=out, 1=in) */
-+static int ath9k_gpio_pin_get_dir(struct gpio_chip *chip, unsigned offset)
-+{
-+	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
-+						  gchip);
-+	struct ath_hw *ah = gc->sc->sc_ah;
-+
-+	return !((REG_READ(ah, AR_GPIO_OE_OUT) >> (offset * 2)) & 3);
-+}
-+
-+/* gpio_chip handler : get GPIO pin value */
-+static int ath9k_gpio_pin_get(struct gpio_chip *chip, unsigned offset)
-+{
-+	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
-+						  gchip);
-+
-+	return ath9k_hw_gpio_get(gc->sc->sc_ah, offset);
-+}
-+
-+/* gpio_chip handler : set GPIO pin to value */
-+static void ath9k_gpio_pin_set(struct gpio_chip *chip, unsigned offset,
-+			       int value)
-+{
-+	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
-+						  gchip);
-+
-+	ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value);
-+}
-+
-+/* register GPIO chip */
-+void ath9k_register_gpio_chip(struct ath_softc *sc)
-+{
-+	struct ath9k_gpio_chip *gc;
-+	u16 ng;
-+
-+	/* for now only AR9285 and AR9287 are recognized */
-+	if (AR_SREV_9287(sc->sc_ah))
-+		ng = AR9287_NUM_GPIO;
-+	else if (AR_SREV_9285(sc->sc_ah))
-+		ng = AR9285_NUM_GPIO;
-+	else
-+		return;
-+
-+	gc = kzalloc(sizeof(struct ath9k_gpio_chip), GFP_KERNEL);
-+	if (!gc)
-+		return;
-+
-+	snprintf(gc->label, sizeof(gc->label), "ath9k-%s",
-+		 wiphy_name(sc->hw->wiphy));
-+	gc->gchip.label = gc->label;
-+	gc->gchip.base = -1;	/* determine base automatically */
-+	gc->gchip.ngpio = ng;
-+	gc->gchip.direction_input = ath9k_gpio_pin_cfg_input;
-+	gc->gchip.direction_output = ath9k_gpio_pin_cfg_output;
-+	gc->gchip.get_direction = ath9k_gpio_pin_get_dir;
-+	gc->gchip.get = ath9k_gpio_pin_get;
-+	gc->gchip.set = ath9k_gpio_pin_set;
-+	gc->gchip.owner = THIS_MODULE;
-+
-+	if (gpiochip_add(&gc->gchip)) {
-+		kfree(gc);
-+		return;
-+	}
-+
-+	sc->gpiochip = gc;
-+	gc->sc = sc;
-+}
-+
-+/* remove GPIO chip */
-+void ath9k_unregister_gpio_chip(struct ath_softc *sc)
-+{
-+	struct ath9k_gpio_chip *gc = sc->gpiochip;
-+
-+	if (!gc)
-+		return;
-+
-+	gpiochip_remove(&gc->gchip);
-+	kfree(gc);
-+	sc->gpiochip = NULL;
-+}
-+
- #endif
- 
- /*******************/
---- a/drivers/net/wireless/ath/ath9k/init.c
-+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -975,6 +975,7 @@ int ath9k_init_device(u16 devid, struct
- 			goto debug_cleanup;
- 	}
- 
-+	ath9k_register_gpio_chip(sc);
- 	ath_init_leds(sc);
- 	ath_start_rfkill_poll(sc);
- 
-@@ -1022,6 +1023,7 @@ void ath9k_deinit_device(struct ath_soft
- 
- 	wiphy_rfkill_stop_polling(sc->hw->wiphy);
- 	ath_deinit_leds(sc);
-+	ath9k_unregister_gpio_chip(sc);
- 
- 	ath9k_ps_restore(sc);
- 
diff --git a/package/kernel/mac80211/patches/550-ath9k_enable_gpio_buttons.patch b/package/kernel/mac80211/patches/550-ath9k_enable_gpio_buttons.patch
deleted file mode 100644
index e3a8cece94..0000000000
--- a/package/kernel/mac80211/patches/550-ath9k_enable_gpio_buttons.patch
+++ /dev/null
@@ -1,169 +0,0 @@
-From: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
-Subject: [PATCH v5 5/8] mac80211: ath9k: enable GPIO buttons
-
-Enable platform-defined GPIO button support for ath9k device.
-Key poller is activated for attached platform buttons.
-Requires ath9k GPIO chip access.
-
-Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
----
- drivers/net/wireless/ath/ath9k/ath9k.h |   16 ++++++
- drivers/net/wireless/ath/ath9k/gpio.c  |   77 +++++++++++++++++++++++++++++++++
- drivers/net/wireless/ath/ath9k/init.c  |    2 
- include/linux/ath9k_platform.h         |    4 +
- 4 files changed, 99 insertions(+)
-
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -825,6 +825,13 @@ int ath_create_gpio_led(struct ath_softc
- void ath9k_register_gpio_chip(struct ath_softc *sc);
- void ath9k_unregister_gpio_chip(struct ath_softc *sc);
- 
-+/******************/
-+/*  GPIO Buttons  */
-+/******************/
-+
-+void ath9k_init_buttons(struct ath_softc *sc);
-+void ath9k_deinit_buttons(struct ath_softc *sc);
-+
- #else
- static inline void ath_init_leds(struct ath_softc *sc)
- {
-@@ -844,6 +851,14 @@ static inline void ath9k_register_gpio_c
- static inline void ath9k_unregister_gpio_chip(struct ath_softc *sc)
- {
- }
-+
-+static inline void ath9k_init_buttons(struct ath_softc *sc)
-+{
-+}
-+
-+static inline void ath9k_deinit_buttons(struct ath_softc *sc)
-+{
-+}
- #endif
- 
- /************************/
-@@ -1040,6 +1055,7 @@ struct ath_softc {
- 	const char *led_default_trigger;
- 	struct list_head leds;
- 	struct ath9k_gpio_chip *gpiochip;
-+	struct platform_device *btnpdev;	/* gpio-keys-polled */
- #endif
- 
- #ifdef CPTCFG_ATH9K_DEBUGFS
---- a/drivers/net/wireless/ath/ath9k/gpio.c
-+++ b/drivers/net/wireless/ath/ath9k/gpio.c
-@@ -24,6 +24,8 @@
- #ifdef CPTCFG_MAC80211_LEDS
- 
- #include <asm-generic/gpio.h>
-+#include <linux/platform_device.h>
-+#include <linux/gpio_keys.h>
- 
- static void ath_led_brightness(struct led_classdev *led_cdev,
- 			       enum led_brightness brightness)
-@@ -159,7 +161,7 @@ void ath_init_leds(struct ath_softc *sc)
- 	ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger,
- 			    !sc->sc_ah->config.led_active_high);
- 
--	if (!pdata)
-+	if (!pdata || !pdata->leds || !pdata->num_leds)
- 		return;
- 
- 	for (i = 0; i < pdata->num_leds; i++)
-@@ -307,6 +309,63 @@ void ath9k_unregister_gpio_chip(struct a
- 	sc->gpiochip = NULL;
- }
- 
-+/******************/
-+/*  GPIO Buttons  */
-+/******************/
-+
-+/* add GPIO buttons */
-+void ath9k_init_buttons(struct ath_softc *sc)
-+{
-+	struct ath9k_platform_data *pdata = sc->dev->platform_data;
-+	struct platform_device *pdev;
-+	struct gpio_keys_platform_data gkpdata;
-+	struct gpio_keys_button *bt;
-+	int i;
-+
-+	if (!sc->gpiochip)
-+		return;
-+
-+	if (!pdata || !pdata->btns || !pdata->num_btns)
-+		return;
-+
-+	bt = devm_kmemdup(sc->dev, pdata->btns,
-+			  pdata->num_btns * sizeof(struct gpio_keys_button),
-+			  GFP_KERNEL);
-+	if (!bt)
-+		return;
-+
-+	for (i = 0; i < pdata->num_btns; i++) {
-+		ath9k_hw_cfg_gpio_input(sc->sc_ah, pdata->btns[i].gpio);
-+		bt[i].gpio = sc->gpiochip->gchip.base + pdata->btns[i].gpio;
-+	}
-+
-+	memset(&gkpdata, 0, sizeof(struct gpio_keys_platform_data));
-+	gkpdata.buttons = bt;
-+	gkpdata.nbuttons = pdata->num_btns;
-+	gkpdata.poll_interval = pdata->btn_poll_interval;
-+
-+	pdev = platform_device_register_data(sc->dev, "gpio-keys-polled",
-+					     PLATFORM_DEVID_AUTO, &gkpdata,
-+					     sizeof(gkpdata));
-+	if (!IS_ERR_OR_NULL(pdev))
-+		sc->btnpdev = pdev;
-+	else {
-+		sc->btnpdev = NULL;
-+		devm_kfree(sc->dev, bt);
-+	}
-+}
-+
-+/* remove GPIO buttons */
-+void ath9k_deinit_buttons(struct ath_softc *sc)
-+{
-+	if (!sc->gpiochip || !sc->btnpdev)
-+		return;
-+
-+	platform_device_unregister(sc->btnpdev);
-+
-+	sc->btnpdev = NULL;
-+}
-+
- #endif
- 
- /*******************/
---- a/drivers/net/wireless/ath/ath9k/init.c
-+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -977,6 +977,7 @@ int ath9k_init_device(u16 devid, struct
- 
- 	ath9k_register_gpio_chip(sc);
- 	ath_init_leds(sc);
-+	ath9k_init_buttons(sc);
- 	ath_start_rfkill_poll(sc);
- 
- 	return 0;
-@@ -1022,6 +1023,7 @@ void ath9k_deinit_device(struct ath_soft
- 	ath9k_ps_wakeup(sc);
- 
- 	wiphy_rfkill_stop_polling(sc->hw->wiphy);
-+	ath9k_deinit_buttons(sc);
- 	ath_deinit_leds(sc);
- 	ath9k_unregister_gpio_chip(sc);
- 
---- a/include/linux/ath9k_platform.h
-+++ b/include/linux/ath9k_platform.h
-@@ -46,6 +46,10 @@ struct ath9k_platform_data {
- 	int num_leds;
- 	const struct gpio_led *leds;
- 	const char *led_name;
-+
-+	unsigned num_btns;
-+	const struct gpio_keys_button *btns;
-+	unsigned btn_poll_interval;
- };
- 
- #endif /* _LINUX_ATH9K_PLATFORM_H */
-- 
cgit v1.2.3