560-ath9k_ubnt_uap_plus_hsr.patch 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. --- a/drivers/net/wireless/ath/ath9k/channel.c
  2. +++ b/drivers/net/wireless/ath/ath9k/channel.c
  3. @@ -15,6 +15,8 @@
  4. */
  5. #include "ath9k.h"
  6. +#include <linux/ath9k_platform.h>
  7. +#include "hsr.h"
  8. /* Set/change channels. If the channel is really being changed, it's done
  9. * by reseting the chip. To accomplish this we must first cleanup any pending
  10. @@ -22,6 +24,7 @@
  11. */
  12. static int ath_set_channel(struct ath_softc *sc)
  13. {
  14. + struct ath9k_platform_data *pdata = sc->dev->platform_data;
  15. struct ath_hw *ah = sc->sc_ah;
  16. struct ath_common *common = ath9k_hw_common(ah);
  17. struct ieee80211_hw *hw = sc->hw;
  18. @@ -41,6 +44,11 @@ static int ath_set_channel(struct ath_so
  19. ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
  20. chan->center_freq, chandef->width);
  21. + if (pdata && pdata->ubnt_hsr) {
  22. + ath9k_hsr_enable(ah, chandef->width, chan->center_freq);
  23. + ath9k_hsr_status(ah);
  24. + }
  25. +
  26. /* update survey stats for the old channel before switching */
  27. spin_lock_bh(&common->cc_lock);
  28. ath_update_survey_stats(sc);
  29. --- /dev/null
  30. +++ b/drivers/net/wireless/ath/ath9k/hsr.c
  31. @@ -0,0 +1,247 @@
  32. +/*
  33. + *
  34. + * The MIT License (MIT)
  35. + *
  36. + * Copyright (c) 2015 Kirill Berezin
  37. + *
  38. + * Permission is hereby granted, free of charge, to any person obtaining a copy
  39. + * of this software and associated documentation files (the "Software"), to deal
  40. + * in the Software without restriction, including without limitation the rights
  41. + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  42. + * copies of the Software, and to permit persons to whom the Software is
  43. + * furnished to do so, subject to the following conditions:
  44. + *
  45. + * The above copyright notice and this permission notice shall be included in
  46. + * all copies or substantial portions of the Software.
  47. + *
  48. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  49. + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  50. + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  51. + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  52. + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  53. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  54. + * SOFTWARE.
  55. + *
  56. + */
  57. +
  58. +#include <linux/io.h>
  59. +#include <linux/slab.h>
  60. +#include <linux/module.h>
  61. +#include <linux/time.h>
  62. +#include <linux/bitops.h>
  63. +#include <linux/etherdevice.h>
  64. +#include <linux/rtnetlink.h>
  65. +#include <asm/unaligned.h>
  66. +
  67. +#include "hw.h"
  68. +#include "ath9k.h"
  69. +
  70. +#define HSR_GPIO_CSN 8
  71. +#define HSR_GPIO_CLK 6
  72. +#define HSR_GPIO_DOUT 7
  73. +#define HSR_GPIO_DIN 5
  74. +
  75. +/* delays are in useconds */
  76. +#define HSR_DELAY_HALF_TICK 100
  77. +#define HSR_DELAY_PRE_WRITE 75
  78. +#define HSR_DELAY_FINAL 20000
  79. +#define HSR_DELAY_TRAILING 200
  80. +
  81. +void ath9k_hsr_init(struct ath_hw *ah)
  82. +{
  83. + ath9k_hw_gpio_request_in(ah, HSR_GPIO_DIN, NULL);
  84. + ath9k_hw_gpio_request_out(ah, HSR_GPIO_CSN, NULL,
  85. + AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
  86. + ath9k_hw_gpio_request_out(ah, HSR_GPIO_CLK, NULL,
  87. + AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
  88. + ath9k_hw_gpio_request_out(ah, HSR_GPIO_DOUT, NULL,
  89. + AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
  90. +
  91. + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1);
  92. + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
  93. + ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, 0);
  94. +
  95. + udelay(HSR_DELAY_TRAILING);
  96. +}
  97. +
  98. +static u32 ath9k_hsr_write_byte(struct ath_hw *ah, int delay, u32 value)
  99. +{
  100. + struct ath_common *common = ath9k_hw_common(ah);
  101. + int i;
  102. + u32 rval = 0;
  103. +
  104. + udelay(delay);
  105. +
  106. + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
  107. + udelay(HSR_DELAY_HALF_TICK);
  108. +
  109. + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 0);
  110. + udelay(HSR_DELAY_HALF_TICK);
  111. +
  112. + for (i = 0; i < 8; ++i) {
  113. + rval = rval << 1;
  114. +
  115. + /* pattern is left to right, that is 7-th bit runs first */
  116. + ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, (value >> (7 - i)) & 0x1);
  117. + udelay(HSR_DELAY_HALF_TICK);
  118. +
  119. + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 1);
  120. + udelay(HSR_DELAY_HALF_TICK);
  121. +
  122. + rval |= ath9k_hw_gpio_get(ah, HSR_GPIO_DIN);
  123. +
  124. + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
  125. + udelay(HSR_DELAY_HALF_TICK);
  126. + }
  127. +
  128. + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1);
  129. + udelay(HSR_DELAY_HALF_TICK);
  130. +
  131. + ath_dbg(common, CONFIG, "ath9k_hsr_write_byte: write byte %d return value is %d %c\n",
  132. + value, rval, rval > 32 ? rval : '-');
  133. +
  134. + return rval & 0xff;
  135. +}
  136. +
  137. +static int ath9k_hsr_write_a_chain(struct ath_hw *ah, char *chain, int items)
  138. +{
  139. + int status = 0;
  140. + int i = 0;
  141. + int err;
  142. +
  143. + /* a preamble */
  144. + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
  145. + status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
  146. +
  147. + /* clear HSR's reply buffer */
  148. + if (status) {
  149. + int loop = 0;
  150. +
  151. + for (loop = 0; (loop < 42) && status; ++loop)
  152. + status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE,
  153. + 0);
  154. +
  155. + if (loop >= 42) {
  156. + ATH_DBG_WARN(1,
  157. + "ath9k_hsr_write_a_chain: can't clear an output buffer after a 42 cycles.\n");
  158. + return -1;
  159. + }
  160. + }
  161. +
  162. + for (i = 0; (i < items) && (chain[i] != 0); ++i)
  163. + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, (u32)chain[i]);
  164. +
  165. + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
  166. + mdelay(HSR_DELAY_FINAL / 1000);
  167. +
  168. + /* reply */
  169. + memset(chain, 0, items);
  170. +
  171. + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
  172. + udelay(HSR_DELAY_TRAILING);
  173. +
  174. + for (i = 0; i < (items - 1); ++i) {
  175. + u32 ret;
  176. +
  177. + ret = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
  178. + if (ret != 0)
  179. + chain[i] = (char)ret;
  180. + else
  181. + break;
  182. +
  183. + udelay(HSR_DELAY_TRAILING);
  184. + }
  185. +
  186. + if (i <= 1)
  187. + return 0;
  188. +
  189. + err = kstrtoint(chain + 1, 10, &i);
  190. + if (err)
  191. + return err;
  192. +
  193. + return i;
  194. +}
  195. +
  196. +int ath9k_hsr_disable(struct ath_hw *ah)
  197. +{
  198. + char cmd[10] = {'b', '4', '0', 0, 0, 0, 0, 0, 0, 0};
  199. + int ret;
  200. +
  201. + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
  202. + if ((ret > 0) && (*cmd == 'B'))
  203. + return 0;
  204. +
  205. + return -1;
  206. +}
  207. +
  208. +int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq)
  209. +{
  210. + char cmd[10];
  211. + int ret;
  212. +
  213. + /* Bandwidth argument is 0 sometimes. Assume default 802.11bgn
  214. + * 20MHz on invalid values
  215. + */
  216. + if ((bw != 5) && (bw != 10) && (bw != 20) && (bw != 40))
  217. + bw = 20;
  218. +
  219. + memset(cmd, 0, sizeof(cmd));
  220. + *cmd = 'b';
  221. + snprintf(cmd + 1, 3, "%02d", bw);
  222. +
  223. + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
  224. + if ((*cmd != 'B') || (ret != bw)) {
  225. + ATH_DBG_WARN(1,
  226. + "ath9k_hsr_enable: failed changing bandwidth -> set (%d,%d) reply (%d, %d)\n",
  227. + 'b', bw, *cmd, ret);
  228. + return -1;
  229. + }
  230. +
  231. + memset(cmd, 0, sizeof(cmd));
  232. + *cmd = 'x';
  233. + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
  234. + if (*cmd != 'X') {
  235. + ATH_DBG_WARN(1,
  236. + "ath9k_hsr_enable: failed 'x' command -> reply (%d, %d)\n",
  237. + *cmd, ret);
  238. + return -1;
  239. + }
  240. +
  241. + memset(cmd, 0, sizeof(cmd));
  242. + *cmd = 'm';
  243. + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
  244. + if (*cmd != 'M') {
  245. + ATH_DBG_WARN(1,
  246. + "ath9k_hsr_enable: failed 'm' command -> reply (%d, %d)\n",
  247. + *cmd, ret);
  248. + return -1;
  249. + }
  250. +
  251. + memset(cmd, 0, sizeof(cmd));
  252. + *cmd = 'f';
  253. + snprintf(cmd + 1, 6, "%05d", fq);
  254. + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
  255. + if ((*cmd != 'F') && (ret != fq)) {
  256. + ATH_DBG_WARN(1,
  257. + "ath9k_hsr_enable: failed set frequency -> reply (%d, %d)\n",
  258. + *cmd, ret);
  259. + return -1;
  260. + }
  261. +
  262. + return 0;
  263. +}
  264. +
  265. +int ath9k_hsr_status(struct ath_hw *ah)
  266. +{
  267. + char cmd[10] = {'s', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  268. + int ret;
  269. +
  270. + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
  271. + if (*cmd != 'S') {
  272. + ATH_DBG_WARN(1, "ath9k_hsr_status: returned %d,%d\n", *cmd,
  273. + ret);
  274. + return -1;
  275. + }
  276. +
  277. + return 0;
  278. +}
  279. --- /dev/null
  280. +++ b/drivers/net/wireless/ath/ath9k/hsr.h
  281. @@ -0,0 +1,48 @@
  282. +/*
  283. + * The MIT License (MIT)
  284. + *
  285. + * Copyright (c) 2015 Kirill Berezin
  286. + *
  287. + * Permission is hereby granted, free of charge, to any person obtaining a copy
  288. + * of this software and associated documentation files (the "Software"), to deal
  289. + * in the Software without restriction, including without limitation the rights
  290. + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  291. + * copies of the Software, and to permit persons to whom the Software is
  292. + * furnished to do so, subject to the following conditions:
  293. + *
  294. + * The above copyright notice and this permission notice shall be included in
  295. + * all copies or substantial portions of the Software.
  296. + *
  297. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  298. + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  299. + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  300. + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  301. + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  302. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  303. + * SOFTWARE.
  304. + */
  305. +
  306. +#ifndef HSR_H
  307. +#define HSR_H
  308. +
  309. +#ifdef CPTCFG_ATH9K_UBNTHSR
  310. +
  311. +void ath9k_hsr_init(struct ath_hw *ah);
  312. +int ath9k_hsr_disable(struct ath_hw *ah);
  313. +int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq);
  314. +int ath9k_hsr_status(struct ath_hw *ah);
  315. +
  316. +#else
  317. +static inline void ath9k_hsr_init(struct ath_hw *ah) {}
  318. +
  319. +static inline int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq)
  320. +{
  321. + return 0;
  322. +}
  323. +
  324. +static inline int ath9k_hsr_disable(struct ath_hw *ah) { return 0; }
  325. +static inline int ath9k_hsr_status(struct ath_hw *ah) { return 0; }
  326. +
  327. +#endif
  328. +
  329. +#endif /* HSR_H */
  330. --- a/drivers/net/wireless/ath/ath9k/main.c
  331. +++ b/drivers/net/wireless/ath/ath9k/main.c
  332. @@ -16,8 +16,10 @@
  333. #include <linux/nl80211.h>
  334. #include <linux/delay.h>
  335. +#include <linux/ath9k_platform.h>
  336. #include "ath9k.h"
  337. #include "btcoex.h"
  338. +#include "hsr.h"
  339. u8 ath9k_parse_mpdudensity(u8 mpdudensity)
  340. {
  341. @@ -652,6 +654,7 @@ void ath_reset_work(struct work_struct *
  342. static int ath9k_start(struct ieee80211_hw *hw)
  343. {
  344. struct ath_softc *sc = hw->priv;
  345. + struct ath9k_platform_data *pdata = sc->dev->platform_data;
  346. struct ath_hw *ah = sc->sc_ah;
  347. struct ath_common *common = ath9k_hw_common(ah);
  348. struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan;
  349. @@ -730,6 +733,11 @@ static int ath9k_start(struct ieee80211_
  350. AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
  351. }
  352. + if (pdata && pdata->ubnt_hsr) {
  353. + ath9k_hsr_init(ah);
  354. + ath9k_hsr_disable(ah);
  355. + }
  356. +
  357. /*
  358. * Reset key cache to sane defaults (all entries cleared) instead of
  359. * semi-random values after suspend/resume.
  360. --- a/drivers/net/wireless/ath/ath9k/Makefile
  361. +++ b/drivers/net/wireless/ath/ath9k/Makefile
  362. @@ -16,6 +16,7 @@ ath9k-$(CPTCFG_ATH9K_DFS_CERTIFIED) += d
  363. ath9k-$(CPTCFG_ATH9K_TX99) += tx99.o
  364. ath9k-$(CPTCFG_ATH9K_WOW) += wow.o
  365. ath9k-$(CPTCFG_ATH9K_HWRNG) += rng.o
  366. +ath9k-$(CPTCFG_ATH9K_UBNTHSR) += hsr.o
  367. ath9k-$(CPTCFG_ATH9K_DEBUGFS) += debug.o
  368. --- a/include/linux/ath9k_platform.h
  369. +++ b/include/linux/ath9k_platform.h
  370. @@ -54,6 +54,8 @@ struct ath9k_platform_data {
  371. unsigned num_btns;
  372. const struct gpio_keys_button *btns;
  373. unsigned btn_poll_interval;
  374. +
  375. + bool ubnt_hsr;
  376. };
  377. #endif /* _LINUX_ATH9K_PLATFORM_H */
  378. --- a/.local-symbols
  379. +++ b/.local-symbols
  380. @@ -153,6 +153,7 @@ ATH9K_WOW=
  381. ATH9K_RFKILL=
  382. ATH9K_CHANNEL_CONTEXT=
  383. ATH9K_PCOEM=
  384. +ATH9K_UBNTHSR=
  385. ATH9K_HTC=
  386. ATH9K_HTC_DEBUGFS=
  387. ATH9K_HWRNG=
  388. --- a/drivers/net/wireless/ath/ath9k/Kconfig
  389. +++ b/drivers/net/wireless/ath/ath9k/Kconfig
  390. @@ -59,6 +59,19 @@ config ATH9K_AHB
  391. Say Y, if you have a SoC with a compatible built-in
  392. wireless MAC. Say N if unsure.
  393. +config ATH9K_UBNTHSR
  394. + bool "Ubiquiti UniFi Outdoor Plus HSR support"
  395. + depends on ATH9K
  396. + ---help---
  397. + This options enables code to control the HSR RF
  398. + filter in the receive path of the Ubiquiti UniFi
  399. + Outdoor Plus access point.
  400. +
  401. + Say Y if you want to use the access point. The
  402. + code will only be used if the device is detected,
  403. + so it does not harm other setup other than occupying
  404. + a bit of memory.
  405. +
  406. config ATH9K_DEBUGFS
  407. bool "Atheros ath9k debugging"
  408. depends on ATH9K && DEBUG_FS