0043-ath9k-add-HSR-tuner-support-for-UniFi-Outdoor-Plus.patch 12 KB

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