Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2008-2011 Atheros Communications Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include "hw.h"
0018 #include <linux/ath9k_platform.h>
0019 
0020 void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
0021 {
0022         REG_WRITE(ah, reg, val);
0023 
0024         if (ah->config.analog_shiftreg)
0025         udelay(100);
0026 }
0027 
0028 void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
0029                    u32 shift, u32 val)
0030 {
0031     REG_RMW(ah, reg, ((val << shift) & mask), mask);
0032 
0033     if (ah->config.analog_shiftreg)
0034         udelay(100);
0035 }
0036 
0037 int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
0038                  int16_t targetLeft, int16_t targetRight)
0039 {
0040     int16_t rv;
0041 
0042     if (srcRight == srcLeft) {
0043         rv = targetLeft;
0044     } else {
0045         rv = (int16_t) (((target - srcLeft) * targetRight +
0046                  (srcRight - target) * targetLeft) /
0047                 (srcRight - srcLeft));
0048     }
0049     return rv;
0050 }
0051 
0052 bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
0053                     u16 *indexL, u16 *indexR)
0054 {
0055     u16 i;
0056 
0057     if (target <= pList[0]) {
0058         *indexL = *indexR = 0;
0059         return true;
0060     }
0061     if (target >= pList[listSize - 1]) {
0062         *indexL = *indexR = (u16) (listSize - 1);
0063         return true;
0064     }
0065 
0066     for (i = 0; i < listSize - 1; i++) {
0067         if (pList[i] == target) {
0068             *indexL = *indexR = i;
0069             return true;
0070         }
0071         if (target < pList[i + 1]) {
0072             *indexL = i;
0073             *indexR = (u16) (i + 1);
0074             return false;
0075         }
0076     }
0077     return false;
0078 }
0079 
0080 void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
0081                   int eep_start_loc, int size)
0082 {
0083     int i = 0, j, addr;
0084     u32 addrdata[8];
0085     u32 data[8];
0086 
0087     for (addr = 0; addr < size; addr++) {
0088         addrdata[i] = AR5416_EEPROM_OFFSET +
0089             ((addr + eep_start_loc) << AR5416_EEPROM_S);
0090         i++;
0091         if (i == 8) {
0092             REG_READ_MULTI(ah, addrdata, data, i);
0093 
0094             for (j = 0; j < i; j++) {
0095                 *eep_data = data[j];
0096                 eep_data++;
0097             }
0098             i = 0;
0099         }
0100     }
0101 
0102     if (i != 0) {
0103         REG_READ_MULTI(ah, addrdata, data, i);
0104 
0105         for (j = 0; j < i; j++) {
0106             *eep_data = data[j];
0107             eep_data++;
0108         }
0109     }
0110 }
0111 
0112 static bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size,
0113                       off_t offset, u16 *data)
0114 {
0115     if (offset >= blob_size)
0116         return false;
0117 
0118     *data =  blob[offset];
0119     return true;
0120 }
0121 
0122 static bool ath9k_hw_nvram_read_pdata(struct ath9k_platform_data *pdata,
0123                       off_t offset, u16 *data)
0124 {
0125     return ath9k_hw_nvram_read_array(pdata->eeprom_data,
0126                      ARRAY_SIZE(pdata->eeprom_data),
0127                      offset, data);
0128 }
0129 
0130 static bool ath9k_hw_nvram_read_firmware(const struct firmware *eeprom_blob,
0131                      off_t offset, u16 *data)
0132 {
0133     return ath9k_hw_nvram_read_array((u16 *) eeprom_blob->data,
0134                      eeprom_blob->size / sizeof(u16),
0135                      offset, data);
0136 }
0137 
0138 static bool ath9k_hw_nvram_read_nvmem(struct ath_hw *ah, off_t offset,
0139                       u16 *data)
0140 {
0141     return ath9k_hw_nvram_read_array(ah->nvmem_blob,
0142                      ah->nvmem_blob_len / sizeof(u16),
0143                      offset, data);
0144 }
0145 
0146 bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
0147 {
0148     struct ath_common *common = ath9k_hw_common(ah);
0149     struct ath9k_platform_data *pdata = ah->dev->platform_data;
0150     bool ret;
0151 
0152     if (ah->nvmem_blob)
0153         ret = ath9k_hw_nvram_read_nvmem(ah, off, data);
0154     else if (ah->eeprom_blob)
0155         ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data);
0156     else if (pdata && !pdata->use_eeprom)
0157         ret = ath9k_hw_nvram_read_pdata(pdata, off, data);
0158     else
0159         ret = common->bus_ops->eeprom_read(common, off, data);
0160 
0161     if (!ret)
0162         ath_dbg(common, EEPROM,
0163             "unable to read eeprom region at offset %u\n", off);
0164 
0165     return ret;
0166 }
0167 
0168 int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)
0169 {
0170     u16 magic;
0171     u16 *eepdata;
0172     int i;
0173     bool needs_byteswap = false;
0174     struct ath_common *common = ath9k_hw_common(ah);
0175 
0176     if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
0177         ath_err(common, "Reading Magic # failed\n");
0178         return -EIO;
0179     }
0180 
0181     if (swab16(magic) == AR5416_EEPROM_MAGIC) {
0182         needs_byteswap = true;
0183         ath_dbg(common, EEPROM,
0184             "EEPROM needs byte-swapping to correct endianness.\n");
0185     } else if (magic != AR5416_EEPROM_MAGIC) {
0186         if (ath9k_hw_use_flash(ah)) {
0187             ath_dbg(common, EEPROM,
0188                 "Ignoring invalid EEPROM magic (0x%04x).\n",
0189                 magic);
0190         } else {
0191             ath_err(common,
0192                 "Invalid EEPROM magic (0x%04x).\n", magic);
0193             return -EINVAL;
0194         }
0195     }
0196 
0197     if (needs_byteswap) {
0198         if (ah->ah_flags & AH_NO_EEP_SWAP) {
0199             ath_info(common,
0200                  "Ignoring endianness difference in EEPROM magic bytes.\n");
0201         } else {
0202             eepdata = (u16 *)(&ah->eeprom);
0203 
0204             for (i = 0; i < size; i++)
0205                 eepdata[i] = swab16(eepdata[i]);
0206         }
0207     }
0208 
0209     if (ah->eep_ops->get_eepmisc(ah) & AR5416_EEPMISC_BIG_ENDIAN) {
0210         *swap_needed = true;
0211         ath_dbg(common, EEPROM,
0212             "Big Endian EEPROM detected according to EEPMISC register.\n");
0213     } else {
0214         *swap_needed = false;
0215     }
0216 
0217     return 0;
0218 }
0219 
0220 bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size)
0221 {
0222     u32 i, sum = 0;
0223     u16 *eepdata = (u16 *)(&ah->eeprom);
0224     struct ath_common *common = ath9k_hw_common(ah);
0225 
0226     for (i = 0; i < size; i++)
0227         sum ^= eepdata[i];
0228 
0229     if (sum != 0xffff) {
0230         ath_err(common, "Bad EEPROM checksum 0x%x\n", sum);
0231         return false;
0232     }
0233 
0234     return true;
0235 }
0236 
0237 bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev)
0238 {
0239     struct ath_common *common = ath9k_hw_common(ah);
0240 
0241     if (ah->eep_ops->get_eeprom_ver(ah) != version ||
0242         ah->eep_ops->get_eeprom_rev(ah) < minrev) {
0243         ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n",
0244             ah->eep_ops->get_eeprom_ver(ah),
0245             ah->eep_ops->get_eeprom_rev(ah));
0246         return false;
0247     }
0248 
0249     return true;
0250 }
0251 
0252 void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
0253                  u8 *pVpdList, u16 numIntercepts,
0254                  u8 *pRetVpdList)
0255 {
0256     u16 i, k;
0257     u8 currPwr = pwrMin;
0258     u16 idxL = 0, idxR = 0;
0259 
0260     for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
0261         ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
0262                            numIntercepts, &(idxL),
0263                            &(idxR));
0264         if (idxR < 1)
0265             idxR = 1;
0266         if (idxL == numIntercepts - 1)
0267             idxL = (u16) (numIntercepts - 2);
0268         if (pPwrList[idxL] == pPwrList[idxR])
0269             k = pVpdList[idxL];
0270         else
0271             k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
0272                    (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
0273                   (pPwrList[idxR] - pPwrList[idxL]));
0274         pRetVpdList[i] = (u8) k;
0275         currPwr += 2;
0276     }
0277 }
0278 
0279 void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
0280                        struct ath9k_channel *chan,
0281                        struct cal_target_power_leg *powInfo,
0282                        u16 numChannels,
0283                        struct cal_target_power_leg *pNewPower,
0284                        u16 numRates, bool isExtTarget)
0285 {
0286     struct chan_centers centers;
0287     u16 clo, chi;
0288     int i;
0289     int matchIndex = -1, lowIndex = -1;
0290     u16 freq;
0291 
0292     ath9k_hw_get_channel_centers(ah, chan, &centers);
0293     freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
0294 
0295     if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
0296                        IS_CHAN_2GHZ(chan))) {
0297         matchIndex = 0;
0298     } else {
0299         for (i = 0; (i < numChannels) &&
0300                  (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
0301             if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
0302                                IS_CHAN_2GHZ(chan))) {
0303                 matchIndex = i;
0304                 break;
0305             } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
0306                         IS_CHAN_2GHZ(chan)) && i > 0 &&
0307                    freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
0308                         IS_CHAN_2GHZ(chan))) {
0309                 lowIndex = i - 1;
0310                 break;
0311             }
0312         }
0313         if ((matchIndex == -1) && (lowIndex == -1))
0314             matchIndex = i - 1;
0315     }
0316 
0317     if (matchIndex != -1) {
0318         *pNewPower = powInfo[matchIndex];
0319     } else {
0320         clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
0321                      IS_CHAN_2GHZ(chan));
0322         chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
0323                      IS_CHAN_2GHZ(chan));
0324 
0325         for (i = 0; i < numRates; i++) {
0326             pNewPower->tPow2x[i] =
0327                 (u8)ath9k_hw_interpolate(freq, clo, chi,
0328                         powInfo[lowIndex].tPow2x[i],
0329                         powInfo[lowIndex + 1].tPow2x[i]);
0330         }
0331     }
0332 }
0333 
0334 void ath9k_hw_get_target_powers(struct ath_hw *ah,
0335                 struct ath9k_channel *chan,
0336                 struct cal_target_power_ht *powInfo,
0337                 u16 numChannels,
0338                 struct cal_target_power_ht *pNewPower,
0339                 u16 numRates, bool isHt40Target)
0340 {
0341     struct chan_centers centers;
0342     u16 clo, chi;
0343     int i;
0344     int matchIndex = -1, lowIndex = -1;
0345     u16 freq;
0346 
0347     ath9k_hw_get_channel_centers(ah, chan, &centers);
0348     freq = isHt40Target ? centers.synth_center : centers.ctl_center;
0349 
0350     if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
0351         matchIndex = 0;
0352     } else {
0353         for (i = 0; (i < numChannels) &&
0354                  (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
0355             if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
0356                                IS_CHAN_2GHZ(chan))) {
0357                 matchIndex = i;
0358                 break;
0359             } else
0360                 if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
0361                         IS_CHAN_2GHZ(chan)) && i > 0 &&
0362                     freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
0363                         IS_CHAN_2GHZ(chan))) {
0364                     lowIndex = i - 1;
0365                     break;
0366                 }
0367         }
0368         if ((matchIndex == -1) && (lowIndex == -1))
0369             matchIndex = i - 1;
0370     }
0371 
0372     if (matchIndex != -1) {
0373         *pNewPower = powInfo[matchIndex];
0374     } else {
0375         clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
0376                      IS_CHAN_2GHZ(chan));
0377         chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
0378                      IS_CHAN_2GHZ(chan));
0379 
0380         for (i = 0; i < numRates; i++) {
0381             pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
0382                         clo, chi,
0383                         powInfo[lowIndex].tPow2x[i],
0384                         powInfo[lowIndex + 1].tPow2x[i]);
0385         }
0386     }
0387 }
0388 
0389 u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
0390                 bool is2GHz, int num_band_edges)
0391 {
0392     u16 twiceMaxEdgePower = MAX_RATE_POWER;
0393     int i;
0394 
0395     for (i = 0; (i < num_band_edges) &&
0396              (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
0397         if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
0398             twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
0399             break;
0400         } else if ((i > 0) &&
0401                (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
0402                               is2GHz))) {
0403             if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
0404                            is2GHz) < freq &&
0405                 CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
0406                 twiceMaxEdgePower =
0407                     CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
0408             }
0409             break;
0410         }
0411     }
0412 
0413     return twiceMaxEdgePower;
0414 }
0415 
0416 u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit,
0417                   u8 antenna_reduction)
0418 {
0419     u16 reduction = antenna_reduction;
0420 
0421     /*
0422      * Reduce scaled Power by number of chains active
0423      * to get the per chain tx power level.
0424      */
0425     switch (ar5416_get_ntxchains(ah->txchainmask)) {
0426     case 1:
0427         break;
0428     case 2:
0429         reduction += POWER_CORRECTION_FOR_TWO_CHAIN;
0430         break;
0431     case 3:
0432         reduction += POWER_CORRECTION_FOR_THREE_CHAIN;
0433         break;
0434     }
0435 
0436     if (power_limit > reduction)
0437         power_limit -= reduction;
0438     else
0439         power_limit = 0;
0440 
0441     return min_t(u16, power_limit, MAX_RATE_POWER);
0442 }
0443 
0444 void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
0445 {
0446     struct ath_common *common = ath9k_hw_common(ah);
0447     struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
0448 
0449     switch (ar5416_get_ntxchains(ah->txchainmask)) {
0450     case 1:
0451         break;
0452     case 2:
0453         regulatory->max_power_level += POWER_CORRECTION_FOR_TWO_CHAIN;
0454         break;
0455     case 3:
0456         regulatory->max_power_level += POWER_CORRECTION_FOR_THREE_CHAIN;
0457         break;
0458     default:
0459         ath_dbg(common, EEPROM, "Invalid chainmask configuration\n");
0460         break;
0461     }
0462 }
0463 
0464 void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
0465                 struct ath9k_channel *chan,
0466                 void *pRawDataSet,
0467                 u8 *bChans, u16 availPiers,
0468                 u16 tPdGainOverlap,
0469                 u16 *pPdGainBoundaries, u8 *pPDADCValues,
0470                 u16 numXpdGains)
0471 {
0472     int i, j, k;
0473     int16_t ss;
0474     u16 idxL = 0, idxR = 0, numPiers;
0475     static u8 vpdTableL[AR5416_NUM_PD_GAINS]
0476         [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
0477     static u8 vpdTableR[AR5416_NUM_PD_GAINS]
0478         [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
0479     static u8 vpdTableI[AR5416_NUM_PD_GAINS]
0480         [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
0481 
0482     u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
0483     u8 minPwrT4[AR5416_NUM_PD_GAINS];
0484     u8 maxPwrT4[AR5416_NUM_PD_GAINS];
0485     int16_t vpdStep;
0486     int16_t tmpVal;
0487     u16 sizeCurrVpdTable, maxIndex, tgtIndex;
0488     bool match;
0489     int16_t minDelta = 0;
0490     struct chan_centers centers;
0491     int pdgain_boundary_default;
0492     struct cal_data_per_freq *data_def = pRawDataSet;
0493     struct cal_data_per_freq_4k *data_4k = pRawDataSet;
0494     struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
0495     bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
0496     int intercepts;
0497 
0498     if (AR_SREV_9287(ah))
0499         intercepts = AR9287_PD_GAIN_ICEPTS;
0500     else
0501         intercepts = AR5416_PD_GAIN_ICEPTS;
0502 
0503     memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
0504     ath9k_hw_get_channel_centers(ah, chan, &centers);
0505 
0506     for (numPiers = 0; numPiers < availPiers; numPiers++) {
0507         if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
0508             break;
0509     }
0510 
0511     match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
0512                                  IS_CHAN_2GHZ(chan)),
0513                            bChans, numPiers, &idxL, &idxR);
0514 
0515     if (match) {
0516         if (AR_SREV_9287(ah)) {
0517             for (i = 0; i < numXpdGains; i++) {
0518                 minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
0519                 maxPwrT4[i] = data_9287[idxL].pwrPdg[i][intercepts - 1];
0520                 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
0521                         data_9287[idxL].pwrPdg[i],
0522                         data_9287[idxL].vpdPdg[i],
0523                         intercepts,
0524                         vpdTableI[i]);
0525             }
0526         } else if (eeprom_4k) {
0527             for (i = 0; i < numXpdGains; i++) {
0528                 minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
0529                 maxPwrT4[i] = data_4k[idxL].pwrPdg[i][intercepts - 1];
0530                 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
0531                         data_4k[idxL].pwrPdg[i],
0532                         data_4k[idxL].vpdPdg[i],
0533                         intercepts,
0534                         vpdTableI[i]);
0535             }
0536         } else {
0537             for (i = 0; i < numXpdGains; i++) {
0538                 minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
0539                 maxPwrT4[i] = data_def[idxL].pwrPdg[i][intercepts - 1];
0540                 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
0541                         data_def[idxL].pwrPdg[i],
0542                         data_def[idxL].vpdPdg[i],
0543                         intercepts,
0544                         vpdTableI[i]);
0545             }
0546         }
0547     } else {
0548         for (i = 0; i < numXpdGains; i++) {
0549             if (AR_SREV_9287(ah)) {
0550                 pVpdL = data_9287[idxL].vpdPdg[i];
0551                 pPwrL = data_9287[idxL].pwrPdg[i];
0552                 pVpdR = data_9287[idxR].vpdPdg[i];
0553                 pPwrR = data_9287[idxR].pwrPdg[i];
0554             } else if (eeprom_4k) {
0555                 pVpdL = data_4k[idxL].vpdPdg[i];
0556                 pPwrL = data_4k[idxL].pwrPdg[i];
0557                 pVpdR = data_4k[idxR].vpdPdg[i];
0558                 pPwrR = data_4k[idxR].pwrPdg[i];
0559             } else {
0560                 pVpdL = data_def[idxL].vpdPdg[i];
0561                 pPwrL = data_def[idxL].pwrPdg[i];
0562                 pVpdR = data_def[idxR].vpdPdg[i];
0563                 pPwrR = data_def[idxR].pwrPdg[i];
0564             }
0565 
0566             minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
0567 
0568             maxPwrT4[i] =
0569                 min(pPwrL[intercepts - 1],
0570                     pPwrR[intercepts - 1]);
0571 
0572 
0573             ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
0574                         pPwrL, pVpdL,
0575                         intercepts,
0576                         vpdTableL[i]);
0577             ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
0578                         pPwrR, pVpdR,
0579                         intercepts,
0580                         vpdTableR[i]);
0581 
0582             for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
0583                 vpdTableI[i][j] =
0584                     (u8)(ath9k_hw_interpolate((u16)
0585                          FREQ2FBIN(centers.
0586                                synth_center,
0587                                IS_CHAN_2GHZ
0588                                (chan)),
0589                          bChans[idxL], bChans[idxR],
0590                          vpdTableL[i][j], vpdTableR[i][j]));
0591             }
0592         }
0593     }
0594 
0595     k = 0;
0596 
0597     for (i = 0; i < numXpdGains; i++) {
0598         if (i == (numXpdGains - 1))
0599             pPdGainBoundaries[i] =
0600                 (u16)(maxPwrT4[i] / 2);
0601         else
0602             pPdGainBoundaries[i] =
0603                 (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
0604 
0605         pPdGainBoundaries[i] =
0606             min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
0607 
0608         minDelta = 0;
0609 
0610         if (i == 0) {
0611             if (AR_SREV_9280_20_OR_LATER(ah))
0612                 ss = (int16_t)(0 - (minPwrT4[i] / 2));
0613             else
0614                 ss = 0;
0615         } else {
0616             ss = (int16_t)((pPdGainBoundaries[i - 1] -
0617                     (minPwrT4[i] / 2)) -
0618                        tPdGainOverlap + 1 + minDelta);
0619         }
0620         vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
0621         vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
0622 
0623         while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
0624             tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
0625             pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
0626             ss++;
0627         }
0628 
0629         sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
0630         tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
0631                 (minPwrT4[i] / 2));
0632         maxIndex = (tgtIndex < sizeCurrVpdTable) ?
0633             tgtIndex : sizeCurrVpdTable;
0634 
0635         while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
0636             pPDADCValues[k++] = vpdTableI[i][ss++];
0637         }
0638 
0639         vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
0640                     vpdTableI[i][sizeCurrVpdTable - 2]);
0641         vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
0642 
0643         if (tgtIndex >= maxIndex) {
0644             while ((ss <= tgtIndex) &&
0645                    (k < (AR5416_NUM_PDADC_VALUES - 1))) {
0646                 tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
0647                             (ss - maxIndex + 1) * vpdStep));
0648                 pPDADCValues[k++] = (u8)((tmpVal > 255) ?
0649                              255 : tmpVal);
0650                 ss++;
0651             }
0652         }
0653     }
0654 
0655     if (eeprom_4k)
0656         pdgain_boundary_default = 58;
0657     else
0658         pdgain_boundary_default = pPdGainBoundaries[i - 1];
0659 
0660     while (i < AR5416_PD_GAINS_IN_MASK) {
0661         pPdGainBoundaries[i] = pdgain_boundary_default;
0662         i++;
0663     }
0664 
0665     while (k < AR5416_NUM_PDADC_VALUES) {
0666         pPDADCValues[k] = pPDADCValues[k - 1];
0667         k++;
0668     }
0669 }
0670 
0671 int ath9k_hw_eeprom_init(struct ath_hw *ah)
0672 {
0673     if (AR_SREV_9300_20_OR_LATER(ah))
0674         ah->eep_ops = &eep_ar9300_ops;
0675     else if (AR_SREV_9287(ah)) {
0676         ah->eep_ops = &eep_ar9287_ops;
0677     } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
0678         ah->eep_ops = &eep_4k_ops;
0679     } else {
0680         ah->eep_ops = &eep_def_ops;
0681     }
0682 
0683     if (!ah->eep_ops->fill_eeprom(ah))
0684         return -EIO;
0685 
0686     return ah->eep_ops->check_eeprom(ah);
0687 }