antenna.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  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(struct ath_ant_comb *antcomb,
  69. int alt_ratio, int maxdelta,
  70. int mindelta, int main_rssi_avg,
  71. int alt_rssi_avg, int pkt_count)
  72. {
  73. if (pkt_count <= 50)
  74. return false;
  75. if (alt_rssi_avg > main_rssi_avg + mindelta)
  76. return true;
  77. if (alt_ratio >= antcomb->ant_ratio2 &&
  78. alt_rssi_avg >= antcomb->low_rssi_thresh &&
  79. (alt_rssi_avg > main_rssi_avg + maxdelta))
  80. return true;
  81. return false;
  82. }
  83. static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf,
  84. struct ath_ant_comb *antcomb,
  85. int alt_ratio, int alt_rssi_avg,
  86. int main_rssi_avg)
  87. {
  88. bool result, set1, set2;
  89. result = set1 = set2 = false;
  90. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2 &&
  91. conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA1)
  92. set1 = true;
  93. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA1 &&
  94. conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  95. set2 = true;
  96. switch (conf->div_group) {
  97. case 0:
  98. if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
  99. result = true;
  100. break;
  101. case 1:
  102. case 2:
  103. if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh)
  104. break;
  105. if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 5))) ||
  106. (set2 && (alt_rssi_avg >= (main_rssi_avg - 2))) ||
  107. (alt_ratio > antcomb->ant_ratio))
  108. result = true;
  109. break;
  110. case 3:
  111. if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh)
  112. break;
  113. if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 3))) ||
  114. (set2 && (alt_rssi_avg >= (main_rssi_avg + 3))) ||
  115. (alt_ratio > antcomb->ant_ratio))
  116. result = true;
  117. break;
  118. }
  119. return result;
  120. }
  121. static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
  122. struct ath_hw_antcomb_conf ant_conf,
  123. int main_rssi_avg)
  124. {
  125. antcomb->quick_scan_cnt = 0;
  126. if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  127. antcomb->rssi_lna2 = main_rssi_avg;
  128. else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
  129. antcomb->rssi_lna1 = main_rssi_avg;
  130. switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
  131. case 0x10: /* LNA2 A-B */
  132. antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  133. antcomb->first_quick_scan_conf =
  134. ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  135. antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
  136. break;
  137. case 0x20: /* LNA1 A-B */
  138. antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  139. antcomb->first_quick_scan_conf =
  140. ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  141. antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
  142. break;
  143. case 0x21: /* LNA1 LNA2 */
  144. antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
  145. antcomb->first_quick_scan_conf =
  146. ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  147. antcomb->second_quick_scan_conf =
  148. ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  149. break;
  150. case 0x12: /* LNA2 LNA1 */
  151. antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
  152. antcomb->first_quick_scan_conf =
  153. ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  154. antcomb->second_quick_scan_conf =
  155. ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  156. break;
  157. case 0x13: /* LNA2 A+B */
  158. antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  159. antcomb->first_quick_scan_conf =
  160. ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  161. antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
  162. break;
  163. case 0x23: /* LNA1 A+B */
  164. antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  165. antcomb->first_quick_scan_conf =
  166. ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  167. antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
  168. break;
  169. default:
  170. break;
  171. }
  172. }
  173. static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb,
  174. struct ath_hw_antcomb_conf *conf)
  175. {
  176. /* set alt to the conf with maximun ratio */
  177. if (antcomb->first_ratio && antcomb->second_ratio) {
  178. if (antcomb->rssi_second > antcomb->rssi_third) {
  179. /* first alt*/
  180. if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
  181. (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
  182. /* Set alt LNA1 or LNA2*/
  183. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  184. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  185. else
  186. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  187. else
  188. /* Set alt to A+B or A-B */
  189. conf->alt_lna_conf =
  190. antcomb->first_quick_scan_conf;
  191. } else if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
  192. (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) {
  193. /* Set alt LNA1 or LNA2 */
  194. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  195. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  196. else
  197. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  198. } else {
  199. /* Set alt to A+B or A-B */
  200. conf->alt_lna_conf = antcomb->second_quick_scan_conf;
  201. }
  202. } else if (antcomb->first_ratio) {
  203. /* first alt */
  204. if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
  205. (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
  206. /* Set alt LNA1 or LNA2 */
  207. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  208. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  209. else
  210. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  211. else
  212. /* Set alt to A+B or A-B */
  213. conf->alt_lna_conf = antcomb->first_quick_scan_conf;
  214. } else if (antcomb->second_ratio) {
  215. /* second alt */
  216. if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
  217. (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
  218. /* Set alt LNA1 or LNA2 */
  219. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  220. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  221. else
  222. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  223. else
  224. /* Set alt to A+B or A-B */
  225. conf->alt_lna_conf = antcomb->second_quick_scan_conf;
  226. } else {
  227. /* main is largest */
  228. if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
  229. (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
  230. /* Set alt LNA1 or LNA2 */
  231. if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
  232. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  233. else
  234. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  235. else
  236. /* Set alt to A+B or A-B */
  237. conf->alt_lna_conf = antcomb->main_conf;
  238. }
  239. }
  240. static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
  241. struct ath_hw_antcomb_conf *div_ant_conf,
  242. int main_rssi_avg, int alt_rssi_avg,
  243. int alt_ratio)
  244. {
  245. /* alt_good */
  246. switch (antcomb->quick_scan_cnt) {
  247. case 0:
  248. /* set alt to main, and alt to first conf */
  249. div_ant_conf->main_lna_conf = antcomb->main_conf;
  250. div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
  251. break;
  252. case 1:
  253. /* set alt to main, and alt to first conf */
  254. div_ant_conf->main_lna_conf = antcomb->main_conf;
  255. div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
  256. antcomb->rssi_first = main_rssi_avg;
  257. antcomb->rssi_second = alt_rssi_avg;
  258. if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
  259. /* main is LNA1 */
  260. if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
  261. ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
  262. ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
  263. main_rssi_avg, alt_rssi_avg,
  264. antcomb->total_pkt_count))
  265. antcomb->first_ratio = true;
  266. else
  267. antcomb->first_ratio = false;
  268. } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
  269. if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
  270. ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
  271. ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
  272. main_rssi_avg, alt_rssi_avg,
  273. antcomb->total_pkt_count))
  274. antcomb->first_ratio = true;
  275. else
  276. antcomb->first_ratio = false;
  277. } else {
  278. if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
  279. ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
  280. 0,
  281. main_rssi_avg, alt_rssi_avg,
  282. antcomb->total_pkt_count))
  283. antcomb->first_ratio = true;
  284. else
  285. antcomb->first_ratio = false;
  286. }
  287. break;
  288. case 2:
  289. antcomb->alt_good = false;
  290. antcomb->scan_not_start = false;
  291. antcomb->scan = false;
  292. antcomb->rssi_first = main_rssi_avg;
  293. antcomb->rssi_third = alt_rssi_avg;
  294. switch(antcomb->second_quick_scan_conf) {
  295. case ATH_ANT_DIV_COMB_LNA1:
  296. antcomb->rssi_lna1 = alt_rssi_avg;
  297. break;
  298. case ATH_ANT_DIV_COMB_LNA2:
  299. antcomb->rssi_lna2 = alt_rssi_avg;
  300. break;
  301. case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
  302. if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
  303. antcomb->rssi_lna2 = main_rssi_avg;
  304. else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
  305. antcomb->rssi_lna1 = main_rssi_avg;
  306. break;
  307. default:
  308. break;
  309. }
  310. if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
  311. div_ant_conf->lna1_lna2_switch_delta)
  312. div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  313. else
  314. div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  315. if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
  316. if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
  317. ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
  318. ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
  319. main_rssi_avg, alt_rssi_avg,
  320. antcomb->total_pkt_count))
  321. antcomb->second_ratio = true;
  322. else
  323. antcomb->second_ratio = false;
  324. } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
  325. if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
  326. ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
  327. ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
  328. main_rssi_avg, alt_rssi_avg,
  329. antcomb->total_pkt_count))
  330. antcomb->second_ratio = true;
  331. else
  332. antcomb->second_ratio = false;
  333. } else {
  334. if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
  335. ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
  336. 0,
  337. main_rssi_avg, alt_rssi_avg,
  338. antcomb->total_pkt_count))
  339. antcomb->second_ratio = true;
  340. else
  341. antcomb->second_ratio = false;
  342. }
  343. ath_ant_set_alt_ratio(antcomb, div_ant_conf);
  344. break;
  345. default:
  346. break;
  347. }
  348. }
  349. static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
  350. struct ath_ant_comb *antcomb,
  351. int alt_ratio)
  352. {
  353. ant_conf->main_gaintb = 0;
  354. ant_conf->alt_gaintb = 0;
  355. if (ant_conf->div_group == 0) {
  356. /* Adjust the fast_div_bias based on main and alt lna conf */
  357. switch ((ant_conf->main_lna_conf << 4) |
  358. ant_conf->alt_lna_conf) {
  359. case 0x01: /* A-B LNA2 */
  360. ant_conf->fast_div_bias = 0x3b;
  361. break;
  362. case 0x02: /* A-B LNA1 */
  363. ant_conf->fast_div_bias = 0x3d;
  364. break;
  365. case 0x03: /* A-B A+B */
  366. ant_conf->fast_div_bias = 0x1;
  367. break;
  368. case 0x10: /* LNA2 A-B */
  369. ant_conf->fast_div_bias = 0x7;
  370. break;
  371. case 0x12: /* LNA2 LNA1 */
  372. ant_conf->fast_div_bias = 0x2;
  373. break;
  374. case 0x13: /* LNA2 A+B */
  375. ant_conf->fast_div_bias = 0x7;
  376. break;
  377. case 0x20: /* LNA1 A-B */
  378. ant_conf->fast_div_bias = 0x6;
  379. break;
  380. case 0x21: /* LNA1 LNA2 */
  381. ant_conf->fast_div_bias = 0x0;
  382. break;
  383. case 0x23: /* LNA1 A+B */
  384. ant_conf->fast_div_bias = 0x6;
  385. break;
  386. case 0x30: /* A+B A-B */
  387. ant_conf->fast_div_bias = 0x1;
  388. break;
  389. case 0x31: /* A+B LNA2 */
  390. ant_conf->fast_div_bias = 0x3b;
  391. break;
  392. case 0x32: /* A+B LNA1 */
  393. ant_conf->fast_div_bias = 0x3d;
  394. break;
  395. default:
  396. break;
  397. }
  398. } else if (ant_conf->div_group == 1) {
  399. /* Adjust the fast_div_bias based on main and alt_lna_conf */
  400. switch ((ant_conf->main_lna_conf << 4) |
  401. ant_conf->alt_lna_conf) {
  402. case 0x01: /* A-B LNA2 */
  403. ant_conf->fast_div_bias = 0x1;
  404. break;
  405. case 0x02: /* A-B LNA1 */
  406. ant_conf->fast_div_bias = 0x1;
  407. break;
  408. case 0x03: /* A-B A+B */
  409. ant_conf->fast_div_bias = 0x1;
  410. break;
  411. case 0x10: /* 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 0x12: /* LNA2 LNA1 */
  419. ant_conf->fast_div_bias = 0x1;
  420. break;
  421. case 0x13: /* LNA2 A+B */
  422. if (!(antcomb->scan) &&
  423. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
  424. ant_conf->fast_div_bias = 0x3f;
  425. else
  426. ant_conf->fast_div_bias = 0x1;
  427. break;
  428. case 0x20: /* 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 0x21: /* LNA1 LNA2 */
  436. ant_conf->fast_div_bias = 0x1;
  437. break;
  438. case 0x23: /* LNA1 A+B */
  439. if (!(antcomb->scan) &&
  440. (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
  441. ant_conf->fast_div_bias = 0x3f;
  442. else
  443. ant_conf->fast_div_bias = 0x1;
  444. break;
  445. case 0x30: /* A+B A-B */
  446. ant_conf->fast_div_bias = 0x1;
  447. break;
  448. case 0x31: /* A+B LNA2 */
  449. ant_conf->fast_div_bias = 0x1;
  450. break;
  451. case 0x32: /* A+B LNA1 */
  452. ant_conf->fast_div_bias = 0x1;
  453. break;
  454. default:
  455. break;
  456. }
  457. } else if (ant_conf->div_group == 2) {
  458. /* Adjust the fast_div_bias based on main and alt_lna_conf */
  459. switch ((ant_conf->main_lna_conf << 4) |
  460. ant_conf->alt_lna_conf) {
  461. case 0x01: /* A-B LNA2 */
  462. ant_conf->fast_div_bias = 0x1;
  463. break;
  464. case 0x02: /* A-B LNA1 */
  465. ant_conf->fast_div_bias = 0x1;
  466. break;
  467. case 0x03: /* A-B A+B */
  468. ant_conf->fast_div_bias = 0x1;
  469. break;
  470. case 0x10: /* LNA2 A-B */
  471. if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
  472. ant_conf->fast_div_bias = 0x1;
  473. else
  474. ant_conf->fast_div_bias = 0x2;
  475. break;
  476. case 0x12: /* LNA2 LNA1 */
  477. ant_conf->fast_div_bias = 0x1;
  478. break;
  479. case 0x13: /* LNA2 A+B */
  480. if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
  481. ant_conf->fast_div_bias = 0x1;
  482. else
  483. ant_conf->fast_div_bias = 0x2;
  484. break;
  485. case 0x20: /* LNA1 A-B */
  486. if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
  487. ant_conf->fast_div_bias = 0x1;
  488. else
  489. ant_conf->fast_div_bias = 0x2;
  490. break;
  491. case 0x21: /* LNA1 LNA2 */
  492. ant_conf->fast_div_bias = 0x1;
  493. break;
  494. case 0x23: /* LNA1 A+B */
  495. if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
  496. ant_conf->fast_div_bias = 0x1;
  497. else
  498. ant_conf->fast_div_bias = 0x2;
  499. break;
  500. case 0x30: /* A+B A-B */
  501. ant_conf->fast_div_bias = 0x1;
  502. break;
  503. case 0x31: /* A+B LNA2 */
  504. ant_conf->fast_div_bias = 0x1;
  505. break;
  506. case 0x32: /* A+B LNA1 */
  507. ant_conf->fast_div_bias = 0x1;
  508. break;
  509. default:
  510. break;
  511. }
  512. if (antcomb->fast_div_bias)
  513. ant_conf->fast_div_bias = antcomb->fast_div_bias;
  514. } else if (ant_conf->div_group == 3) {
  515. switch ((ant_conf->main_lna_conf << 4) |
  516. ant_conf->alt_lna_conf) {
  517. case 0x01: /* A-B LNA2 */
  518. ant_conf->fast_div_bias = 0x1;
  519. break;
  520. case 0x02: /* A-B LNA1 */
  521. ant_conf->fast_div_bias = 0x39;
  522. break;
  523. case 0x03: /* A-B A+B */
  524. ant_conf->fast_div_bias = 0x1;
  525. break;
  526. case 0x10: /* LNA2 A-B */
  527. ant_conf->fast_div_bias = 0x2;
  528. break;
  529. case 0x12: /* LNA2 LNA1 */
  530. ant_conf->fast_div_bias = 0x3f;
  531. break;
  532. case 0x13: /* LNA2 A+B */
  533. ant_conf->fast_div_bias = 0x2;
  534. break;
  535. case 0x20: /* LNA1 A-B */
  536. ant_conf->fast_div_bias = 0x3;
  537. break;
  538. case 0x21: /* LNA1 LNA2 */
  539. ant_conf->fast_div_bias = 0x3;
  540. break;
  541. case 0x23: /* LNA1 A+B */
  542. ant_conf->fast_div_bias = 0x3;
  543. break;
  544. case 0x30: /* A+B A-B */
  545. ant_conf->fast_div_bias = 0x1;
  546. break;
  547. case 0x31: /* A+B LNA2 */
  548. ant_conf->fast_div_bias = 0x6;
  549. break;
  550. case 0x32: /* A+B LNA1 */
  551. ant_conf->fast_div_bias = 0x1;
  552. break;
  553. default:
  554. break;
  555. }
  556. }
  557. }
  558. static void ath_ant_try_scan(struct ath_ant_comb *antcomb,
  559. struct ath_hw_antcomb_conf *conf,
  560. int curr_alt_set, int alt_rssi_avg,
  561. int main_rssi_avg)
  562. {
  563. switch (curr_alt_set) {
  564. case ATH_ANT_DIV_COMB_LNA2:
  565. antcomb->rssi_lna2 = alt_rssi_avg;
  566. antcomb->rssi_lna1 = main_rssi_avg;
  567. antcomb->scan = true;
  568. /* set to A+B */
  569. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  570. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  571. break;
  572. case ATH_ANT_DIV_COMB_LNA1:
  573. antcomb->rssi_lna1 = alt_rssi_avg;
  574. antcomb->rssi_lna2 = main_rssi_avg;
  575. antcomb->scan = true;
  576. /* set to A+B */
  577. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  578. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  579. break;
  580. case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
  581. antcomb->rssi_add = alt_rssi_avg;
  582. antcomb->scan = true;
  583. /* set to A-B */
  584. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  585. break;
  586. case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
  587. antcomb->rssi_sub = alt_rssi_avg;
  588. antcomb->scan = false;
  589. if (antcomb->rssi_lna2 >
  590. (antcomb->rssi_lna1 + conf->lna1_lna2_switch_delta)) {
  591. /* use LNA2 as main LNA */
  592. if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
  593. (antcomb->rssi_add > antcomb->rssi_sub)) {
  594. /* set to A+B */
  595. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  596. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  597. } else if (antcomb->rssi_sub >
  598. antcomb->rssi_lna1) {
  599. /* set to A-B */
  600. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  601. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  602. } else {
  603. /* set to LNA1 */
  604. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  605. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  606. }
  607. } else {
  608. /* use LNA1 as main LNA */
  609. if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
  610. (antcomb->rssi_add > antcomb->rssi_sub)) {
  611. /* set to A+B */
  612. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  613. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
  614. } else if (antcomb->rssi_sub >
  615. antcomb->rssi_lna1) {
  616. /* set to A-B */
  617. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  618. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
  619. } else {
  620. /* set to LNA2 */
  621. conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  622. conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  623. }
  624. }
  625. break;
  626. default:
  627. break;
  628. }
  629. }
  630. static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf,
  631. struct ath_ant_comb *antcomb,
  632. int alt_ratio, int alt_rssi_avg,
  633. int main_rssi_avg, int curr_main_set,
  634. int curr_alt_set)
  635. {
  636. bool ret = false;
  637. if (ath_ant_div_comb_alt_check(div_ant_conf, antcomb, alt_ratio,
  638. alt_rssi_avg, main_rssi_avg)) {
  639. if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
  640. /*
  641. * Switch main and alt LNA.
  642. */
  643. div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  644. div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  645. } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
  646. div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  647. div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  648. }
  649. ret = true;
  650. } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
  651. (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
  652. /*
  653. Set alt to another LNA.
  654. */
  655. if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
  656. div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
  657. else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
  658. div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
  659. ret = true;
  660. }
  661. return ret;
  662. }
  663. static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
  664. {
  665. int alt_ratio;
  666. if (!antcomb->scan || !antcomb->alt_good)
  667. return false;
  668. if (time_after(jiffies, antcomb->scan_start_time +
  669. msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
  670. return true;
  671. if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
  672. alt_ratio = ((antcomb->alt_recv_cnt * 100) /
  673. antcomb->total_pkt_count);
  674. if (alt_ratio < antcomb->ant_ratio)
  675. return true;
  676. }
  677. return false;
  678. }
  679. void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
  680. {
  681. struct ath_hw_antcomb_conf div_ant_conf;
  682. struct ath_ant_comb *antcomb = &sc->ant_comb;
  683. int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
  684. int curr_main_set;
  685. int main_rssi = rs->rs_rssi_ctl[0];
  686. int alt_rssi = rs->rs_rssi_ctl[1];
  687. int rx_ant_conf, main_ant_conf;
  688. bool short_scan = false, ret;
  689. rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &
  690. ATH_ANT_RX_MASK;
  691. main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &
  692. ATH_ANT_RX_MASK;
  693. if (alt_rssi >= antcomb->low_rssi_thresh) {
  694. antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO;
  695. antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2;
  696. } else {
  697. antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI;
  698. antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI;
  699. }
  700. /* Record packet only when both main_rssi and alt_rssi is positive */
  701. if (main_rssi > 0 && alt_rssi > 0) {
  702. antcomb->total_pkt_count++;
  703. antcomb->main_total_rssi += main_rssi;
  704. antcomb->alt_total_rssi += alt_rssi;
  705. if (main_ant_conf == rx_ant_conf)
  706. antcomb->main_recv_cnt++;
  707. else
  708. antcomb->alt_recv_cnt++;
  709. }
  710. if (main_ant_conf == rx_ant_conf) {
  711. ANT_STAT_INC(ANT_MAIN, recv_cnt);
  712. ANT_LNA_INC(ANT_MAIN, rx_ant_conf);
  713. } else {
  714. ANT_STAT_INC(ANT_ALT, recv_cnt);
  715. ANT_LNA_INC(ANT_ALT, rx_ant_conf);
  716. }
  717. /* Short scan check */
  718. short_scan = ath_ant_short_scan_check(antcomb);
  719. if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
  720. rs->rs_moreaggr) && !short_scan)
  721. return;
  722. if (antcomb->total_pkt_count) {
  723. alt_ratio = ((antcomb->alt_recv_cnt * 100) /
  724. antcomb->total_pkt_count);
  725. main_rssi_avg = (antcomb->main_total_rssi /
  726. antcomb->total_pkt_count);
  727. alt_rssi_avg = (antcomb->alt_total_rssi /
  728. antcomb->total_pkt_count);
  729. }
  730. ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
  731. curr_alt_set = div_ant_conf.alt_lna_conf;
  732. curr_main_set = div_ant_conf.main_lna_conf;
  733. antcomb->count++;
  734. if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
  735. if (alt_ratio > antcomb->ant_ratio) {
  736. ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
  737. main_rssi_avg);
  738. antcomb->alt_good = true;
  739. } else {
  740. antcomb->alt_good = false;
  741. }
  742. antcomb->count = 0;
  743. antcomb->scan = true;
  744. antcomb->scan_not_start = true;
  745. }
  746. if (!antcomb->scan) {
  747. ret = ath_ant_try_switch(&div_ant_conf, antcomb, alt_ratio,
  748. alt_rssi_avg, main_rssi_avg,
  749. curr_main_set, curr_alt_set);
  750. if (ret)
  751. goto div_comb_done;
  752. }
  753. if (!antcomb->scan &&
  754. (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta)))
  755. goto div_comb_done;
  756. if (!antcomb->scan_not_start) {
  757. ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set,
  758. alt_rssi_avg, main_rssi_avg);
  759. } else {
  760. if (!antcomb->alt_good) {
  761. antcomb->scan_not_start = false;
  762. /* Set alt to another LNA */
  763. if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
  764. div_ant_conf.main_lna_conf =
  765. ATH_ANT_DIV_COMB_LNA2;
  766. div_ant_conf.alt_lna_conf =
  767. ATH_ANT_DIV_COMB_LNA1;
  768. } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
  769. div_ant_conf.main_lna_conf =
  770. ATH_ANT_DIV_COMB_LNA1;
  771. div_ant_conf.alt_lna_conf =
  772. ATH_ANT_DIV_COMB_LNA2;
  773. }
  774. goto div_comb_done;
  775. }
  776. ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
  777. main_rssi_avg, alt_rssi_avg,
  778. alt_ratio);
  779. antcomb->quick_scan_cnt++;
  780. }
  781. div_comb_done:
  782. ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
  783. ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
  784. ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg);
  785. antcomb->scan_start_time = jiffies;
  786. antcomb->total_pkt_count = 0;
  787. antcomb->main_total_rssi = 0;
  788. antcomb->alt_total_rssi = 0;
  789. antcomb->main_recv_cnt = 0;
  790. antcomb->alt_recv_cnt = 0;
  791. }