Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 17fe8aa0 authored by Swaminathan Sathappan's avatar Swaminathan Sathappan Committed by Stephen Boyd
Browse files

ASoC: Handle slimbus port disconnection before opening another



Problem Description:
Open and close the same set of slimbus ports after
certain iterations will fail port open, as that port
was not disconnected successfully.

Fix Description:
Handle sequence of closing slimbus ports. Store
the channel masks associated with each codec dai
and reset them after they are closed from slimbus
Then, release the close slimbus port event, after
all the channels are closed completely

Change-Id: Ie14b9f0920b37f905151b48f18df181503acc21d
CRs-fixed: 370761
Signed-off-by: default avatarSwaminathan Sathappan <Swami@codeaurora.org>
parent 9eb92ee2
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -537,3 +537,18 @@ err:
	return ret;
}
EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_tx);

int wcd9xxx_get_slave_port(unsigned int ch_num)
{
	int ret = 0;

	pr_debug("%s: ch_num[%d]\n", __func__, ch_num);
	ret = (ch_num - BASE_CH_NUM);
	if (ret < 0) {
		pr_err("%s: Error:- Invalid slave port found = %d\n",
			__func__, ret);
		return -EINVAL;
	}
	return ret;
}
EXPORT_SYMBOL_GPL(wcd9xxx_get_slave_port);
+1 −0
Original line number Diff line number Diff line
@@ -99,4 +99,5 @@ int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx,
			unsigned int *rx_ch,
			unsigned int *tx_ch);
int wcd9xxx_get_slave_port(unsigned int ch_num);
#endif /* __WCD9310_SLIMSLAVE_H_ */
+75 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/printk.h>
#include <linux/ratelimit.h>
#include <linux/debugfs.h>
#include <linux/wait.h>
#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
@@ -47,6 +48,8 @@
#define MBHC_FW_READ_ATTEMPTS 15
#define MBHC_FW_READ_TIMEOUT 2000000

#define SLIM_CLOSE_TIMEOUT 1000

enum {
	MBHC_USE_HPHL_TRIGGER = 1,
	MBHC_USE_MB_TRIGGER = 2
@@ -78,6 +81,8 @@ struct tabla_codec_dai_data {
	u32 *ch_num;
	u32 ch_act;
	u32 ch_tot;
	u32 ch_mask;
	wait_queue_head_t dai_wait;
};

#define TABLA_MCLK_RATE_12288KHZ 12288000
@@ -4416,6 +4421,41 @@ static struct snd_soc_dai_driver tabla_i2s_dai[] = {
	},
};

static int tabla_codec_enable_chmask(struct tabla_priv *tabla_p,
	int event, int index)
{
	int  ret = 0;
	u32 k = 0;
	switch (event) {
	case SND_SOC_DAPM_POST_PMU:
		for (k = 0; k < tabla_p->dai[index].ch_tot; k++) {
			ret = wcd9xxx_get_slave_port(
					tabla_p->dai[index].ch_num[k]);
			if (ret < 0) {
				pr_err("%s: Invalid slave port ID: %d\n",
					__func__, ret);
				ret = -EINVAL;
				break;
			}
			tabla_p->dai[index].ch_mask |= 1 << ret;
		}
		ret = 0;
		break;
	case SND_SOC_DAPM_POST_PMD:
		ret = wait_event_timeout(tabla_p->dai[index].dai_wait,
					(tabla_p->dai[index].ch_mask == 0),
				msecs_to_jiffies(SLIM_CLOSE_TIMEOUT));
		if (!ret) {
			pr_err("%s: Slim close tx/rx wait timeout\n",
				__func__);
			ret = -EINVAL;
		}
		ret = 0;
		break;
	}
	return ret;
}

static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
	struct snd_kcontrol *kcontrol, int event)
{
@@ -4445,11 +4485,15 @@ static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
				break;
			}
		}
		if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
		if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot) {
			ret = tabla_codec_enable_chmask(tabla_p,
							SND_SOC_DAPM_POST_PMU,
							j);
			ret = wcd9xxx_cfg_slim_sch_rx(tabla,
					tabla_p->dai[j].ch_num,
					tabla_p->dai[j].ch_tot,
					tabla_p->dai[j].rate);
		}
		break;
	case SND_SOC_DAPM_POST_PMD:
		for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
@@ -4468,11 +4512,13 @@ static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
			ret = wcd9xxx_close_slim_sch_rx(tabla,
						tabla_p->dai[j].ch_num,
						tabla_p->dai[j].ch_tot);
			usleep_range(15000, 15000);
			tabla_p->dai[j].rate = 0;
			memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
					tabla_p->dai[j].ch_tot));
			tabla_p->dai[j].ch_tot = 0;
			ret = tabla_codec_enable_chmask(tabla_p,
							SND_SOC_DAPM_POST_PMD,
							j);
		}
	}
	return ret;
@@ -4510,11 +4556,15 @@ static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
				break;
			}
		}
		if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
		if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot) {
			ret = tabla_codec_enable_chmask(tabla_p,
							SND_SOC_DAPM_POST_PMU,
							j);
			ret = wcd9xxx_cfg_slim_sch_tx(tabla,
						tabla_p->dai[j].ch_num,
						tabla_p->dai[j].ch_tot,
						tabla_p->dai[j].rate);
		}
		break;
	case SND_SOC_DAPM_POST_PMD:
		for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
@@ -4536,6 +4586,9 @@ static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
			memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
					tabla_p->dai[j].ch_tot));
			tabla_p->dai[j].ch_tot = 0;
			ret = tabla_codec_enable_chmask(tabla_p,
							SND_SOC_DAPM_POST_PMD,
							j);
		}
	}
	return ret;
@@ -7154,7 +7207,8 @@ static irqreturn_t tabla_slimbus_irq(int irq, void *data)
{
	struct tabla_priv *priv = data;
	struct snd_soc_codec *codec = priv->codec;
	int i, j;
	struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
	int i, j, port_id, k, ch_mask_temp;
	u8 val;

	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
@@ -7169,6 +7223,22 @@ static irqreturn_t tabla_slimbus_irq(int irq, void *data)
			if (val & 0x2)
				pr_err_ratelimited("underflow error on port %x,"
					" value %x\n", i*8 + j, val);
			if (val & 0x4) {
				pr_debug("%s: port %x disconnect value %x\n",
					__func__, i*8 + j, val);
				port_id = i*8 + j;
				for (k = 0; k < ARRAY_SIZE(tabla_dai); k++) {
					ch_mask_temp = 1 << port_id;
					if (ch_mask_temp &
						tabla_p->dai[k].ch_mask) {
						tabla_p->dai[k].ch_mask &=
								~ch_mask_temp;
					if (!tabla_p->dai[k].ch_mask)
							wake_up(
						&tabla_p->dai[k].dai_wait);
					}
				}
			}
		}
		wcd9xxx_interface_reg_write(codec->control_data,
			TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
@@ -7825,6 +7895,7 @@ static int tabla_codec_probe(struct snd_soc_codec *codec)
		}
		tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
					ch_cnt), GFP_KERNEL);
		init_waitqueue_head(&tabla->dai[i].dai_wait);
	}

#ifdef CONFIG_DEBUG_FS