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