beee169fbc1f5b860096b4fa1a2df1c7859b51e3
[openwrt.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