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