calib.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973
  1. /*
  2. * Copyright (c) 2008 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. #include "core.h"
  17. #include "hw.h"
  18. #include "reg.h"
  19. #include "phy.h"
  20. /* We can tune this as we go by monitoring really low values */
  21. #define ATH9K_NF_TOO_LOW -60
  22. /* AR5416 may return very high value (like -31 dBm), in those cases the nf
  23. * is incorrect and we should use the static NF value. Later we can try to
  24. * find out why they are reporting these values */
  25. static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
  26. {
  27. if (nf > ATH9K_NF_TOO_LOW) {
  28. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  29. "noise floor value detected (%d) is "
  30. "lower than what we think is a "
  31. "reasonable value (%d)\n",
  32. nf, ATH9K_NF_TOO_LOW);
  33. return false;
  34. }
  35. return true;
  36. }
  37. static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
  38. {
  39. int16_t nfval;
  40. int16_t sort[ATH9K_NF_CAL_HIST_MAX];
  41. int i, j;
  42. for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
  43. sort[i] = nfCalBuffer[i];
  44. for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
  45. for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
  46. if (sort[j] > sort[j - 1]) {
  47. nfval = sort[j];
  48. sort[j] = sort[j - 1];
  49. sort[j - 1] = nfval;
  50. }
  51. }
  52. }
  53. nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
  54. return nfval;
  55. }
  56. static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
  57. int16_t *nfarray)
  58. {
  59. int i;
  60. for (i = 0; i < NUM_NF_READINGS; i++) {
  61. h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
  62. if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
  63. h[i].currIndex = 0;
  64. if (h[i].invalidNFcount > 0) {
  65. if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
  66. nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
  67. h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
  68. } else {
  69. h[i].invalidNFcount--;
  70. h[i].privNF = nfarray[i];
  71. }
  72. } else {
  73. h[i].privNF =
  74. ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
  75. }
  76. }
  77. return;
  78. }
  79. static void ath9k_hw_do_getnf(struct ath_hal *ah,
  80. int16_t nfarray[NUM_NF_READINGS])
  81. {
  82. int16_t nf;
  83. if (AR_SREV_9280_10_OR_LATER(ah))
  84. nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
  85. else
  86. nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
  87. if (nf & 0x100)
  88. nf = 0 - ((nf ^ 0x1ff) + 1);
  89. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  90. "NF calibrated [ctl] [chain 0] is %d\n", nf);
  91. nfarray[0] = nf;
  92. if (AR_SREV_9280_10_OR_LATER(ah))
  93. nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
  94. AR9280_PHY_CH1_MINCCA_PWR);
  95. else
  96. nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
  97. AR_PHY_CH1_MINCCA_PWR);
  98. if (nf & 0x100)
  99. nf = 0 - ((nf ^ 0x1ff) + 1);
  100. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  101. "NF calibrated [ctl] [chain 1] is %d\n", nf);
  102. nfarray[1] = nf;
  103. if (!AR_SREV_9280(ah)) {
  104. nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
  105. AR_PHY_CH2_MINCCA_PWR);
  106. if (nf & 0x100)
  107. nf = 0 - ((nf ^ 0x1ff) + 1);
  108. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  109. "NF calibrated [ctl] [chain 2] is %d\n", nf);
  110. nfarray[2] = nf;
  111. }
  112. if (AR_SREV_9280_10_OR_LATER(ah))
  113. nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
  114. AR9280_PHY_EXT_MINCCA_PWR);
  115. else
  116. nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
  117. AR_PHY_EXT_MINCCA_PWR);
  118. if (nf & 0x100)
  119. nf = 0 - ((nf ^ 0x1ff) + 1);
  120. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  121. "NF calibrated [ext] [chain 0] is %d\n", nf);
  122. nfarray[3] = nf;
  123. if (AR_SREV_9280_10_OR_LATER(ah))
  124. nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
  125. AR9280_PHY_CH1_EXT_MINCCA_PWR);
  126. else
  127. nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
  128. AR_PHY_CH1_EXT_MINCCA_PWR);
  129. if (nf & 0x100)
  130. nf = 0 - ((nf ^ 0x1ff) + 1);
  131. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  132. "NF calibrated [ext] [chain 1] is %d\n", nf);
  133. nfarray[4] = nf;
  134. if (!AR_SREV_9280(ah)) {
  135. nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
  136. AR_PHY_CH2_EXT_MINCCA_PWR);
  137. if (nf & 0x100)
  138. nf = 0 - ((nf ^ 0x1ff) + 1);
  139. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  140. "NF calibrated [ext] [chain 2] is %d\n", nf);
  141. nfarray[5] = nf;
  142. }
  143. }
  144. static bool getNoiseFloorThresh(struct ath_hal *ah,
  145. enum ieee80211_band band,
  146. int16_t *nft)
  147. {
  148. switch (band) {
  149. case IEEE80211_BAND_5GHZ:
  150. *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5);
  151. break;
  152. case IEEE80211_BAND_2GHZ:
  153. *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2);
  154. break;
  155. default:
  156. BUG_ON(1);
  157. return false;
  158. }
  159. return true;
  160. }
  161. static void ath9k_hw_setup_calibration(struct ath_hal *ah,
  162. struct hal_cal_list *currCal)
  163. {
  164. REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
  165. AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
  166. currCal->calData->calCountMax);
  167. switch (currCal->calData->calType) {
  168. case IQ_MISMATCH_CAL:
  169. REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
  170. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  171. "starting IQ Mismatch Calibration\n");
  172. break;
  173. case ADC_GAIN_CAL:
  174. REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
  175. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  176. "starting ADC Gain Calibration\n");
  177. break;
  178. case ADC_DC_CAL:
  179. REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
  180. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  181. "starting ADC DC Calibration\n");
  182. break;
  183. case ADC_DC_INIT_CAL:
  184. REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
  185. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  186. "starting Init ADC DC Calibration\n");
  187. break;
  188. }
  189. REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
  190. AR_PHY_TIMING_CTRL4_DO_CAL);
  191. }
  192. static void ath9k_hw_reset_calibration(struct ath_hal *ah,
  193. struct hal_cal_list *currCal)
  194. {
  195. struct ath_hal_5416 *ahp = AH5416(ah);
  196. int i;
  197. ath9k_hw_setup_calibration(ah, currCal);
  198. currCal->calState = CAL_RUNNING;
  199. for (i = 0; i < AR5416_MAX_CHAINS; i++) {
  200. ahp->ah_Meas0.sign[i] = 0;
  201. ahp->ah_Meas1.sign[i] = 0;
  202. ahp->ah_Meas2.sign[i] = 0;
  203. ahp->ah_Meas3.sign[i] = 0;
  204. }
  205. ahp->ah_CalSamples = 0;
  206. }
  207. static void ath9k_hw_per_calibration(struct ath_hal *ah,
  208. struct ath9k_channel *ichan,
  209. u8 rxchainmask,
  210. struct hal_cal_list *currCal,
  211. bool *isCalDone)
  212. {
  213. struct ath_hal_5416 *ahp = AH5416(ah);
  214. *isCalDone = false;
  215. if (currCal->calState == CAL_RUNNING) {
  216. if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
  217. AR_PHY_TIMING_CTRL4_DO_CAL)) {
  218. currCal->calData->calCollect(ah);
  219. ahp->ah_CalSamples++;
  220. if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) {
  221. int i, numChains = 0;
  222. for (i = 0; i < AR5416_MAX_CHAINS; i++) {
  223. if (rxchainmask & (1 << i))
  224. numChains++;
  225. }
  226. currCal->calData->calPostProc(ah, numChains);
  227. ichan->CalValid |= currCal->calData->calType;
  228. currCal->calState = CAL_DONE;
  229. *isCalDone = true;
  230. } else {
  231. ath9k_hw_setup_calibration(ah, currCal);
  232. }
  233. }
  234. } else if (!(ichan->CalValid & currCal->calData->calType)) {
  235. ath9k_hw_reset_calibration(ah, currCal);
  236. }
  237. }
  238. /* Assumes you are talking about the currently configured channel */
  239. static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
  240. enum hal_cal_types calType)
  241. {
  242. struct ath_hal_5416 *ahp = AH5416(ah);
  243. struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
  244. switch (calType & ahp->ah_suppCals) {
  245. case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */
  246. return true;
  247. case ADC_GAIN_CAL:
  248. case ADC_DC_CAL:
  249. if (conf->channel->band == IEEE80211_BAND_5GHZ &&
  250. conf_is_ht20(conf))
  251. return true;
  252. break;
  253. }
  254. return false;
  255. }
  256. static void ath9k_hw_iqcal_collect(struct ath_hal *ah)
  257. {
  258. struct ath_hal_5416 *ahp = AH5416(ah);
  259. int i;
  260. for (i = 0; i < AR5416_MAX_CHAINS; i++) {
  261. ahp->ah_totalPowerMeasI[i] +=
  262. REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
  263. ahp->ah_totalPowerMeasQ[i] +=
  264. REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
  265. ahp->ah_totalIqCorrMeas[i] +=
  266. (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
  267. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  268. "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
  269. ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
  270. ahp->ah_totalPowerMeasQ[i],
  271. ahp->ah_totalIqCorrMeas[i]);
  272. }
  273. }
  274. static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
  275. {
  276. struct ath_hal_5416 *ahp = AH5416(ah);
  277. int i;
  278. for (i = 0; i < AR5416_MAX_CHAINS; i++) {
  279. ahp->ah_totalAdcIOddPhase[i] +=
  280. REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
  281. ahp->ah_totalAdcIEvenPhase[i] +=
  282. REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
  283. ahp->ah_totalAdcQOddPhase[i] +=
  284. REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
  285. ahp->ah_totalAdcQEvenPhase[i] +=
  286. REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
  287. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  288. "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
  289. "oddq=0x%08x; evenq=0x%08x;\n",
  290. ahp->ah_CalSamples, i,
  291. ahp->ah_totalAdcIOddPhase[i],
  292. ahp->ah_totalAdcIEvenPhase[i],
  293. ahp->ah_totalAdcQOddPhase[i],
  294. ahp->ah_totalAdcQEvenPhase[i]);
  295. }
  296. }
  297. static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
  298. {
  299. struct ath_hal_5416 *ahp = AH5416(ah);
  300. int i;
  301. for (i = 0; i < AR5416_MAX_CHAINS; i++) {
  302. ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
  303. (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
  304. ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
  305. (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
  306. ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
  307. (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
  308. ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
  309. (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
  310. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  311. "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
  312. "oddq=0x%08x; evenq=0x%08x;\n",
  313. ahp->ah_CalSamples, i,
  314. ahp->ah_totalAdcDcOffsetIOddPhase[i],
  315. ahp->ah_totalAdcDcOffsetIEvenPhase[i],
  316. ahp->ah_totalAdcDcOffsetQOddPhase[i],
  317. ahp->ah_totalAdcDcOffsetQEvenPhase[i]);
  318. }
  319. }
  320. static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
  321. {
  322. struct ath_hal_5416 *ahp = AH5416(ah);
  323. u32 powerMeasQ, powerMeasI, iqCorrMeas;
  324. u32 qCoffDenom, iCoffDenom;
  325. int32_t qCoff, iCoff;
  326. int iqCorrNeg, i;
  327. for (i = 0; i < numChains; i++) {
  328. powerMeasI = ahp->ah_totalPowerMeasI[i];
  329. powerMeasQ = ahp->ah_totalPowerMeasQ[i];
  330. iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
  331. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  332. "Starting IQ Cal and Correction for Chain %d\n",
  333. i);
  334. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  335. "Orignal: Chn %diq_corr_meas = 0x%08x\n",
  336. i, ahp->ah_totalIqCorrMeas[i]);
  337. iqCorrNeg = 0;
  338. if (iqCorrMeas > 0x80000000) {
  339. iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
  340. iqCorrNeg = 1;
  341. }
  342. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  343. "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
  344. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  345. "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
  346. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
  347. iqCorrNeg);
  348. iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
  349. qCoffDenom = powerMeasQ / 64;
  350. if (powerMeasQ != 0) {
  351. iCoff = iqCorrMeas / iCoffDenom;
  352. qCoff = powerMeasI / qCoffDenom - 64;
  353. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  354. "Chn %d iCoff = 0x%08x\n", i, iCoff);
  355. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  356. "Chn %d qCoff = 0x%08x\n", i, qCoff);
  357. iCoff = iCoff & 0x3f;
  358. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  359. "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
  360. if (iqCorrNeg == 0x0)
  361. iCoff = 0x40 - iCoff;
  362. if (qCoff > 15)
  363. qCoff = 15;
  364. else if (qCoff <= -16)
  365. qCoff = 16;
  366. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  367. "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
  368. i, iCoff, qCoff);
  369. REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
  370. AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
  371. iCoff);
  372. REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
  373. AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
  374. qCoff);
  375. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  376. "IQ Cal and Correction done for Chain %d\n",
  377. i);
  378. }
  379. }
  380. REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
  381. AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
  382. }
  383. static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
  384. {
  385. struct ath_hal_5416 *ahp = AH5416(ah);
  386. u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
  387. u32 qGainMismatch, iGainMismatch, val, i;
  388. for (i = 0; i < numChains; i++) {
  389. iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
  390. iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
  391. qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
  392. qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
  393. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  394. "Starting ADC Gain Cal for Chain %d\n", i);
  395. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  396. "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
  397. iOddMeasOffset);
  398. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  399. "Chn %d pwr_meas_even_i = 0x%08x\n", i,
  400. iEvenMeasOffset);
  401. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  402. "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
  403. qOddMeasOffset);
  404. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  405. "Chn %d pwr_meas_even_q = 0x%08x\n", i,
  406. qEvenMeasOffset);
  407. if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
  408. iGainMismatch =
  409. ((iEvenMeasOffset * 32) /
  410. iOddMeasOffset) & 0x3f;
  411. qGainMismatch =
  412. ((qOddMeasOffset * 32) /
  413. qEvenMeasOffset) & 0x3f;
  414. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  415. "Chn %d gain_mismatch_i = 0x%08x\n", i,
  416. iGainMismatch);
  417. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  418. "Chn %d gain_mismatch_q = 0x%08x\n", i,
  419. qGainMismatch);
  420. val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
  421. val &= 0xfffff000;
  422. val |= (qGainMismatch) | (iGainMismatch << 6);
  423. REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
  424. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  425. "ADC Gain Cal done for Chain %d\n", i);
  426. }
  427. }
  428. REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
  429. REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
  430. AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
  431. }
  432. static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
  433. {
  434. struct ath_hal_5416 *ahp = AH5416(ah);
  435. u32 iOddMeasOffset, iEvenMeasOffset, val, i;
  436. int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
  437. const struct hal_percal_data *calData =
  438. ahp->ah_cal_list_curr->calData;
  439. u32 numSamples =
  440. (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
  441. for (i = 0; i < numChains; i++) {
  442. iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
  443. iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
  444. qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
  445. qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
  446. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  447. "Starting ADC DC Offset Cal for Chain %d\n", i);
  448. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  449. "Chn %d pwr_meas_odd_i = %d\n", i,
  450. iOddMeasOffset);
  451. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  452. "Chn %d pwr_meas_even_i = %d\n", i,
  453. iEvenMeasOffset);
  454. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  455. "Chn %d pwr_meas_odd_q = %d\n", i,
  456. qOddMeasOffset);
  457. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  458. "Chn %d pwr_meas_even_q = %d\n", i,
  459. qEvenMeasOffset);
  460. iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
  461. numSamples) & 0x1ff;
  462. qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
  463. numSamples) & 0x1ff;
  464. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  465. "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
  466. iDcMismatch);
  467. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  468. "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
  469. qDcMismatch);
  470. val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
  471. val &= 0xc0000fff;
  472. val |= (qDcMismatch << 12) | (iDcMismatch << 21);
  473. REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
  474. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  475. "ADC DC Offset Cal done for Chain %d\n", i);
  476. }
  477. REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
  478. REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
  479. AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
  480. }
  481. /* This is done for the currently configured channel */
  482. bool ath9k_hw_reset_calvalid(struct ath_hal *ah)
  483. {
  484. struct ath_hal_5416 *ahp = AH5416(ah);
  485. struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
  486. struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
  487. if (!ah->ah_curchan)
  488. return true;
  489. if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
  490. return true;
  491. if (currCal == NULL)
  492. return true;
  493. if (currCal->calState != CAL_DONE) {
  494. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  495. "Calibration state incorrect, %d\n",
  496. currCal->calState);
  497. return true;
  498. }
  499. if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType))
  500. return true;
  501. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  502. "Resetting Cal %d state for channel %u\n",
  503. currCal->calData->calType, conf->channel->center_freq);
  504. ah->ah_curchan->CalValid &= ~currCal->calData->calType;
  505. currCal->calState = CAL_WAITING;
  506. return false;
  507. }
  508. void ath9k_hw_start_nfcal(struct ath_hal *ah)
  509. {
  510. REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
  511. AR_PHY_AGC_CONTROL_ENABLE_NF);
  512. REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
  513. AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
  514. REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
  515. }
  516. void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
  517. {
  518. struct ath9k_nfcal_hist *h;
  519. int i, j;
  520. int32_t val;
  521. const u32 ar5416_cca_regs[6] = {
  522. AR_PHY_CCA,
  523. AR_PHY_CH1_CCA,
  524. AR_PHY_CH2_CCA,
  525. AR_PHY_EXT_CCA,
  526. AR_PHY_CH1_EXT_CCA,
  527. AR_PHY_CH2_EXT_CCA
  528. };
  529. u8 chainmask;
  530. if (AR_SREV_9285(ah))
  531. chainmask = 0x9;
  532. else if (AR_SREV_9280(ah))
  533. chainmask = 0x1B;
  534. else
  535. chainmask = 0x3F;
  536. h = ah->nfCalHist;
  537. for (i = 0; i < NUM_NF_READINGS; i++) {
  538. if (chainmask & (1 << i)) {
  539. val = REG_READ(ah, ar5416_cca_regs[i]);
  540. val &= 0xFFFFFE00;
  541. val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
  542. REG_WRITE(ah, ar5416_cca_regs[i], val);
  543. }
  544. }
  545. REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
  546. AR_PHY_AGC_CONTROL_ENABLE_NF);
  547. REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
  548. AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
  549. REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
  550. for (j = 0; j < 1000; j++) {
  551. if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
  552. AR_PHY_AGC_CONTROL_NF) == 0)
  553. break;
  554. udelay(10);
  555. }
  556. for (i = 0; i < NUM_NF_READINGS; i++) {
  557. if (chainmask & (1 << i)) {
  558. val = REG_READ(ah, ar5416_cca_regs[i]);
  559. val &= 0xFFFFFE00;
  560. val |= (((u32) (-50) << 1) & 0x1ff);
  561. REG_WRITE(ah, ar5416_cca_regs[i], val);
  562. }
  563. }
  564. }
  565. int16_t ath9k_hw_getnf(struct ath_hal *ah,
  566. struct ath9k_channel *chan)
  567. {
  568. int16_t nf, nfThresh;
  569. int16_t nfarray[NUM_NF_READINGS] = { 0 };
  570. struct ath9k_nfcal_hist *h;
  571. struct ieee80211_channel *c = chan->chan;
  572. u8 chainmask;
  573. if (AR_SREV_9280(ah))
  574. chainmask = 0x1B;
  575. else
  576. chainmask = 0x3F;
  577. chan->channelFlags &= (~CHANNEL_CW_INT);
  578. if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
  579. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  580. "NF did not complete in calibration window\n");
  581. nf = 0;
  582. chan->rawNoiseFloor = nf;
  583. return chan->rawNoiseFloor;
  584. } else {
  585. ath9k_hw_do_getnf(ah, nfarray);
  586. nf = nfarray[0];
  587. if (getNoiseFloorThresh(ah, c->band, &nfThresh)
  588. && nf > nfThresh) {
  589. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  590. "noise floor failed detected; "
  591. "detected %d, threshold %d\n",
  592. nf, nfThresh);
  593. chan->channelFlags |= CHANNEL_CW_INT;
  594. }
  595. }
  596. h = ah->nfCalHist;
  597. ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
  598. chan->rawNoiseFloor = h[0].privNF;
  599. return chan->rawNoiseFloor;
  600. }
  601. void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
  602. {
  603. int i, j;
  604. for (i = 0; i < NUM_NF_READINGS; i++) {
  605. ah->nfCalHist[i].currIndex = 0;
  606. ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
  607. ah->nfCalHist[i].invalidNFcount =
  608. AR_PHY_CCA_FILTERWINDOW_LENGTH;
  609. for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
  610. ah->nfCalHist[i].nfCalBuffer[j] =
  611. AR_PHY_CCA_MAX_GOOD_VALUE;
  612. }
  613. }
  614. return;
  615. }
  616. s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
  617. {
  618. s16 nf;
  619. if (chan->rawNoiseFloor == 0)
  620. nf = -96;
  621. else
  622. nf = chan->rawNoiseFloor;
  623. if (!ath9k_hw_nf_in_range(ah, nf))
  624. nf = ATH_DEFAULT_NOISE_FLOOR;
  625. return nf;
  626. }
  627. bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
  628. u8 rxchainmask, bool longcal,
  629. bool *isCalDone)
  630. {
  631. struct ath_hal_5416 *ahp = AH5416(ah);
  632. struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
  633. *isCalDone = true;
  634. if (currCal &&
  635. (currCal->calState == CAL_RUNNING ||
  636. currCal->calState == CAL_WAITING)) {
  637. ath9k_hw_per_calibration(ah, chan, rxchainmask, currCal,
  638. isCalDone);
  639. if (*isCalDone) {
  640. ahp->ah_cal_list_curr = currCal = currCal->calNext;
  641. if (currCal->calState == CAL_WAITING) {
  642. *isCalDone = false;
  643. ath9k_hw_reset_calibration(ah, currCal);
  644. }
  645. }
  646. }
  647. if (longcal) {
  648. ath9k_hw_getnf(ah, chan);
  649. ath9k_hw_loadnf(ah, ah->ah_curchan);
  650. ath9k_hw_start_nfcal(ah);
  651. if (chan->channelFlags & CHANNEL_CW_INT)
  652. chan->channelFlags &= ~CHANNEL_CW_INT;
  653. }
  654. return true;
  655. }
  656. static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah)
  657. {
  658. u32 regVal;
  659. int i, offset, offs_6_1, offs_0;
  660. u32 ccomp_org, reg_field;
  661. u32 regList[][2] = {
  662. { 0x786c, 0 },
  663. { 0x7854, 0 },
  664. { 0x7820, 0 },
  665. { 0x7824, 0 },
  666. { 0x7868, 0 },
  667. { 0x783c, 0 },
  668. { 0x7838, 0 },
  669. };
  670. if (AR_SREV_9285_11(ah)) {
  671. REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
  672. udelay(10);
  673. }
  674. for (i = 0; i < ARRAY_SIZE(regList); i++)
  675. regList[i][1] = REG_READ(ah, regList[i][0]);
  676. regVal = REG_READ(ah, 0x7834);
  677. regVal &= (~(0x1));
  678. REG_WRITE(ah, 0x7834, regVal);
  679. regVal = REG_READ(ah, 0x9808);
  680. regVal |= (0x1 << 27);
  681. REG_WRITE(ah, 0x9808, regVal);
  682. REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
  683. REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
  684. REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
  685. REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
  686. REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
  687. REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
  688. REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
  689. REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1);
  690. REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
  691. REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
  692. REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
  693. REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
  694. ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
  695. REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7);
  696. REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
  697. udelay(30);
  698. REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
  699. REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);
  700. for (i = 6; i > 0; i--) {
  701. regVal = REG_READ(ah, 0x7834);
  702. regVal |= (1 << (19 + i));
  703. REG_WRITE(ah, 0x7834, regVal);
  704. udelay(1);
  705. regVal = REG_READ(ah, 0x7834);
  706. regVal &= (~(0x1 << (19 + i)));
  707. reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
  708. regVal |= (reg_field << (19 + i));
  709. REG_WRITE(ah, 0x7834, regVal);
  710. }
  711. REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
  712. udelay(1);
  713. reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
  714. REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
  715. offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
  716. offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);
  717. offset = (offs_6_1<<1) | offs_0;
  718. offset = offset - 0;
  719. offs_6_1 = offset>>1;
  720. offs_0 = offset & 1;
  721. REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
  722. REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
  723. regVal = REG_READ(ah, 0x7834);
  724. regVal |= 0x1;
  725. REG_WRITE(ah, 0x7834, regVal);
  726. regVal = REG_READ(ah, 0x9808);
  727. regVal &= (~(0x1 << 27));
  728. REG_WRITE(ah, 0x9808, regVal);
  729. for (i = 0; i < ARRAY_SIZE(regList); i++)
  730. REG_WRITE(ah, regList[i][0], regList[i][1]);
  731. REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
  732. if (AR_SREV_9285_11(ah))
  733. REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
  734. }
  735. bool ath9k_hw_init_cal(struct ath_hal *ah,
  736. struct ath9k_channel *chan)
  737. {
  738. struct ath_hal_5416 *ahp = AH5416(ah);
  739. REG_WRITE(ah, AR_PHY_AGC_CONTROL,
  740. REG_READ(ah, AR_PHY_AGC_CONTROL) |
  741. AR_PHY_AGC_CONTROL_CAL);
  742. if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
  743. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  744. "offset calibration failed to complete in 1ms; "
  745. "noisy environment?\n");
  746. return false;
  747. }
  748. if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah))
  749. ath9k_hw_9285_pa_cal(ah);
  750. REG_WRITE(ah, AR_PHY_AGC_CONTROL,
  751. REG_READ(ah, AR_PHY_AGC_CONTROL) |
  752. AR_PHY_AGC_CONTROL_NF);
  753. ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
  754. if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
  755. if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
  756. INIT_CAL(&ahp->ah_adcGainCalData);
  757. INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
  758. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  759. "enabling ADC Gain Calibration.\n");
  760. }
  761. if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
  762. INIT_CAL(&ahp->ah_adcDcCalData);
  763. INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
  764. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  765. "enabling ADC DC Calibration.\n");
  766. }
  767. if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
  768. INIT_CAL(&ahp->ah_iqCalData);
  769. INSERT_CAL(ahp, &ahp->ah_iqCalData);
  770. DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
  771. "enabling IQ Calibration.\n");
  772. }
  773. ahp->ah_cal_list_curr = ahp->ah_cal_list;
  774. if (ahp->ah_cal_list_curr)
  775. ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr);
  776. }
  777. chan->CalValid = 0;
  778. return true;
  779. }
  780. const struct hal_percal_data iq_cal_multi_sample = {
  781. IQ_MISMATCH_CAL,
  782. MAX_CAL_SAMPLES,
  783. PER_MIN_LOG_COUNT,
  784. ath9k_hw_iqcal_collect,
  785. ath9k_hw_iqcalibrate
  786. };
  787. const struct hal_percal_data iq_cal_single_sample = {
  788. IQ_MISMATCH_CAL,
  789. MIN_CAL_SAMPLES,
  790. PER_MAX_LOG_COUNT,
  791. ath9k_hw_iqcal_collect,
  792. ath9k_hw_iqcalibrate
  793. };
  794. const struct hal_percal_data adc_gain_cal_multi_sample = {
  795. ADC_GAIN_CAL,
  796. MAX_CAL_SAMPLES,
  797. PER_MIN_LOG_COUNT,
  798. ath9k_hw_adc_gaincal_collect,
  799. ath9k_hw_adc_gaincal_calibrate
  800. };
  801. const struct hal_percal_data adc_gain_cal_single_sample = {
  802. ADC_GAIN_CAL,
  803. MIN_CAL_SAMPLES,
  804. PER_MAX_LOG_COUNT,
  805. ath9k_hw_adc_gaincal_collect,
  806. ath9k_hw_adc_gaincal_calibrate
  807. };
  808. const struct hal_percal_data adc_dc_cal_multi_sample = {
  809. ADC_DC_CAL,
  810. MAX_CAL_SAMPLES,
  811. PER_MIN_LOG_COUNT,
  812. ath9k_hw_adc_dccal_collect,
  813. ath9k_hw_adc_dccal_calibrate
  814. };
  815. const struct hal_percal_data adc_dc_cal_single_sample = {
  816. ADC_DC_CAL,
  817. MIN_CAL_SAMPLES,
  818. PER_MAX_LOG_COUNT,
  819. ath9k_hw_adc_dccal_collect,
  820. ath9k_hw_adc_dccal_calibrate
  821. };
  822. const struct hal_percal_data adc_init_dc_cal = {
  823. ADC_DC_INIT_CAL,
  824. MIN_CAL_SAMPLES,
  825. INIT_LOG_COUNT,
  826. ath9k_hw_adc_dccal_collect,
  827. ath9k_hw_adc_dccal_calibrate
  828. };