551-ath9k_ubnt_uap_plus_hsr.patch 11 KB

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