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

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