blob: 4cd2bcead1e55132052e8f04105227d98ac0c345 [file] [log] [blame]
Sujith Manoharan8da07832012-06-04 20:23:49 +05301/*
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
17#include "ath9k.h"
18
Sujith Manoharanfd7f8382013-08-04 14:21:52 +053019/*
20 * AR9285
21 * ======
22 *
23 * EEPROM has 2 4-bit fields containing the card configuration.
24 *
25 * antdiv_ctl1:
26 * ------------
27 * bb_enable_ant_div_lnadiv : 1
28 * bb_ant_div_alt_gaintb : 1
29 * bb_ant_div_main_gaintb : 1
30 * bb_enable_ant_fast_div : 1
31 *
32 * antdiv_ctl2:
33 * -----------
34 * bb_ant_div_alt_lnaconf : 2
35 * bb_ant_div_main_lnaconf : 2
36 *
37 * The EEPROM bits are used as follows:
38 * ------------------------------------
39 *
40 * bb_enable_ant_div_lnadiv - Enable LNA path rx antenna diversity/combining.
41 * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
42 *
43 * bb_ant_div_[alt/main]_gaintb - 0 -> Antenna config Alt/Main uses gaintable 0
44 * 1 -> Antenna config Alt/Main uses gaintable 1
45 * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
46 *
47 * bb_enable_ant_fast_div - Enable fast antenna diversity.
48 * Set in AR_PHY_CCK_DETECT.
49 *
50 * bb_ant_div_[alt/main]_lnaconf - Alt/Main LNA diversity/combining input config.
51 * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
52 * 10=LNA1
53 * 01=LNA2
54 * 11=LNA1+LNA2
55 * 00=LNA1-LNA2
56 *
57 * AR9485 / AR9565 / AR9331
58 * ========================
59 *
60 * The same bits are present in the EEPROM, but the location in the
61 * EEPROM is different (ant_div_control in ar9300_BaseExtension_1).
62 *
63 * ant_div_alt_lnaconf ==> bit 0~1
64 * ant_div_main_lnaconf ==> bit 2~3
65 * ant_div_alt_gaintb ==> bit 4
66 * ant_div_main_gaintb ==> bit 5
67 * enable_ant_div_lnadiv ==> bit 6
68 * enable_ant_fast_div ==> bit 7
69 */
70
Sujith Manoharan8da07832012-06-04 20:23:49 +053071static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
72 int mindelta, int main_rssi_avg,
73 int alt_rssi_avg, int pkt_count)
74{
75 return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
76 (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
77 (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
78}
79
Sujith Manoharanef999112013-08-01 11:53:20 +053080static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf,
Sujith Manoharan552bde42013-08-01 11:53:19 +053081 int alt_ratio, int alt_rssi_avg,
82 int main_rssi_avg)
Sujith Manoharan8da07832012-06-04 20:23:49 +053083{
Sujith Manoharan552bde42013-08-01 11:53:19 +053084 bool result, set1, set2;
85
86 result = set1 = set2 = false;
87
Sujith Manoharanef999112013-08-01 11:53:20 +053088 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2 &&
89 conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA1)
Sujith Manoharan552bde42013-08-01 11:53:19 +053090 set1 = true;
91
Sujith Manoharanef999112013-08-01 11:53:20 +053092 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA1 &&
93 conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA2)
Sujith Manoharan552bde42013-08-01 11:53:19 +053094 set2 = true;
95
Sujith Manoharanef999112013-08-01 11:53:20 +053096 switch (conf->div_group) {
Sujith Manoharan8da07832012-06-04 20:23:49 +053097 case 0:
98 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
99 result = true;
100 break;
101 case 1:
102 case 2:
Sujith Manoharan552bde42013-08-01 11:53:19 +0530103 if (alt_rssi_avg < 4)
104 break;
105
106 if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 5))) ||
107 (set2 && (alt_rssi_avg >= (main_rssi_avg - 2))))
Sujith Manoharan8da07832012-06-04 20:23:49 +0530108 result = true;
Sujith Manoharan552bde42013-08-01 11:53:19 +0530109
110 break;
111 case 3:
112 if (alt_rssi_avg < 4)
113 break;
114
115 if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 3))) ||
116 (set2 && (alt_rssi_avg >= (main_rssi_avg + 3))))
117 result = true;
118
Sujith Manoharan8da07832012-06-04 20:23:49 +0530119 break;
120 }
121
122 return result;
123}
124
125static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
126 struct ath_hw_antcomb_conf ant_conf,
127 int main_rssi_avg)
128{
129 antcomb->quick_scan_cnt = 0;
130
131 if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
132 antcomb->rssi_lna2 = main_rssi_avg;
133 else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
134 antcomb->rssi_lna1 = main_rssi_avg;
135
136 switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
137 case 0x10: /* LNA2 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_LNA1;
142 break;
143 case 0x20: /* LNA1 A-B */
144 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
145 antcomb->first_quick_scan_conf =
146 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
147 antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
148 break;
149 case 0x21: /* LNA1 LNA2 */
150 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
151 antcomb->first_quick_scan_conf =
152 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
153 antcomb->second_quick_scan_conf =
154 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
155 break;
156 case 0x12: /* LNA2 LNA1 */
157 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
158 antcomb->first_quick_scan_conf =
159 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
160 antcomb->second_quick_scan_conf =
161 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
162 break;
163 case 0x13: /* LNA2 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_LNA1;
168 break;
169 case 0x23: /* LNA1 A+B */
170 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
171 antcomb->first_quick_scan_conf =
172 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
173 antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
174 break;
175 default:
176 break;
177 }
178}
179
Sujith Manoharan37133002013-08-01 11:53:23 +0530180static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb,
181 struct ath_hw_antcomb_conf *conf)
182{
183 /* set alt to the conf with maximun ratio */
184 if (antcomb->first_ratio && antcomb->second_ratio) {
185 if (antcomb->rssi_second > antcomb->rssi_third) {
186 /* first alt*/
187 if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
188 (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
189 /* Set alt LNA1 or LNA2*/
190 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
191 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
192 else
193 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
194 else
195 /* Set alt to A+B or A-B */
196 conf->alt_lna_conf =
197 antcomb->first_quick_scan_conf;
198 } else if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
199 (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) {
200 /* Set alt LNA1 or LNA2 */
201 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
202 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
203 else
204 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
205 } else {
206 /* Set alt to A+B or A-B */
207 conf->alt_lna_conf = antcomb->second_quick_scan_conf;
208 }
209 } else if (antcomb->first_ratio) {
210 /* first alt */
211 if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
212 (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
213 /* Set alt LNA1 or LNA2 */
214 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
215 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
216 else
217 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
218 else
219 /* Set alt to A+B or A-B */
220 conf->alt_lna_conf = antcomb->first_quick_scan_conf;
221 } else if (antcomb->second_ratio) {
222 /* second alt */
223 if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
224 (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
225 /* Set alt LNA1 or LNA2 */
226 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
227 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
228 else
229 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
230 else
231 /* Set alt to A+B or A-B */
232 conf->alt_lna_conf = antcomb->second_quick_scan_conf;
233 } else {
234 /* main is largest */
235 if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
236 (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
237 /* Set alt LNA1 or LNA2 */
238 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
239 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
240 else
241 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
242 else
243 /* Set alt to A+B or A-B */
244 conf->alt_lna_conf = antcomb->main_conf;
245 }
246}
247
Sujith Manoharan8da07832012-06-04 20:23:49 +0530248static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
249 struct ath_hw_antcomb_conf *div_ant_conf,
250 int main_rssi_avg, int alt_rssi_avg,
251 int alt_ratio)
252{
253 /* alt_good */
254 switch (antcomb->quick_scan_cnt) {
255 case 0:
256 /* set alt to main, and alt to first conf */
257 div_ant_conf->main_lna_conf = antcomb->main_conf;
258 div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
259 break;
260 case 1:
261 /* set alt to main, and alt to first conf */
262 div_ant_conf->main_lna_conf = antcomb->main_conf;
263 div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
264 antcomb->rssi_first = main_rssi_avg;
265 antcomb->rssi_second = alt_rssi_avg;
266
267 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
268 /* main is LNA1 */
269 if (ath_is_alt_ant_ratio_better(alt_ratio,
270 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
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 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
278 if (ath_is_alt_ant_ratio_better(alt_ratio,
279 ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
280 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
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 } else {
Sujith Manoharan9ddf0302013-08-01 11:53:22 +0530287 if (ath_is_alt_ant_ratio_better(alt_ratio,
288 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
289 0,
290 main_rssi_avg, alt_rssi_avg,
291 antcomb->total_pkt_count))
Sujith Manoharan8da07832012-06-04 20:23:49 +0530292 antcomb->first_ratio = true;
293 else
294 antcomb->first_ratio = false;
295 }
296 break;
297 case 2:
298 antcomb->alt_good = false;
299 antcomb->scan_not_start = false;
300 antcomb->scan = false;
301 antcomb->rssi_first = main_rssi_avg;
302 antcomb->rssi_third = alt_rssi_avg;
303
Sujith Manoharan37133002013-08-01 11:53:23 +0530304 switch(antcomb->second_quick_scan_conf) {
305 case ATH_ANT_DIV_COMB_LNA1:
Sujith Manoharan8da07832012-06-04 20:23:49 +0530306 antcomb->rssi_lna1 = alt_rssi_avg;
Sujith Manoharan37133002013-08-01 11:53:23 +0530307 break;
308 case ATH_ANT_DIV_COMB_LNA2:
Sujith Manoharan8da07832012-06-04 20:23:49 +0530309 antcomb->rssi_lna2 = alt_rssi_avg;
Sujith Manoharan37133002013-08-01 11:53:23 +0530310 break;
311 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
Sujith Manoharan8da07832012-06-04 20:23:49 +0530312 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
313 antcomb->rssi_lna2 = main_rssi_avg;
314 else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
315 antcomb->rssi_lna1 = main_rssi_avg;
Sujith Manoharan37133002013-08-01 11:53:23 +0530316 break;
317 default:
318 break;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530319 }
320
321 if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
322 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
323 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
324 else
325 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
326
327 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
328 if (ath_is_alt_ant_ratio_better(alt_ratio,
329 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
330 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
331 main_rssi_avg, alt_rssi_avg,
332 antcomb->total_pkt_count))
333 antcomb->second_ratio = true;
334 else
335 antcomb->second_ratio = false;
336 } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
337 if (ath_is_alt_ant_ratio_better(alt_ratio,
338 ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
339 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
340 main_rssi_avg, alt_rssi_avg,
341 antcomb->total_pkt_count))
342 antcomb->second_ratio = true;
343 else
344 antcomb->second_ratio = false;
345 } else {
Sujith Manoharan9ddf0302013-08-01 11:53:22 +0530346 if (ath_is_alt_ant_ratio_better(alt_ratio,
347 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
348 0,
349 main_rssi_avg, alt_rssi_avg,
350 antcomb->total_pkt_count))
Sujith Manoharan8da07832012-06-04 20:23:49 +0530351 antcomb->second_ratio = true;
352 else
353 antcomb->second_ratio = false;
354 }
355
Sujith Manoharan37133002013-08-01 11:53:23 +0530356 ath_ant_set_alt_ratio(antcomb, div_ant_conf);
357
Sujith Manoharan8da07832012-06-04 20:23:49 +0530358 break;
359 default:
360 break;
361 }
362}
363
364static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
365 struct ath_ant_comb *antcomb,
366 int alt_ratio)
367{
Sujith Manoharand85ed412012-09-16 08:05:40 +0530368 ant_conf->main_gaintb = 0;
369 ant_conf->alt_gaintb = 0;
370
Sujith Manoharan8da07832012-06-04 20:23:49 +0530371 if (ant_conf->div_group == 0) {
372 /* Adjust the fast_div_bias based on main and alt lna conf */
373 switch ((ant_conf->main_lna_conf << 4) |
374 ant_conf->alt_lna_conf) {
375 case 0x01: /* A-B LNA2 */
376 ant_conf->fast_div_bias = 0x3b;
377 break;
378 case 0x02: /* A-B LNA1 */
379 ant_conf->fast_div_bias = 0x3d;
380 break;
381 case 0x03: /* A-B A+B */
382 ant_conf->fast_div_bias = 0x1;
383 break;
384 case 0x10: /* LNA2 A-B */
385 ant_conf->fast_div_bias = 0x7;
386 break;
387 case 0x12: /* LNA2 LNA1 */
388 ant_conf->fast_div_bias = 0x2;
389 break;
390 case 0x13: /* LNA2 A+B */
391 ant_conf->fast_div_bias = 0x7;
392 break;
393 case 0x20: /* LNA1 A-B */
394 ant_conf->fast_div_bias = 0x6;
395 break;
396 case 0x21: /* LNA1 LNA2 */
397 ant_conf->fast_div_bias = 0x0;
398 break;
399 case 0x23: /* LNA1 A+B */
400 ant_conf->fast_div_bias = 0x6;
401 break;
402 case 0x30: /* A+B A-B */
403 ant_conf->fast_div_bias = 0x1;
404 break;
405 case 0x31: /* A+B LNA2 */
406 ant_conf->fast_div_bias = 0x3b;
407 break;
408 case 0x32: /* A+B LNA1 */
409 ant_conf->fast_div_bias = 0x3d;
410 break;
411 default:
412 break;
413 }
414 } else if (ant_conf->div_group == 1) {
415 /* Adjust the fast_div_bias based on main and alt_lna_conf */
416 switch ((ant_conf->main_lna_conf << 4) |
417 ant_conf->alt_lna_conf) {
418 case 0x01: /* A-B LNA2 */
419 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530420 break;
421 case 0x02: /* A-B LNA1 */
422 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530423 break;
424 case 0x03: /* A-B A+B */
425 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530426 break;
427 case 0x10: /* LNA2 A-B */
428 if (!(antcomb->scan) &&
429 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
430 ant_conf->fast_div_bias = 0x3f;
431 else
432 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530433 break;
434 case 0x12: /* LNA2 LNA1 */
435 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530436 break;
437 case 0x13: /* LNA2 A+B */
438 if (!(antcomb->scan) &&
439 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
440 ant_conf->fast_div_bias = 0x3f;
441 else
442 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530443 break;
444 case 0x20: /* LNA1 A-B */
445 if (!(antcomb->scan) &&
446 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
447 ant_conf->fast_div_bias = 0x3f;
448 else
449 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530450 break;
451 case 0x21: /* LNA1 LNA2 */
452 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530453 break;
454 case 0x23: /* LNA1 A+B */
455 if (!(antcomb->scan) &&
456 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
457 ant_conf->fast_div_bias = 0x3f;
458 else
459 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530460 break;
461 case 0x30: /* A+B A-B */
462 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530463 break;
464 case 0x31: /* A+B LNA2 */
465 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530466 break;
467 case 0x32: /* A+B LNA1 */
468 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530469 break;
470 default:
471 break;
472 }
473 } else if (ant_conf->div_group == 2) {
474 /* Adjust the fast_div_bias based on main and alt_lna_conf */
475 switch ((ant_conf->main_lna_conf << 4) |
476 ant_conf->alt_lna_conf) {
477 case 0x01: /* A-B LNA2 */
478 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530479 break;
480 case 0x02: /* A-B LNA1 */
481 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530482 break;
483 case 0x03: /* A-B A+B */
484 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530485 break;
486 case 0x10: /* LNA2 A-B */
487 if (!(antcomb->scan) &&
488 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
489 ant_conf->fast_div_bias = 0x1;
490 else
491 ant_conf->fast_div_bias = 0x2;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530492 break;
493 case 0x12: /* LNA2 LNA1 */
494 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530495 break;
496 case 0x13: /* LNA2 A+B */
497 if (!(antcomb->scan) &&
498 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
499 ant_conf->fast_div_bias = 0x1;
500 else
501 ant_conf->fast_div_bias = 0x2;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530502 break;
503 case 0x20: /* LNA1 A-B */
504 if (!(antcomb->scan) &&
505 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
506 ant_conf->fast_div_bias = 0x1;
507 else
508 ant_conf->fast_div_bias = 0x2;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530509 break;
510 case 0x21: /* LNA1 LNA2 */
511 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530512 break;
513 case 0x23: /* LNA1 A+B */
514 if (!(antcomb->scan) &&
515 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
516 ant_conf->fast_div_bias = 0x1;
517 else
518 ant_conf->fast_div_bias = 0x2;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530519 break;
520 case 0x30: /* A+B A-B */
521 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530522 break;
523 case 0x31: /* A+B LNA2 */
524 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530525 break;
526 case 0x32: /* A+B LNA1 */
527 ant_conf->fast_div_bias = 0x1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530528 break;
529 default:
530 break;
531 }
Sujith Manoharan5317c9c2012-09-16 08:06:08 +0530532 } else if (ant_conf->div_group == 3) {
533 switch ((ant_conf->main_lna_conf << 4) |
534 ant_conf->alt_lna_conf) {
535 case 0x01: /* A-B LNA2 */
536 ant_conf->fast_div_bias = 0x1;
537 break;
538 case 0x02: /* A-B LNA1 */
539 ant_conf->fast_div_bias = 0x39;
540 break;
541 case 0x03: /* A-B A+B */
542 ant_conf->fast_div_bias = 0x1;
543 break;
544 case 0x10: /* LNA2 A-B */
545 if ((antcomb->scan == 0) &&
546 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
547 ant_conf->fast_div_bias = 0x3f;
548 } else {
549 ant_conf->fast_div_bias = 0x1;
550 }
551 break;
552 case 0x12: /* LNA2 LNA1 */
553 ant_conf->fast_div_bias = 0x39;
554 break;
555 case 0x13: /* LNA2 A+B */
556 if ((antcomb->scan == 0) &&
557 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
558 ant_conf->fast_div_bias = 0x3f;
559 } else {
560 ant_conf->fast_div_bias = 0x1;
561 }
562 break;
563 case 0x20: /* LNA1 A-B */
564 if ((antcomb->scan == 0) &&
565 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
566 ant_conf->fast_div_bias = 0x3f;
567 } else {
568 ant_conf->fast_div_bias = 0x4;
569 }
570 break;
571 case 0x21: /* LNA1 LNA2 */
572 ant_conf->fast_div_bias = 0x6;
573 break;
574 case 0x23: /* LNA1 A+B */
575 if ((antcomb->scan == 0) &&
576 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
577 ant_conf->fast_div_bias = 0x3f;
578 } else {
579 ant_conf->fast_div_bias = 0x6;
580 }
581 break;
582 case 0x30: /* A+B A-B */
583 ant_conf->fast_div_bias = 0x1;
584 break;
585 case 0x31: /* A+B LNA2 */
586 ant_conf->fast_div_bias = 0x6;
587 break;
588 case 0x32: /* A+B LNA1 */
589 ant_conf->fast_div_bias = 0x1;
590 break;
591 default:
592 break;
593 }
Sujith Manoharan8da07832012-06-04 20:23:49 +0530594 }
595}
596
Sujith Manoharan5f800ff2013-08-01 11:53:21 +0530597static void ath_ant_try_scan(struct ath_ant_comb *antcomb,
598 struct ath_hw_antcomb_conf *conf,
599 int curr_alt_set, int alt_rssi_avg,
600 int main_rssi_avg)
601{
602 switch (curr_alt_set) {
603 case ATH_ANT_DIV_COMB_LNA2:
604 antcomb->rssi_lna2 = alt_rssi_avg;
605 antcomb->rssi_lna1 = main_rssi_avg;
606 antcomb->scan = true;
607 /* set to A+B */
608 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
609 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
610 break;
611 case ATH_ANT_DIV_COMB_LNA1:
612 antcomb->rssi_lna1 = alt_rssi_avg;
613 antcomb->rssi_lna2 = main_rssi_avg;
614 antcomb->scan = true;
615 /* set to A+B */
616 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
617 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
618 break;
619 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
620 antcomb->rssi_add = alt_rssi_avg;
621 antcomb->scan = true;
622 /* set to A-B */
623 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
624 break;
625 case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
626 antcomb->rssi_sub = alt_rssi_avg;
627 antcomb->scan = false;
628 if (antcomb->rssi_lna2 >
629 (antcomb->rssi_lna1 + ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
630 /* use LNA2 as main LNA */
631 if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
632 (antcomb->rssi_add > antcomb->rssi_sub)) {
633 /* set to A+B */
634 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
635 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
636 } else if (antcomb->rssi_sub >
637 antcomb->rssi_lna1) {
638 /* set to A-B */
639 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
640 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
641 } else {
642 /* set to LNA1 */
643 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
644 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
645 }
646 } else {
647 /* use LNA1 as main LNA */
648 if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
649 (antcomb->rssi_add > antcomb->rssi_sub)) {
650 /* set to A+B */
651 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
652 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
653 } else if (antcomb->rssi_sub >
654 antcomb->rssi_lna1) {
655 /* set to A-B */
656 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
657 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
658 } else {
659 /* set to LNA2 */
660 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
661 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
662 }
663 }
664 break;
665 default:
666 break;
667 }
668}
669
Sujith Manoharanef999112013-08-01 11:53:20 +0530670static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf,
671 int alt_ratio, int alt_rssi_avg,
672 int main_rssi_avg, int curr_main_set,
673 int curr_alt_set)
674{
675 bool ret = false;
676
677 if (ath_ant_div_comb_alt_check(div_ant_conf, alt_ratio,
678 alt_rssi_avg, main_rssi_avg)) {
679 if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
680 /*
681 * Switch main and alt LNA.
682 */
683 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
684 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
685 } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
686 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
687 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
688 }
689
690 ret = true;
691 } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
692 (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
693 /*
694 Set alt to another LNA.
695 */
696 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
697 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
698 else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
699 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
700
701 ret = true;
702 }
703
704 return ret;
705}
706
Sujith Manoharan9383be42013-08-01 11:53:18 +0530707static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
708{
709 int alt_ratio;
710
711 if (!antcomb->scan || !antcomb->alt_good)
712 return false;
713
714 if (time_after(jiffies, antcomb->scan_start_time +
715 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
716 return true;
717
718 if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
719 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
720 antcomb->total_pkt_count);
721 if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
722 return true;
723 }
724
725 return false;
726}
727
Sujith Manoharan8da07832012-06-04 20:23:49 +0530728void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
729{
730 struct ath_hw_antcomb_conf div_ant_conf;
731 struct ath_ant_comb *antcomb = &sc->ant_comb;
732 int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
733 int curr_main_set;
734 int main_rssi = rs->rs_rssi_ctl0;
735 int alt_rssi = rs->rs_rssi_ctl1;
736 int rx_ant_conf, main_ant_conf;
Sujith Manoharanef999112013-08-01 11:53:20 +0530737 bool short_scan = false, ret;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530738
739 rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
740 ATH_ANT_RX_MASK;
741 main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
742 ATH_ANT_RX_MASK;
743
744 /* Record packet only when both main_rssi and alt_rssi is positive */
745 if (main_rssi > 0 && alt_rssi > 0) {
746 antcomb->total_pkt_count++;
747 antcomb->main_total_rssi += main_rssi;
748 antcomb->alt_total_rssi += alt_rssi;
Sujith Manoharan3fbaf4c2013-08-01 11:53:17 +0530749
Sujith Manoharane3d52912013-08-01 20:57:06 +0530750 if (main_ant_conf == rx_ant_conf)
Sujith Manoharan8da07832012-06-04 20:23:49 +0530751 antcomb->main_recv_cnt++;
Sujith Manoharane3d52912013-08-01 20:57:06 +0530752 else
Sujith Manoharan8da07832012-06-04 20:23:49 +0530753 antcomb->alt_recv_cnt++;
Sujith Manoharane3d52912013-08-01 20:57:06 +0530754 }
755
756 if (main_ant_conf == rx_ant_conf) {
757 ANT_STAT_INC(ANT_MAIN, recv_cnt);
758 ANT_LNA_INC(ANT_MAIN, rx_ant_conf);
759 } else {
760 ANT_STAT_INC(ANT_ALT, recv_cnt);
761 ANT_LNA_INC(ANT_ALT, rx_ant_conf);
Sujith Manoharan8da07832012-06-04 20:23:49 +0530762 }
763
764 /* Short scan check */
Sujith Manoharan9383be42013-08-01 11:53:18 +0530765 short_scan = ath_ant_short_scan_check(antcomb);
Sujith Manoharan8da07832012-06-04 20:23:49 +0530766
767 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
Sujith Manoharan9383be42013-08-01 11:53:18 +0530768 rs->rs_moreaggr) && !short_scan)
Sujith Manoharan8da07832012-06-04 20:23:49 +0530769 return;
770
771 if (antcomb->total_pkt_count) {
772 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
773 antcomb->total_pkt_count);
774 main_rssi_avg = (antcomb->main_total_rssi /
775 antcomb->total_pkt_count);
776 alt_rssi_avg = (antcomb->alt_total_rssi /
777 antcomb->total_pkt_count);
778 }
779
Sujith Manoharan8da07832012-06-04 20:23:49 +0530780 ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
781 curr_alt_set = div_ant_conf.alt_lna_conf;
782 curr_main_set = div_ant_conf.main_lna_conf;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530783 antcomb->count++;
784
785 if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
786 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
787 ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
788 main_rssi_avg);
789 antcomb->alt_good = true;
790 } else {
791 antcomb->alt_good = false;
792 }
793
794 antcomb->count = 0;
795 antcomb->scan = true;
796 antcomb->scan_not_start = true;
797 }
798
799 if (!antcomb->scan) {
Sujith Manoharanef999112013-08-01 11:53:20 +0530800 ret = ath_ant_try_switch(&div_ant_conf, alt_ratio,
801 alt_rssi_avg, main_rssi_avg,
802 curr_main_set, curr_alt_set);
803 if (ret)
Sujith Manoharan8da07832012-06-04 20:23:49 +0530804 goto div_comb_done;
805 }
806
Sujith Manoharanef999112013-08-01 11:53:20 +0530807 if (!antcomb->scan &&
808 (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta)))
809 goto div_comb_done;
810
Sujith Manoharan8da07832012-06-04 20:23:49 +0530811 if (!antcomb->scan_not_start) {
Sujith Manoharan5f800ff2013-08-01 11:53:21 +0530812 ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set,
813 alt_rssi_avg, main_rssi_avg);
Sujith Manoharan8da07832012-06-04 20:23:49 +0530814 } else {
815 if (!antcomb->alt_good) {
816 antcomb->scan_not_start = false;
817 /* Set alt to another LNA */
818 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
819 div_ant_conf.main_lna_conf =
Sujith Manoharan5f800ff2013-08-01 11:53:21 +0530820 ATH_ANT_DIV_COMB_LNA2;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530821 div_ant_conf.alt_lna_conf =
Sujith Manoharan5f800ff2013-08-01 11:53:21 +0530822 ATH_ANT_DIV_COMB_LNA1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530823 } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
824 div_ant_conf.main_lna_conf =
Sujith Manoharan5f800ff2013-08-01 11:53:21 +0530825 ATH_ANT_DIV_COMB_LNA1;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530826 div_ant_conf.alt_lna_conf =
Sujith Manoharan5f800ff2013-08-01 11:53:21 +0530827 ATH_ANT_DIV_COMB_LNA2;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530828 }
829 goto div_comb_done;
830 }
Sujith Manoharan3fbaf4c2013-08-01 11:53:17 +0530831 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
832 main_rssi_avg, alt_rssi_avg,
833 alt_ratio);
834 antcomb->quick_scan_cnt++;
Sujith Manoharan8da07832012-06-04 20:23:49 +0530835 }
836
Sujith Manoharan8da07832012-06-04 20:23:49 +0530837div_comb_done:
838 ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
839 ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
Sujith Manoharane3d52912013-08-01 20:57:06 +0530840 ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg);
Sujith Manoharan8da07832012-06-04 20:23:49 +0530841
842 antcomb->scan_start_time = jiffies;
843 antcomb->total_pkt_count = 0;
844 antcomb->main_total_rssi = 0;
845 antcomb->alt_total_rssi = 0;
846 antcomb->main_recv_cnt = 0;
847 antcomb->alt_recv_cnt = 0;
848}
849
850void ath_ant_comb_update(struct ath_softc *sc)
851{
852 struct ath_hw *ah = sc->sc_ah;
Sujith Manoharane09f2dc2012-09-16 08:06:56 +0530853 struct ath_common *common = ath9k_hw_common(ah);
Sujith Manoharan8da07832012-06-04 20:23:49 +0530854 struct ath_hw_antcomb_conf div_ant_conf;
855 u8 lna_conf;
856
857 ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
858
859 if (sc->ant_rx == 1)
860 lna_conf = ATH_ANT_DIV_COMB_LNA1;
861 else
862 lna_conf = ATH_ANT_DIV_COMB_LNA2;
863
864 div_ant_conf.main_lna_conf = lna_conf;
865 div_ant_conf.alt_lna_conf = lna_conf;
866
867 ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
Sujith Manoharane09f2dc2012-09-16 08:06:56 +0530868
869 if (common->antenna_diversity)
870 ath9k_hw_antctrl_shared_chain_lnadiv(ah, true);
Sujith Manoharan8da07832012-06-04 20:23:49 +0530871}