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