iPXE
ath9k_eeprom.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008-2011 Atheros Communications Inc.
00003  *
00004  * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
00005  * Original from Linux kernel 3.0.1
00006  *
00007  * Permission to use, copy, modify, and/or distribute this software for any
00008  * purpose with or without fee is hereby granted, provided that the above
00009  * copyright notice and this permission notice appear in all copies.
00010  *
00011  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00012  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00013  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00014  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00015  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00016  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00017  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00018  */
00019 
00020 #include <ipxe/io.h>
00021 
00022 #include "hw.h"
00023 
00024 static inline u16 ath9k_hw_fbin2freq(u8 fbin, int is2GHz)
00025 {
00026         if (fbin == AR5416_BCHAN_UNUSED)
00027                 return fbin;
00028 
00029         return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
00030 }
00031 
00032 void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
00033 {
00034         REG_WRITE(ah, reg, val);
00035 
00036         if (ah->config.analog_shiftreg)
00037                 udelay(100);
00038 }
00039 
00040 void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
00041                                u32 shift, u32 val)
00042 {
00043         u32 regVal;
00044 
00045         regVal = REG_READ(ah, reg) & ~mask;
00046         regVal |= (val << shift) & mask;
00047 
00048         REG_WRITE(ah, reg, regVal);
00049 
00050         if (ah->config.analog_shiftreg)
00051                 udelay(100);
00052 }
00053 
00054 int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
00055                              int16_t targetLeft, int16_t targetRight)
00056 {
00057         int16_t rv;
00058 
00059         if (srcRight == srcLeft) {
00060                 rv = targetLeft;
00061         } else {
00062                 rv = (int16_t) (((target - srcLeft) * targetRight +
00063                                  (srcRight - target) * targetLeft) /
00064                                 (srcRight - srcLeft));
00065         }
00066         return rv;
00067 }
00068 
00069 int ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
00070                                     u16 *indexL, u16 *indexR)
00071 {
00072         u16 i;
00073 
00074         if (target <= pList[0]) {
00075                 *indexL = *indexR = 0;
00076                 return 1;
00077         }
00078         if (target >= pList[listSize - 1]) {
00079                 *indexL = *indexR = (u16) (listSize - 1);
00080                 return 1;
00081         }
00082 
00083         for (i = 0; i < listSize - 1; i++) {
00084                 if (pList[i] == target) {
00085                         *indexL = *indexR = i;
00086                         return 1;
00087                 }
00088                 if (target < pList[i + 1]) {
00089                         *indexL = i;
00090                         *indexR = (u16) (i + 1);
00091                         return 0;
00092                 }
00093         }
00094         return 0;
00095 }
00096 
00097 void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
00098                                   int eep_start_loc, int size)
00099 {
00100         int i = 0, j, addr;
00101         u32 addrdata[8];
00102         u32 data[8];
00103 
00104         for (addr = 0; addr < size; addr++) {
00105                 addrdata[i] = AR5416_EEPROM_OFFSET +
00106                         ((addr + eep_start_loc) << AR5416_EEPROM_S);
00107                 i++;
00108                 if (i == 8) {
00109                         REG_READ_MULTI(ah, addrdata, data, i);
00110 
00111                         for (j = 0; j < i; j++) {
00112                                 *eep_data = data[j];
00113                                 eep_data++;
00114                         }
00115                         i = 0;
00116                 }
00117         }
00118 
00119         if (i != 0) {
00120                 REG_READ_MULTI(ah, addrdata, data, i);
00121 
00122                 for (j = 0; j < i; j++) {
00123                         *eep_data = data[j];
00124                         eep_data++;
00125                 }
00126         }
00127 }
00128 
00129 int ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data)
00130 {
00131         return common->bus_ops->eeprom_read(common, off, data);
00132 }
00133 
00134 void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
00135                              u8 *pVpdList, u16 numIntercepts,
00136                              u8 *pRetVpdList)
00137 {
00138         u16 i, k;
00139         u8 currPwr = pwrMin;
00140         u16 idxL = 0, idxR = 0;
00141 
00142         for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
00143                 ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
00144                                                numIntercepts, &(idxL),
00145                                                &(idxR));
00146                 if (idxR < 1)
00147                         idxR = 1;
00148                 if (idxL == numIntercepts - 1)
00149                         idxL = (u16) (numIntercepts - 2);
00150                 if (pPwrList[idxL] == pPwrList[idxR])
00151                         k = pVpdList[idxL];
00152                 else
00153                         k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
00154                                    (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
00155                                   (pPwrList[idxR] - pPwrList[idxL]));
00156                 pRetVpdList[i] = (u8) k;
00157                 currPwr += 2;
00158         }
00159 }
00160 
00161 void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
00162                                        struct ath9k_channel *chan,
00163                                        struct cal_target_power_leg *powInfo,
00164                                        u16 numChannels,
00165                                        struct cal_target_power_leg *pNewPower,
00166                                        u16 numRates, int isExtTarget)
00167 {
00168         struct chan_centers centers;
00169         u16 clo, chi;
00170         int i;
00171         int matchIndex = -1, lowIndex = -1;
00172         u16 freq;
00173 
00174         ath9k_hw_get_channel_centers(ah, chan, &centers);
00175         freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
00176 
00177         if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
00178                                        IS_CHAN_2GHZ(chan))) {
00179                 matchIndex = 0;
00180         } else {
00181                 for (i = 0; (i < numChannels) &&
00182                              (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
00183                         if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
00184                                                        IS_CHAN_2GHZ(chan))) {
00185                                 matchIndex = i;
00186                                 break;
00187                         } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
00188                                                 IS_CHAN_2GHZ(chan)) && i > 0 &&
00189                                    freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
00190                                                 IS_CHAN_2GHZ(chan))) {
00191                                 lowIndex = i - 1;
00192                                 break;
00193                         }
00194                 }
00195                 if ((matchIndex == -1) && (lowIndex == -1))
00196                         matchIndex = i - 1;
00197         }
00198 
00199         if (matchIndex != -1) {
00200                 *pNewPower = powInfo[matchIndex];
00201         } else {
00202                 clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
00203                                          IS_CHAN_2GHZ(chan));
00204                 chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
00205                                          IS_CHAN_2GHZ(chan));
00206 
00207                 for (i = 0; i < numRates; i++) {
00208                         pNewPower->tPow2x[i] =
00209                                 (u8)ath9k_hw_interpolate(freq, clo, chi,
00210                                                 powInfo[lowIndex].tPow2x[i],
00211                                                 powInfo[lowIndex + 1].tPow2x[i]);
00212                 }
00213         }
00214 }
00215 
00216 void ath9k_hw_get_target_powers(struct ath_hw *ah,
00217                                 struct ath9k_channel *chan,
00218                                 struct cal_target_power_ht *powInfo,
00219                                 u16 numChannels,
00220                                 struct cal_target_power_ht *pNewPower,
00221                                 u16 numRates, int isHt40Target)
00222 {
00223         struct chan_centers centers;
00224         u16 clo, chi;
00225         int i;
00226         int matchIndex = -1, lowIndex = -1;
00227         u16 freq;
00228 
00229         ath9k_hw_get_channel_centers(ah, chan, &centers);
00230         freq = isHt40Target ? centers.synth_center : centers.ctl_center;
00231 
00232         if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
00233                 matchIndex = 0;
00234         } else {
00235                 for (i = 0; (i < numChannels) &&
00236                              (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
00237                         if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
00238                                                        IS_CHAN_2GHZ(chan))) {
00239                                 matchIndex = i;
00240                                 break;
00241                         } else
00242                                 if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
00243                                                 IS_CHAN_2GHZ(chan)) && i > 0 &&
00244                                     freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
00245                                                 IS_CHAN_2GHZ(chan))) {
00246                                         lowIndex = i - 1;
00247                                         break;
00248                                 }
00249                 }
00250                 if ((matchIndex == -1) && (lowIndex == -1))
00251                         matchIndex = i - 1;
00252         }
00253 
00254         if (matchIndex != -1) {
00255                 *pNewPower = powInfo[matchIndex];
00256         } else {
00257                 clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
00258                                          IS_CHAN_2GHZ(chan));
00259                 chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
00260                                          IS_CHAN_2GHZ(chan));
00261 
00262                 for (i = 0; i < numRates; i++) {
00263                         pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
00264                                                 clo, chi,
00265                                                 powInfo[lowIndex].tPow2x[i],
00266                                                 powInfo[lowIndex + 1].tPow2x[i]);
00267                 }
00268         }
00269 }
00270 
00271 u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
00272                                 int is2GHz, int num_band_edges)
00273 {
00274         u16 twiceMaxEdgePower = MAX_RATE_POWER;
00275         int i;
00276 
00277         for (i = 0; (i < num_band_edges) &&
00278                      (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
00279                 if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
00280                         twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
00281                         break;
00282                 } else if ((i > 0) &&
00283                            (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
00284                                                       is2GHz))) {
00285                         if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
00286                                                is2GHz) < freq &&
00287                             CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
00288                                 twiceMaxEdgePower =
00289                                         CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
00290                         }
00291                         break;
00292                 }
00293         }
00294 
00295         return twiceMaxEdgePower;
00296 }
00297 
00298 void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
00299 {
00300         struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
00301 
00302         switch (ar5416_get_ntxchains(ah->txchainmask)) {
00303         case 1:
00304                 break;
00305         case 2:
00306                 regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
00307                 break;
00308         case 3:
00309                 regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
00310                 break;
00311         default:
00312                 DBG2("ath9k: "
00313                         "Invalid chainmask configuration\n");
00314                 break;
00315         }
00316 }
00317 
00318 void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
00319                                 struct ath9k_channel *chan,
00320                                 void *pRawDataSet,
00321                                 u8 *bChans, u16 availPiers,
00322                                 u16 tPdGainOverlap,
00323                                 u16 *pPdGainBoundaries, u8 *pPDADCValues,
00324                                 u16 numXpdGains)
00325 {
00326         int i, j, k;
00327         int16_t ss;
00328         u16 idxL = 0, idxR = 0, numPiers;
00329         static u8 vpdTableL[AR5416_NUM_PD_GAINS]
00330                 [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
00331         static u8 vpdTableR[AR5416_NUM_PD_GAINS]
00332                 [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
00333         static u8 vpdTableI[AR5416_NUM_PD_GAINS]
00334                 [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
00335 
00336         u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
00337         u8 minPwrT4[AR5416_NUM_PD_GAINS];
00338         u8 maxPwrT4[AR5416_NUM_PD_GAINS];
00339         int16_t vpdStep;
00340         int16_t tmpVal;
00341         u16 sizeCurrVpdTable, maxIndex, tgtIndex;
00342         int match;
00343         int16_t minDelta = 0;
00344         struct chan_centers centers;
00345         int pdgain_boundary_default;
00346         struct cal_data_per_freq *data_def = pRawDataSet;
00347         struct cal_data_per_freq_4k *data_4k = pRawDataSet;
00348         struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
00349         int eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
00350         int intercepts;
00351 
00352         if (AR_SREV_9287(ah))
00353                 intercepts = AR9287_PD_GAIN_ICEPTS;
00354         else
00355                 intercepts = AR5416_PD_GAIN_ICEPTS;
00356 
00357         memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
00358         ath9k_hw_get_channel_centers(ah, chan, &centers);
00359 
00360         for (numPiers = 0; numPiers < availPiers; numPiers++) {
00361                 if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
00362                         break;
00363         }
00364 
00365         match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
00366                                                              IS_CHAN_2GHZ(chan)),
00367                                                bChans, numPiers, &idxL, &idxR);
00368 
00369         if (match) {
00370                 if (AR_SREV_9287(ah)) {
00371                         for (i = 0; i < numXpdGains; i++) {
00372                                 minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
00373                                 maxPwrT4[i] = data_9287[idxL].pwrPdg[i][intercepts - 1];
00374                                 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
00375                                                 data_9287[idxL].pwrPdg[i],
00376                                                 data_9287[idxL].vpdPdg[i],
00377                                                 intercepts,
00378                                                 vpdTableI[i]);
00379                         }
00380                 } else if (eeprom_4k) {
00381                         for (i = 0; i < numXpdGains; i++) {
00382                                 minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
00383                                 maxPwrT4[i] = data_4k[idxL].pwrPdg[i][intercepts - 1];
00384                                 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
00385                                                 data_4k[idxL].pwrPdg[i],
00386                                                 data_4k[idxL].vpdPdg[i],
00387                                                 intercepts,
00388                                                 vpdTableI[i]);
00389                         }
00390                 } else {
00391                         for (i = 0; i < numXpdGains; i++) {
00392                                 minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
00393                                 maxPwrT4[i] = data_def[idxL].pwrPdg[i][intercepts - 1];
00394                                 ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
00395                                                 data_def[idxL].pwrPdg[i],
00396                                                 data_def[idxL].vpdPdg[i],
00397                                                 intercepts,
00398                                                 vpdTableI[i]);
00399                         }
00400                 }
00401         } else {
00402                 for (i = 0; i < numXpdGains; i++) {
00403                         if (AR_SREV_9287(ah)) {
00404                                 pVpdL = data_9287[idxL].vpdPdg[i];
00405                                 pPwrL = data_9287[idxL].pwrPdg[i];
00406                                 pVpdR = data_9287[idxR].vpdPdg[i];
00407                                 pPwrR = data_9287[idxR].pwrPdg[i];
00408                         } else if (eeprom_4k) {
00409                                 pVpdL = data_4k[idxL].vpdPdg[i];
00410                                 pPwrL = data_4k[idxL].pwrPdg[i];
00411                                 pVpdR = data_4k[idxR].vpdPdg[i];
00412                                 pPwrR = data_4k[idxR].pwrPdg[i];
00413                         } else {
00414                                 pVpdL = data_def[idxL].vpdPdg[i];
00415                                 pPwrL = data_def[idxL].pwrPdg[i];
00416                                 pVpdR = data_def[idxR].vpdPdg[i];
00417                                 pPwrR = data_def[idxR].pwrPdg[i];
00418                         }
00419 
00420                         minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
00421 
00422                         maxPwrT4[i] =
00423                                 min(pPwrL[intercepts - 1],
00424                                     pPwrR[intercepts - 1]);
00425 
00426 
00427                         ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
00428                                                 pPwrL, pVpdL,
00429                                                 intercepts,
00430                                                 vpdTableL[i]);
00431                         ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
00432                                                 pPwrR, pVpdR,
00433                                                 intercepts,
00434                                                 vpdTableR[i]);
00435 
00436                         for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
00437                                 vpdTableI[i][j] =
00438                                         (u8)(ath9k_hw_interpolate((u16)
00439                                              FREQ2FBIN(centers.
00440                                                        synth_center,
00441                                                        IS_CHAN_2GHZ
00442                                                        (chan)),
00443                                              bChans[idxL], bChans[idxR],
00444                                              vpdTableL[i][j], vpdTableR[i][j]));
00445                         }
00446                 }
00447         }
00448 
00449         k = 0;
00450 
00451         for (i = 0; i < numXpdGains; i++) {
00452                 if (i == (numXpdGains - 1))
00453                         pPdGainBoundaries[i] =
00454                                 (u16)(maxPwrT4[i] / 2);
00455                 else
00456                         pPdGainBoundaries[i] =
00457                                 (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
00458 
00459                 pPdGainBoundaries[i] =
00460                         min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
00461 
00462                 if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
00463                         minDelta = pPdGainBoundaries[0] - 23;
00464                         pPdGainBoundaries[0] = 23;
00465                 } else {
00466                         minDelta = 0;
00467                 }
00468 
00469                 if (i == 0) {
00470                         if (AR_SREV_9280_20_OR_LATER(ah))
00471                                 ss = (int16_t)(0 - (minPwrT4[i] / 2));
00472                         else
00473                                 ss = 0;
00474                 } else {
00475                         ss = (int16_t)((pPdGainBoundaries[i - 1] -
00476                                         (minPwrT4[i] / 2)) -
00477                                        tPdGainOverlap + 1 + minDelta);
00478                 }
00479                 vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
00480                 vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
00481 
00482                 while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
00483                         tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
00484                         pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
00485                         ss++;
00486                 }
00487 
00488                 sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
00489                 tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
00490                                 (minPwrT4[i] / 2));
00491                 maxIndex = (tgtIndex < sizeCurrVpdTable) ?
00492                         tgtIndex : sizeCurrVpdTable;
00493 
00494                 while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
00495                         pPDADCValues[k++] = vpdTableI[i][ss++];
00496                 }
00497 
00498                 vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
00499                                     vpdTableI[i][sizeCurrVpdTable - 2]);
00500                 vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
00501 
00502                 if (tgtIndex >= maxIndex) {
00503                         while ((ss <= tgtIndex) &&
00504                                (k < (AR5416_NUM_PDADC_VALUES - 1))) {
00505                                 tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
00506                                                     (ss - maxIndex + 1) * vpdStep));
00507                                 pPDADCValues[k++] = (u8)((tmpVal > 255) ?
00508                                                          255 : tmpVal);
00509                                 ss++;
00510                         }
00511                 }
00512         }
00513 
00514         if (eeprom_4k)
00515                 pdgain_boundary_default = 58;
00516         else
00517                 pdgain_boundary_default = pPdGainBoundaries[i - 1];
00518 
00519         while (i < AR5416_PD_GAINS_IN_MASK) {
00520                 pPdGainBoundaries[i] = pdgain_boundary_default;
00521                 i++;
00522         }
00523 
00524         while (k < AR5416_NUM_PDADC_VALUES) {
00525                 pPDADCValues[k] = pPDADCValues[k - 1];
00526                 k++;
00527         }
00528 }
00529 
00530 int ath9k_hw_eeprom_init(struct ath_hw *ah)
00531 {
00532         int status;
00533 
00534         if (AR_SREV_9300_20_OR_LATER(ah))
00535                 ah->eep_ops = &eep_ar9300_ops;
00536         else if (AR_SREV_9287(ah)) {
00537                 ah->eep_ops = &eep_ar9287_ops;
00538         } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
00539                 ah->eep_ops = &eep_4k_ops;
00540         } else {
00541                 ah->eep_ops = &eep_def_ops;
00542         }
00543 
00544         if (!ah->eep_ops->fill_eeprom(ah))
00545                 return -EIO;
00546 
00547         status = ah->eep_ops->check_eeprom(ah);
00548 
00549         return status;
00550 }