1 --- a/drivers/net/wireless/ath/ath9k/channel.c
2 +++ b/drivers/net/wireless/ath/ath9k/channel.c
7 +#include <linux/ath9k_platform.h>
10 /* Set/change channels. If the channel is really being changed, it's done
11 * by reseting the chip. To accomplish this we must first cleanup any pending
14 static int ath_set_channel(struct ath_softc *sc)
16 + struct ath9k_platform_data *pdata = sc->dev->platform_data;
17 struct ath_hw *ah = sc->sc_ah;
18 struct ath_common *common = ath9k_hw_common(ah);
19 struct ieee80211_hw *hw = sc->hw;
20 @@ -41,6 +44,11 @@ static int ath_set_channel(struct ath_so
21 ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
22 chan->center_freq, chandef->width);
24 + if (pdata && pdata->ubnt_hsr) {
25 + ath9k_hsr_enable(ah, chandef->width, chan->center_freq);
26 + ath9k_hsr_status(ah);
29 /* update survey stats for the old channel before switching */
30 spin_lock_bh(&common->cc_lock);
31 ath_update_survey_stats(sc);
33 +++ b/drivers/net/wireless/ath/ath9k/hsr.c
37 + * The MIT License (MIT)
39 + * Copyright (c) 2015 Kirill Berezin
41 + * Permission is hereby granted, free of charge, to any person obtaining a copy
42 + * of this software and associated documentation files (the "Software"), to deal
43 + * in the Software without restriction, including without limitation the rights
44 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
45 + * copies of the Software, and to permit persons to whom the Software is
46 + * furnished to do so, subject to the following conditions:
48 + * The above copyright notice and this permission notice shall be included in
49 + * all copies or substantial portions of the Software.
51 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
52 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
53 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
54 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
55 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
56 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
61 +#include <linux/io.h>
62 +#include <linux/slab.h>
63 +#include <linux/module.h>
64 +#include <linux/time.h>
65 +#include <linux/bitops.h>
66 +#include <linux/etherdevice.h>
67 +#include <linux/rtnetlink.h>
68 +#include <asm/unaligned.h>
73 +#define HSR_GPIO_CSN 8
74 +#define HSR_GPIO_CLK 6
75 +#define HSR_GPIO_DOUT 7
76 +#define HSR_GPIO_DIN 5
78 +/* delays are in useconds */
79 +#define HSR_DELAY_HALF_TICK 100
80 +#define HSR_DELAY_PRE_WRITE 75
81 +#define HSR_DELAY_FINAL 20000
82 +#define HSR_DELAY_TRAILING 200
84 +void ath9k_hsr_init(struct ath_hw *ah)
86 + ath9k_hw_gpio_request_in(ah, HSR_GPIO_DIN, NULL);
87 + ath9k_hw_gpio_request_out(ah, HSR_GPIO_CSN, NULL,
88 + AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
89 + ath9k_hw_gpio_request_out(ah, HSR_GPIO_CLK, NULL,
90 + AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
91 + ath9k_hw_gpio_request_out(ah, HSR_GPIO_DOUT, NULL,
92 + AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
94 + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1);
95 + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
96 + ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, 0);
98 + udelay(HSR_DELAY_TRAILING);
101 +static u32 ath9k_hsr_write_byte(struct ath_hw *ah, int delay, u32 value)
103 + struct ath_common *common = ath9k_hw_common(ah);
109 + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
110 + udelay(HSR_DELAY_HALF_TICK);
112 + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 0);
113 + udelay(HSR_DELAY_HALF_TICK);
115 + for (i = 0; i < 8; ++i) {
118 + /* pattern is left to right, that is 7-th bit runs first */
119 + ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, (value >> (7 - i)) & 0x1);
120 + udelay(HSR_DELAY_HALF_TICK);
122 + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 1);
123 + udelay(HSR_DELAY_HALF_TICK);
125 + rval |= ath9k_hw_gpio_get(ah, HSR_GPIO_DIN);
127 + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
128 + udelay(HSR_DELAY_HALF_TICK);
131 + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1);
132 + udelay(HSR_DELAY_HALF_TICK);
134 + ath_dbg(common, CONFIG, "ath9k_hsr_write_byte: write byte %d return value is %d %c\n",
135 + value, rval, rval > 32 ? rval : '-');
137 + return rval & 0xff;
140 +static int ath9k_hsr_write_a_chain(struct ath_hw *ah, char *chain, int items)
147 + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
148 + status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
150 + /* clear HSR's reply buffer */
154 + for (loop = 0; (loop < 42) && status; ++loop)
155 + status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE,
160 + "ath9k_hsr_write_a_chain: can't clear an output buffer after a 42 cycles.\n");
165 + for (i = 0; (i < items) && (chain[i] != 0); ++i)
166 + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, (u32)chain[i]);
168 + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
169 + mdelay(HSR_DELAY_FINAL / 1000);
172 + memset(chain, 0, items);
174 + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
175 + udelay(HSR_DELAY_TRAILING);
177 + for (i = 0; i < (items - 1); ++i) {
180 + ret = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
182 + chain[i] = (char)ret;
186 + udelay(HSR_DELAY_TRAILING);
192 + err = kstrtoint(chain + 1, 10, &i);
199 +int ath9k_hsr_disable(struct ath_hw *ah)
201 + char cmd[10] = {'b', '4', '0', 0, 0, 0, 0, 0, 0, 0};
204 + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
205 + if ((ret > 0) && (*cmd == 'B'))
211 +int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq)
216 + /* Bandwidth argument is 0 sometimes. Assume default 802.11bgn
217 + * 20MHz on invalid values
219 + if ((bw != 5) && (bw != 10) && (bw != 20) && (bw != 40))
222 + memset(cmd, 0, sizeof(cmd));
224 + snprintf(cmd + 1, 3, "%02d", bw);
226 + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
227 + if ((*cmd != 'B') || (ret != bw)) {
229 + "ath9k_hsr_enable: failed changing bandwidth -> set (%d,%d) reply (%d, %d)\n",
230 + 'b', bw, *cmd, ret);
234 + memset(cmd, 0, sizeof(cmd));
236 + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
239 + "ath9k_hsr_enable: failed 'x' command -> reply (%d, %d)\n",
244 + memset(cmd, 0, sizeof(cmd));
246 + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
249 + "ath9k_hsr_enable: failed 'm' command -> reply (%d, %d)\n",
254 + memset(cmd, 0, sizeof(cmd));
256 + snprintf(cmd + 1, 6, "%05d", fq);
257 + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
258 + if ((*cmd != 'F') && (ret != fq)) {
260 + "ath9k_hsr_enable: failed set frequency -> reply (%d, %d)\n",
268 +int ath9k_hsr_status(struct ath_hw *ah)
270 + char cmd[10] = {'s', 0, 0, 0, 0, 0, 0, 0, 0, 0};
273 + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
275 + ATH_DBG_WARN(1, "ath9k_hsr_status: returned %d,%d\n", *cmd,
283 +++ b/drivers/net/wireless/ath/ath9k/hsr.h
286 + * The MIT License (MIT)
288 + * Copyright (c) 2015 Kirill Berezin
290 + * Permission is hereby granted, free of charge, to any person obtaining a copy
291 + * of this software and associated documentation files (the "Software"), to deal
292 + * in the Software without restriction, including without limitation the rights
293 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
294 + * copies of the Software, and to permit persons to whom the Software is
295 + * furnished to do so, subject to the following conditions:
297 + * The above copyright notice and this permission notice shall be included in
298 + * all copies or substantial portions of the Software.
300 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
301 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
302 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
303 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
304 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
305 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
312 +#ifdef CPTCFG_ATH9K_UBNTHSR
314 +void ath9k_hsr_init(struct ath_hw *ah);
315 +int ath9k_hsr_disable(struct ath_hw *ah);
316 +int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq);
317 +int ath9k_hsr_status(struct ath_hw *ah);
320 +static inline void ath9k_hsr_init(struct ath_hw *ah) {}
322 +static inline int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq)
327 +static inline int ath9k_hsr_disable(struct ath_hw *ah) { return 0; }
328 +static inline int ath9k_hsr_status(struct ath_hw *ah) { return 0; }
333 --- a/drivers/net/wireless/ath/ath9k/main.c
334 +++ b/drivers/net/wireless/ath/ath9k/main.c
337 #include <linux/nl80211.h>
338 #include <linux/delay.h>
339 +#include <linux/ath9k_platform.h>
344 u8 ath9k_parse_mpdudensity(u8 mpdudensity)
346 @@ -648,6 +650,7 @@ void ath_reset_work(struct work_struct *
347 static int ath9k_start(struct ieee80211_hw *hw)
349 struct ath_softc *sc = hw->priv;
350 + struct ath9k_platform_data *pdata = sc->dev->platform_data;
351 struct ath_hw *ah = sc->sc_ah;
352 struct ath_common *common = ath9k_hw_common(ah);
353 struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan;
354 @@ -726,6 +729,11 @@ static int ath9k_start(struct ieee80211_
355 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
358 + if (pdata && pdata->ubnt_hsr) {
359 + ath9k_hsr_init(ah);
360 + ath9k_hsr_disable(ah);
364 * Reset key cache to sane defaults (all entries cleared) instead of
365 * semi-random values after suspend/resume.
366 --- a/drivers/net/wireless/ath/ath9k/Makefile
367 +++ b/drivers/net/wireless/ath/ath9k/Makefile
368 @@ -16,6 +16,7 @@ ath9k-$(CPTCFG_ATH9K_DFS_CERTIFIED) += d
369 ath9k-$(CPTCFG_ATH9K_TX99) += tx99.o
370 ath9k-$(CPTCFG_ATH9K_WOW) += wow.o
371 ath9k-$(CPTCFG_ATH9K_HWRNG) += rng.o
372 +ath9k-$(CPTCFG_ATH9K_UBNTHSR) += hsr.o
374 ath9k-$(CPTCFG_ATH9K_DEBUGFS) += debug.o
376 --- a/include/linux/ath9k_platform.h
377 +++ b/include/linux/ath9k_platform.h
378 @@ -54,6 +54,8 @@ struct ath9k_platform_data {
380 const struct gpio_keys_button *btns;
381 unsigned btn_poll_interval;
386 #endif /* _LINUX_ATH9K_PLATFORM_H */
389 @@ -157,6 +157,7 @@ ATH9K_WOW=
391 ATH9K_CHANNEL_CONTEXT=
397 --- a/drivers/net/wireless/ath/ath9k/Kconfig
398 +++ b/drivers/net/wireless/ath/ath9k/Kconfig
399 @@ -59,6 +59,19 @@ config ATH9K_AHB
400 Say Y, if you have a SoC with a compatible built-in
401 wireless MAC. Say N if unsure.
403 +config ATH9K_UBNTHSR
404 + bool "Ubiquiti UniFi Outdoor Plus HSR support"
407 + This options enables code to control the HSR RF
408 + filter in the receive path of the Ubiquiti UniFi
409 + Outdoor Plus access point.
411 + Say Y if you want to use the access point. The
412 + code will only be used if the device is detected,
413 + so it does not harm other setup other than occupying
417 bool "Atheros ath9k debugging"
418 depends on ATH9K && DEBUG_FS