linux/drivers/net/wireless/ath/ath9k/eeprom.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008-2009 Atheros Communications Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include "ath9k.h"
  18
  19static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
  20{
  21        if (fbin == AR5416_BCHAN_UNUSED)
  22                return fbin;
  23
  24        return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
  25}
  26
  27void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
  28                               u32 shift, u32 val)
  29{
  30        u32 regVal;
  31
  32        regVal = REG_READ(ah, reg) & ~mask;
  33        regVal |= (val << shift) & mask;
  34
  35        REG_WRITE(ah, reg, regVal);
  36
  37        if (ah->config.analog_shiftreg)
  38                udelay(100);
  39
  40        return;
  41}
  42
  43int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
  44                             int16_t targetLeft, int16_t targetRight)
  45{
  46        int16_t rv;
  47
  48        if (srcRight == srcLeft) {
  49                rv = targetLeft;
  50        } else {
  51                rv = (int16_t) (((target - srcLeft) * targetRight +
  52                                 (srcRight - target) * targetLeft) /
  53                                (srcRight - srcLeft));
  54        }
  55        return rv;
  56}
  57
  58bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
  59                                    u16 *indexL, u16 *indexR)
  60{
  61        u16 i;
  62
  63        if (target <= pList[0]) {
  64                *indexL = *indexR = 0;
  65                return true;
  66        }
  67        if (target >= pList[listSize - 1]) {
  68                *indexL = *indexR = (u16) (listSize - 1);
  69                return true;
  70        }
  71
  72        for (i = 0; i < listSize - 1; i++) {
  73                if (pList[i] == target) {
  74                        *indexL = *indexR = i;
  75                        return true;
  76                }
  77                if (target < pList[i + 1]) {
  78                        *indexL = i;
  79                        *indexR = (u16) (i + 1);
  80                        return false;
  81                }
  82        }
  83        return false;
  84}
  85
  86bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
  87{
  88        struct ath_softc *sc = ah->ah_sc;
  89
  90        return sc->bus_ops->eeprom_read(ah, off, data);
  91}
  92
  93void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
  94                             u8 *pVpdList, u16 numIntercepts,
  95                             u8 *pRetVpdList)
  96{
  97        u16 i, k;
  98        u8 currPwr = pwrMin;
  99        u16 idxL = 0, idxR = 0;
 100
 101        for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
 102                ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
 103                                               numIntercepts, &(idxL),
 104                                               &(idxR));
 105                if (idxR < 1)
 106                        idxR = 1;
 107                if (idxL == numIntercepts - 1)
 108                        idxL = (u16) (numIntercepts - 2);
 109                if (pPwrList[idxL] == pPwrList[idxR])
 110                        k = pVpdList[idxL];
 111                else
 112                        k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
 113                                   (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
 114                                  (pPwrList[idxR] - pPwrList[idxL]));
 115                pRetVpdList[i] = (u8) k;
 116                currPwr += 2;
 117        }
 118}
 119
 120void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
 121                                       struct ath9k_channel *chan,
 122                                       struct cal_target_power_leg *powInfo,
 123                                       u16 numChannels,
 124                                       struct cal_target_power_leg *pNewPower,
 125                                       u16 numRates, bool isExtTarget)
 126{
 127        struct chan_centers centers;
 128        u16 clo, chi;
 129        int i;
 130        int matchIndex = -1, lowIndex = -1;
 131        u16 freq;
 132
 133        ath9k_hw_get_channel_centers(ah, chan, &centers);
 134        freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
 135
 136        if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
 137                                       IS_CHAN_2GHZ(chan))) {
 138                matchIndex = 0;
 139        } else {
 140                for (i = 0; (i < numChannels) &&
 141                             (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
 142                        if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
 143                                                       IS_CHAN_2GHZ(chan))) {
 144                                matchIndex = i;
 145                                break;
 146                        } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
 147                                                IS_CHAN_2GHZ(chan)) && i > 0 &&
 148                                   freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
 149                                                IS_CHAN_2GHZ(chan))) {
 150                                lowIndex = i - 1;
 151                                break;
 152                        }
 153                }
 154                if ((matchIndex == -1) && (lowIndex == -1))
 155                        matchIndex = i - 1;
 156        }
 157
 158        if (matchIndex != -1) {
 159                *pNewPower = powInfo[matchIndex];
 160        } else {
 161                clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
 162                                         IS_CHAN_2GHZ(chan));
 163                chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
 164                                         IS_CHAN_2GHZ(chan));
 165
 166                for (i = 0; i < numRates; i++) {
 167                        pNewPower->tPow2x[i] =
 168                                (u8)ath9k_hw_interpolate(freq, clo, chi,
 169                                                powInfo[lowIndex].tPow2x[i],
 170                                                powInfo[lowIndex + 1].tPow2x[i]);
 171                }
 172        }
 173}
 174
 175void ath9k_hw_get_target_powers(struct ath_hw *ah,
 176                                struct ath9k_channel *chan,
 177                                struct cal_target_power_ht *powInfo,
 178                                u16 numChannels,
 179                                struct cal_target_power_ht *pNewPower,
 180                                u16 numRates, bool isHt40Target)
 181{
 182        struct chan_centers centers;
 183        u16 clo, chi;
 184        int i;
 185        int matchIndex = -1, lowIndex = -1;
 186        u16 freq;
 187
 188        ath9k_hw_get_channel_centers(ah, chan, &centers);
 189        freq = isHt40Target ? centers.synth_center : centers.ctl_center;
 190
 191        if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
 192                matchIndex = 0;
 193        } else {
 194                for (i = 0; (i < numChannels) &&
 195                             (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
 196                        if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
 197                                                       IS_CHAN_2GHZ(chan))) {
 198                                matchIndex = i;
 199                                break;
 200                        } else
 201                                if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
 202                                                IS_CHAN_2GHZ(chan)) && i > 0 &&
 203                                    freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
 204                                                IS_CHAN_2GHZ(chan))) {
 205                                        lowIndex = i - 1;
 206                                        break;
 207                                }
 208                }
 209                if ((matchIndex == -1) && (lowIndex == -1))
 210                        matchIndex = i - 1;
 211        }
 212
 213        if (matchIndex != -1) {
 214                *pNewPower = powInfo[matchIndex];
 215        } else {
 216                clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
 217                                         IS_CHAN_2GHZ(chan));
 218                chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
 219                                         IS_CHAN_2GHZ(chan));
 220
 221                for (i = 0; i < numRates; i++) {
 222                        pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
 223                                                clo, chi,
 224                                                powInfo[lowIndex].tPow2x[i],
 225                                                powInfo[lowIndex + 1].tPow2x[i]);
 226                }
 227        }
 228}
 229
 230u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
 231                                bool is2GHz, int num_band_edges)
 232{
 233        u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
 234        int i;
 235
 236        for (i = 0; (i < num_band_edges) &&
 237                     (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
 238                if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
 239                        twiceMaxEdgePower = pRdEdgesPower[i].tPower;
 240                        break;
 241                } else if ((i > 0) &&
 242                           (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
 243                                                      is2GHz))) {
 244                        if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
 245                                               is2GHz) < freq &&
 246                            pRdEdgesPower[i - 1].flag) {
 247                                twiceMaxEdgePower =
 248                                        pRdEdgesPower[i - 1].tPower;
 249                        }
 250                        break;
 251                }
 252        }
 253
 254        return twiceMaxEdgePower;
 255}
 256
 257int ath9k_hw_eeprom_init(struct ath_hw *ah)
 258{
 259        int status;
 260
 261        if (AR_SREV_9287(ah)) {
 262                ah->eep_map = EEP_MAP_AR9287;
 263                ah->eep_ops = &eep_AR9287_ops;
 264        } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
 265                ah->eep_map = EEP_MAP_4KBITS;
 266                ah->eep_ops = &eep_4k_ops;
 267        } else {
 268                ah->eep_map = EEP_MAP_DEFAULT;
 269                ah->eep_ops = &eep_def_ops;
 270        }
 271
 272        if (!ah->eep_ops->fill_eeprom(ah))
 273                return -EIO;
 274
 275        status = ah->eep_ops->check_eeprom(ah);
 276
 277        return status;
 278}
 279