Unverified Commit f060f46f authored by KaiChieh Chuang's avatar KaiChieh Chuang Committed by Mark Brown
Browse files

ASoC: mediatek: btcvsd add loopback



add direct loopback path from rx to tx

Signed-off-by: default avatarKaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 7b6b0049
Loading
Loading
Loading
Loading
+68 −1
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ enum bt_sco_state {
	BT_SCO_STATE_IDLE,
	BT_SCO_STATE_RUNNING,
	BT_SCO_STATE_ENDING,
	BT_SCO_STATE_LOOPBACK,
};

enum bt_sco_direct {
@@ -486,7 +487,8 @@ static irqreturn_t mtk_btcvsd_snd_irq_handler(int irq_id, void *dev)
	if (bt->rx->state != BT_SCO_STATE_RUNNING &&
	    bt->rx->state != BT_SCO_STATE_ENDING &&
	    bt->tx->state != BT_SCO_STATE_RUNNING &&
	    bt->tx->state != BT_SCO_STATE_ENDING) {
	    bt->tx->state != BT_SCO_STATE_ENDING &&
	    bt->tx->state != BT_SCO_STATE_LOOPBACK) {
		dev_warn(bt->dev, "%s(), in idle state: rx->state: %d, tx->state: %d\n",
			 __func__, bt->rx->state, bt->tx->state);
		goto irq_handler_exit;
@@ -512,6 +514,42 @@ static irqreturn_t mtk_btcvsd_snd_irq_handler(int irq_id, void *dev)
	buf_cnt_tx = btsco_packet_info[packet_type][2];
	buf_cnt_rx = btsco_packet_info[packet_type][3];

	if (bt->tx->state == BT_SCO_STATE_LOOPBACK) {
		u8 *src, *dst;
		unsigned long connsys_addr_rx, ap_addr_rx;
		unsigned long connsys_addr_tx, ap_addr_tx;

		connsys_addr_rx = *bt->bt_reg_pkt_r;
		ap_addr_rx = (unsigned long)bt->bt_sram_bank2_base +
			     (connsys_addr_rx & 0xFFFF);

		connsys_addr_tx = *bt->bt_reg_pkt_w;
		ap_addr_tx = (unsigned long)bt->bt_sram_bank2_base +
			     (connsys_addr_tx & 0xFFFF);

		if (connsys_addr_tx == 0xdeadfeed ||
		    connsys_addr_rx == 0xdeadfeed) {
			/* bt return 0xdeadfeed if read reg during bt sleep */
			dev_warn(bt->dev, "%s(), connsys_addr_tx == 0xdeadfeed\n",
				 __func__);
			goto irq_handler_exit;
		}

		src = (u8 *)ap_addr_rx;
		dst = (u8 *)ap_addr_tx;

		mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_BT2ARM, src,
					     bt->tx->temp_packet_buf,
					     packet_length,
					     packet_num);
		mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_ARM2BT,
					     bt->tx->temp_packet_buf, dst,
					     packet_length,
					     packet_num);
		bt->rx->rw_cnt++;
		bt->tx->rw_cnt++;
	}

	if (bt->rx->state == BT_SCO_STATE_RUNNING ||
	    bt->rx->state == BT_SCO_STATE_ENDING) {
		if (bt->rx->xrun) {
@@ -1067,6 +1105,33 @@ static int btcvsd_band_set(struct snd_kcontrol *kcontrol,
	return 0;
}

static int btcvsd_loopback_get(struct snd_kcontrol *kcontrol,
			       struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
	struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
	bool lpbk_en = bt->tx->state == BT_SCO_STATE_LOOPBACK;

	ucontrol->value.integer.value[0] = lpbk_en;
	return 0;
}

static int btcvsd_loopback_set(struct snd_kcontrol *kcontrol,
			       struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
	struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);

	if (ucontrol->value.integer.value[0]) {
		mtk_btcvsd_snd_set_state(bt, bt->tx, BT_SCO_STATE_LOOPBACK);
		mtk_btcvsd_snd_set_state(bt, bt->rx, BT_SCO_STATE_LOOPBACK);
	} else {
		mtk_btcvsd_snd_set_state(bt, bt->tx, BT_SCO_STATE_RUNNING);
		mtk_btcvsd_snd_set_state(bt, bt->rx, BT_SCO_STATE_RUNNING);
	}
	return 0;
}

static int btcvsd_tx_mute_get(struct snd_kcontrol *kcontrol,
			      struct snd_ctl_elem_value *ucontrol)
{
@@ -1202,6 +1267,8 @@ static int btcvsd_tx_timestamp_get(struct snd_kcontrol *kcontrol,
static const struct snd_kcontrol_new mtk_btcvsd_snd_controls[] = {
	SOC_ENUM_EXT("BTCVSD Band", btcvsd_enum[0],
		     btcvsd_band_get, btcvsd_band_set),
	SOC_SINGLE_BOOL_EXT("BTCVSD Loopback Switch", 0,
			    btcvsd_loopback_get, btcvsd_loopback_set),
	SOC_SINGLE_BOOL_EXT("BTCVSD Tx Mute Switch", 0,
			    btcvsd_tx_mute_get, btcvsd_tx_mute_set),
	SOC_SINGLE_BOOL_EXT("BTCVSD Tx Irq Received Switch", 0,