beee169fbc1f5b860096b4fa1a2df1c7859b51e3
[openwrt/staging/lynxis/omap.git] / package / kernel / mac80211 / patches / 549-ath9k_enable_gpio_chip.patch
1 From: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
2 Date: Sun, 31 Jan 2016 21:01:31 +0100
3 Subject: [PATCH v4 4/8] mac80211: ath9k: enable access to GPIO
4
5 Enable access to GPIO chip and its pins for Atheros AR92xx
6 wireless devices. For now AR9285 and AR9287 are supported.
7
8 Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
9 ---
10 ath9k.h | 23 ++++++++++++
11 gpio.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12 init.c | 2 +
13 3 files changed, 146 insertions(+)
14
15 --- a/drivers/net/wireless/ath/ath9k/ath9k.h
16 +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
17 @@ -24,6 +24,7 @@
18 #include <linux/completion.h>
19 #include <linux/time.h>
20 #include <linux/hw_random.h>
21 +#include <linux/gpio/driver.h>
22
23 #include "common.h"
24 #include "debug.h"
25 @@ -817,6 +818,13 @@ void ath_fill_led_pin(struct ath_softc *
26 int ath_create_gpio_led(struct ath_softc *sc, int gpio, const char *name,
27 const char *trigger, bool active_low);
28
29 +/***************/
30 +/* GPIO Chip */
31 +/***************/
32 +
33 +void ath9k_register_gpio_chip(struct ath_softc *sc);
34 +void ath9k_unregister_gpio_chip(struct ath_softc *sc);
35 +
36 #else
37 static inline void ath_init_leds(struct ath_softc *sc)
38 {
39 @@ -828,6 +836,14 @@ static inline void ath_deinit_leds(struc
40 static inline void ath_fill_led_pin(struct ath_softc *sc)
41 {
42 }
43 +
44 +static inline void ath9k_register_gpio_chip(struct ath_softc *sc)
45 +{
46 +}
47 +
48 +static inline void ath9k_unregister_gpio_chip(struct ath_softc *sc)
49 +{
50 +}
51 #endif
52
53 /************************/
54 @@ -963,6 +979,12 @@ struct ath_led {
55 struct led_classdev cdev;
56 };
57
58 +struct ath9k_gpio_chip {
59 + struct ath_softc *sc;
60 + char label[32];
61 + struct gpio_chip gchip;
62 +};
63 +
64 struct ath_softc {
65 struct ieee80211_hw *hw;
66 struct device *dev;
67 @@ -1017,6 +1039,7 @@ struct ath_softc {
68 #ifdef CPTCFG_MAC80211_LEDS
69 const char *led_default_trigger;
70 struct list_head leds;
71 + struct ath9k_gpio_chip *gpiochip;
72 #endif
73
74 #ifdef CPTCFG_ATH9K_DEBUGFS
75 --- a/drivers/net/wireless/ath/ath9k/gpio.c
76 +++ b/drivers/net/wireless/ath/ath9k/gpio.c
77 @@ -22,6 +22,9 @@
78 /********************************/
79
80 #ifdef CPTCFG_MAC80211_LEDS
81 +
82 +#include <asm-generic/gpio.h>
83 +
84 static void ath_led_brightness(struct led_classdev *led_cdev,
85 enum led_brightness brightness)
86 {
87 @@ -60,6 +63,10 @@ static int ath_add_led(struct ath_softc
88 else
89 ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
90
91 + /* If there is GPIO chip configured, reserve LED pin */
92 + if (sc->gpiochip)
93 + gpio_request(sc->gpiochip->gchip.base + gpio->gpio, gpio->name);
94 +
95 return 0;
96 }
97
98 @@ -116,6 +123,9 @@ void ath_deinit_leds(struct ath_softc *s
99
100 while (!list_empty(&sc->leds)) {
101 led = list_first_entry(&sc->leds, struct ath_led, list);
102 + /* If there is GPIO chip configured, free LED pin */
103 + if (sc->gpiochip)
104 + gpio_free(sc->gpiochip->gchip.base + led->gpio->gpio);
105 list_del(&led->list);
106 ath_led_brightness(&led->cdev, LED_OFF);
107 led_classdev_unregister(&led->cdev);
108 @@ -186,6 +196,117 @@ void ath_fill_led_pin(struct ath_softc *
109 /* LED off, active low */
110 ath9k_hw_set_gpio(ah, ah->led_pin, (ah->config.led_active_high) ? 0 : 1);
111 }
112 +
113 +/***************/
114 +/* GPIO Chip */
115 +/***************/
116 +
117 +/* gpio_chip handler : set GPIO to input */
118 +static int ath9k_gpio_pin_cfg_input(struct gpio_chip *chip, unsigned offset)
119 +{
120 + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
121 + gchip);
122 +
123 + ath9k_hw_cfg_gpio_input(gc->sc->sc_ah, offset);
124 +
125 + return 0;
126 +}
127 +
128 +/* gpio_chip handler : set GPIO to output */
129 +static int ath9k_gpio_pin_cfg_output(struct gpio_chip *chip, unsigned offset,
130 + int value)
131 +{
132 + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
133 + gchip);
134 +
135 + ath9k_hw_cfg_output(gc->sc->sc_ah, offset,
136 + AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
137 + ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value);
138 +
139 + return 0;
140 +}
141 +
142 +/* gpio_chip handler : query GPIO direction (0=out, 1=in) */
143 +static int ath9k_gpio_pin_get_dir(struct gpio_chip *chip, unsigned offset)
144 +{
145 + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
146 + gchip);
147 + struct ath_hw *ah = gc->sc->sc_ah;
148 +
149 + return !((REG_READ(ah, AR_GPIO_OE_OUT) >> (offset * 2)) & 3);
150 +}
151 +
152 +/* gpio_chip handler : get GPIO pin value */
153 +static int ath9k_gpio_pin_get(struct gpio_chip *chip, unsigned offset)
154 +{
155 + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
156 + gchip);
157 +
158 + return ath9k_hw_gpio_get(gc->sc->sc_ah, offset);
159 +}
160 +
161 +/* gpio_chip handler : set GPIO pin to value */
162 +static void ath9k_gpio_pin_set(struct gpio_chip *chip, unsigned offset,
163 + int value)
164 +{
165 + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
166 + gchip);
167 +
168 + ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value);
169 +}
170 +
171 +/* register GPIO chip */
172 +void ath9k_register_gpio_chip(struct ath_softc *sc)
173 +{
174 + struct ath9k_gpio_chip *gc;
175 + u16 ng;
176 +
177 + /* for now only AR9285 and AR9287 are recognized */
178 + if (AR_SREV_9287(sc->sc_ah))
179 + ng = AR9287_NUM_GPIO;
180 + else if (AR_SREV_9285(sc->sc_ah))
181 + ng = AR9285_NUM_GPIO;
182 + else
183 + return;
184 +
185 + gc = kzalloc(sizeof(struct ath9k_gpio_chip), GFP_KERNEL);
186 + if (!gc)
187 + return;
188 +
189 + snprintf(gc->label, sizeof(gc->label), "ath9k-%s",
190 + wiphy_name(sc->hw->wiphy));
191 + gc->gchip.label = gc->label;
192 + gc->gchip.base = -1; /* determine base automatically */
193 + gc->gchip.ngpio = ng;
194 + gc->gchip.direction_input = ath9k_gpio_pin_cfg_input;
195 + gc->gchip.direction_output = ath9k_gpio_pin_cfg_output;
196 + gc->gchip.get_direction = ath9k_gpio_pin_get_dir;
197 + gc->gchip.get = ath9k_gpio_pin_get;
198 + gc->gchip.set = ath9k_gpio_pin_set;
199 + gc->gchip.owner = THIS_MODULE;
200 +
201 + if (gpiochip_add(&gc->gchip)) {
202 + kfree(gc);
203 + return;
204 + }
205 +
206 + sc->gpiochip = gc;
207 + gc->sc = sc;
208 +}
209 +
210 +/* remove GPIO chip */
211 +void ath9k_unregister_gpio_chip(struct ath_softc *sc)
212 +{
213 + struct ath9k_gpio_chip *gc = sc->gpiochip;
214 +
215 + if (!gc)
216 + return;
217 +
218 + gpiochip_remove(&gc->gchip);
219 + kfree(gc);
220 + sc->gpiochip = NULL;
221 +}
222 +
223 #endif
224
225 /*******************/
226 --- a/drivers/net/wireless/ath/ath9k/init.c
227 +++ b/drivers/net/wireless/ath/ath9k/init.c
228 @@ -979,6 +979,7 @@ int ath9k_init_device(u16 devid, struct
229 goto debug_cleanup;
230 }
231
232 + ath9k_register_gpio_chip(sc);
233 ath_init_leds(sc);
234 ath_start_rfkill_poll(sc);
235
236 @@ -1026,6 +1027,7 @@ void ath9k_deinit_device(struct ath_soft
237
238 wiphy_rfkill_stop_polling(sc->hw->wiphy);
239 ath_deinit_leds(sc);
240 + ath9k_unregister_gpio_chip(sc);
241
242 ath9k_ps_restore(sc);
243