Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
eeprom.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008-2011 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 "hw.h"
18 
20 {
21  REG_WRITE(ah, reg, val);
22 
23  if (ah->config.analog_shiftreg)
24  udelay(100);
25 }
26 
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 
42  int16_t targetLeft, int16_t targetRight)
43 {
44  int16_t rv;
45 
46  if (srcRight == srcLeft) {
47  rv = targetLeft;
48  } else {
49  rv = (int16_t) (((target - srcLeft) * targetRight +
50  (srcRight - target) * targetLeft) /
51  (srcRight - srcLeft));
52  }
53  return rv;
54 }
55 
57  u16 *indexL, u16 *indexR)
58 {
59  u16 i;
60 
61  if (target <= pList[0]) {
62  *indexL = *indexR = 0;
63  return true;
64  }
65  if (target >= pList[listSize - 1]) {
66  *indexL = *indexR = (u16) (listSize - 1);
67  return true;
68  }
69 
70  for (i = 0; i < listSize - 1; i++) {
71  if (pList[i] == target) {
72  *indexL = *indexR = i;
73  return true;
74  }
75  if (target < pList[i + 1]) {
76  *indexL = i;
77  *indexR = (u16) (i + 1);
78  return false;
79  }
80  }
81  return false;
82 }
83 
84 void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
85  int eep_start_loc, int size)
86 {
87  int i = 0, j, addr;
88  u32 addrdata[8];
89  u32 data[8];
90 
91  for (addr = 0; addr < size; addr++) {
92  addrdata[i] = AR5416_EEPROM_OFFSET +
93  ((addr + eep_start_loc) << AR5416_EEPROM_S);
94  i++;
95  if (i == 8) {
96  REG_READ_MULTI(ah, addrdata, data, i);
97 
98  for (j = 0; j < i; j++) {
99  *eep_data = data[j];
100  eep_data++;
101  }
102  i = 0;
103  }
104  }
105 
106  if (i != 0) {
107  REG_READ_MULTI(ah, addrdata, data, i);
108 
109  for (j = 0; j < i; j++) {
110  *eep_data = data[j];
111  eep_data++;
112  }
113  }
114 }
115 
117 {
118  return common->bus_ops->eeprom_read(common, off, data);
119 }
120 
121 void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
122  u8 *pVpdList, u16 numIntercepts,
123  u8 *pRetVpdList)
124 {
125  u16 i, k;
126  u8 currPwr = pwrMin;
127  u16 idxL = 0, idxR = 0;
128 
129  for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
130  ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
131  numIntercepts, &(idxL),
132  &(idxR));
133  if (idxR < 1)
134  idxR = 1;
135  if (idxL == numIntercepts - 1)
136  idxL = (u16) (numIntercepts - 2);
137  if (pPwrList[idxL] == pPwrList[idxR])
138  k = pVpdList[idxL];
139  else
140  k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
141  (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
142  (pPwrList[idxR] - pPwrList[idxL]));
143  pRetVpdList[i] = (u8) k;
144  currPwr += 2;
145  }
146 }
147 
149  struct ath9k_channel *chan,
150  struct cal_target_power_leg *powInfo,
151  u16 numChannels,
152  struct cal_target_power_leg *pNewPower,
153  u16 numRates, bool isExtTarget)
154 {
155  struct chan_centers centers;
156  u16 clo, chi;
157  int i;
158  int matchIndex = -1, lowIndex = -1;
159  u16 freq;
160 
161  ath9k_hw_get_channel_centers(ah, chan, &centers);
162  freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
163 
164  if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
165  IS_CHAN_2GHZ(chan))) {
166  matchIndex = 0;
167  } else {
168  for (i = 0; (i < numChannels) &&
169  (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
170  if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
171  IS_CHAN_2GHZ(chan))) {
172  matchIndex = i;
173  break;
174  } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
175  IS_CHAN_2GHZ(chan)) && i > 0 &&
176  freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
177  IS_CHAN_2GHZ(chan))) {
178  lowIndex = i - 1;
179  break;
180  }
181  }
182  if ((matchIndex == -1) && (lowIndex == -1))
183  matchIndex = i - 1;
184  }
185 
186  if (matchIndex != -1) {
187  *pNewPower = powInfo[matchIndex];
188  } else {
189  clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
190  IS_CHAN_2GHZ(chan));
191  chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
192  IS_CHAN_2GHZ(chan));
193 
194  for (i = 0; i < numRates; i++) {
195  pNewPower->tPow2x[i] =
196  (u8)ath9k_hw_interpolate(freq, clo, chi,
197  powInfo[lowIndex].tPow2x[i],
198  powInfo[lowIndex + 1].tPow2x[i]);
199  }
200  }
201 }
202 
204  struct ath9k_channel *chan,
205  struct cal_target_power_ht *powInfo,
206  u16 numChannels,
207  struct cal_target_power_ht *pNewPower,
208  u16 numRates, bool isHt40Target)
209 {
210  struct chan_centers centers;
211  u16 clo, chi;
212  int i;
213  int matchIndex = -1, lowIndex = -1;
214  u16 freq;
215 
216  ath9k_hw_get_channel_centers(ah, chan, &centers);
217  freq = isHt40Target ? centers.synth_center : centers.ctl_center;
218 
219  if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
220  matchIndex = 0;
221  } else {
222  for (i = 0; (i < numChannels) &&
223  (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
224  if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
225  IS_CHAN_2GHZ(chan))) {
226  matchIndex = i;
227  break;
228  } else
229  if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
230  IS_CHAN_2GHZ(chan)) && i > 0 &&
231  freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
232  IS_CHAN_2GHZ(chan))) {
233  lowIndex = i - 1;
234  break;
235  }
236  }
237  if ((matchIndex == -1) && (lowIndex == -1))
238  matchIndex = i - 1;
239  }
240 
241  if (matchIndex != -1) {
242  *pNewPower = powInfo[matchIndex];
243  } else {
244  clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
245  IS_CHAN_2GHZ(chan));
246  chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
247  IS_CHAN_2GHZ(chan));
248 
249  for (i = 0; i < numRates; i++) {
250  pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
251  clo, chi,
252  powInfo[lowIndex].tPow2x[i],
253  powInfo[lowIndex + 1].tPow2x[i]);
254  }
255  }
256 }
257 
259  bool is2GHz, int num_band_edges)
260 {
261  u16 twiceMaxEdgePower = MAX_RATE_POWER;
262  int i;
263 
264  for (i = 0; (i < num_band_edges) &&
265  (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
266  if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
267  twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
268  break;
269  } else if ((i > 0) &&
270  (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
271  is2GHz))) {
272  if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
273  is2GHz) < freq &&
274  CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
275  twiceMaxEdgePower =
276  CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
277  }
278  break;
279  }
280  }
281 
282  return twiceMaxEdgePower;
283 }
284 
286  u8 antenna_reduction)
287 {
288  u16 reduction = antenna_reduction;
289 
290  /*
291  * Reduce scaled Power by number of chains active
292  * to get the per chain tx power level.
293  */
294  switch (ar5416_get_ntxchains(ah->txchainmask)) {
295  case 1:
296  break;
297  case 2:
298  reduction += POWER_CORRECTION_FOR_TWO_CHAIN;
299  break;
300  case 3:
302  break;
303  }
304 
305  if (power_limit > reduction)
306  power_limit -= reduction;
307  else
308  power_limit = 0;
309 
310  return power_limit;
311 }
312 
314 {
315  struct ath_common *common = ath9k_hw_common(ah);
316  struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
317 
318  switch (ar5416_get_ntxchains(ah->txchainmask)) {
319  case 1:
320  break;
321  case 2:
323  break;
324  case 3:
326  break;
327  default:
328  ath_dbg(common, EEPROM, "Invalid chainmask configuration\n");
329  break;
330  }
331 }
332 
334  struct ath9k_channel *chan,
335  void *pRawDataSet,
336  u8 *bChans, u16 availPiers,
337  u16 tPdGainOverlap,
338  u16 *pPdGainBoundaries, u8 *pPDADCValues,
339  u16 numXpdGains)
340 {
341  int i, j, k;
342  int16_t ss;
343  u16 idxL = 0, idxR = 0, numPiers;
344  static u8 vpdTableL[AR5416_NUM_PD_GAINS]
346  static u8 vpdTableR[AR5416_NUM_PD_GAINS]
348  static u8 vpdTableI[AR5416_NUM_PD_GAINS]
350 
351  u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
352  u8 minPwrT4[AR5416_NUM_PD_GAINS];
353  u8 maxPwrT4[AR5416_NUM_PD_GAINS];
354  int16_t vpdStep;
355  int16_t tmpVal;
356  u16 sizeCurrVpdTable, maxIndex, tgtIndex;
357  bool match;
358  int16_t minDelta = 0;
359  struct chan_centers centers;
360  int pdgain_boundary_default;
361  struct cal_data_per_freq *data_def = pRawDataSet;
362  struct cal_data_per_freq_4k *data_4k = pRawDataSet;
363  struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
364  bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
365  int intercepts;
366 
367  if (AR_SREV_9287(ah))
368  intercepts = AR9287_PD_GAIN_ICEPTS;
369  else
370  intercepts = AR5416_PD_GAIN_ICEPTS;
371 
372  memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
373  ath9k_hw_get_channel_centers(ah, chan, &centers);
374 
375  for (numPiers = 0; numPiers < availPiers; numPiers++) {
376  if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
377  break;
378  }
379 
381  IS_CHAN_2GHZ(chan)),
382  bChans, numPiers, &idxL, &idxR);
383 
384  if (match) {
385  if (AR_SREV_9287(ah)) {
386  /* FIXME: array overrun? */
387  for (i = 0; i < numXpdGains; i++) {
388  minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
389  maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4];
390  ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
391  data_9287[idxL].pwrPdg[i],
392  data_9287[idxL].vpdPdg[i],
393  intercepts,
394  vpdTableI[i]);
395  }
396  } else if (eeprom_4k) {
397  for (i = 0; i < numXpdGains; i++) {
398  minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
399  maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4];
400  ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
401  data_4k[idxL].pwrPdg[i],
402  data_4k[idxL].vpdPdg[i],
403  intercepts,
404  vpdTableI[i]);
405  }
406  } else {
407  for (i = 0; i < numXpdGains; i++) {
408  minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
409  maxPwrT4[i] = data_def[idxL].pwrPdg[i][4];
410  ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
411  data_def[idxL].pwrPdg[i],
412  data_def[idxL].vpdPdg[i],
413  intercepts,
414  vpdTableI[i]);
415  }
416  }
417  } else {
418  for (i = 0; i < numXpdGains; i++) {
419  if (AR_SREV_9287(ah)) {
420  pVpdL = data_9287[idxL].vpdPdg[i];
421  pPwrL = data_9287[idxL].pwrPdg[i];
422  pVpdR = data_9287[idxR].vpdPdg[i];
423  pPwrR = data_9287[idxR].pwrPdg[i];
424  } else if (eeprom_4k) {
425  pVpdL = data_4k[idxL].vpdPdg[i];
426  pPwrL = data_4k[idxL].pwrPdg[i];
427  pVpdR = data_4k[idxR].vpdPdg[i];
428  pPwrR = data_4k[idxR].pwrPdg[i];
429  } else {
430  pVpdL = data_def[idxL].vpdPdg[i];
431  pPwrL = data_def[idxL].pwrPdg[i];
432  pVpdR = data_def[idxR].vpdPdg[i];
433  pPwrR = data_def[idxR].pwrPdg[i];
434  }
435 
436  minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
437 
438  maxPwrT4[i] =
439  min(pPwrL[intercepts - 1],
440  pPwrR[intercepts - 1]);
441 
442 
443  ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
444  pPwrL, pVpdL,
445  intercepts,
446  vpdTableL[i]);
447  ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
448  pPwrR, pVpdR,
449  intercepts,
450  vpdTableR[i]);
451 
452  for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
453  vpdTableI[i][j] =
455  FREQ2FBIN(centers.
456  synth_center,
458  (chan)),
459  bChans[idxL], bChans[idxR],
460  vpdTableL[i][j], vpdTableR[i][j]));
461  }
462  }
463  }
464 
465  k = 0;
466 
467  for (i = 0; i < numXpdGains; i++) {
468  if (i == (numXpdGains - 1))
469  pPdGainBoundaries[i] =
470  (u16)(maxPwrT4[i] / 2);
471  else
472  pPdGainBoundaries[i] =
473  (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
474 
475  pPdGainBoundaries[i] =
476  min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
477 
478  minDelta = 0;
479 
480  if (i == 0) {
481  if (AR_SREV_9280_20_OR_LATER(ah))
482  ss = (int16_t)(0 - (minPwrT4[i] / 2));
483  else
484  ss = 0;
485  } else {
486  ss = (int16_t)((pPdGainBoundaries[i - 1] -
487  (minPwrT4[i] / 2)) -
488  tPdGainOverlap + 1 + minDelta);
489  }
490  vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
491  vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
492 
493  while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
494  tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
495  pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
496  ss++;
497  }
498 
499  sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
500  tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
501  (minPwrT4[i] / 2));
502  maxIndex = (tgtIndex < sizeCurrVpdTable) ?
503  tgtIndex : sizeCurrVpdTable;
504 
505  while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
506  pPDADCValues[k++] = vpdTableI[i][ss++];
507  }
508 
509  vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
510  vpdTableI[i][sizeCurrVpdTable - 2]);
511  vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
512 
513  if (tgtIndex >= maxIndex) {
514  while ((ss <= tgtIndex) &&
515  (k < (AR5416_NUM_PDADC_VALUES - 1))) {
516  tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
517  (ss - maxIndex + 1) * vpdStep));
518  pPDADCValues[k++] = (u8)((tmpVal > 255) ?
519  255 : tmpVal);
520  ss++;
521  }
522  }
523  }
524 
525  if (eeprom_4k)
526  pdgain_boundary_default = 58;
527  else
528  pdgain_boundary_default = pPdGainBoundaries[i - 1];
529 
530  while (i < AR5416_PD_GAINS_IN_MASK) {
531  pPdGainBoundaries[i] = pdgain_boundary_default;
532  i++;
533  }
534 
535  while (k < AR5416_NUM_PDADC_VALUES) {
536  pPDADCValues[k] = pPDADCValues[k - 1];
537  k++;
538  }
539 }
540 
542 {
543  int status;
544 
545  if (AR_SREV_9300_20_OR_LATER(ah))
546  ah->eep_ops = &eep_ar9300_ops;
547  else if (AR_SREV_9287(ah)) {
548  ah->eep_ops = &eep_ar9287_ops;
549  } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
550  ah->eep_ops = &eep_4k_ops;
551  } else {
552  ah->eep_ops = &eep_def_ops;
553  }
554 
555  if (!ah->eep_ops->fill_eeprom(ah))
556  return -EIO;
557 
558  status = ah->eep_ops->check_eeprom(ah);
559 
560  return status;
561 }