Merge branches 'acpica', 'acpidump', 'intel-idle', 'misc', 'module_acpi_driver-simpli...
[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         if (ant_conf->div_group == 0) {
315                 /* Adjust the fast_div_bias based on main and alt lna conf */
316                 switch ((ant_conf->main_lna_conf << 4) |
317                                 ant_conf->alt_lna_conf) {
318                 case 0x01: /* A-B LNA2 */
319                         ant_conf->fast_div_bias = 0x3b;
320                         break;
321                 case 0x02: /* A-B LNA1 */
322                         ant_conf->fast_div_bias = 0x3d;
323                         break;
324                 case 0x03: /* A-B A+B */
325                         ant_conf->fast_div_bias = 0x1;
326                         break;
327                 case 0x10: /* LNA2 A-B */
328                         ant_conf->fast_div_bias = 0x7;
329                         break;
330                 case 0x12: /* LNA2 LNA1 */
331                         ant_conf->fast_div_bias = 0x2;
332                         break;
333                 case 0x13: /* LNA2 A+B */
334                         ant_conf->fast_div_bias = 0x7;
335                         break;
336                 case 0x20: /* LNA1 A-B */
337                         ant_conf->fast_div_bias = 0x6;
338                         break;
339                 case 0x21: /* LNA1 LNA2 */
340                         ant_conf->fast_div_bias = 0x0;
341                         break;
342                 case 0x23: /* LNA1 A+B */
343                         ant_conf->fast_div_bias = 0x6;
344                         break;
345                 case 0x30: /* A+B A-B */
346                         ant_conf->fast_div_bias = 0x1;
347                         break;
348                 case 0x31: /* A+B LNA2 */
349                         ant_conf->fast_div_bias = 0x3b;
350                         break;
351                 case 0x32: /* A+B LNA1 */
352                         ant_conf->fast_div_bias = 0x3d;
353                         break;
354                 default:
355                         break;
356                 }
357         } else if (ant_conf->div_group == 1) {
358                 /* Adjust the fast_div_bias based on main and alt_lna_conf */
359                 switch ((ant_conf->main_lna_conf << 4) |
360                         ant_conf->alt_lna_conf) {
361                 case 0x01: /* A-B LNA2 */
362                         ant_conf->fast_div_bias = 0x1;
363                         ant_conf->main_gaintb = 0;
364                         ant_conf->alt_gaintb = 0;
365                         break;
366                 case 0x02: /* A-B LNA1 */
367                         ant_conf->fast_div_bias = 0x1;
368                         ant_conf->main_gaintb = 0;
369                         ant_conf->alt_gaintb = 0;
370                         break;
371                 case 0x03: /* A-B A+B */
372                         ant_conf->fast_div_bias = 0x1;
373                         ant_conf->main_gaintb = 0;
374                         ant_conf->alt_gaintb = 0;
375                         break;
376                 case 0x10: /* LNA2 A-B */
377                         if (!(antcomb->scan) &&
378                             (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
379                                 ant_conf->fast_div_bias = 0x3f;
380                         else
381                                 ant_conf->fast_div_bias = 0x1;
382                         ant_conf->main_gaintb = 0;
383                         ant_conf->alt_gaintb = 0;
384                         break;
385                 case 0x12: /* LNA2 LNA1 */
386                         ant_conf->fast_div_bias = 0x1;
387                         ant_conf->main_gaintb = 0;
388                         ant_conf->alt_gaintb = 0;
389                         break;
390                 case 0x13: /* LNA2 A+B */
391                         if (!(antcomb->scan) &&
392                             (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
393                                 ant_conf->fast_div_bias = 0x3f;
394                         else
395                                 ant_conf->fast_div_bias = 0x1;
396                         ant_conf->main_gaintb = 0;
397                         ant_conf->alt_gaintb = 0;
398                         break;
399                 case 0x20: /* LNA1 A-B */
400                         if (!(antcomb->scan) &&
401                             (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
402                                 ant_conf->fast_div_bias = 0x3f;
403                         else
404                                 ant_conf->fast_div_bias = 0x1;
405                         ant_conf->main_gaintb = 0;
406                         ant_conf->alt_gaintb = 0;
407                         break;
408                 case 0x21: /* LNA1 LNA2 */
409                         ant_conf->fast_div_bias = 0x1;
410                         ant_conf->main_gaintb = 0;
411                         ant_conf->alt_gaintb = 0;
412                         break;
413                 case 0x23: /* LNA1 A+B */
414                         if (!(antcomb->scan) &&
415                             (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
416                                 ant_conf->fast_div_bias = 0x3f;
417                         else
418                                 ant_conf->fast_div_bias = 0x1;
419                         ant_conf->main_gaintb = 0;
420                         ant_conf->alt_gaintb = 0;
421                         break;
422                 case 0x30: /* A+B A-B */
423                         ant_conf->fast_div_bias = 0x1;
424                         ant_conf->main_gaintb = 0;
425                         ant_conf->alt_gaintb = 0;
426                         break;
427                 case 0x31: /* A+B LNA2 */
428                         ant_conf->fast_div_bias = 0x1;
429                         ant_conf->main_gaintb = 0;
430                         ant_conf->alt_gaintb = 0;
431                         break;
432                 case 0x32: /* A+B LNA1 */
433                         ant_conf->fast_div_bias = 0x1;
434                         ant_conf->main_gaintb = 0;
435                         ant_conf->alt_gaintb = 0;
436                         break;
437                 default:
438                         break;
439                 }
440         } else if (ant_conf->div_group == 2) {
441                 /* Adjust the fast_div_bias based on main and alt_lna_conf */
442                 switch ((ant_conf->main_lna_conf << 4) |
443                                 ant_conf->alt_lna_conf) {
444                 case 0x01: /* A-B LNA2 */
445                         ant_conf->fast_div_bias = 0x1;
446                         ant_conf->main_gaintb = 0;
447                         ant_conf->alt_gaintb = 0;
448                         break;
449                 case 0x02: /* A-B LNA1 */
450                         ant_conf->fast_div_bias = 0x1;
451                         ant_conf->main_gaintb = 0;
452                         ant_conf->alt_gaintb = 0;
453                         break;
454                 case 0x03: /* A-B A+B */
455                         ant_conf->fast_div_bias = 0x1;
456                         ant_conf->main_gaintb = 0;
457                         ant_conf->alt_gaintb = 0;
458                         break;
459                 case 0x10: /* LNA2 A-B */
460                         if (!(antcomb->scan) &&
461                                 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
462                                 ant_conf->fast_div_bias = 0x1;
463                         else
464                                 ant_conf->fast_div_bias = 0x2;
465                         ant_conf->main_gaintb = 0;
466                         ant_conf->alt_gaintb = 0;
467                         break;
468                 case 0x12: /* LNA2 LNA1 */
469                         ant_conf->fast_div_bias = 0x1;
470                         ant_conf->main_gaintb = 0;
471                         ant_conf->alt_gaintb = 0;
472                         break;
473                 case 0x13: /* LNA2 A+B */
474                         if (!(antcomb->scan) &&
475                                 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
476                                 ant_conf->fast_div_bias = 0x1;
477                         else
478                                 ant_conf->fast_div_bias = 0x2;
479                         ant_conf->main_gaintb = 0;
480                         ant_conf->alt_gaintb = 0;
481                         break;
482                 case 0x20: /* LNA1 A-B */
483                         if (!(antcomb->scan) &&
484                                 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
485                                 ant_conf->fast_div_bias = 0x1;
486                         else
487                                 ant_conf->fast_div_bias = 0x2;
488                         ant_conf->main_gaintb = 0;
489                         ant_conf->alt_gaintb = 0;
490                         break;
491                 case 0x21: /* LNA1 LNA2 */
492                         ant_conf->fast_div_bias = 0x1;
493                         ant_conf->main_gaintb = 0;
494                         ant_conf->alt_gaintb = 0;
495                         break;
496                 case 0x23: /* LNA1 A+B */
497                         if (!(antcomb->scan) &&
498                                 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
499                                 ant_conf->fast_div_bias = 0x1;
500                         else
501                                 ant_conf->fast_div_bias = 0x2;
502                         ant_conf->main_gaintb = 0;
503                         ant_conf->alt_gaintb = 0;
504                         break;
505                 case 0x30: /* A+B A-B */
506                         ant_conf->fast_div_bias = 0x1;
507                         ant_conf->main_gaintb = 0;
508                         ant_conf->alt_gaintb = 0;
509                         break;
510                 case 0x31: /* A+B LNA2 */
511                         ant_conf->fast_div_bias = 0x1;
512                         ant_conf->main_gaintb = 0;
513                         ant_conf->alt_gaintb = 0;
514                         break;
515                 case 0x32: /* A+B LNA1 */
516                         ant_conf->fast_div_bias = 0x1;
517                         ant_conf->main_gaintb = 0;
518                         ant_conf->alt_gaintb = 0;
519                         break;
520                 default:
521                         break;
522                 }
523         }
524 }
525
526 void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
527 {
528         struct ath_hw_antcomb_conf div_ant_conf;
529         struct ath_ant_comb *antcomb = &sc->ant_comb;
530         int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
531         int curr_main_set;
532         int main_rssi = rs->rs_rssi_ctl0;
533         int alt_rssi = rs->rs_rssi_ctl1;
534         int rx_ant_conf,  main_ant_conf;
535         bool short_scan = false;
536
537         rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
538                        ATH_ANT_RX_MASK;
539         main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
540                          ATH_ANT_RX_MASK;
541
542         /* Record packet only when both main_rssi and  alt_rssi is positive */
543         if (main_rssi > 0 && alt_rssi > 0) {
544                 antcomb->total_pkt_count++;
545                 antcomb->main_total_rssi += main_rssi;
546                 antcomb->alt_total_rssi  += alt_rssi;
547                 if (main_ant_conf == rx_ant_conf)
548                         antcomb->main_recv_cnt++;
549                 else
550                         antcomb->alt_recv_cnt++;
551         }
552
553         /* Short scan check */
554         if (antcomb->scan && antcomb->alt_good) {
555                 if (time_after(jiffies, antcomb->scan_start_time +
556                     msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
557                         short_scan = true;
558                 else
559                         if (antcomb->total_pkt_count ==
560                             ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
561                                 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
562                                             antcomb->total_pkt_count);
563                                 if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
564                                         short_scan = true;
565                         }
566         }
567
568         if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
569             rs->rs_moreaggr) && !short_scan)
570                 return;
571
572         if (antcomb->total_pkt_count) {
573                 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
574                              antcomb->total_pkt_count);
575                 main_rssi_avg = (antcomb->main_total_rssi /
576                                  antcomb->total_pkt_count);
577                 alt_rssi_avg = (antcomb->alt_total_rssi /
578                                  antcomb->total_pkt_count);
579         }
580
581
582         ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
583         curr_alt_set = div_ant_conf.alt_lna_conf;
584         curr_main_set = div_ant_conf.main_lna_conf;
585
586         antcomb->count++;
587
588         if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
589                 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
590                         ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
591                                                   main_rssi_avg);
592                         antcomb->alt_good = true;
593                 } else {
594                         antcomb->alt_good = false;
595                 }
596
597                 antcomb->count = 0;
598                 antcomb->scan = true;
599                 antcomb->scan_not_start = true;
600         }
601
602         if (!antcomb->scan) {
603                 if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
604                                         alt_ratio, curr_main_set, curr_alt_set,
605                                         alt_rssi_avg, main_rssi_avg)) {
606                         if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
607                                 /* Switch main and alt LNA */
608                                 div_ant_conf.main_lna_conf =
609                                                 ATH_ANT_DIV_COMB_LNA2;
610                                 div_ant_conf.alt_lna_conf  =
611                                                 ATH_ANT_DIV_COMB_LNA1;
612                         } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
613                                 div_ant_conf.main_lna_conf =
614                                                 ATH_ANT_DIV_COMB_LNA1;
615                                 div_ant_conf.alt_lna_conf  =
616                                                 ATH_ANT_DIV_COMB_LNA2;
617                         }
618
619                         goto div_comb_done;
620                 } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
621                            (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
622                         /* Set alt to another LNA */
623                         if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
624                                 div_ant_conf.alt_lna_conf =
625                                                 ATH_ANT_DIV_COMB_LNA1;
626                         else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
627                                 div_ant_conf.alt_lna_conf =
628                                                 ATH_ANT_DIV_COMB_LNA2;
629
630                         goto div_comb_done;
631                 }
632
633                 if ((alt_rssi_avg < (main_rssi_avg +
634                                      div_ant_conf.lna1_lna2_delta)))
635                         goto div_comb_done;
636         }
637
638         if (!antcomb->scan_not_start) {
639                 switch (curr_alt_set) {
640                 case ATH_ANT_DIV_COMB_LNA2:
641                         antcomb->rssi_lna2 = alt_rssi_avg;
642                         antcomb->rssi_lna1 = main_rssi_avg;
643                         antcomb->scan = true;
644                         /* set to A+B */
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_LNA1_PLUS_LNA2;
649                         break;
650                 case ATH_ANT_DIV_COMB_LNA1:
651                         antcomb->rssi_lna1 = alt_rssi_avg;
652                         antcomb->rssi_lna2 = main_rssi_avg;
653                         antcomb->scan = true;
654                         /* set to A+B */
655                         div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
656                         div_ant_conf.alt_lna_conf  =
657                                 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
658                         break;
659                 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
660                         antcomb->rssi_add = alt_rssi_avg;
661                         antcomb->scan = true;
662                         /* set to A-B */
663                         div_ant_conf.alt_lna_conf =
664                                 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
665                         break;
666                 case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
667                         antcomb->rssi_sub = alt_rssi_avg;
668                         antcomb->scan = false;
669                         if (antcomb->rssi_lna2 >
670                             (antcomb->rssi_lna1 +
671                             ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
672                                 /* use LNA2 as main LNA */
673                                 if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
674                                     (antcomb->rssi_add > antcomb->rssi_sub)) {
675                                         /* set to A+B */
676                                         div_ant_conf.main_lna_conf =
677                                                 ATH_ANT_DIV_COMB_LNA2;
678                                         div_ant_conf.alt_lna_conf  =
679                                                 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
680                                 } else if (antcomb->rssi_sub >
681                                            antcomb->rssi_lna1) {
682                                         /* set to A-B */
683                                         div_ant_conf.main_lna_conf =
684                                                 ATH_ANT_DIV_COMB_LNA2;
685                                         div_ant_conf.alt_lna_conf =
686                                                 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
687                                 } else {
688                                         /* set to LNA1 */
689                                         div_ant_conf.main_lna_conf =
690                                                 ATH_ANT_DIV_COMB_LNA2;
691                                         div_ant_conf.alt_lna_conf =
692                                                 ATH_ANT_DIV_COMB_LNA1;
693                                 }
694                         } else {
695                                 /* use LNA1 as main LNA */
696                                 if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
697                                     (antcomb->rssi_add > antcomb->rssi_sub)) {
698                                         /* set to A+B */
699                                         div_ant_conf.main_lna_conf =
700                                                 ATH_ANT_DIV_COMB_LNA1;
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_LNA1;
708                                         div_ant_conf.alt_lna_conf =
709                                                 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
710                                 } else {
711                                         /* set to LNA2 */
712                                         div_ant_conf.main_lna_conf =
713                                                 ATH_ANT_DIV_COMB_LNA1;
714                                         div_ant_conf.alt_lna_conf =
715                                                 ATH_ANT_DIV_COMB_LNA2;
716                                 }
717                         }
718                         break;
719                 default:
720                         break;
721                 }
722         } else {
723                 if (!antcomb->alt_good) {
724                         antcomb->scan_not_start = false;
725                         /* Set alt to another LNA */
726                         if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
727                                 div_ant_conf.main_lna_conf =
728                                                 ATH_ANT_DIV_COMB_LNA2;
729                                 div_ant_conf.alt_lna_conf =
730                                                 ATH_ANT_DIV_COMB_LNA1;
731                         } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
732                                 div_ant_conf.main_lna_conf =
733                                                 ATH_ANT_DIV_COMB_LNA1;
734                                 div_ant_conf.alt_lna_conf =
735                                                 ATH_ANT_DIV_COMB_LNA2;
736                         }
737                         goto div_comb_done;
738                 }
739         }
740
741         ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
742                                            main_rssi_avg, alt_rssi_avg,
743                                            alt_ratio);
744
745         antcomb->quick_scan_cnt++;
746
747 div_comb_done:
748         ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
749         ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
750
751         antcomb->scan_start_time = jiffies;
752         antcomb->total_pkt_count = 0;
753         antcomb->main_total_rssi = 0;
754         antcomb->alt_total_rssi = 0;
755         antcomb->main_recv_cnt = 0;
756         antcomb->alt_recv_cnt = 0;
757 }
758
759 void ath_ant_comb_update(struct ath_softc *sc)
760 {
761         struct ath_hw *ah = sc->sc_ah;
762         struct ath_hw_antcomb_conf div_ant_conf;
763         u8 lna_conf;
764
765         ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
766
767         if (sc->ant_rx == 1)
768                 lna_conf = ATH_ANT_DIV_COMB_LNA1;
769         else
770                 lna_conf = ATH_ANT_DIV_COMB_LNA2;
771
772         div_ant_conf.main_lna_conf = lna_conf;
773         div_ant_conf.alt_lna_conf = lna_conf;
774
775         ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
776 }