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


ros_rt_wmp
Author(s): Danilo Tardioli, dantard@unizar.es
autogenerated on Fri Jan 3 2014 12:07:54