antenna.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. /*
  2. * Copyright (c) 2012 Qualcomm Atheros, Inc.
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "ath9k.h"
  17. /*
  18. * AR9285
  19. * ======
  20. *
  21. * EEPROM has 2 4-bit fields containing the card configuration.
  22. *
  23. * antdiv_ctl1:
  24. * ------------
  25. * bb_enable_ant_div_lnadiv : 1
  26. * bb_ant_div_alt_gaintb : 1
  27. * bb_ant_div_main_gaintb : 1
  28. * bb_enable_ant_fast_div : 1
  29. *
  30. * antdiv_ctl2:
  31. * -----------
  32. * bb_ant_div_alt_lnaconf : 2
  33. * bb_ant_div_main_lnaconf : 2
  34. *
  35. * The EEPROM bits are used as follows:
  36. * ------------------------------------
  37. *
  38. * bb_enable_ant_div_lnadiv - Enable LNA path rx antenna diversity/combining.
  39. * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
  40. *
  41. * bb_ant_div_[alt/main]_gaintb - 0 -> Antenna config Alt/Main uses gaintable 0
  42. * 1 -> Antenna config Alt/Main uses gaintable 1
  43. * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
  44. *
  45. * bb_enable_ant_fast_div - Enable fast antenna diversity.
  46. * Set in AR_PHY_CCK_DETECT.
  47. *
  48. * bb_ant_div_[alt/main]_lnaconf - Alt/Main LNA diversity/combining input config.
  49. * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
  50. * 10=LNA1
  51. * 01=LNA2
  52. * 11=LNA1+LNA2
  53. * 00=LNA1-LNA2
  54. *
  55. * AR9485 / AR9565 / AR9331
  56. * ========================
  57. *
  58. * The same bits are present in the EEPROM, but the location in the
  59. * EEPROM is different (ant_div_control in ar9300_BaseExtension_1).
  60. *
  61. * ant_div_alt_lnaconf ==> bit 0~1
  62. * ant_div_main_lnaconf ==> bit 2~3
  63. * ant_div_alt_gaintb ==> bit 4
  64. * ant_div_main_gaintb ==> bit 5
  65. * enable_ant_div_lnadiv ==> bit 6
  66. * enable_ant_fast_div ==> bit 7
  67. */
  68. static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
  69. int mindelta, int main_rssi_avg,
  70. int alt_rssi_avg, int pkt_count)
  71. {
  72. return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
  73. (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
  74. (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
  75. }
  76. static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf,
  77. int alt_ratio, int alt_rssi_avg,
  78. int main_rssi_avg)
  79. {
  80. bool result, set1, set2;
  81. result = set1 = set2 = false;
  82. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2 &&
  83. conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA1)
  84. set1 = true;
  85. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA1 &&
  86. conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  87. set2 = true;
  88. switch (conf->div_group) {
  89. case 0:
  90. if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
  91. result = true;
  92. break;
  93. case 1:
  94. case 2:
  95. if (alt_rssi_avg < 4)
  96. break;
  97. if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 5))) ||
  98. (set2 && (alt_rssi_avg >= (main_rssi_avg - 2))))
  99. result = true;
  100. break;
  101. case 3:
  102. if (alt_rssi_avg < 4)
  103. break;
  104. if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 3))) ||
  105. (set2 && (alt_rssi_avg >= (main_rssi_avg + 3))))
  106. result = true;
  107. break;
  108. }
  109. return result;
  110. }
  111. static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
  112. struct ath_hw_antcomb_conf ant_conf,
  113. int main_rssi_avg)
  114. {
  115. antcomb->quick_scan_cnt = 0;
  116. if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  117. antcomb->rssi_lna2 = main_rssi_avg;
  118. else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
  119. antcomb->rssi_lna1 = main_rssi_avg;
  120. switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
  121. case 0x10: /* LNA2 A-B */
  122. antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  123. antcomb->first_quick_scan_conf =
  124. ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  125. antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
  126. break;
  127. case 0x20: /* LNA1 A-B */
  128. antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  129. antcomb->first_quick_scan_conf =
  130. ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  131. antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
  132. break;
  133. case 0x21: /* LNA1 LNA2 */
  134. antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
  135. antcomb->first_quick_scan_conf =
  136. ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  137. antcomb->second_quick_scan_conf =
  138. ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  139. break;
  140. case 0x12: /* LNA2 LNA1 */
  141. antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
  142. antcomb->first_quick_scan_conf =
  143. ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  144. antcomb->second_quick_scan_conf =
  145. ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  146. break;
  147. case 0x13: /* LNA2 A+B */
  148. antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  149. antcomb->first_quick_scan_conf =
  150. ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  151. antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
  152. break;
  153. case 0x23: /* LNA1 A+B */
  154. antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  155. antcomb->first_quick_scan_conf =
  156. ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  157. antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
  158. break;
  159. default:
  160. break;
  161. }
  162. }
  163. static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb,
  164. struct ath_hw_antcomb_conf *conf)
  165. {
  166. /* set alt to the conf with maximun ratio */
  167. if (antcomb->first_ratio && antcomb->second_ratio) {
  168. if (antcomb->rssi_second > antcomb->rssi_third) {
  169. /* first alt*/
  170. if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
  171. (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
  172. /* Set alt LNA1 or LNA2*/
  173. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  174. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  175. else
  176. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  177. else
  178. /* Set alt to A+B or A-B */
  179. conf->alt_lna_conf =
  180. antcomb->first_quick_scan_conf;
  181. } else if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
  182. (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) {
  183. /* Set alt LNA1 or LNA2 */
  184. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  185. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  186. else
  187. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  188. } else {
  189. /* Set alt to A+B or A-B */
  190. conf->alt_lna_conf = antcomb->second_quick_scan_conf;
  191. }
  192. } else if (antcomb->first_ratio) {
  193. /* first alt */
  194. if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
  195. (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
  196. /* Set alt LNA1 or LNA2 */
  197. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  198. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  199. else
  200. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  201. else
  202. /* Set alt to A+B or A-B */
  203. conf->alt_lna_conf = antcomb->first_quick_scan_conf;
  204. } else if (antcomb->second_ratio) {
  205. /* second alt */
  206. if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
  207. (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
  208. /* Set alt LNA1 or LNA2 */
  209. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  210. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  211. else
  212. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  213. else
  214. /* Set alt to A+B or A-B */
  215. conf->alt_lna_conf = antcomb->second_quick_scan_conf;
  216. } else {
  217. /* main is largest */
  218. if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
  219. (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
  220. /* Set alt LNA1 or LNA2 */
  221. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  222. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  223. else
  224. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  225. else
  226. /* Set alt to A+B or A-B */
  227. conf->alt_lna_conf = antcomb->main_conf;
  228. }
  229. }
  230. static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
  231. struct ath_hw_antcomb_conf *div_ant_conf,
  232. int main_rssi_avg, int alt_rssi_avg,
  233. int alt_ratio)
  234. {
  235. /* alt_good */
  236. switch (antcomb->quick_scan_cnt) {
  237. case 0:
  238. /* set alt to main, and alt to first conf */
  239. div_ant_conf->main_lna_conf = antcomb->main_conf;
  240. div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
  241. break;
  242. case 1:
  243. /* set alt to main, and alt to first conf */
  244. div_ant_conf->main_lna_conf = antcomb->main_conf;
  245. div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
  246. antcomb->rssi_first = main_rssi_avg;
  247. antcomb->rssi_second = alt_rssi_avg;
  248. if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
  249. /* main is LNA1 */
  250. if (ath_is_alt_ant_ratio_better(alt_ratio,
  251. ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
  252. ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
  253. main_rssi_avg, alt_rssi_avg,
  254. antcomb->total_pkt_count))
  255. antcomb->first_ratio = true;
  256. else
  257. antcomb->first_ratio = false;
  258. } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
  259. if (ath_is_alt_ant_ratio_better(alt_ratio,
  260. ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
  261. ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
  262. main_rssi_avg, alt_rssi_avg,
  263. antcomb->total_pkt_count))
  264. antcomb->first_ratio = true;
  265. else
  266. antcomb->first_ratio = false;
  267. } else {
  268. if (ath_is_alt_ant_ratio_better(alt_ratio,
  269. ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
  270. 0,
  271. main_rssi_avg, alt_rssi_avg,
  272. antcomb->total_pkt_count))
  273. antcomb->first_ratio = true;
  274. else
  275. antcomb->first_ratio = false;
  276. }
  277. break;
  278. case 2:
  279. antcomb->alt_good = false;
  280. antcomb->scan_not_start = false;
  281. antcomb->scan = false;
  282. antcomb->rssi_first = main_rssi_avg;
  283. antcomb->rssi_third = alt_rssi_avg;
  284. switch(antcomb->second_quick_scan_conf) {
  285. case ATH_ANT_DIV_COMB_LNA1:
  286. antcomb->rssi_lna1 = alt_rssi_avg;
  287. break;
  288. case ATH_ANT_DIV_COMB_LNA2:
  289. antcomb->rssi_lna2 = alt_rssi_avg;
  290. break;
  291. case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
  292. if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
  293. antcomb->rssi_lna2 = main_rssi_avg;
  294. else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
  295. antcomb->rssi_lna1 = main_rssi_avg;
  296. break;
  297. default:
  298. break;
  299. }
  300. if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
  301. ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
  302. div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  303. else
  304. div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  305. if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
  306. if (ath_is_alt_ant_ratio_better(alt_ratio,
  307. ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
  308. ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
  309. main_rssi_avg, alt_rssi_avg,
  310. antcomb->total_pkt_count))
  311. antcomb->second_ratio = true;
  312. else
  313. antcomb->second_ratio = false;
  314. } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
  315. if (ath_is_alt_ant_ratio_better(alt_ratio,
  316. ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
  317. ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
  318. main_rssi_avg, alt_rssi_avg,
  319. antcomb->total_pkt_count))
  320. antcomb->second_ratio = true;
  321. else
  322. antcomb->second_ratio = false;
  323. } else {
  324. if (ath_is_alt_ant_ratio_better(alt_ratio,
  325. ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
  326. 0,
  327. main_rssi_avg, alt_rssi_avg,
  328. antcomb->total_pkt_count))
  329. antcomb->second_ratio = true;
  330. else
  331. antcomb->second_ratio = false;
  332. }
  333. ath_ant_set_alt_ratio(antcomb, div_ant_conf);
  334. break;
  335. default:
  336. break;
  337. }
  338. }
  339. static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
  340. struct ath_ant_comb *antcomb,
  341. int alt_ratio)
  342. {
  343. ant_conf->main_gaintb = 0;
  344. ant_conf->alt_gaintb = 0;
  345. if (ant_conf->div_group == 0) {
  346. /* Adjust the fast_div_bias based on main and alt lna conf */
  347. switch ((ant_conf->main_lna_conf << 4) |
  348. ant_conf->alt_lna_conf) {
  349. case 0x01: /* A-B LNA2 */
  350. ant_conf->fast_div_bias = 0x3b;
  351. break;
  352. case 0x02: /* A-B LNA1 */
  353. ant_conf->fast_div_bias = 0x3d;
  354. break;
  355. case 0x03: /* A-B A+B */
  356. ant_conf->fast_div_bias = 0x1;
  357. break;
  358. case 0x10: /* LNA2 A-B */
  359. ant_conf->fast_div_bias = 0x7;
  360. break;
  361. case 0x12: /* LNA2 LNA1 */
  362. ant_conf->fast_div_bias = 0x2;
  363. break;
  364. case 0x13: /* LNA2 A+B */
  365. ant_conf->fast_div_bias = 0x7;
  366. break;
  367. case 0x20: /* LNA1 A-B */
  368. ant_conf->fast_div_bias = 0x6;
  369. break;
  370. case 0x21: /* LNA1 LNA2 */
  371. ant_conf->fast_div_bias = 0x0;
  372. break;
  373. case 0x23: /* LNA1 A+B */
  374. ant_conf->fast_div_bias = 0x6;
  375. break;
  376. case 0x30: /* A+B A-B */
  377. ant_conf->fast_div_bias = 0x1;
  378. break;
  379. case 0x31: /* A+B LNA2 */
  380. ant_conf->fast_div_bias = 0x3b;
  381. break;
  382. case 0x32: /* A+B LNA1 */
  383. ant_conf->fast_div_bias = 0x3d;
  384. break;
  385. default:
  386. break;
  387. }
  388. } else if (ant_conf->div_group == 1) {
  389. /* Adjust the fast_div_bias based on main and alt_lna_conf */
  390. switch ((ant_conf->main_lna_conf << 4) |
  391. ant_conf->alt_lna_conf) {
  392. case 0x01: /* A-B LNA2 */
  393. ant_conf->fast_div_bias = 0x1;
  394. break;
  395. case 0x02: /* A-B LNA1 */
  396. ant_conf->fast_div_bias = 0x1;
  397. break;
  398. case 0x03: /* A-B A+B */
  399. ant_conf->fast_div_bias = 0x1;
  400. break;
  401. case 0x10: /* LNA2 A-B */
  402. if (!(antcomb->scan) &&
  403. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
  404. ant_conf->fast_div_bias = 0x3f;
  405. else
  406. ant_conf->fast_div_bias = 0x1;
  407. break;
  408. case 0x12: /* LNA2 LNA1 */
  409. ant_conf->fast_div_bias = 0x1;
  410. break;
  411. case 0x13: /* LNA2 A+B */
  412. if (!(antcomb->scan) &&
  413. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
  414. ant_conf->fast_div_bias = 0x3f;
  415. else
  416. ant_conf->fast_div_bias = 0x1;
  417. break;
  418. case 0x20: /* LNA1 A-B */
  419. if (!(antcomb->scan) &&
  420. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
  421. ant_conf->fast_div_bias = 0x3f;
  422. else
  423. ant_conf->fast_div_bias = 0x1;
  424. break;
  425. case 0x21: /* LNA1 LNA2 */
  426. ant_conf->fast_div_bias = 0x1;
  427. break;
  428. case 0x23: /* LNA1 A+B */
  429. if (!(antcomb->scan) &&
  430. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
  431. ant_conf->fast_div_bias = 0x3f;
  432. else
  433. ant_conf->fast_div_bias = 0x1;
  434. break;
  435. case 0x30: /* A+B A-B */
  436. ant_conf->fast_div_bias = 0x1;
  437. break;
  438. case 0x31: /* A+B LNA2 */
  439. ant_conf->fast_div_bias = 0x1;
  440. break;
  441. case 0x32: /* A+B LNA1 */
  442. ant_conf->fast_div_bias = 0x1;
  443. break;
  444. default:
  445. break;
  446. }
  447. } else if (ant_conf->div_group == 2) {
  448. /* Adjust the fast_div_bias based on main and alt_lna_conf */
  449. switch ((ant_conf->main_lna_conf << 4) |
  450. ant_conf->alt_lna_conf) {
  451. case 0x01: /* A-B LNA2 */
  452. ant_conf->fast_div_bias = 0x1;
  453. break;
  454. case 0x02: /* A-B LNA1 */
  455. ant_conf->fast_div_bias = 0x1;
  456. break;
  457. case 0x03: /* A-B A+B */
  458. ant_conf->fast_div_bias = 0x1;
  459. break;
  460. case 0x10: /* LNA2 A-B */
  461. if (!(antcomb->scan) &&
  462. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
  463. ant_conf->fast_div_bias = 0x1;
  464. else
  465. ant_conf->fast_div_bias = 0x2;
  466. break;
  467. case 0x12: /* LNA2 LNA1 */
  468. ant_conf->fast_div_bias = 0x1;
  469. break;
  470. case 0x13: /* LNA2 A+B */
  471. if (!(antcomb->scan) &&
  472. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
  473. ant_conf->fast_div_bias = 0x1;
  474. else
  475. ant_conf->fast_div_bias = 0x2;
  476. break;
  477. case 0x20: /* LNA1 A-B */
  478. if (!(antcomb->scan) &&
  479. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
  480. ant_conf->fast_div_bias = 0x1;
  481. else
  482. ant_conf->fast_div_bias = 0x2;
  483. break;
  484. case 0x21: /* LNA1 LNA2 */
  485. ant_conf->fast_div_bias = 0x1;
  486. break;
  487. case 0x23: /* LNA1 A+B */
  488. if (!(antcomb->scan) &&
  489. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
  490. ant_conf->fast_div_bias = 0x1;
  491. else
  492. ant_conf->fast_div_bias = 0x2;
  493. break;
  494. case 0x30: /* A+B A-B */
  495. ant_conf->fast_div_bias = 0x1;
  496. break;
  497. case 0x31: /* A+B LNA2 */
  498. ant_conf->fast_div_bias = 0x1;
  499. break;
  500. case 0x32: /* A+B LNA1 */
  501. ant_conf->fast_div_bias = 0x1;
  502. break;
  503. default:
  504. break;
  505. }
  506. } else if (ant_conf->div_group == 3) {
  507. switch ((ant_conf->main_lna_conf << 4) |
  508. ant_conf->alt_lna_conf) {
  509. case 0x01: /* A-B LNA2 */
  510. ant_conf->fast_div_bias = 0x1;
  511. break;
  512. case 0x02: /* A-B LNA1 */
  513. ant_conf->fast_div_bias = 0x39;
  514. break;
  515. case 0x03: /* A-B A+B */
  516. ant_conf->fast_div_bias = 0x1;
  517. break;
  518. case 0x10: /* LNA2 A-B */
  519. if ((antcomb->scan == 0) &&
  520. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
  521. ant_conf->fast_div_bias = 0x3f;
  522. } else {
  523. ant_conf->fast_div_bias = 0x1;
  524. }
  525. break;
  526. case 0x12: /* LNA2 LNA1 */
  527. ant_conf->fast_div_bias = 0x39;
  528. break;
  529. case 0x13: /* LNA2 A+B */
  530. if ((antcomb->scan == 0) &&
  531. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
  532. ant_conf->fast_div_bias = 0x3f;
  533. } else {
  534. ant_conf->fast_div_bias = 0x1;
  535. }
  536. break;
  537. case 0x20: /* LNA1 A-B */
  538. if ((antcomb->scan == 0) &&
  539. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
  540. ant_conf->fast_div_bias = 0x3f;
  541. } else {
  542. ant_conf->fast_div_bias = 0x4;
  543. }
  544. break;
  545. case 0x21: /* LNA1 LNA2 */
  546. ant_conf->fast_div_bias = 0x6;
  547. break;
  548. case 0x23: /* LNA1 A+B */
  549. if ((antcomb->scan == 0) &&
  550. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
  551. ant_conf->fast_div_bias = 0x3f;
  552. } else {
  553. ant_conf->fast_div_bias = 0x6;
  554. }
  555. break;
  556. case 0x30: /* A+B A-B */
  557. ant_conf->fast_div_bias = 0x1;
  558. break;
  559. case 0x31: /* A+B LNA2 */
  560. ant_conf->fast_div_bias = 0x6;
  561. break;
  562. case 0x32: /* A+B LNA1 */
  563. ant_conf->fast_div_bias = 0x1;
  564. break;
  565. default:
  566. break;
  567. }
  568. }
  569. }
  570. static void ath_ant_try_scan(struct ath_ant_comb *antcomb,
  571. struct ath_hw_antcomb_conf *conf,
  572. int curr_alt_set, int alt_rssi_avg,
  573. int main_rssi_avg)
  574. {
  575. switch (curr_alt_set) {
  576. case ATH_ANT_DIV_COMB_LNA2:
  577. antcomb->rssi_lna2 = alt_rssi_avg;
  578. antcomb->rssi_lna1 = main_rssi_avg;
  579. antcomb->scan = true;
  580. /* set to A+B */
  581. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  582. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  583. break;
  584. case ATH_ANT_DIV_COMB_LNA1:
  585. antcomb->rssi_lna1 = alt_rssi_avg;
  586. antcomb->rssi_lna2 = main_rssi_avg;
  587. antcomb->scan = true;
  588. /* set to A+B */
  589. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  590. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  591. break;
  592. case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
  593. antcomb->rssi_add = alt_rssi_avg;
  594. antcomb->scan = true;
  595. /* set to A-B */
  596. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  597. break;
  598. case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
  599. antcomb->rssi_sub = alt_rssi_avg;
  600. antcomb->scan = false;
  601. if (antcomb->rssi_lna2 >
  602. (antcomb->rssi_lna1 + ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
  603. /* use LNA2 as main LNA */
  604. if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
  605. (antcomb->rssi_add > antcomb->rssi_sub)) {
  606. /* set to A+B */
  607. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  608. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  609. } else if (antcomb->rssi_sub >
  610. antcomb->rssi_lna1) {
  611. /* set to A-B */
  612. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  613. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  614. } else {
  615. /* set to LNA1 */
  616. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  617. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  618. }
  619. } else {
  620. /* use LNA1 as main LNA */
  621. if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
  622. (antcomb->rssi_add > antcomb->rssi_sub)) {
  623. /* set to A+B */
  624. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  625. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  626. } else if (antcomb->rssi_sub >
  627. antcomb->rssi_lna1) {
  628. /* set to A-B */
  629. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  630. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  631. } else {
  632. /* set to LNA2 */
  633. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  634. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  635. }
  636. }
  637. break;
  638. default:
  639. break;
  640. }
  641. }
  642. static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf,
  643. int alt_ratio, int alt_rssi_avg,
  644. int main_rssi_avg, int curr_main_set,
  645. int curr_alt_set)
  646. {
  647. bool ret = false;
  648. if (ath_ant_div_comb_alt_check(div_ant_conf, alt_ratio,
  649. alt_rssi_avg, main_rssi_avg)) {
  650. if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
  651. /*
  652. * Switch main and alt LNA.
  653. */
  654. div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  655. div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  656. } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
  657. div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  658. div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  659. }
  660. ret = true;
  661. } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
  662. (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
  663. /*
  664. Set alt to another LNA.
  665. */
  666. if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
  667. div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  668. else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
  669. div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  670. ret = true;
  671. }
  672. return ret;
  673. }
  674. static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
  675. {
  676. int alt_ratio;
  677. if (!antcomb->scan || !antcomb->alt_good)
  678. return false;
  679. if (time_after(jiffies, antcomb->scan_start_time +
  680. msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
  681. return true;
  682. if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
  683. alt_ratio = ((antcomb->alt_recv_cnt * 100) /
  684. antcomb->total_pkt_count);
  685. if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
  686. return true;
  687. }
  688. return false;
  689. }
  690. void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
  691. {
  692. struct ath_hw_antcomb_conf div_ant_conf;
  693. struct ath_ant_comb *antcomb = &sc->ant_comb;
  694. int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
  695. int curr_main_set;
  696. int main_rssi = rs->rs_rssi_ctl0;
  697. int alt_rssi = rs->rs_rssi_ctl1;
  698. int rx_ant_conf, main_ant_conf;
  699. bool short_scan = false, ret;
  700. rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
  701. ATH_ANT_RX_MASK;
  702. main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
  703. ATH_ANT_RX_MASK;
  704. /* Record packet only when both main_rssi and alt_rssi is positive */
  705. if (main_rssi > 0 && alt_rssi > 0) {
  706. antcomb->total_pkt_count++;
  707. antcomb->main_total_rssi += main_rssi;
  708. antcomb->alt_total_rssi += alt_rssi;
  709. if (main_ant_conf == rx_ant_conf)
  710. antcomb->main_recv_cnt++;
  711. else
  712. antcomb->alt_recv_cnt++;
  713. }
  714. if (main_ant_conf == rx_ant_conf) {
  715. ANT_STAT_INC(ANT_MAIN, recv_cnt);
  716. ANT_LNA_INC(ANT_MAIN, rx_ant_conf);
  717. } else {
  718. ANT_STAT_INC(ANT_ALT, recv_cnt);
  719. ANT_LNA_INC(ANT_ALT, rx_ant_conf);
  720. }
  721. /* Short scan check */
  722. short_scan = ath_ant_short_scan_check(antcomb);
  723. if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
  724. rs->rs_moreaggr) && !short_scan)
  725. return;
  726. if (antcomb->total_pkt_count) {
  727. alt_ratio = ((antcomb->alt_recv_cnt * 100) /
  728. antcomb->total_pkt_count);
  729. main_rssi_avg = (antcomb->main_total_rssi /
  730. antcomb->total_pkt_count);
  731. alt_rssi_avg = (antcomb->alt_total_rssi /
  732. antcomb->total_pkt_count);
  733. }
  734. ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
  735. curr_alt_set = div_ant_conf.alt_lna_conf;
  736. curr_main_set = div_ant_conf.main_lna_conf;
  737. antcomb->count++;
  738. if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
  739. if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
  740. ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
  741. main_rssi_avg);
  742. antcomb->alt_good = true;
  743. } else {
  744. antcomb->alt_good = false;
  745. }
  746. antcomb->count = 0;
  747. antcomb->scan = true;
  748. antcomb->scan_not_start = true;
  749. }
  750. if (!antcomb->scan) {
  751. ret = ath_ant_try_switch(&div_ant_conf, alt_ratio,
  752. alt_rssi_avg, main_rssi_avg,
  753. curr_main_set, curr_alt_set);
  754. if (ret)
  755. goto div_comb_done;
  756. }
  757. if (!antcomb->scan &&
  758. (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta)))
  759. goto div_comb_done;
  760. if (!antcomb->scan_not_start) {
  761. ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set,
  762. alt_rssi_avg, main_rssi_avg);
  763. } else {
  764. if (!antcomb->alt_good) {
  765. antcomb->scan_not_start = false;
  766. /* Set alt to another LNA */
  767. if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
  768. div_ant_conf.main_lna_conf =
  769. ATH_ANT_DIV_COMB_LNA2;
  770. div_ant_conf.alt_lna_conf =
  771. ATH_ANT_DIV_COMB_LNA1;
  772. } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
  773. div_ant_conf.main_lna_conf =
  774. ATH_ANT_DIV_COMB_LNA1;
  775. div_ant_conf.alt_lna_conf =
  776. ATH_ANT_DIV_COMB_LNA2;
  777. }
  778. goto div_comb_done;
  779. }
  780. ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
  781. main_rssi_avg, alt_rssi_avg,
  782. alt_ratio);
  783. antcomb->quick_scan_cnt++;
  784. }
  785. div_comb_done:
  786. ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
  787. ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
  788. ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg);
  789. antcomb->scan_start_time = jiffies;
  790. antcomb->total_pkt_count = 0;
  791. antcomb->main_total_rssi = 0;
  792. antcomb->alt_total_rssi = 0;
  793. antcomb->main_recv_cnt = 0;
  794. antcomb->alt_recv_cnt = 0;
  795. }
  796. void ath_ant_comb_update(struct ath_softc *sc)
  797. {
  798. struct ath_hw *ah = sc->sc_ah;
  799. struct ath_common *common = ath9k_hw_common(ah);
  800. struct ath_hw_antcomb_conf div_ant_conf;
  801. u8 lna_conf;
  802. ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
  803. if (sc->ant_rx == 1)
  804. lna_conf = ATH_ANT_DIV_COMB_LNA1;
  805. else
  806. lna_conf = ATH_ANT_DIV_COMB_LNA2;
  807. div_ant_conf.main_lna_conf = lna_conf;
  808. div_ant_conf.alt_lna_conf = lna_conf;
  809. ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
  810. if (common->antenna_diversity)
  811. ath9k_hw_antctrl_shared_chain_lnadiv(ah, true);
  812. }