* [ath9k-devel] [PATCH v1 3/3] support for antenna configuration profiles
@ 2011-11-28 14:57 Daniel Golle
0 siblings, 0 replies; only message in thread
From: Daniel Golle @ 2011-11-28 14:57 UTC (permalink / raw)
To: ath9k-devel
This adds support for controlling AR_PHY_SWITCH_COM of the AR9285 by using
antenna configuration profiles to ath9k.
Signed-off-by: Daniel Golle <dgolle@allnet.de>
---
drivers/net/wireless/ath/ath9k/ar9002_phy.c | 13 ++++
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 8 ++-
drivers/net/wireless/ath/ath9k/eeprom.h | 1 +
drivers/net/wireless/ath/ath9k/eeprom_4k.c | 29 +++++++-
drivers/net/wireless/ath/ath9k/eeprom_9287.c | 8 ++-
drivers/net/wireless/ath/ath9k/eeprom_def.c | 8 ++-
drivers/net/wireless/ath/ath9k/hw.h | 28 +++++++
drivers/net/wireless/ath/ath9k/init.c | 93 ++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/main.c | 36 +++++++++
include/linux/ath9k_platform.h | 6 ++
10 files changed, 225 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index 3cbbb03..babf8b0 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -556,6 +556,16 @@ static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
}
+static void ar9002_hw_extant_switchcom_set(struct ath_hw *ah, u32 switch_com_value)
+{
+ REG_WRITE(ah, AR_PHY_SWITCH_COM, switch_com_value);
+}
+
+static u32 ar9002_hw_extant_switchcom_get(struct ath_hw *ah)
+{
+ return REG_READ(ah, AR_PHY_SWITCH_COM);
+}
+
void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
@@ -573,5 +583,8 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get;
ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set;
+ ops->extant_switchcom_set = ar9002_hw_extant_switchcom_set;
+ ops->extant_switchcom_get = ar9002_hw_extant_switchcom_get;
+
ar9002_hw_set_nf_limits(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index a93bd63..85196de 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -5140,6 +5140,11 @@ unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah,
}
}
+static u32 ath9k_hw_ar9300_get_switch_com(struct ath_hw *ah)
+{
+ return 0;
+}
+
const struct eeprom_ops eep_ar9300_ops = {
.check_eeprom = ath9k_hw_ar9300_check_eeprom,
.get_eeprom = ath9k_hw_ar9300_get_eeprom,
@@ -5150,5 +5155,6 @@ const struct eeprom_ops eep_ar9300_ops = {
.set_board_values = ath9k_hw_ar9300_set_board_values,
.set_addac = ath9k_hw_ar9300_set_addac,
.set_txpower = ath9k_hw_ar9300_set_txpower,
- .get_spur_channel = ath9k_hw_ar9300_get_spur_channel
+ .get_spur_channel = ath9k_hw_ar9300_get_spur_channel,
+ .get_switch_com = ath9k_hw_ar9300_get_switch_com
};
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 5ff7ab9..98da6c5 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -656,6 +656,7 @@ struct eeprom_ops {
u16 cfgCtl, u8 twiceAntennaReduction,
u8 powerLimit, bool test);
u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
+ u32 (*get_switch_com)(struct ath_hw *ah);
};
void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val);
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 9a7520f..b295ac0 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -815,6 +815,30 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
}
/*
+ * Get common antenna configuration bits
+ */
+static u32 ath9k_hw_4k_get_switch_com(struct ath_hw *ah)
+{
+ struct ath_hw_switch_com_profile *easp;
+ struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+ struct modal_eep_4k_header *pModal = &eep->modalHeader;
+
+ /* return value from eeprom if there are no profiles */
+ if (!ah->switch_com_profiles)
+ return pModal->antCtrlCommon;
+
+ /* find matching value for profile id */
+ for(easp = ah->switch_com_profiles;easp->id >= 0; easp++) {
+ if ( easp->id == ah->selected_extant_profile )
+ return easp->switch_com_value;
+ }
+
+ /* invalid profile selected, return an error */
+ return 1;
+}
+
+
+/*
* Read EEPROM header info and program the device for correct operation
* given the channel value.
*/
@@ -833,7 +857,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
pModal = &eep->modalHeader;
txRxAttenLocal = 23;
- REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
+ REG_WRITE(ah, AR_PHY_SWITCH_COM, ath9k_hw_4k_get_switch_com(ah));
/* Single chain for 4K EEPROM*/
ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal);
@@ -1112,5 +1136,6 @@ const struct eeprom_ops eep_4k_ops = {
.get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev,
.set_board_values = ath9k_hw_4k_set_board_values,
.set_txpower = ath9k_hw_4k_set_txpower,
- .get_spur_channel = ath9k_hw_4k_get_spur_channel
+ .get_spur_channel = ath9k_hw_4k_get_spur_channel,
+ .get_switch_com = ath9k_hw_4k_get_switch_com
};
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index 4f5c50a..cf634a7 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -1062,6 +1062,11 @@ static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
#undef EEP_MAP9287_SPURCHAN
}
+static u32 ath9k_hw_ar9287_get_switch_com(struct ath_hw *ah)
+{
+ return 0;
+}
+
const struct eeprom_ops eep_ar9287_ops = {
.check_eeprom = ath9k_hw_ar9287_check_eeprom,
.get_eeprom = ath9k_hw_ar9287_get_eeprom,
@@ -1071,5 +1076,6 @@ const struct eeprom_ops eep_ar9287_ops = {
.get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev,
.set_board_values = ath9k_hw_ar9287_set_board_values,
.set_txpower = ath9k_hw_ar9287_set_txpower,
- .get_spur_channel = ath9k_hw_ar9287_get_spur_channel
+ .get_spur_channel = ath9k_hw_ar9287_get_spur_channel,
+ .get_switch_com = ath9k_hw_ar9287_get_switch_com
};
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 81e6296..37f60d3 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -1420,6 +1420,11 @@ static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
#undef EEP_DEF_SPURCHAN
}
+static u32 ath9k_hw_def_get_switch_com(struct ath_hw *ah)
+{
+ return 0;
+}
+
const struct eeprom_ops eep_def_ops = {
.check_eeprom = ath9k_hw_def_check_eeprom,
.get_eeprom = ath9k_hw_def_get_eeprom,
@@ -1430,5 +1435,6 @@ const struct eeprom_ops eep_def_ops = {
.set_board_values = ath9k_hw_def_set_board_values,
.set_addac = ath9k_hw_def_set_addac,
.set_txpower = ath9k_hw_def_set_txpower,
- .get_spur_channel = ath9k_hw_def_get_spur_channel
+ .get_spur_channel = ath9k_hw_def_get_spur_channel,
+ .get_switch_com = ath9k_hw_def_get_switch_com
};
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 3cb878c..a33e355 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -545,6 +545,25 @@ struct ath_hw_radar_conf {
bool ext_channel;
};
+
+/**
+ * struct ath_hw_switch_com_profile - external antenna switch settings
+ *
+ * This structure holds a platform_data-supplied alternative value
+ * of AR_PHY_SWITCH_COM.
+ *
+ * @id: unique identifier
+ * @switch_com_value: bit-field to be set in register AR_PHY_SWITCH_COM
+ * @name: profile name
+ * @desc: profile description
+ */
+struct ath_hw_switch_com_profile {
+ int id;
+ u32 switch_com_value;
+ char *name;
+ char *desc;
+};
+
/**
* struct ath_hw_private_ops - callbacks used internally by hardware code
*
@@ -643,6 +662,9 @@ struct ath_hw_ops {
void (*antdiv_comb_conf_set)(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf);
+ u32 (*extant_switchcom_get)(struct ath_hw *ah);
+ void (*extant_switchcom_set)(struct ath_hw *ah,
+ u32 switch_com_value);
};
struct ath_nf_limits {
@@ -882,6 +904,12 @@ struct ath_hw {
bool is_clk_25mhz;
int (*get_mac_revision)(void);
int (*external_reset)(void);
+
+ /*
+ * External antenna switch configuration profiles
+ */
+ struct ath_hw_switch_com_profile *switch_com_profiles;
+ u32 selected_extant_profile;
};
struct ath_bus_ops {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index e046de9..6420b00 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -522,6 +522,43 @@ static void ath9k_init_misc(struct ath_softc *sc)
sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
}
+static int ath9k_init_switch_com_profiles(struct ath_softc *sc, struct ath_hw *ah)
+{
+ struct ath9k_platform_data *pdata = sc->dev->platform_data;
+ int i,j;
+
+ /* count valid profiles in platform data */
+ j=0;
+ for(i=0;i<ATH9K_PLAT_MAX_SWITCH_COM_PROFILES;i++) {
+ if ( pdata->switch_com_profiles[i].name )
+ j++;
+ }
+ /*
+ * allocate space for the j profiles found + 1 for termination
+ */
+ if ( j>0 && ! ah->switch_com_profiles ) {
+ ah->switch_com_profiles = kcalloc(j + 1,
+ sizeof(struct ath_hw_switch_com_profile),
+ GFP_KERNEL);
+ if ( ! ah->switch_com_profiles )
+ return -ENOMEM;
+ }
+ /* populate the space from platform_data */
+ j=0;
+ for(i=0;i<ATH9K_PLAT_MAX_SWITCH_COM_PROFILES;i++) {
+ if ( pdata->switch_com_profiles[i].name ) {
+ ah->switch_com_profiles[j].id = j;
+ ah->switch_com_profiles[j].switch_com_value = pdata->switch_com_profiles[i].val;
+ ah->switch_com_profiles[j].name = pdata->switch_com_profiles[i].name;
+ ah->switch_com_profiles[j].desc = pdata->switch_com_profiles[i].desc;
+ j++;
+ }
+ }
+ if ( j>0 )
+ ah->switch_com_profiles[j].id = -1;
+ return 0;
+}
+
static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops)
{
@@ -605,11 +642,15 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
if (ret)
goto err_btcoex;
+ ret = ath9k_init_switch_com_profiles(sc, ah);
+ if (ret)
+ goto err_easp;
ath9k_cmn_init_crypto(sc->sc_ah);
ath9k_init_misc(sc);
return 0;
+err_easp:
err_btcoex:
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
if (ATH_TXQ_SETUP(sc, i))
@@ -618,6 +659,8 @@ err_queues:
ath9k_hw_deinit(ah);
err_hw:
+ if ( ah->switch_com_profiles )
+ kfree(ah->switch_com_profiles);
kfree(ah);
sc->sc_ah = NULL;
@@ -733,6 +776,48 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
}
+int ath9k_set_extant_profiles(struct ath_hw *ah, struct ieee80211_hw *hw)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ int i;
+ /* nothing to do if there are no profiles */
+ if (! ah->switch_com_profiles)
+ return 0;
+
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Device got extant support.\n");
+ hw->wiphy->flags |= WIPHY_FLAG_HAS_EXTANT_SWITCH;
+
+ /* allocate profile structure in wiphy for all available profiles + 1 */
+ for (i=0; ah->switch_com_profiles[i].id >= 0; i++);
+ hw->wiphy->extant = kcalloc(i+1, sizeof(struct wiphy_extant_profile), GFP_KERNEL);
+ if ( ! hw->wiphy->extant )
+ return -ENOMEM;
+
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Detected %d antenna configuration profiles:\n", i);
+ /* populate wiphy->exant structure */
+ for (i=0; ah->switch_com_profiles[i].id >= 0; i++) {
+ hw->wiphy->extant[i].id = ah->switch_com_profiles[i].id;
+ hw->wiphy->extant[i].name = ah->switch_com_profiles[i].name;
+ hw->wiphy->extant[i].desc = ah->switch_com_profiles[i].desc;
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "\t%d \"%s\" (%s)\n",
+ hw->wiphy->extant[i].id,
+ hw->wiphy->extant[i].name,
+ hw->wiphy->extant[i].desc);
+ }
+ /* terminate with dummy */
+ hw->wiphy->extant[i].id = -1;
+ return 0;
+}
+
+void ath9k_free_extant_profiles(struct ieee80211_hw *hw)
+{
+ if (hw->wiphy->extant)
+ kfree(hw->wiphy->extant);
+}
+
int ath9k_init_device(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops)
{
@@ -751,6 +836,11 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
common = ath9k_hw_common(ah);
ath9k_set_hw_capab(sc, hw);
+ /* Initialize extant profiles */
+ error = ath9k_set_extant_profiles(ah, hw);
+ if (error != 0)
+ goto error_extant;
+
/* Initialize regulatory */
error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
ath9k_reg_notifier);
@@ -816,6 +906,8 @@ error_rx:
error_tx:
/* Nothing */
error_regd:
+ ath9k_free_extant_profiles(hw);
+error_extant:
ath9k_deinit_softc(sc);
error_init:
return error;
@@ -863,6 +955,7 @@ void ath9k_deinit_device(struct ath_softc *sc)
ieee80211_unregister_hw(hw);
ath_rx_cleanup(sc);
ath_tx_cleanup(sc);
+ ath9k_free_extant_profiles(hw);
ath9k_deinit_softc(sc);
}
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index e43c41c..8f03642 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2484,6 +2484,40 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
return 0;
}
+static int ath9k_set_extant(struct ieee80211_hw *hw, u32 extant)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ u32 backup_extant = ah->selected_extant_profile;
+ u32 switch_com_value = 0;
+
+ ath_dbg(common, ATH_DBG_CONFIG, "entering set_extant(%d)\n", extant);
+
+ ah->selected_extant_profile = extant;
+ switch_com_value = ah->eep_ops->get_switch_com(ah);
+ if (switch_com_value & 0xf)
+ goto invalid_profile;
+
+ ath_dbg(common, ATH_DBG_CONFIG, "switch_com: %08x\n", switch_com_value);
+ return 0;
+
+invalid_profile:
+ ath_dbg(common, ATH_DBG_CONFIG, "invalid profile (%08x)\n", switch_com_value);
+ ah->selected_extant_profile = backup_extant;
+ return -EINVAL;
+}
+
+static int ath9k_get_extant(struct ieee80211_hw *hw, u32 *extant)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+ if (!ah->switch_com_profiles)
+ return -EINVAL;
+ *extant = ah->selected_extant_profile;
+ return 0;
+}
+
struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
.start = ath9k_start,
@@ -2512,4 +2546,6 @@ struct ieee80211_ops ath9k_ops = {
.get_stats = ath9k_get_stats,
.set_antenna = ath9k_set_antenna,
.get_antenna = ath9k_get_antenna,
+ .set_extant = ath9k_set_extant,
+ .get_extant = ath9k_get_extant,
};
diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h
index 6e3f54f..1bfe926 100644
--- a/include/linux/ath9k_platform.h
+++ b/include/linux/ath9k_platform.h
@@ -20,6 +20,7 @@
#define _LINUX_ATH9K_PLATFORM_H
#define ATH9K_PLAT_EEP_MAX_WORDS 2048
+#define ATH9K_PLAT_MAX_SWITCH_COM_PROFILES 4
struct ath9k_platform_data {
u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS];
@@ -32,6 +33,11 @@ struct ath9k_platform_data {
bool is_clk_25mhz;
int (*get_mac_revision)(void);
int (*external_reset)(void);
+ struct {
+ u32 val;
+ char *name;
+ char *desc;
+ } switch_com_profiles[ATH9K_PLAT_MAX_SWITCH_COM_PROFILES];
};
#endif /* _LINUX_ATH9K_PLATFORM_H */
--
1.7.4.1
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
Url : http://lists.ath9k.org/pipermail/ath9k-devel/attachments/20111128/f54461b7/attachment.pgp
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2011-11-28 14:57 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-28 14:57 [ath9k-devel] [PATCH v1 3/3] support for antenna configuration profiles Daniel Golle
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.