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
5 Enable access to GPIO chip and its pins for Atheros AR92xx
6 wireless devices. For now AR9285 and AR9287 are supported.
8 Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
10 ath9k.h | 23 ++++++++++++
11 gpio.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13 3 files changed, 146 insertions(+)
15 --- a/drivers/net/wireless/ath/ath9k/ath9k.h
16 +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
18 #include <linux/completion.h>
19 #include <linux/time.h>
20 #include <linux/hw_random.h>
21 +#include <linux/gpio/driver.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);
33 +void ath9k_register_gpio_chip(struct ath_softc *sc);
34 +void ath9k_unregister_gpio_chip(struct ath_softc *sc);
37 static inline void ath_init_leds(struct ath_softc *sc)
39 @@ -828,6 +836,14 @@ static inline void ath_deinit_leds(struc
40 static inline void ath_fill_led_pin(struct ath_softc *sc)
44 +static inline void ath9k_register_gpio_chip(struct ath_softc *sc)
48 +static inline void ath9k_unregister_gpio_chip(struct ath_softc *sc)
53 /************************/
54 @@ -963,6 +979,12 @@ struct ath_led {
55 struct led_classdev cdev;
58 +struct ath9k_gpio_chip {
59 + struct ath_softc *sc;
61 + struct gpio_chip gchip;
65 struct ieee80211_hw *hw;
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;
74 #ifdef CPTCFG_ATH9K_DEBUGFS
75 --- a/drivers/net/wireless/ath/ath9k/gpio.c
76 +++ b/drivers/net/wireless/ath/ath9k/gpio.c
78 /********************************/
80 #ifdef CPTCFG_MAC80211_LEDS
82 +#include <asm-generic/gpio.h>
84 static void ath_led_brightness(struct led_classdev *led_cdev,
85 enum led_brightness brightness)
87 @@ -60,6 +63,10 @@ static int ath_add_led(struct ath_softc
89 ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
91 + /* If there is GPIO chip configured, reserve LED pin */
93 + gpio_request(sc->gpiochip->gchip.base + gpio->gpio, gpio->name);
98 @@ -116,6 +123,9 @@ void ath_deinit_leds(struct ath_softc *s
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 */
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);
117 +/* gpio_chip handler : set GPIO to input */
118 +static int ath9k_gpio_pin_cfg_input(struct gpio_chip *chip, unsigned offset)
120 + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
123 + ath9k_hw_cfg_gpio_input(gc->sc->sc_ah, offset);
128 +/* gpio_chip handler : set GPIO to output */
129 +static int ath9k_gpio_pin_cfg_output(struct gpio_chip *chip, unsigned offset,
132 + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
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);
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)
145 + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
147 + struct ath_hw *ah = gc->sc->sc_ah;
149 + return !((REG_READ(ah, AR_GPIO_OE_OUT) >> (offset * 2)) & 3);
152 +/* gpio_chip handler : get GPIO pin value */
153 +static int ath9k_gpio_pin_get(struct gpio_chip *chip, unsigned offset)
155 + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
158 + return ath9k_hw_gpio_get(gc->sc->sc_ah, offset);
161 +/* gpio_chip handler : set GPIO pin to value */
162 +static void ath9k_gpio_pin_set(struct gpio_chip *chip, unsigned offset,
165 + struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
168 + ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value);
171 +/* register GPIO chip */
172 +void ath9k_register_gpio_chip(struct ath_softc *sc)
174 + struct ath9k_gpio_chip *gc;
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;
185 + gc = kzalloc(sizeof(struct ath9k_gpio_chip), GFP_KERNEL);
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;
201 + if (gpiochip_add(&gc->gchip)) {
210 +/* remove GPIO chip */
211 +void ath9k_unregister_gpio_chip(struct ath_softc *sc)
213 + struct ath9k_gpio_chip *gc = sc->gpiochip;
218 + gpiochip_remove(&gc->gchip);
220 + sc->gpiochip = NULL;
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
232 + ath9k_register_gpio_chip(sc);
234 ath_start_rfkill_poll(sc);
236 @@ -1026,6 +1027,7 @@ void ath9k_deinit_device(struct ath_soft
238 wiphy_rfkill_stop_polling(sc->hw->wiphy);
240 + ath9k_unregister_gpio_chip(sc);
242 ath9k_ps_restore(sc);