eeprom.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
00003  * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
00004  * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org>
00005  *
00006  * Permission to use, copy, modify, and distribute this software for any
00007  * purpose with or without fee is hereby granted, provided that the above
00008  * copyright notice and this permission notice appear in all copies.
00009  *
00010  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00011  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00012  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00013  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00014  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00015  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00016  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00017  *
00018  */
00019 
00020 /*************************************\
00021 * EEPROM access functions and helpers *
00022 \*************************************/
00023 
00024 #include "ath5k.h"
00025 #include "reg.h"
00026 #include "debug.h"
00027 #include "base.h"
00028 
00029 /*
00030  * Read from eeprom
00031  */
00032 static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
00033 {
00034         u32 status, timeout;
00035 
00036         ATH5K_TRACE(ah->ah_sc);
00037         /*
00038          * Initialize EEPROM access
00039          */
00040         if (ah->ah_version == AR5K_AR5210) {
00041                 AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
00042                 (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
00043         } else {
00044                 ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
00045                 AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
00046                                 AR5K_EEPROM_CMD_READ);
00047         }
00048 
00049         for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
00050                 status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
00051                 if (status & AR5K_EEPROM_STAT_RDDONE) {
00052                         if (status & AR5K_EEPROM_STAT_RDERR)
00053                                 return -EIO;
00054                         *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
00055                                         0xffff);
00056                         return 0;
00057                 }
00058                 udelay(15);
00059         }
00060 
00061         return -ETIMEDOUT;
00062 }
00063 
00064 /*
00065  * Translate binary channel representation in EEPROM to frequency
00066  */
00067 static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,
00068                                  unsigned int mode)
00069 {
00070         u16 val;
00071 
00072         if (bin == AR5K_EEPROM_CHANNEL_DIS)
00073                 return bin;
00074 
00075         if (mode == AR5K_EEPROM_MODE_11A) {
00076                 if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
00077                         val = (5 * bin) + 4800;
00078                 else
00079                         val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
00080                                 (bin * 10) + 5100;
00081         } else {
00082                 if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
00083                         val = bin + 2300;
00084                 else
00085                         val = bin + 2400;
00086         }
00087 
00088         return val;
00089 }
00090 
00091 /*
00092  * Initialize eeprom & capabilities structs
00093  */
00094 static int
00095 ath5k_eeprom_init_header(struct ath5k_hw *ah)
00096 {
00097         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00098         int ret;
00099         u16 val;
00100 
00101         /*
00102          * Read values from EEPROM and store them in the capability structure
00103          */
00104         AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
00105         AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
00106         AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
00107         AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
00108         AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
00109 
00110         /* Return if we have an old EEPROM */
00111         if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
00112                 return 0;
00113 
00114 #ifdef notyet
00115         /*
00116          * Validate the checksum of the EEPROM date. There are some
00117          * devices with invalid EEPROMs.
00118          */
00119         for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
00120                 AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
00121                 cksum ^= val;
00122         }
00123         if (cksum != AR5K_EEPROM_INFO_CKSUM) {
00124                 ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
00125                 return -EIO;
00126         }
00127 #endif
00128 
00129         AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
00130             ee_ant_gain);
00131 
00132         if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
00133                 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
00134                 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
00135 
00136                 /* XXX: Don't know which versions include these two */
00137                 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2);
00138 
00139                 if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3)
00140                         AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3);
00141 
00142                 if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) {
00143                         AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4);
00144                         AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5);
00145                         AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6);
00146                 }
00147         }
00148 
00149         if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
00150                 AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
00151                 ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
00152                 ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
00153 
00154                 AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
00155                 ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
00156                 ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
00157         }
00158 
00159         AR5K_EEPROM_READ(AR5K_EEPROM_IS_HB63, val);
00160 
00161         if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && val)
00162                 ee->ee_is_hb63 = true;
00163         else
00164                 ee->ee_is_hb63 = false;
00165 
00166         AR5K_EEPROM_READ(AR5K_EEPROM_RFKILL, val);
00167         ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL);
00168         ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? true : false;
00169 
00170         /* Check if PCIE_OFFSET points to PCIE_SERDES_SECTION
00171          * and enable serdes programming if needed.
00172          *
00173          * XXX: Serdes values seem to be fixed so
00174          * no need to read them here, we write them
00175          * during ath5k_hw_attach */
00176         AR5K_EEPROM_READ(AR5K_EEPROM_PCIE_OFFSET, val);
00177         ee->ee_serdes = (val == AR5K_EEPROM_PCIE_SERDES_SECTION) ?
00178                                                         true : false;
00179 
00180         return 0;
00181 }
00182 
00183 
00184 /*
00185  * Read antenna infos from eeprom
00186  */
00187 static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
00188                 unsigned int mode)
00189 {
00190         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00191         u32 o = *offset;
00192         u16 val;
00193         int ret, i = 0;
00194 
00195         AR5K_EEPROM_READ(o++, val);
00196         ee->ee_switch_settling[mode]    = (val >> 8) & 0x7f;
00197         ee->ee_atn_tx_rx[mode]          = (val >> 2) & 0x3f;
00198         ee->ee_ant_control[mode][i]     = (val << 4) & 0x3f;
00199 
00200         AR5K_EEPROM_READ(o++, val);
00201         ee->ee_ant_control[mode][i++]   |= (val >> 12) & 0xf;
00202         ee->ee_ant_control[mode][i++]   = (val >> 6) & 0x3f;
00203         ee->ee_ant_control[mode][i++]   = val & 0x3f;
00204 
00205         AR5K_EEPROM_READ(o++, val);
00206         ee->ee_ant_control[mode][i++]   = (val >> 10) & 0x3f;
00207         ee->ee_ant_control[mode][i++]   = (val >> 4) & 0x3f;
00208         ee->ee_ant_control[mode][i]     = (val << 2) & 0x3f;
00209 
00210         AR5K_EEPROM_READ(o++, val);
00211         ee->ee_ant_control[mode][i++]   |= (val >> 14) & 0x3;
00212         ee->ee_ant_control[mode][i++]   = (val >> 8) & 0x3f;
00213         ee->ee_ant_control[mode][i++]   = (val >> 2) & 0x3f;
00214         ee->ee_ant_control[mode][i]     = (val << 4) & 0x3f;
00215 
00216         AR5K_EEPROM_READ(o++, val);
00217         ee->ee_ant_control[mode][i++]   |= (val >> 12) & 0xf;
00218         ee->ee_ant_control[mode][i++]   = (val >> 6) & 0x3f;
00219         ee->ee_ant_control[mode][i++]   = val & 0x3f;
00220 
00221         /* Get antenna switch tables */
00222         ah->ah_ant_ctl[mode][AR5K_ANT_CTL] =
00223             (ee->ee_ant_control[mode][0] << 4);
00224         ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_A] =
00225              ee->ee_ant_control[mode][1]        |
00226             (ee->ee_ant_control[mode][2] << 6)  |
00227             (ee->ee_ant_control[mode][3] << 12) |
00228             (ee->ee_ant_control[mode][4] << 18) |
00229             (ee->ee_ant_control[mode][5] << 24);
00230         ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_B] =
00231              ee->ee_ant_control[mode][6]        |
00232             (ee->ee_ant_control[mode][7] << 6)  |
00233             (ee->ee_ant_control[mode][8] << 12) |
00234             (ee->ee_ant_control[mode][9] << 18) |
00235             (ee->ee_ant_control[mode][10] << 24);
00236 
00237         /* return new offset */
00238         *offset = o;
00239 
00240         return 0;
00241 }
00242 
00243 /*
00244  * Read supported modes and some mode-specific calibration data
00245  * from eeprom
00246  */
00247 static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
00248                 unsigned int mode)
00249 {
00250         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00251         u32 o = *offset;
00252         u16 val;
00253         int ret;
00254 
00255         ee->ee_n_piers[mode] = 0;
00256         AR5K_EEPROM_READ(o++, val);
00257         ee->ee_adc_desired_size[mode]   = (s8)((val >> 8) & 0xff);
00258         switch(mode) {
00259         case AR5K_EEPROM_MODE_11A:
00260                 ee->ee_ob[mode][3]      = (val >> 5) & 0x7;
00261                 ee->ee_db[mode][3]      = (val >> 2) & 0x7;
00262                 ee->ee_ob[mode][2]      = (val << 1) & 0x7;
00263 
00264                 AR5K_EEPROM_READ(o++, val);
00265                 ee->ee_ob[mode][2]      |= (val >> 15) & 0x1;
00266                 ee->ee_db[mode][2]      = (val >> 12) & 0x7;
00267                 ee->ee_ob[mode][1]      = (val >> 9) & 0x7;
00268                 ee->ee_db[mode][1]      = (val >> 6) & 0x7;
00269                 ee->ee_ob[mode][0]      = (val >> 3) & 0x7;
00270                 ee->ee_db[mode][0]      = val & 0x7;
00271                 break;
00272         case AR5K_EEPROM_MODE_11G:
00273         case AR5K_EEPROM_MODE_11B:
00274                 ee->ee_ob[mode][1]      = (val >> 4) & 0x7;
00275                 ee->ee_db[mode][1]      = val & 0x7;
00276                 break;
00277         }
00278 
00279         AR5K_EEPROM_READ(o++, val);
00280         ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff;
00281         ee->ee_thr_62[mode]             = val & 0xff;
00282 
00283         if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
00284                 ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
00285 
00286         AR5K_EEPROM_READ(o++, val);
00287         ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff;
00288         ee->ee_tx_frm2xpa_enable[mode]  = val & 0xff;
00289 
00290         AR5K_EEPROM_READ(o++, val);
00291         ee->ee_pga_desired_size[mode]   = (val >> 8) & 0xff;
00292 
00293         if ((val & 0xff) & 0x80)
00294                 ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
00295         else
00296                 ee->ee_noise_floor_thr[mode] = val & 0xff;
00297 
00298         if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
00299                 ee->ee_noise_floor_thr[mode] =
00300                     mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
00301 
00302         AR5K_EEPROM_READ(o++, val);
00303         ee->ee_xlna_gain[mode]          = (val >> 5) & 0xff;
00304         ee->ee_x_gain[mode]             = (val >> 1) & 0xf;
00305         ee->ee_xpd[mode]                = val & 0x1;
00306 
00307         if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
00308                 ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
00309 
00310         if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
00311                 AR5K_EEPROM_READ(o++, val);
00312                 ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
00313 
00314                 if (mode == AR5K_EEPROM_MODE_11A)
00315                         ee->ee_xr_power[mode] = val & 0x3f;
00316                 else {
00317                         ee->ee_ob[mode][0] = val & 0x7;
00318                         ee->ee_db[mode][0] = (val >> 3) & 0x7;
00319                 }
00320         }
00321 
00322         if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {
00323                 ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
00324                 ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
00325         } else {
00326                 ee->ee_i_gain[mode] = (val >> 13) & 0x7;
00327 
00328                 AR5K_EEPROM_READ(o++, val);
00329                 ee->ee_i_gain[mode] |= (val << 3) & 0x38;
00330 
00331                 if (mode == AR5K_EEPROM_MODE_11G) {
00332                         ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
00333                         if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6)
00334                                 ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
00335                 }
00336         }
00337 
00338         if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
00339                         mode == AR5K_EEPROM_MODE_11A) {
00340                 ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
00341                 ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
00342         }
00343 
00344         if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0)
00345                 goto done;
00346 
00347         /* Note: >= v5 have bg freq piers on another location
00348          * so these freq piers are ignored for >= v5 (should be 0xff
00349          * anyway) */
00350         switch(mode) {
00351         case AR5K_EEPROM_MODE_11A:
00352                 if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1)
00353                         break;
00354 
00355                 AR5K_EEPROM_READ(o++, val);
00356                 ee->ee_margin_tx_rx[mode] = val & 0x3f;
00357                 break;
00358         case AR5K_EEPROM_MODE_11B:
00359                 AR5K_EEPROM_READ(o++, val);
00360 
00361                 ee->ee_pwr_cal_b[0].freq =
00362                         ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
00363                 if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS)
00364                         ee->ee_n_piers[mode]++;
00365 
00366                 ee->ee_pwr_cal_b[1].freq =
00367                         ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
00368                 if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS)
00369                         ee->ee_n_piers[mode]++;
00370 
00371                 AR5K_EEPROM_READ(o++, val);
00372                 ee->ee_pwr_cal_b[2].freq =
00373                         ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
00374                 if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS)
00375                         ee->ee_n_piers[mode]++;
00376 
00377                 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
00378                         ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
00379                 break;
00380         case AR5K_EEPROM_MODE_11G:
00381                 AR5K_EEPROM_READ(o++, val);
00382 
00383                 ee->ee_pwr_cal_g[0].freq =
00384                         ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
00385                 if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS)
00386                         ee->ee_n_piers[mode]++;
00387 
00388                 ee->ee_pwr_cal_g[1].freq =
00389                         ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
00390                 if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS)
00391                         ee->ee_n_piers[mode]++;
00392 
00393                 AR5K_EEPROM_READ(o++, val);
00394                 ee->ee_turbo_max_power[mode] = val & 0x7f;
00395                 ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
00396 
00397                 AR5K_EEPROM_READ(o++, val);
00398                 ee->ee_pwr_cal_g[2].freq =
00399                         ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
00400                 if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS)
00401                         ee->ee_n_piers[mode]++;
00402 
00403                 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
00404                         ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
00405 
00406                 AR5K_EEPROM_READ(o++, val);
00407                 ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
00408                 ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
00409 
00410                 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
00411                         AR5K_EEPROM_READ(o++, val);
00412                         ee->ee_cck_ofdm_gain_delta = val & 0xff;
00413                 }
00414                 break;
00415         }
00416 
00417         /*
00418          * Read turbo mode information on newer EEPROM versions
00419          */
00420         if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
00421                 goto done;
00422 
00423         switch (mode){
00424         case AR5K_EEPROM_MODE_11A:
00425                 ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;
00426 
00427                 ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7;
00428                 AR5K_EEPROM_READ(o++, val);
00429                 ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3;
00430                 ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f;
00431 
00432                 ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f;
00433                 AR5K_EEPROM_READ(o++, val);
00434                 ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7;
00435                 ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff;
00436 
00437                 if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2)
00438                         ee->ee_pd_gain_overlap = (val >> 9) & 0xf;
00439                 break;
00440         case AR5K_EEPROM_MODE_11G:
00441                 ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f;
00442 
00443                 ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7;
00444                 AR5K_EEPROM_READ(o++, val);
00445                 ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1;
00446                 ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f;
00447 
00448                 ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f;
00449                 AR5K_EEPROM_READ(o++, val);
00450                 ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5;
00451                 ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff;
00452                 break;
00453         }
00454 
00455 done:
00456         /* return new offset */
00457         *offset = o;
00458 
00459         return 0;
00460 }
00461 
00462 /* Read mode-specific data (except power calibration data) */
00463 static int
00464 ath5k_eeprom_init_modes(struct ath5k_hw *ah)
00465 {
00466         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00467         u32 mode_offset[3];
00468         unsigned int mode;
00469         u32 offset;
00470         int ret;
00471 
00472         /*
00473          * Get values for all modes
00474          */
00475         mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
00476         mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
00477         mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
00478 
00479         ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] =
00480                 AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
00481 
00482         for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
00483                 offset = mode_offset[mode];
00484 
00485                 ret = ath5k_eeprom_read_ants(ah, &offset, mode);
00486                 if (ret)
00487                         return ret;
00488 
00489                 ret = ath5k_eeprom_read_modes(ah, &offset, mode);
00490                 if (ret)
00491                         return ret;
00492         }
00493 
00494         /* override for older eeprom versions for better performance */
00495         if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) {
00496                 ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15;
00497                 ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28;
00498                 ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28;
00499         }
00500 
00501         return 0;
00502 }
00503 
00504 /* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff
00505  * frequency mask) */
00506 static inline int
00507 ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
00508                         struct ath5k_chan_pcal_info *pc, unsigned int mode)
00509 {
00510         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00511         int o = *offset;
00512         int i = 0;
00513         u8 freq1, freq2;
00514         int ret;
00515         u16 val;
00516 
00517         ee->ee_n_piers[mode] = 0;
00518         while(i < max) {
00519                 AR5K_EEPROM_READ(o++, val);
00520 
00521                 freq1 = val & 0xff;
00522                 if (!freq1)
00523                         break;
00524 
00525                 pc[i++].freq = ath5k_eeprom_bin2freq(ee,
00526                                 freq1, mode);
00527                 ee->ee_n_piers[mode]++;
00528 
00529                 freq2 = (val >> 8) & 0xff;
00530                 if (!freq2)
00531                         break;
00532 
00533                 pc[i++].freq = ath5k_eeprom_bin2freq(ee,
00534                                 freq2, mode);
00535                 ee->ee_n_piers[mode]++;
00536         }
00537 
00538         /* return new offset */
00539         *offset = o;
00540 
00541         return 0;
00542 }
00543 
00544 /* Read frequency piers for 802.11a */
00545 static int
00546 ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)
00547 {
00548         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00549         struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a;
00550         int i, ret;
00551         u16 val;
00552         u8 mask;
00553 
00554         if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
00555                 ath5k_eeprom_read_freq_list(ah, &offset,
00556                         AR5K_EEPROM_N_5GHZ_CHAN, pcal,
00557                         AR5K_EEPROM_MODE_11A);
00558         } else {
00559                 mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version);
00560 
00561                 AR5K_EEPROM_READ(offset++, val);
00562                 pcal[0].freq  = (val >> 9) & mask;
00563                 pcal[1].freq  = (val >> 2) & mask;
00564                 pcal[2].freq  = (val << 5) & mask;
00565 
00566                 AR5K_EEPROM_READ(offset++, val);
00567                 pcal[2].freq |= (val >> 11) & 0x1f;
00568                 pcal[3].freq  = (val >> 4) & mask;
00569                 pcal[4].freq  = (val << 3) & mask;
00570 
00571                 AR5K_EEPROM_READ(offset++, val);
00572                 pcal[4].freq |= (val >> 13) & 0x7;
00573                 pcal[5].freq  = (val >> 6) & mask;
00574                 pcal[6].freq  = (val << 1) & mask;
00575 
00576                 AR5K_EEPROM_READ(offset++, val);
00577                 pcal[6].freq |= (val >> 15) & 0x1;
00578                 pcal[7].freq  = (val >> 8) & mask;
00579                 pcal[8].freq  = (val >> 1) & mask;
00580                 pcal[9].freq  = (val << 6) & mask;
00581 
00582                 AR5K_EEPROM_READ(offset++, val);
00583                 pcal[9].freq |= (val >> 10) & 0x3f;
00584 
00585                 /* Fixed number of piers */
00586                 ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10;
00587 
00588                 for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) {
00589                         pcal[i].freq = ath5k_eeprom_bin2freq(ee,
00590                                 pcal[i].freq, AR5K_EEPROM_MODE_11A);
00591                 }
00592         }
00593 
00594         return 0;
00595 }
00596 
00597 /* Read frequency piers for 802.11bg on eeprom versions >= 5 and eemap >= 2 */
00598 static inline int
00599 ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
00600 {
00601         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00602         struct ath5k_chan_pcal_info *pcal;
00603 
00604         switch(mode) {
00605         case AR5K_EEPROM_MODE_11B:
00606                 pcal = ee->ee_pwr_cal_b;
00607                 break;
00608         case AR5K_EEPROM_MODE_11G:
00609                 pcal = ee->ee_pwr_cal_g;
00610                 break;
00611         default:
00612                 return -EINVAL;
00613         }
00614 
00615         ath5k_eeprom_read_freq_list(ah, &offset,
00616                 AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal,
00617                 mode);
00618 
00619         return 0;
00620 }
00621 
00622 /*
00623  * Read power calibration for RF5111 chips
00624  *
00625  * For RF5111 we have an XPD -eXternal Power Detector- curve
00626  * for each calibrated channel. Each curve has 0,5dB Power steps
00627  * on x axis and PCDAC steps (offsets) on y axis and looks like an
00628  * exponential function. To recreate the curve we read 11 points
00629  * here and interpolate later.
00630  */
00631 
00632 /* Used to match PCDAC steps with power values on RF5111 chips
00633  * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC
00634  * steps that match with the power values we read from eeprom. On
00635  * older eeprom versions (< 3.2) these steps are equaly spaced at
00636  * 10% of the pcdac curve -until the curve reaches it's maximum-
00637  * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)
00638  * these 11 steps are spaced in a different way. This function returns
00639  * the pcdac steps based on eeprom version and curve min/max so that we
00640  * can have pcdac/pwr points.
00641  */
00642 static inline void
00643 ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
00644 {
00645         static const u16 intercepts3[] =
00646                 { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
00647         static const u16 intercepts3_2[] =
00648                 { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
00649         const u16 *ip;
00650         int i;
00651 
00652         if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2)
00653                 ip = intercepts3_2;
00654         else
00655                 ip = intercepts3;
00656 
00657         for (i = 0; i < ARRAY_SIZE(intercepts3); i++)
00658                 vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100;
00659 }
00660 
00661 /* Convert RF5111 specific data to generic raw data
00662  * used by interpolation code */
00663 static int
00664 ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
00665                                 struct ath5k_chan_pcal_info *chinfo)
00666 {
00667         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00668         struct ath5k_chan_pcal_info_rf5111 *pcinfo;
00669         struct ath5k_pdgain_info *pd;
00670         u8 pier, point, idx;
00671         u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
00672 
00673         /* Fill raw data for each calibration pier */
00674         for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
00675 
00676                 pcinfo = &chinfo[pier].rf5111_info;
00677 
00678                 /* Allocate pd_curves for this cal pier */
00679                 chinfo[pier].pd_curves =
00680                         kcalloc(AR5K_EEPROM_N_PD_CURVES,
00681                                 sizeof(struct ath5k_pdgain_info),
00682                                 GFP_KERNEL);
00683 
00684                 if (!chinfo[pier].pd_curves)
00685                         return -ENOMEM;
00686 
00687                 /* Only one curve for RF5111
00688                  * find out which one and place
00689                  * in in pd_curves.
00690                  * Note: ee_x_gain is reversed here */
00691                 for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) {
00692 
00693                         if (!((ee->ee_x_gain[mode] >> idx) & 0x1)) {
00694                                 pdgain_idx[0] = idx;
00695                                 break;
00696                         }
00697                 }
00698 
00699                 ee->ee_pd_gains[mode] = 1;
00700 
00701                 pd = &chinfo[pier].pd_curves[idx];
00702 
00703                 pd->pd_points = AR5K_EEPROM_N_PWR_POINTS_5111;
00704 
00705                 /* Allocate pd points for this curve */
00706                 pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
00707                                         sizeof(u8), GFP_KERNEL);
00708                 if (!pd->pd_step)
00709                         return -ENOMEM;
00710 
00711                 pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
00712                                         sizeof(s16), GFP_KERNEL);
00713                 if (!pd->pd_pwr)
00714                         return -ENOMEM;
00715 
00716                 /* Fill raw dataset
00717                  * (convert power to 0.25dB units
00718                  * for RF5112 combatibility) */
00719                 for (point = 0; point < pd->pd_points; point++) {
00720 
00721                         /* Absolute values */
00722                         pd->pd_pwr[point] = 2 * pcinfo->pwr[point];
00723 
00724                         /* Already sorted */
00725                         pd->pd_step[point] = pcinfo->pcdac[point];
00726                 }
00727 
00728                 /* Set min/max pwr */
00729                 chinfo[pier].min_pwr = pd->pd_pwr[0];
00730                 chinfo[pier].max_pwr = pd->pd_pwr[10];
00731 
00732         }
00733 
00734         return 0;
00735 }
00736 
00737 /* Parse EEPROM data */
00738 static int
00739 ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
00740 {
00741         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00742         struct ath5k_chan_pcal_info *pcal;
00743         int offset, ret;
00744         int i;
00745         u16 val;
00746 
00747         offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
00748         switch(mode) {
00749         case AR5K_EEPROM_MODE_11A:
00750                 if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
00751                         return 0;
00752 
00753                 ret = ath5k_eeprom_init_11a_pcal_freq(ah,
00754                         offset + AR5K_EEPROM_GROUP1_OFFSET);
00755                 if (ret < 0)
00756                         return ret;
00757 
00758                 offset += AR5K_EEPROM_GROUP2_OFFSET;
00759                 pcal = ee->ee_pwr_cal_a;
00760                 break;
00761         case AR5K_EEPROM_MODE_11B:
00762                 if (!AR5K_EEPROM_HDR_11B(ee->ee_header) &&
00763                     !AR5K_EEPROM_HDR_11G(ee->ee_header))
00764                         return 0;
00765 
00766                 pcal = ee->ee_pwr_cal_b;
00767                 offset += AR5K_EEPROM_GROUP3_OFFSET;
00768 
00769                 /* fixed piers */
00770                 pcal[0].freq = 2412;
00771                 pcal[1].freq = 2447;
00772                 pcal[2].freq = 2484;
00773                 ee->ee_n_piers[mode] = 3;
00774                 break;
00775         case AR5K_EEPROM_MODE_11G:
00776                 if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
00777                         return 0;
00778 
00779                 pcal = ee->ee_pwr_cal_g;
00780                 offset += AR5K_EEPROM_GROUP4_OFFSET;
00781 
00782                 /* fixed piers */
00783                 pcal[0].freq = 2312;
00784                 pcal[1].freq = 2412;
00785                 pcal[2].freq = 2484;
00786                 ee->ee_n_piers[mode] = 3;
00787                 break;
00788         default:
00789                 return -EINVAL;
00790         }
00791 
00792         for (i = 0; i < ee->ee_n_piers[mode]; i++) {
00793                 struct ath5k_chan_pcal_info_rf5111 *cdata =
00794                         &pcal[i].rf5111_info;
00795 
00796                 AR5K_EEPROM_READ(offset++, val);
00797                 cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M);
00798                 cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M);
00799                 cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M);
00800 
00801                 AR5K_EEPROM_READ(offset++, val);
00802                 cdata->pwr[0] |= ((val >> 14) & 0x3);
00803                 cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M);
00804                 cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M);
00805                 cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M);
00806 
00807                 AR5K_EEPROM_READ(offset++, val);
00808                 cdata->pwr[3] |= ((val >> 12) & 0xf);
00809                 cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M);
00810                 cdata->pwr[5] = (val  & AR5K_EEPROM_POWER_M);
00811 
00812                 AR5K_EEPROM_READ(offset++, val);
00813                 cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M);
00814                 cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M);
00815                 cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M);
00816 
00817                 AR5K_EEPROM_READ(offset++, val);
00818                 cdata->pwr[8] |= ((val >> 14) & 0x3);
00819                 cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M);
00820                 cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M);
00821 
00822                 ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min,
00823                         cdata->pcdac_max, cdata->pcdac);
00824         }
00825 
00826         return ath5k_eeprom_convert_pcal_info_5111(ah, mode, pcal);
00827 }
00828 
00829 
00830 /*
00831  * Read power calibration for RF5112 chips
00832  *
00833  * For RF5112 we have 4 XPD -eXternal Power Detector- curves
00834  * for each calibrated channel on 0, -6, -12 and -18dbm but we only
00835  * use the higher (3) and the lower (0) curves. Each curve has 0.5dB
00836  * power steps on x axis and PCDAC steps on y axis and looks like a
00837  * linear function. To recreate the curve and pass the power values
00838  * on hw, we read 4 points for xpd 0 (lower gain -> max power)
00839  * and 3 points for xpd 3 (higher gain -> lower power) here and
00840  * interpolate later.
00841  *
00842  * Note: Many vendors just use xpd 0 so xpd 3 is zeroed.
00843  */
00844 
00845 /* Convert RF5112 specific data to generic raw data
00846  * used by interpolation code */
00847 static int
00848 ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
00849                                 struct ath5k_chan_pcal_info *chinfo)
00850 {
00851         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00852         struct ath5k_chan_pcal_info_rf5112 *pcinfo;
00853         u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
00854         unsigned int pier, pdg, point;
00855 
00856         /* Fill raw data for each calibration pier */
00857         for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
00858 
00859                 pcinfo = &chinfo[pier].rf5112_info;
00860 
00861                 /* Allocate pd_curves for this cal pier */
00862                 chinfo[pier].pd_curves =
00863                                 kcalloc(AR5K_EEPROM_N_PD_CURVES,
00864                                         sizeof(struct ath5k_pdgain_info),
00865                                         GFP_KERNEL);
00866 
00867                 if (!chinfo[pier].pd_curves)
00868                         return -ENOMEM;
00869 
00870                 /* Fill pd_curves */
00871                 for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
00872 
00873                         u8 idx = pdgain_idx[pdg];
00874                         struct ath5k_pdgain_info *pd =
00875                                         &chinfo[pier].pd_curves[idx];
00876 
00877                         /* Lowest gain curve (max power) */
00878                         if (pdg == 0) {
00879                                 /* One more point for better accuracy */
00880                                 pd->pd_points = AR5K_EEPROM_N_XPD0_POINTS;
00881 
00882                                 /* Allocate pd points for this curve */
00883                                 pd->pd_step = kcalloc(pd->pd_points,
00884                                                 sizeof(u8), GFP_KERNEL);
00885 
00886                                 if (!pd->pd_step)
00887                                         return -ENOMEM;
00888 
00889                                 pd->pd_pwr = kcalloc(pd->pd_points,
00890                                                 sizeof(s16), GFP_KERNEL);
00891 
00892                                 if (!pd->pd_pwr)
00893                                         return -ENOMEM;
00894 
00895 
00896                                 /* Fill raw dataset
00897                                  * (all power levels are in 0.25dB units) */
00898                                 pd->pd_step[0] = pcinfo->pcdac_x0[0];
00899                                 pd->pd_pwr[0] = pcinfo->pwr_x0[0];
00900 
00901                                 for (point = 1; point < pd->pd_points;
00902                                 point++) {
00903                                         /* Absolute values */
00904                                         pd->pd_pwr[point] =
00905                                                 pcinfo->pwr_x0[point];
00906 
00907                                         /* Deltas */
00908                                         pd->pd_step[point] =
00909                                                 pd->pd_step[point - 1] +
00910                                                 pcinfo->pcdac_x0[point];
00911                                 }
00912 
00913                                 /* Set min power for this frequency */
00914                                 chinfo[pier].min_pwr = pd->pd_pwr[0];
00915 
00916                         /* Highest gain curve (min power) */
00917                         } else if (pdg == 1) {
00918 
00919                                 pd->pd_points = AR5K_EEPROM_N_XPD3_POINTS;
00920 
00921                                 /* Allocate pd points for this curve */
00922                                 pd->pd_step = kcalloc(pd->pd_points,
00923                                                 sizeof(u8), GFP_KERNEL);
00924 
00925                                 if (!pd->pd_step)
00926                                         return -ENOMEM;
00927 
00928                                 pd->pd_pwr = kcalloc(pd->pd_points,
00929                                                 sizeof(s16), GFP_KERNEL);
00930 
00931                                 if (!pd->pd_pwr)
00932                                         return -ENOMEM;
00933 
00934                                 /* Fill raw dataset
00935                                  * (all power levels are in 0.25dB units) */
00936                                 for (point = 0; point < pd->pd_points;
00937                                 point++) {
00938                                         /* Absolute values */
00939                                         pd->pd_pwr[point] =
00940                                                 pcinfo->pwr_x3[point];
00941 
00942                                         /* Fixed points */
00943                                         pd->pd_step[point] =
00944                                                 pcinfo->pcdac_x3[point];
00945                                 }
00946 
00947                                 /* Since we have a higher gain curve
00948                                  * override min power */
00949                                 chinfo[pier].min_pwr = pd->pd_pwr[0];
00950                         }
00951                 }
00952         }
00953 
00954         return 0;
00955 }
00956 
00957 /* Parse EEPROM data */
00958 static int
00959 ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
00960 {
00961         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00962         struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info;
00963         struct ath5k_chan_pcal_info *gen_chan_info;
00964         u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
00965         u32 offset;
00966         u8 i, c;
00967         u16 val;
00968         int ret;
00969         u8 pd_gains = 0;
00970 
00971         /* Count how many curves we have and
00972          * identify them (which one of the 4
00973          * available curves we have on each count).
00974          * Curves are stored from lower (x0) to
00975          * higher (x3) gain */
00976         for (i = 0; i < AR5K_EEPROM_N_PD_CURVES; i++) {
00977                 /* ee_x_gain[mode] is x gain mask */
00978                 if ((ee->ee_x_gain[mode] >> i) & 0x1)
00979                         pdgain_idx[pd_gains++] = i;
00980         }
00981         ee->ee_pd_gains[mode] = pd_gains;
00982 
00983         if (pd_gains == 0 || pd_gains > 2)
00984                 return -EINVAL;
00985 
00986         switch (mode) {
00987         case AR5K_EEPROM_MODE_11A:
00988                 /*
00989                  * Read 5GHz EEPROM channels
00990                  */
00991                 offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
00992                 ath5k_eeprom_init_11a_pcal_freq(ah, offset);
00993 
00994                 offset += AR5K_EEPROM_GROUP2_OFFSET;
00995                 gen_chan_info = ee->ee_pwr_cal_a;
00996                 break;
00997         case AR5K_EEPROM_MODE_11B:
00998                 offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
00999                 if (AR5K_EEPROM_HDR_11A(ee->ee_header))
01000                         offset += AR5K_EEPROM_GROUP3_OFFSET;
01001 
01002                 /* NB: frequency piers parsed during mode init */
01003                 gen_chan_info = ee->ee_pwr_cal_b;
01004                 break;
01005         case AR5K_EEPROM_MODE_11G:
01006                 offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
01007                 if (AR5K_EEPROM_HDR_11A(ee->ee_header))
01008                         offset += AR5K_EEPROM_GROUP4_OFFSET;
01009                 else if (AR5K_EEPROM_HDR_11B(ee->ee_header))
01010                         offset += AR5K_EEPROM_GROUP2_OFFSET;
01011 
01012                 /* NB: frequency piers parsed during mode init */
01013                 gen_chan_info = ee->ee_pwr_cal_g;
01014                 break;
01015         default:
01016                 return -EINVAL;
01017         }
01018 
01019         for (i = 0; i < ee->ee_n_piers[mode]; i++) {
01020                 chan_pcal_info = &gen_chan_info[i].rf5112_info;
01021 
01022                 /* Power values in quarter dB
01023                  * for the lower xpd gain curve
01024                  * (0 dBm -> higher output power) */
01025                 for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
01026                         AR5K_EEPROM_READ(offset++, val);
01027                         chan_pcal_info->pwr_x0[c] = (s8) (val & 0xff);
01028                         chan_pcal_info->pwr_x0[++c] = (s8) ((val >> 8) & 0xff);
01029                 }
01030 
01031                 /* PCDAC steps
01032                  * corresponding to the above power
01033                  * measurements */
01034                 AR5K_EEPROM_READ(offset++, val);
01035                 chan_pcal_info->pcdac_x0[1] = (val & 0x1f);
01036                 chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f);
01037                 chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f);
01038 
01039                 /* Power values in quarter dB
01040                  * for the higher xpd gain curve
01041                  * (18 dBm -> lower output power) */
01042                 AR5K_EEPROM_READ(offset++, val);
01043                 chan_pcal_info->pwr_x3[0] = (s8) (val & 0xff);
01044                 chan_pcal_info->pwr_x3[1] = (s8) ((val >> 8) & 0xff);
01045 
01046                 AR5K_EEPROM_READ(offset++, val);
01047                 chan_pcal_info->pwr_x3[2] = (val & 0xff);
01048 
01049                 /* PCDAC steps
01050                  * corresponding to the above power
01051                  * measurements (fixed) */
01052                 chan_pcal_info->pcdac_x3[0] = 20;
01053                 chan_pcal_info->pcdac_x3[1] = 35;
01054                 chan_pcal_info->pcdac_x3[2] = 63;
01055 
01056                 if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) {
01057                         chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0x3f);
01058 
01059                         /* Last xpd0 power level is also channel maximum */
01060                         gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3];
01061                 } else {
01062                         chan_pcal_info->pcdac_x0[0] = 1;
01063                         gen_chan_info[i].max_pwr = (s8) ((val >> 8) & 0xff);
01064                 }
01065 
01066         }
01067 
01068         return ath5k_eeprom_convert_pcal_info_5112(ah, mode, gen_chan_info);
01069 }
01070 
01071 
01072 /*
01073  * Read power calibration for RF2413 chips
01074  *
01075  * For RF2413 we have a Power to PDDAC table (Power Detector)
01076  * instead of a PCDAC and 4 pd gain curves for each calibrated channel.
01077  * Each curve has power on x axis in 0.5 db steps and PDDADC steps on y
01078  * axis and looks like an exponential function like the RF5111 curve.
01079  *
01080  * To recreate the curves we read here the points and interpolate
01081  * later. Note that in most cases only 2 (higher and lower) curves are
01082  * used (like RF5112) but vendors have the oportunity to include all
01083  * 4 curves on eeprom. The final curve (higher power) has an extra
01084  * point for better accuracy like RF5112.
01085  */
01086 
01087 /* For RF2413 power calibration data doesn't start on a fixed location and
01088  * if a mode is not supported, it's section is missing -not zeroed-.
01089  * So we need to calculate the starting offset for each section by using
01090  * these two functions */
01091 
01092 /* Return the size of each section based on the mode and the number of pd
01093  * gains available (maximum 4). */
01094 static inline unsigned int
01095 ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode)
01096 {
01097         static const unsigned int pdgains_size[] = { 4, 6, 9, 12 };
01098         unsigned int sz;
01099 
01100         sz = pdgains_size[ee->ee_pd_gains[mode] - 1];
01101         sz *= ee->ee_n_piers[mode];
01102 
01103         return sz;
01104 }
01105 
01106 /* Return the starting offset for a section based on the modes supported
01107  * and each section's size. */
01108 static unsigned int
01109 ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
01110 {
01111         u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4);
01112 
01113         switch(mode) {
01114         case AR5K_EEPROM_MODE_11G:
01115                 if (AR5K_EEPROM_HDR_11B(ee->ee_header))
01116                         offset += ath5k_pdgains_size_2413(ee,
01117                                         AR5K_EEPROM_MODE_11B) +
01118                                         AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
01119                 /* fall through */
01120         case AR5K_EEPROM_MODE_11B:
01121                 if (AR5K_EEPROM_HDR_11A(ee->ee_header))
01122                         offset += ath5k_pdgains_size_2413(ee,
01123                                         AR5K_EEPROM_MODE_11A) +
01124                                         AR5K_EEPROM_N_5GHZ_CHAN / 2;
01125                 /* fall through */
01126         case AR5K_EEPROM_MODE_11A:
01127                 break;
01128         default:
01129                 break;
01130         }
01131 
01132         return offset;
01133 }
01134 
01135 /* Convert RF2413 specific data to generic raw data
01136  * used by interpolation code */
01137 static int
01138 ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
01139                                 struct ath5k_chan_pcal_info *chinfo)
01140 {
01141         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01142         struct ath5k_chan_pcal_info_rf2413 *pcinfo;
01143         u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
01144         unsigned int pier, pdg, point;
01145 
01146         /* Fill raw data for each calibration pier */
01147         for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
01148 
01149                 pcinfo = &chinfo[pier].rf2413_info;
01150 
01151                 /* Allocate pd_curves for this cal pier */
01152                 chinfo[pier].pd_curves =
01153                                 kcalloc(AR5K_EEPROM_N_PD_CURVES,
01154                                         sizeof(struct ath5k_pdgain_info),
01155                                         GFP_KERNEL);
01156 
01157                 if (!chinfo[pier].pd_curves)
01158                         return -ENOMEM;
01159 
01160                 /* Fill pd_curves */
01161                 for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
01162 
01163                         u8 idx = pdgain_idx[pdg];
01164                         struct ath5k_pdgain_info *pd =
01165                                         &chinfo[pier].pd_curves[idx];
01166 
01167                         /* One more point for the highest power
01168                          * curve (lowest gain) */
01169                         if (pdg == ee->ee_pd_gains[mode] - 1)
01170                                 pd->pd_points = AR5K_EEPROM_N_PD_POINTS;
01171                         else
01172                                 pd->pd_points = AR5K_EEPROM_N_PD_POINTS - 1;
01173 
01174                         /* Allocate pd points for this curve */
01175                         pd->pd_step = kcalloc(pd->pd_points,
01176                                         sizeof(u8), GFP_KERNEL);
01177 
01178                         if (!pd->pd_step)
01179                                 return -ENOMEM;
01180 
01181                         pd->pd_pwr = kcalloc(pd->pd_points,
01182                                         sizeof(s16), GFP_KERNEL);
01183 
01184                         if (!pd->pd_pwr)
01185                                 return -ENOMEM;
01186 
01187                         /* Fill raw dataset
01188                          * convert all pwr levels to
01189                          * quarter dB for RF5112 combatibility */
01190                         pd->pd_step[0] = pcinfo->pddac_i[pdg];
01191                         pd->pd_pwr[0] = 4 * pcinfo->pwr_i[pdg];
01192 
01193                         for (point = 1; point < pd->pd_points; point++) {
01194 
01195                                 pd->pd_pwr[point] = pd->pd_pwr[point - 1] +
01196                                         2 * pcinfo->pwr[pdg][point - 1];
01197 
01198                                 pd->pd_step[point] = pd->pd_step[point - 1] +
01199                                                 pcinfo->pddac[pdg][point - 1];
01200 
01201                         }
01202 
01203                         /* Highest gain curve -> min power */
01204                         if (pdg == 0)
01205                                 chinfo[pier].min_pwr = pd->pd_pwr[0];
01206 
01207                         /* Lowest gain curve -> max power */
01208                         if (pdg == ee->ee_pd_gains[mode] - 1)
01209                                 chinfo[pier].max_pwr =
01210                                         pd->pd_pwr[pd->pd_points - 1];
01211                 }
01212         }
01213 
01214         return 0;
01215 }
01216 
01217 /* Parse EEPROM data */
01218 static int
01219 ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
01220 {
01221         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01222         struct ath5k_chan_pcal_info_rf2413 *pcinfo;
01223         struct ath5k_chan_pcal_info *chinfo;
01224         u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
01225         u32 offset;
01226         int idx, i, ret;
01227         u16 val;
01228         u8 pd_gains = 0;
01229 
01230         /* Count how many curves we have and
01231          * identify them (which one of the 4
01232          * available curves we have on each count).
01233          * Curves are stored from higher to
01234          * lower gain so we go backwards */
01235         for (idx = AR5K_EEPROM_N_PD_CURVES - 1; idx >= 0; idx--) {
01236                 /* ee_x_gain[mode] is x gain mask */
01237                 if ((ee->ee_x_gain[mode] >> idx) & 0x1)
01238                         pdgain_idx[pd_gains++] = idx;
01239 
01240         }
01241         ee->ee_pd_gains[mode] = pd_gains;
01242 
01243         if (pd_gains == 0)
01244                 return -EINVAL;
01245 
01246         offset = ath5k_cal_data_offset_2413(ee, mode);
01247         switch (mode) {
01248         case AR5K_EEPROM_MODE_11A:
01249                 if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
01250                         return 0;
01251 
01252                 ath5k_eeprom_init_11a_pcal_freq(ah, offset);
01253                 offset += AR5K_EEPROM_N_5GHZ_CHAN / 2;
01254                 chinfo = ee->ee_pwr_cal_a;
01255                 break;
01256         case AR5K_EEPROM_MODE_11B:
01257                 if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
01258                         return 0;
01259 
01260                 ath5k_eeprom_init_11bg_2413(ah, mode, offset);
01261                 offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
01262                 chinfo = ee->ee_pwr_cal_b;
01263                 break;
01264         case AR5K_EEPROM_MODE_11G:
01265                 if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
01266                         return 0;
01267 
01268                 ath5k_eeprom_init_11bg_2413(ah, mode, offset);
01269                 offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
01270                 chinfo = ee->ee_pwr_cal_g;
01271                 break;
01272         default:
01273                 return -EINVAL;
01274         }
01275 
01276         for (i = 0; i < ee->ee_n_piers[mode]; i++) {
01277                 pcinfo = &chinfo[i].rf2413_info;
01278 
01279                 /*
01280                  * Read pwr_i, pddac_i and the first
01281                  * 2 pd points (pwr, pddac)
01282                  */
01283                 AR5K_EEPROM_READ(offset++, val);
01284                 pcinfo->pwr_i[0] = val & 0x1f;
01285                 pcinfo->pddac_i[0] = (val >> 5) & 0x7f;
01286                 pcinfo->pwr[0][0] = (val >> 12) & 0xf;
01287 
01288                 AR5K_EEPROM_READ(offset++, val);
01289                 pcinfo->pddac[0][0] = val & 0x3f;
01290                 pcinfo->pwr[0][1] = (val >> 6) & 0xf;
01291                 pcinfo->pddac[0][1] = (val >> 10) & 0x3f;
01292 
01293                 AR5K_EEPROM_READ(offset++, val);
01294                 pcinfo->pwr[0][2] = val & 0xf;
01295                 pcinfo->pddac[0][2] = (val >> 4) & 0x3f;
01296 
01297                 pcinfo->pwr[0][3] = 0;
01298                 pcinfo->pddac[0][3] = 0;
01299 
01300                 if (pd_gains > 1) {
01301                         /*
01302                          * Pd gain 0 is not the last pd gain
01303                          * so it only has 2 pd points.
01304                          * Continue wih pd gain 1.
01305                          */
01306                         pcinfo->pwr_i[1] = (val >> 10) & 0x1f;
01307 
01308                         pcinfo->pddac_i[1] = (val >> 15) & 0x1;
01309                         AR5K_EEPROM_READ(offset++, val);
01310                         pcinfo->pddac_i[1] |= (val & 0x3F) << 1;
01311 
01312                         pcinfo->pwr[1][0] = (val >> 6) & 0xf;
01313                         pcinfo->pddac[1][0] = (val >> 10) & 0x3f;
01314 
01315                         AR5K_EEPROM_READ(offset++, val);
01316                         pcinfo->pwr[1][1] = val & 0xf;
01317                         pcinfo->pddac[1][1] = (val >> 4) & 0x3f;
01318                         pcinfo->pwr[1][2] = (val >> 10) & 0xf;
01319 
01320                         pcinfo->pddac[1][2] = (val >> 14) & 0x3;
01321                         AR5K_EEPROM_READ(offset++, val);
01322                         pcinfo->pddac[1][2] |= (val & 0xF) << 2;
01323 
01324                         pcinfo->pwr[1][3] = 0;
01325                         pcinfo->pddac[1][3] = 0;
01326                 } else if (pd_gains == 1) {
01327                         /*
01328                          * Pd gain 0 is the last one so
01329                          * read the extra point.
01330                          */
01331                         pcinfo->pwr[0][3] = (val >> 10) & 0xf;
01332 
01333                         pcinfo->pddac[0][3] = (val >> 14) & 0x3;
01334                         AR5K_EEPROM_READ(offset++, val);
01335                         pcinfo->pddac[0][3] |= (val & 0xF) << 2;
01336                 }
01337 
01338                 /*
01339                  * Proceed with the other pd_gains
01340                  * as above.
01341                  */
01342                 if (pd_gains > 2) {
01343                         pcinfo->pwr_i[2] = (val >> 4) & 0x1f;
01344                         pcinfo->pddac_i[2] = (val >> 9) & 0x7f;
01345 
01346                         AR5K_EEPROM_READ(offset++, val);
01347                         pcinfo->pwr[2][0] = (val >> 0) & 0xf;
01348                         pcinfo->pddac[2][0] = (val >> 4) & 0x3f;
01349                         pcinfo->pwr[2][1] = (val >> 10) & 0xf;
01350 
01351                         pcinfo->pddac[2][1] = (val >> 14) & 0x3;
01352                         AR5K_EEPROM_READ(offset++, val);
01353                         pcinfo->pddac[2][1] |= (val & 0xF) << 2;
01354 
01355                         pcinfo->pwr[2][2] = (val >> 4) & 0xf;
01356                         pcinfo->pddac[2][2] = (val >> 8) & 0x3f;
01357 
01358                         pcinfo->pwr[2][3] = 0;
01359                         pcinfo->pddac[2][3] = 0;
01360                 } else if (pd_gains == 2) {
01361                         pcinfo->pwr[1][3] = (val >> 4) & 0xf;
01362                         pcinfo->pddac[1][3] = (val >> 8) & 0x3f;
01363                 }
01364 
01365                 if (pd_gains > 3) {
01366                         pcinfo->pwr_i[3] = (val >> 14) & 0x3;
01367                         AR5K_EEPROM_READ(offset++, val);
01368                         pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2;
01369 
01370                         pcinfo->pddac_i[3] = (val >> 3) & 0x7f;
01371                         pcinfo->pwr[3][0] = (val >> 10) & 0xf;
01372                         pcinfo->pddac[3][0] = (val >> 14) & 0x3;
01373 
01374                         AR5K_EEPROM_READ(offset++, val);
01375                         pcinfo->pddac[3][0] |= (val & 0xF) << 2;
01376                         pcinfo->pwr[3][1] = (val >> 4) & 0xf;
01377                         pcinfo->pddac[3][1] = (val >> 8) & 0x3f;
01378 
01379                         pcinfo->pwr[3][2] = (val >> 14) & 0x3;
01380                         AR5K_EEPROM_READ(offset++, val);
01381                         pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2;
01382 
01383                         pcinfo->pddac[3][2] = (val >> 2) & 0x3f;
01384                         pcinfo->pwr[3][3] = (val >> 8) & 0xf;
01385 
01386                         pcinfo->pddac[3][3] = (val >> 12) & 0xF;
01387                         AR5K_EEPROM_READ(offset++, val);
01388                         pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4;
01389                 } else if (pd_gains == 3) {
01390                         pcinfo->pwr[2][3] = (val >> 14) & 0x3;
01391                         AR5K_EEPROM_READ(offset++, val);
01392                         pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2;
01393 
01394                         pcinfo->pddac[2][3] = (val >> 2) & 0x3f;
01395                 }
01396         }
01397 
01398         return ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo);
01399 }
01400 
01401 
01402 /*
01403  * Read per rate target power (this is the maximum tx power
01404  * supported by the card). This info is used when setting
01405  * tx power, no matter the channel.
01406  *
01407  * This also works for v5 EEPROMs.
01408  */
01409 static int
01410 ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
01411 {
01412         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01413         struct ath5k_rate_pcal_info *rate_pcal_info;
01414         u8 *rate_target_pwr_num;
01415         u32 offset;
01416         u16 val;
01417         int ret, i;
01418 
01419         offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1);
01420         rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode];
01421         switch (mode) {
01422         case AR5K_EEPROM_MODE_11A:
01423                 offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
01424                 rate_pcal_info = ee->ee_rate_tpwr_a;
01425                 ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN;
01426                 break;
01427         case AR5K_EEPROM_MODE_11B:
01428                 offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
01429                 rate_pcal_info = ee->ee_rate_tpwr_b;
01430                 ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */
01431                 break;
01432         case AR5K_EEPROM_MODE_11G:
01433                 offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version);
01434                 rate_pcal_info = ee->ee_rate_tpwr_g;
01435                 ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN;
01436                 break;
01437         default:
01438                 return -EINVAL;
01439         }
01440 
01441         /* Different freq mask for older eeproms (<= v3.2) */
01442         if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) {
01443                 for (i = 0; i < (*rate_target_pwr_num); i++) {
01444                         AR5K_EEPROM_READ(offset++, val);
01445                         rate_pcal_info[i].freq =
01446                             ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode);
01447 
01448                         rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f);
01449                         rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f;
01450 
01451                         AR5K_EEPROM_READ(offset++, val);
01452 
01453                         if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
01454                             val == 0) {
01455                                 (*rate_target_pwr_num) = i;
01456                                 break;
01457                         }
01458 
01459                         rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7);
01460                         rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f);
01461                         rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f);
01462                 }
01463         } else {
01464                 for (i = 0; i < (*rate_target_pwr_num); i++) {
01465                         AR5K_EEPROM_READ(offset++, val);
01466                         rate_pcal_info[i].freq =
01467                             ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
01468 
01469                         rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f);
01470                         rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f;
01471 
01472                         AR5K_EEPROM_READ(offset++, val);
01473 
01474                         if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
01475                             val == 0) {
01476                                 (*rate_target_pwr_num) = i;
01477                                 break;
01478                         }
01479 
01480                         rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf;
01481                         rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f);
01482                         rate_pcal_info[i].target_power_54 = (val & 0x3f);
01483                 }
01484         }
01485 
01486         return 0;
01487 }
01488 
01489 /*
01490  * Read per channel calibration info from EEPROM
01491  *
01492  * This info is used to calibrate the baseband power table. Imagine
01493  * that for each channel there is a power curve that's hw specific
01494  * (depends on amplifier etc) and we try to "correct" this curve using
01495  * offests we pass on to phy chip (baseband -> before amplifier) so that
01496  * it can use accurate power values when setting tx power (takes amplifier's
01497  * performance on each channel into account).
01498  *
01499  * EEPROM provides us with the offsets for some pre-calibrated channels
01500  * and we have to interpolate to create the full table for these channels and
01501  * also the table for any channel.
01502  */
01503 static int
01504 ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
01505 {
01506         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01507         int (*read_pcal)(struct ath5k_hw *hw, int mode);
01508         int mode;
01509         int err;
01510 
01511         if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) &&
01512                         (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1))
01513                 read_pcal = ath5k_eeprom_read_pcal_info_5112;
01514         else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) &&
01515                         (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2))
01516                 read_pcal = ath5k_eeprom_read_pcal_info_2413;
01517         else
01518                 read_pcal = ath5k_eeprom_read_pcal_info_5111;
01519 
01520 
01521         for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G;
01522         mode++) {
01523                 err = read_pcal(ah, mode);
01524                 if (err)
01525                         return err;
01526 
01527                 err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode);
01528                 if (err < 0)
01529                         return err;
01530         }
01531 
01532         return 0;
01533 }
01534 
01535 static int
01536 ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
01537 {
01538         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01539         struct ath5k_chan_pcal_info *chinfo;
01540         u8 pier, pdg;
01541 
01542         switch (mode) {
01543         case AR5K_EEPROM_MODE_11A:
01544                 if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
01545                         return 0;
01546                 chinfo = ee->ee_pwr_cal_a;
01547                 break;
01548         case AR5K_EEPROM_MODE_11B:
01549                 if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
01550                         return 0;
01551                 chinfo = ee->ee_pwr_cal_b;
01552                 break;
01553         case AR5K_EEPROM_MODE_11G:
01554                 if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
01555                         return 0;
01556                 chinfo = ee->ee_pwr_cal_g;
01557                 break;
01558         default:
01559                 return -EINVAL;
01560         }
01561 
01562         for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
01563                 if (!chinfo[pier].pd_curves)
01564                         continue;
01565 
01566                 for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
01567                         struct ath5k_pdgain_info *pd =
01568                                         &chinfo[pier].pd_curves[pdg];
01569 
01570                         if (pd != NULL) {
01571                                 kfree(pd->pd_step);
01572                                 kfree(pd->pd_pwr);
01573                         }
01574                 }
01575 
01576                 kfree(chinfo[pier].pd_curves);
01577         }
01578 
01579         return 0;
01580 }
01581 
01582 void
01583 ath5k_eeprom_detach(struct ath5k_hw *ah)
01584 {
01585         u8 mode;
01586 
01587         for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++)
01588                 ath5k_eeprom_free_pcal_info(ah, mode);
01589 }
01590 
01591 /* Read conformance test limits used for regulatory control */
01592 static int
01593 ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
01594 {
01595         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01596         struct ath5k_edge_power *rep;
01597         unsigned int fmask, pmask;
01598         unsigned int ctl_mode;
01599         int ret, i, j;
01600         u32 offset;
01601         u16 val;
01602 
01603         pmask = AR5K_EEPROM_POWER_M;
01604         fmask = AR5K_EEPROM_FREQ_M(ee->ee_version);
01605         offset = AR5K_EEPROM_CTL(ee->ee_version);
01606         ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version);
01607         for (i = 0; i < ee->ee_ctls; i += 2) {
01608                 AR5K_EEPROM_READ(offset++, val);
01609                 ee->ee_ctl[i] = (val >> 8) & 0xff;
01610                 ee->ee_ctl[i + 1] = val & 0xff;
01611         }
01612 
01613         offset = AR5K_EEPROM_GROUP8_OFFSET;
01614         if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0)
01615                 offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) -
01616                         AR5K_EEPROM_GROUP5_OFFSET;
01617         else
01618                 offset += AR5K_EEPROM_GROUPS_START(ee->ee_version);
01619 
01620         rep = ee->ee_ctl_pwr;
01621         for(i = 0; i < ee->ee_ctls; i++) {
01622                 switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) {
01623                 case AR5K_CTL_11A:
01624                 case AR5K_CTL_TURBO:
01625                         ctl_mode = AR5K_EEPROM_MODE_11A;
01626                         break;
01627                 default:
01628                         ctl_mode = AR5K_EEPROM_MODE_11G;
01629                         break;
01630                 }
01631                 if (ee->ee_ctl[i] == 0) {
01632                         if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3)
01633                                 offset += 8;
01634                         else
01635                                 offset += 7;
01636                         rep += AR5K_EEPROM_N_EDGES;
01637                         continue;
01638                 }
01639                 if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
01640                         for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
01641                                 AR5K_EEPROM_READ(offset++, val);
01642                                 rep[j].freq = (val >> 8) & fmask;
01643                                 rep[j + 1].freq = val & fmask;
01644                         }
01645                         for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
01646                                 AR5K_EEPROM_READ(offset++, val);
01647                                 rep[j].edge = (val >> 8) & pmask;
01648                                 rep[j].flag = (val >> 14) & 1;
01649                                 rep[j + 1].edge = val & pmask;
01650                                 rep[j + 1].flag = (val >> 6) & 1;
01651                         }
01652                 } else {
01653                         AR5K_EEPROM_READ(offset++, val);
01654                         rep[0].freq = (val >> 9) & fmask;
01655                         rep[1].freq = (val >> 2) & fmask;
01656                         rep[2].freq = (val << 5) & fmask;
01657 
01658                         AR5K_EEPROM_READ(offset++, val);
01659                         rep[2].freq |= (val >> 11) & 0x1f;
01660                         rep[3].freq = (val >> 4) & fmask;
01661                         rep[4].freq = (val << 3) & fmask;
01662 
01663                         AR5K_EEPROM_READ(offset++, val);
01664                         rep[4].freq |= (val >> 13) & 0x7;
01665                         rep[5].freq = (val >> 6) & fmask;
01666                         rep[6].freq = (val << 1) & fmask;
01667 
01668                         AR5K_EEPROM_READ(offset++, val);
01669                         rep[6].freq |= (val >> 15) & 0x1;
01670                         rep[7].freq = (val >> 8) & fmask;
01671 
01672                         rep[0].edge = (val >> 2) & pmask;
01673                         rep[1].edge = (val << 4) & pmask;
01674 
01675                         AR5K_EEPROM_READ(offset++, val);
01676                         rep[1].edge |= (val >> 12) & 0xf;
01677                         rep[2].edge = (val >> 6) & pmask;
01678                         rep[3].edge = val & pmask;
01679 
01680                         AR5K_EEPROM_READ(offset++, val);
01681                         rep[4].edge = (val >> 10) & pmask;
01682                         rep[5].edge = (val >> 4) & pmask;
01683                         rep[6].edge = (val << 2) & pmask;
01684 
01685                         AR5K_EEPROM_READ(offset++, val);
01686                         rep[6].edge |= (val >> 14) & 0x3;
01687                         rep[7].edge = (val >> 8) & pmask;
01688                 }
01689                 for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) {
01690                         rep[j].freq = ath5k_eeprom_bin2freq(ee,
01691                                 rep[j].freq, ctl_mode);
01692                 }
01693                 rep += AR5K_EEPROM_N_EDGES;
01694         }
01695 
01696         return 0;
01697 }
01698 
01699 static int
01700 ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah)
01701 {
01702         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01703         u32 offset;
01704         u16 val;
01705         int ret = 0, i;
01706 
01707         offset = AR5K_EEPROM_CTL(ee->ee_version) +
01708                                 AR5K_EEPROM_N_CTLS(ee->ee_version);
01709 
01710         if (ee->ee_version < AR5K_EEPROM_VERSION_5_3) {
01711                 /* No spur info for 5GHz */
01712                 ee->ee_spur_chans[0][0] = AR5K_EEPROM_NO_SPUR;
01713                 /* 2 channels for 2GHz (2464/2420) */
01714                 ee->ee_spur_chans[0][1] = AR5K_EEPROM_5413_SPUR_CHAN_1;
01715                 ee->ee_spur_chans[1][1] = AR5K_EEPROM_5413_SPUR_CHAN_2;
01716                 ee->ee_spur_chans[2][1] = AR5K_EEPROM_NO_SPUR;
01717         } else if (ee->ee_version >= AR5K_EEPROM_VERSION_5_3) {
01718                 for (i = 0; i < AR5K_EEPROM_N_SPUR_CHANS; i++) {
01719                         AR5K_EEPROM_READ(offset, val);
01720                         ee->ee_spur_chans[i][0] = val;
01721                         AR5K_EEPROM_READ(offset + AR5K_EEPROM_N_SPUR_CHANS,
01722                                                                         val);
01723                         ee->ee_spur_chans[i][1] = val;
01724                         offset++;
01725                 }
01726         }
01727 
01728         return ret;
01729 }
01730 
01731 /*
01732  * Initialize eeprom data structure
01733  */
01734 int
01735 ath5k_eeprom_init(struct ath5k_hw *ah)
01736 {
01737         int err;
01738 
01739         err = ath5k_eeprom_init_header(ah);
01740         if (err < 0)
01741                 return err;
01742 
01743         err = ath5k_eeprom_init_modes(ah);
01744         if (err < 0)
01745                 return err;
01746 
01747         err = ath5k_eeprom_read_pcal_info(ah);
01748         if (err < 0)
01749                 return err;
01750 
01751         err = ath5k_eeprom_read_ctl_info(ah);
01752         if (err < 0)
01753                 return err;
01754 
01755         err = ath5k_eeprom_read_spur_chans(ah);
01756         if (err < 0)
01757                 return err;
01758 
01759         return 0;
01760 }
01761 
01762 /*
01763  * Read the MAC address from eeprom
01764  */
01765 int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
01766 {
01767         u8 mac_d[ETH_ALEN] = {};
01768         u32 total, offset;
01769         u16 data;
01770         int octet, ret;
01771 
01772         ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
01773         if (ret)
01774                 return ret;
01775 
01776         for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
01777                 ret = ath5k_hw_eeprom_read(ah, offset, &data);
01778                 if (ret)
01779                         return ret;
01780 
01781                 total += data;
01782                 mac_d[octet + 1] = data & 0xff;
01783                 mac_d[octet] = data >> 8;
01784                 octet += 2;
01785         }
01786 
01787         if (!total || total == 3 * 0xffff)
01788                 return -EINVAL;
01789 
01790         memcpy(mac, mac_d, ETH_ALEN);
01791 
01792         return 0;
01793 }


ros_rt_wmp
Author(s): Danilo Tardioli, dantard@unizar.es
autogenerated on Mon Oct 6 2014 08:27:10