ath9k: Simplify checks in quick_scan
[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 (ath_is_alt_ant_ratio_better(alt_ratio,
168                                                 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
169                                                 0,
170                                                 main_rssi_avg, alt_rssi_avg,
171                                                 antcomb->total_pkt_count))
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 (ath_is_alt_ant_ratio_better(alt_ratio,
223                                                 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
224                                                 0,
225                                                 main_rssi_avg, alt_rssi_avg,
226                                                 antcomb->total_pkt_count))
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 void ath_ant_try_scan(struct ath_ant_comb *antcomb,
561                              struct ath_hw_antcomb_conf *conf,
562                              int curr_alt_set, int alt_rssi_avg,
563                              int main_rssi_avg)
564 {
565         switch (curr_alt_set) {
566         case ATH_ANT_DIV_COMB_LNA2:
567                 antcomb->rssi_lna2 = alt_rssi_avg;
568                 antcomb->rssi_lna1 = main_rssi_avg;
569                 antcomb->scan = true;
570                 /* set to A+B */
571                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
572                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
573                 break;
574         case ATH_ANT_DIV_COMB_LNA1:
575                 antcomb->rssi_lna1 = alt_rssi_avg;
576                 antcomb->rssi_lna2 = main_rssi_avg;
577                 antcomb->scan = true;
578                 /* set to A+B */
579                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
580                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
581                 break;
582         case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
583                 antcomb->rssi_add = alt_rssi_avg;
584                 antcomb->scan = true;
585                 /* set to A-B */
586                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
587                 break;
588         case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
589                 antcomb->rssi_sub = alt_rssi_avg;
590                 antcomb->scan = false;
591                 if (antcomb->rssi_lna2 >
592                     (antcomb->rssi_lna1 + ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
593                         /* use LNA2 as main LNA */
594                         if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
595                             (antcomb->rssi_add > antcomb->rssi_sub)) {
596                                 /* set to A+B */
597                                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
598                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
599                         } else if (antcomb->rssi_sub >
600                                    antcomb->rssi_lna1) {
601                                 /* set to A-B */
602                                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
603                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
604                         } else {
605                                 /* set to LNA1 */
606                                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
607                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
608                         }
609                 } else {
610                         /* use LNA1 as main LNA */
611                         if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
612                             (antcomb->rssi_add > antcomb->rssi_sub)) {
613                                 /* set to A+B */
614                                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
615                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
616                         } else if (antcomb->rssi_sub >
617                                    antcomb->rssi_lna1) {
618                                 /* set to A-B */
619                                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
620                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
621                         } else {
622                                 /* set to LNA2 */
623                                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
624                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
625                         }
626                 }
627                 break;
628         default:
629                 break;
630         }
631 }
632
633 static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf,
634                                int alt_ratio, int alt_rssi_avg,
635                                int main_rssi_avg, int curr_main_set,
636                                int curr_alt_set)
637 {
638         bool ret = false;
639
640         if (ath_ant_div_comb_alt_check(div_ant_conf, alt_ratio,
641                                        alt_rssi_avg, main_rssi_avg)) {
642                 if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
643                         /*
644                          * Switch main and alt LNA.
645                          */
646                         div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
647                         div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
648                 } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
649                         div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
650                         div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
651                 }
652
653                 ret = true;
654         } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
655                    (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
656                 /*
657                   Set alt to another LNA.
658                 */
659                 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
660                         div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
661                 else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
662                         div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
663
664                 ret = true;
665         }
666
667         return ret;
668 }
669
670 static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
671 {
672         int alt_ratio;
673
674         if (!antcomb->scan || !antcomb->alt_good)
675                 return false;
676
677         if (time_after(jiffies, antcomb->scan_start_time +
678                        msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
679                 return true;
680
681         if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
682                 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
683                              antcomb->total_pkt_count);
684                 if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
685                         return true;
686         }
687
688         return false;
689 }
690
691 void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
692 {
693         struct ath_hw_antcomb_conf div_ant_conf;
694         struct ath_ant_comb *antcomb = &sc->ant_comb;
695         int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
696         int curr_main_set;
697         int main_rssi = rs->rs_rssi_ctl0;
698         int alt_rssi = rs->rs_rssi_ctl1;
699         int rx_ant_conf,  main_ant_conf;
700         bool short_scan = false, ret;
701
702         rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
703                        ATH_ANT_RX_MASK;
704         main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
705                          ATH_ANT_RX_MASK;
706
707         /* Record packet only when both main_rssi and  alt_rssi is positive */
708         if (main_rssi > 0 && alt_rssi > 0) {
709                 antcomb->total_pkt_count++;
710                 antcomb->main_total_rssi += main_rssi;
711                 antcomb->alt_total_rssi  += alt_rssi;
712
713                 if (main_ant_conf == rx_ant_conf) {
714                         antcomb->main_recv_cnt++;
715                         ANT_STAT_INC(ANT_MAIN, recv_cnt);
716                         ANT_LNA_INC(ANT_MAIN, rx_ant_conf);
717                 } else {
718                         antcomb->alt_recv_cnt++;
719                         ANT_STAT_INC(ANT_ALT, recv_cnt);
720                         ANT_LNA_INC(ANT_ALT, rx_ant_conf);
721                 }
722         }
723
724         /* Short scan check */
725         short_scan = ath_ant_short_scan_check(antcomb);
726
727         if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
728              rs->rs_moreaggr) && !short_scan)
729                 return;
730
731         if (antcomb->total_pkt_count) {
732                 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
733                              antcomb->total_pkt_count);
734                 main_rssi_avg = (antcomb->main_total_rssi /
735                                  antcomb->total_pkt_count);
736                 alt_rssi_avg = (antcomb->alt_total_rssi /
737                                  antcomb->total_pkt_count);
738         }
739
740         ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
741         curr_alt_set = div_ant_conf.alt_lna_conf;
742         curr_main_set = div_ant_conf.main_lna_conf;
743         antcomb->count++;
744
745         if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
746                 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
747                         ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
748                                                   main_rssi_avg);
749                         antcomb->alt_good = true;
750                 } else {
751                         antcomb->alt_good = false;
752                 }
753
754                 antcomb->count = 0;
755                 antcomb->scan = true;
756                 antcomb->scan_not_start = true;
757         }
758
759         if (!antcomb->scan) {
760                 ret = ath_ant_try_switch(&div_ant_conf, alt_ratio,
761                                          alt_rssi_avg, main_rssi_avg,
762                                          curr_main_set, curr_alt_set);
763                 if (ret)
764                         goto div_comb_done;
765         }
766
767         if (!antcomb->scan &&
768             (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta)))
769                 goto div_comb_done;
770
771         if (!antcomb->scan_not_start) {
772                 ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set,
773                                  alt_rssi_avg, main_rssi_avg);
774         } else {
775                 if (!antcomb->alt_good) {
776                         antcomb->scan_not_start = false;
777                         /* Set alt to another LNA */
778                         if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
779                                 div_ant_conf.main_lna_conf =
780                                         ATH_ANT_DIV_COMB_LNA2;
781                                 div_ant_conf.alt_lna_conf =
782                                         ATH_ANT_DIV_COMB_LNA1;
783                         } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
784                                 div_ant_conf.main_lna_conf =
785                                         ATH_ANT_DIV_COMB_LNA1;
786                                 div_ant_conf.alt_lna_conf =
787                                         ATH_ANT_DIV_COMB_LNA2;
788                         }
789                         goto div_comb_done;
790                 }
791                 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
792                                                    main_rssi_avg, alt_rssi_avg,
793                                                    alt_ratio);
794                 antcomb->quick_scan_cnt++;
795         }
796
797 div_comb_done:
798         ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
799         ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
800
801         antcomb->scan_start_time = jiffies;
802         antcomb->total_pkt_count = 0;
803         antcomb->main_total_rssi = 0;
804         antcomb->alt_total_rssi = 0;
805         antcomb->main_recv_cnt = 0;
806         antcomb->alt_recv_cnt = 0;
807 }
808
809 void ath_ant_comb_update(struct ath_softc *sc)
810 {
811         struct ath_hw *ah = sc->sc_ah;
812         struct ath_common *common = ath9k_hw_common(ah);
813         struct ath_hw_antcomb_conf div_ant_conf;
814         u8 lna_conf;
815
816         ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
817
818         if (sc->ant_rx == 1)
819                 lna_conf = ATH_ANT_DIV_COMB_LNA1;
820         else
821                 lna_conf = ATH_ANT_DIV_COMB_LNA2;
822
823         div_ant_conf.main_lna_conf = lna_conf;
824         div_ant_conf.alt_lna_conf = lna_conf;
825
826         ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
827
828         if (common->antenna_diversity)
829                 ath9k_hw_antctrl_shared_chain_lnadiv(ah, true);
830 }