drivers/net/wireless/ath/ath9k/htc_drv_gpio.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
Extension
.c
Size
9467 bytes
Lines
335
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
		clear_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
		clear_bit(OP_BT_SCAN, &priv->op_flags);
		/* Detect if colocated bt started scanning */
		if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
			ath_dbg(ath9k_hw_common(ah), BTCOEX,
				"BT scan detected\n");
			set_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
			set_bit(OP_BT_SCAN, &priv->op_flags);
		} else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
			ath_dbg(ath9k_hw_common(ah), BTCOEX,
				"BT priority traffic detected\n");
			set_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
		}

		btcoex->bt_priority_cnt = 0;
		btcoex->bt_priority_time = jiffies;
	}
}

/*
 * This is the master bt coex work which runs for every
 * 45ms, bt traffic will be given priority during 55% of this
 * period while wlan gets remaining 45%
 */
static void ath_btcoex_period_work(struct work_struct *work)
{
	struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
						   coex_period_work.work);
	struct ath_btcoex *btcoex = &priv->btcoex;
	struct ath_common *common = ath9k_hw_common(priv->ah);
	u32 timer_period;
	int ret;

	ath_detect_bt_priority(priv);

	ret = ath9k_htc_update_cap_target(priv,
			  test_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags));
	if (ret) {
		ath_err(common, "Unable to set BTCOEX parameters\n");
		return;
	}

	ath9k_hw_btcoex_bt_stomp(priv->ah, test_bit(OP_BT_SCAN, &priv->op_flags) ?
				 ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type);

	ath9k_hw_btcoex_enable(priv->ah);
	timer_period = test_bit(OP_BT_SCAN, &priv->op_flags) ?
		btcoex->btscan_no_stomp : btcoex->btcoex_no_stomp;
	ieee80211_queue_delayed_work(priv->hw, &priv->duty_cycle_work,
				     msecs_to_jiffies(timer_period));
	ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work,
				     msecs_to_jiffies(btcoex->btcoex_period));
}

/*
 * Work to time slice between wlan and bt traffic and
 * configure weight registers
 */
static void ath_btcoex_duty_cycle_work(struct work_struct *work)
{
	struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
						   duty_cycle_work.work);
	struct ath_hw *ah = priv->ah;
	struct ath_btcoex *btcoex = &priv->btcoex;
	struct ath_common *common = ath9k_hw_common(ah);

	ath_dbg(common, BTCOEX, "time slice work for bt and wlan\n");

	if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW ||
	    test_bit(OP_BT_SCAN, &priv->op_flags))
		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
	else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);

	ath9k_hw_btcoex_enable(priv->ah);
}

static void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
{
	struct ath_btcoex *btcoex = &priv->btcoex;

	btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
	btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
		btcoex->btcoex_period / 100;
	btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
				   btcoex->btcoex_period / 100;
	INIT_DELAYED_WORK(&priv->coex_period_work, ath_btcoex_period_work);
	INIT_DELAYED_WORK(&priv->duty_cycle_work, ath_btcoex_duty_cycle_work);
}

Annotation

Implementation Notes