summaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/550-ath9k_enable_gpio_buttons.patch
blob: e3a8cece94a4f41cd705ab2679fa7c16743a29e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
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 */