calib.c 26 KB

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