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