summaryrefslogtreecommitdiff
path: root/sys/dev/ic/ar9285.c
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2010-04-07 16:19:34 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2010-04-07 16:19:34 +0000
commitb7f0230b09ce0d8d16620767b90102947f724c07 (patch)
treed1cbf55fd0932d1a78c4ee190b700415bdde1b2e /sys/dev/ic/ar9285.c
parentfb138ccb2d70c270163d288c43e54b23bf546828 (diff)
update initvals and TX gains for AR9285 >=1.2
check result of carrier leakage calibration and redo calibration if needed add support for newer AR9285 chips (AR9285 XE 2.0). tested for non-regression on a DNXA-95 "Still seems to work here" kettenis@
Diffstat (limited to 'sys/dev/ic/ar9285.c')
-rw-r--r--sys/dev/ic/ar9285.c77
1 files changed, 66 insertions, 11 deletions
diff --git a/sys/dev/ic/ar9285.c b/sys/dev/ic/ar9285.c
index b5e8d3cae85..432e4af1dad 100644
--- a/sys/dev/ic/ar9285.c
+++ b/sys/dev/ic/ar9285.c
@@ -1,8 +1,8 @@
-/* $OpenBSD: ar9285.c,v 1.5 2010/02/07 12:02:52 damien Exp $ */
+/* $OpenBSD: ar9285.c,v 1.6 2010/04/07 16:19:33 damien Exp $ */
/*-
- * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2008-2010 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -73,7 +73,7 @@ const struct ar_spur_chan *ar9285_get_spur_chans(struct athn_softc *, int);
void ar9285_init_from_rom(struct athn_softc *, struct ieee80211_channel *,
struct ieee80211_channel *);
void ar9285_pa_calib(struct athn_softc *);
-int ar9285_1_2_init_calib(struct athn_softc *, struct ieee80211_channel *,
+int ar9285_1_2_cl_cal(struct athn_softc *, struct ieee80211_channel *,
struct ieee80211_channel *);
void ar9285_get_pdadcs(struct athn_softc *, struct ieee80211_channel *,
int, uint8_t, uint8_t *, uint8_t *);
@@ -113,14 +113,21 @@ ar9285_setup(struct athn_softc *sc)
const struct ar9285_eeprom *eep = sc->eep;
uint8_t type;
- if (AR_SREV_9285_12(sc)) {
+ if (AR_SREV_9285_12_OR_LATER(sc)) {
/* Select initialization values based on ROM. */
type = eep->baseEepHeader.txGainType;
DPRINTF(("Tx gain type=0x%x\n", type));
- if (type == AR_EEP_TXGAIN_HIGH_POWER)
- sc->tx_gain = &ar9285_1_2_tx_gain_high_power;
- else
- sc->tx_gain = &ar9285_1_2_tx_gain;
+ if ((AR_READ(sc, AR_AN_SYNTH9) & 0x7) == 0x1) { /* XE rev. */
+ if (type == AR_EEP_TXGAIN_HIGH_POWER)
+ sc->tx_gain = &ar9285_2_0_tx_gain_high_power;
+ else
+ sc->tx_gain = &ar9285_2_0_tx_gain;
+ } else {
+ if (type == AR_EEP_TXGAIN_HIGH_POWER)
+ sc->tx_gain = &ar9285_1_2_tx_gain_high_power;
+ else
+ sc->tx_gain = &ar9285_1_2_tx_gain;
+ }
}
}
@@ -456,10 +463,10 @@ ar9285_pa_calib(struct athn_softc *sc)
}
/*
- * Carrier Leak Calibration (>= AR9285 1.2 only.)
+ * Carrier Leakage Calibration (>= AR9285 1.2 only.)
*/
int
-ar9285_1_2_init_calib(struct athn_softc *sc, struct ieee80211_channel *c,
+ar9285_1_2_cl_cal(struct athn_softc *sc, struct ieee80211_channel *c,
struct ieee80211_channel *extc)
{
int ntries;
@@ -504,6 +511,54 @@ ar9285_1_2_init_calib(struct athn_softc *sc, struct ieee80211_channel *c,
return (0);
}
+int
+ar9285_1_2_init_calib(struct athn_softc *sc, struct ieee80211_channel *c,
+ struct ieee80211_channel *extc)
+{
+ uint32_t reg, mask, clcgain, rf2g5_svg;
+ int i, maxgain, nclcs, thresh, error;
+
+ /* Do carrier leakage calibration. */
+ if ((error = ar9285_1_2_cl_cal(sc, c, extc)) != 0)
+ return (error);
+
+ mask = 0;
+ nclcs = 0;
+ reg = AR_READ(sc, AR_PHY_TX_PWRCTRL7);
+ maxgain = MS(reg, AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX);
+ for (i = 0; i <= maxgain; i++) {
+ reg = AR_READ(sc, AR_PHY_TX_GAIN_TBL(i));
+ clcgain = MS(reg, AR_PHY_TX_GAIN_CLC);
+ /* NB: clcgain <= 0xf. */
+ if (!(mask & (1 << clcgain))) {
+ mask |= 1 << clcgain;
+ nclcs++;
+ }
+ }
+ thresh = 0;
+ for (i = 0; i < nclcs; i++) {
+ reg = AR_READ(sc, AR_PHY_CLC_TBL(i));
+ if (MS(reg, AR_PHY_CLC_I0) == 0)
+ thresh++;
+ if (MS(reg, AR_PHY_CLC_Q0) == 0)
+ thresh++;
+ }
+ if (thresh <= AR9285_CL_CAL_REDO_THRESH)
+ return (0); /* No need to redo. */
+
+ /* Threshold reached, redo carrier leakage calibration. */
+ DPRINTFN(2, ("CLC threshold=%d\n", thresh));
+ rf2g5_svg = reg = AR_READ(sc, AR9285_AN_RF2G5);
+ if ((AR_READ(sc, AR_AN_SYNTH9) & 0x7) == 0x1) /* XE rev. */
+ reg = RW(reg, AR9285_AN_RF2G5_IC50TX, 0x5);
+ else
+ reg = RW(reg, AR9285_AN_RF2G5_IC50TX, 0x4);
+ AR_WRITE(sc, AR9285_AN_RF2G5, reg);
+ error = ar9285_1_2_cl_cal(sc, c, extc);
+ AR_WRITE(sc, AR9285_AN_RF2G5, rf2g5_svg);
+ return (error);
+}
+
void
ar9285_get_pdadcs(struct athn_softc *sc, struct ieee80211_channel *c,
int nxpdgains, uint8_t overlap, uint8_t *boundaries, uint8_t *pdadcs)