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

Commit d97fa6fc authored by Sanjana B's avatar Sanjana B
Browse files

asoc: qcs405: Add support for TDM interface



Add mixer controls for TDM interface in machine driver.

Change-Id: Ic177bcde59607c7ef3aecb78dfffdaf0388ed444
Signed-off-by: default avatarSanjana B <sanjb@codeaurora.org>
parent 18d788af
Loading
Loading
Loading
Loading
+583 −25
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@
#define WCN_CDC_SLIM_RX_CH_MAX 2
#define WCN_CDC_SLIM_TX_CH_MAX 4
#define TDM_CHANNEL_MAX 8
#define TDM_SLOT_OFFSET_MAX 32
#define TDM_MAX_CLK_FREQ 24576000
#define BT_SLIM_TX SLIM_TX_9

#define ADSP_STATE_READY_TIMEOUT_MS 3000
@@ -239,6 +241,7 @@ enum {
	TDM_TERT,
	TDM_QUAT,
	TDM_QUIN,
	TDM_SEN,
	TDM_INTERFACE_MAX,
};

@@ -298,6 +301,16 @@ static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
	},
	{ /* SEN TDM */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
	}
};

@@ -352,8 +365,19 @@ static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
	},
	{ /* SEN TDM */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
		{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
	}
};

static struct dev_config ext_hdmi_rx_cfg[] = {
	[HDMI_RX_IDX] =   {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
};
@@ -475,6 +499,59 @@ static struct dev_config afe_lb_tx_cfg = {
	.channels = 2,
};

/* TDM default slot config */
struct tdm_slot_cfg {
	u32 width;
	u32 num;
};

static struct tdm_slot_cfg tdm_slot[TDM_INTERFACE_MAX] = {
	/* PRI TDM */
	{32, 8},
	/* SEC TDM */
	{32, 8},
	/* TERT TDM */
	{32, 8},
	/* QUAT TDM */
	{32, 8},
	/* QUIN TDM */
	{32, 8},
	/* SEN TDM*/
	{32, 8}
};

static unsigned int tdm_rx_slot_offset
	[TDM_INTERFACE_MAX][TDM_SLOT_OFFSET_MAX] = {
	/* PRI TDM */
	{0, 4, 8, 12, 16, 20, 24, 0xFFFF},
	/* SEC TDM */
	{0, 4, 8, 12, 16, 20, 24, 0xFFFF},
	/* TERT TDM */
	{0, 4, 8, 12, 16, 20, 24, 0xFFFF},
	/* QUAT TDM */
	{0, 4, 8, 12, 16, 20, 24, 0xFFFF},
	/* QUIN TDM */
	{0, 4, 8, 12, 16, 20, 24, 0xFFFF},
	/* SEN TDM */
	{0, 4, 8, 12, 16, 20, 24, 0xFFFF}
};

static unsigned int tdm_tx_slot_offset
	[TDM_INTERFACE_MAX][TDM_SLOT_OFFSET_MAX] = {
	/* PRI TDM */
	{0, 4, 8, 12, 16, 20, 24, 0xFFFF},
	/* SEC TDM */
	{0, 4, 8, 12, 16, 20, 24, 0xFFFF},
	/* TERT TDM */
	{0, 4, 8, 12, 16, 20, 24, 0xFFFF},
	/* QUAT TDM */
	{0, 4, 8, 12, 16, 20, 24, 0xFFFF},
	/* QUIN TDM */
	{0, 4, 8, 12, 16, 20, 24, 0xFFFF},
	/* SEN TDM */
	{0, 4, 8, 12, 16, 20, 24, 0xFFFF}
};

static int msm_vi_feed_tx_ch = 2;
static const char *const slim_rx_ch_text[] = {"One", "Two"};
static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four",
@@ -525,6 +602,9 @@ static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32",
					     "KHZ_48", "KHZ_176P4",
					     "KHZ_352P8"};
static const char *const tdm_slot_num_text[] = {"One", "Two", "Four",
					"Eight", "Sixteen", "ThirtyTwo"};
static const char *const tdm_slot_width_text[] = {"16", "24", "32"};
static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_16",
				      "KHZ_22P05", "KHZ_32", "KHZ_44P1",
@@ -596,6 +676,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_chs, tdm_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_format, tdm_bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(tdm_slot_num, tdm_slot_num_text);
static SOC_ENUM_SINGLE_EXT_DECL(tdm_slot_width, tdm_slot_width_text);
static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_rx_sample_rate, auxpcm_rate_text);
@@ -2444,31 +2526,43 @@ static int aux_pcm_get_sample_rate_val(int sample_rate)
	return sample_rate_val;
}

static int tdm_get_port_idx(struct snd_kcontrol *kcontrol,
			    struct tdm_port *port)
static int tdm_get_mode(struct snd_kcontrol *kcontrol)
{
	if (port) {
	int mode;

	if (strnstr(kcontrol->id.name, "PRI",
		sizeof(kcontrol->id.name))) {
			port->mode = TDM_PRI;
		mode = TDM_PRI;
	} else if (strnstr(kcontrol->id.name, "SEC",
		sizeof(kcontrol->id.name))) {
			port->mode = TDM_SEC;
		mode = TDM_SEC;
	} else if (strnstr(kcontrol->id.name, "TERT",
		sizeof(kcontrol->id.name))) {
			port->mode = TDM_TERT;
		mode = TDM_TERT;
	} else if (strnstr(kcontrol->id.name, "QUAT",
		sizeof(kcontrol->id.name))) {
			port->mode = TDM_QUAT;
		mode = TDM_QUAT;
	} else if (strnstr(kcontrol->id.name, "QUIN",
		sizeof(kcontrol->id.name))) {
			port->mode = TDM_QUIN;
		mode = TDM_QUIN;
	} else if (strnstr(kcontrol->id.name, "SEN",
		sizeof(kcontrol->id.name))) {
		mode = TDM_SEN;
	} else {
			pr_err("%s: unsupported mode in: %s",
		pr_err("%s: unsupported mode in: %s\n",
			__func__, kcontrol->id.name);
		return -EINVAL;
	}
	return mode;
}

static int tdm_get_port_idx(struct snd_kcontrol *kcontrol,
			    struct tdm_port *port)
{
	if (port) {
		port->mode = tdm_get_mode(kcontrol);
		if (port->mode < 0)
			return port->mode;
		if (strnstr(kcontrol->id.name, "RX_0",
		    sizeof(kcontrol->id.name)) ||
		    strnstr(kcontrol->id.name, "TX_0",
@@ -2510,7 +2604,7 @@ static int tdm_get_port_idx(struct snd_kcontrol *kcontrol,
			   sizeof(kcontrol->id.name))) {
			port->channel = TDM_7;
		} else {
			pr_err("%s: unsupported channel in: %s",
			pr_err("%s: unsupported channel in: %s\n",
				__func__, kcontrol->id.name);
			return -EINVAL;
		}
@@ -2802,6 +2896,264 @@ static int tdm_tx_ch_put(struct snd_kcontrol *kcontrol,
	return ret;
}

static int tdm_get_slot_num_val(int slot_num)
{
	int slot_num_val;

	switch (slot_num) {
	case 1:
		slot_num_val = 0;
		break;
	case 2:
		slot_num_val = 1;
		break;
	case 4:
		slot_num_val = 2;
		break;
	case 8:
		slot_num_val = 3;
		break;
	case 16:
		slot_num_val = 4;
		break;
	case 32:
		slot_num_val = 5;
		break;
	default:
		slot_num_val = 5;
		break;
	}
	return slot_num_val;
}

static int tdm_get_slot_num(int value)
{
	int slot_num;

	switch (value) {
	case 0:
		slot_num = 1;
		break;
	case 1:
		slot_num = 2;
		break;
	case 2:
		slot_num = 4;
		break;
	case 3:
		slot_num = 8;
		break;
	case 4:
		slot_num = 16;
		break;
	case 5:
		slot_num = 32;
		break;
	default:
		slot_num = 8;
		break;
	}
	return slot_num;
}

static int tdm_slot_num_get(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
	int mode = tdm_get_mode(kcontrol);

	if (mode < 0) {
		pr_err("%s: unsupported control: %s\n",
			__func__, kcontrol->id.name);
		return mode;
	}
	ucontrol->value.enumerated.item[0] =
		tdm_get_slot_num_val(tdm_slot[mode].num);
	pr_debug("%s: mode = %d, tdm_slot_num = %d, item = %d\n", __func__,
		mode, tdm_slot[mode].num,
		ucontrol->value.enumerated.item[0]);
	return 0;
}

static int tdm_slot_num_put(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
	int mode = tdm_get_mode(kcontrol);

	if (mode < 0) {
		pr_err("%s: unsupported control: %s\n",
			__func__, kcontrol->id.name);
		return mode;
	}
	tdm_slot[mode].num =
		tdm_get_slot_num(ucontrol->value.enumerated.item[0]);
	pr_debug("%s: mode = %d, tdm_slot_num = %d, item = %d\n", __func__,
		mode, tdm_slot[mode].num,
		ucontrol->value.enumerated.item[0]);
	return 0;
}

static int tdm_get_slot_width_val(int slot_width)
{
	int slot_width_val;

	switch (slot_width) {
	case 16:
		slot_width_val = 0;
		break;
	case 24:
		slot_width_val = 1;
		break;
	case 32:
		slot_width_val = 2;
		break;
	default:
		slot_width_val = 2;
		break;
	}
	return slot_width_val;
}

static int tdm_slot_width_get(struct snd_kcontrol *kcontrol,
		struct snd_ctl_elem_value *ucontrol)
{
	int mode = tdm_get_mode(kcontrol);

	if (mode < 0) {
		pr_err("%s: unsupported control: %s\n",
			__func__, kcontrol->id.name);
		return mode;
	}
	ucontrol->value.enumerated.item[0] =
		tdm_get_slot_width_val(tdm_slot[mode].width);
	pr_debug("%s: mode = %d, tdm_slot_width = %d, item = %d\n", __func__,
		mode, tdm_slot[mode].width,
		ucontrol->value.enumerated.item[0]);
	return 0;
}

static int tdm_get_slot_width(int value)
{
	int slot_width;

	switch (value) {
	case 0:
		slot_width = 16;
		break;
	case 1:
		slot_width = 24;
		break;
	case 2:
		slot_width = 32;
		break;
	default:
		slot_width = 32;
		break;
	}
	return slot_width;
}

static int tdm_slot_width_put(struct snd_kcontrol *kcontrol,
		struct snd_ctl_elem_value *ucontrol)
{
	int mode = tdm_get_mode(kcontrol);

	if (mode < 0) {
		pr_err("%s: unsupported control: %s\n",
			__func__, kcontrol->id.name);
		return mode;
	}
	tdm_slot[mode].width =
		tdm_get_slot_width(ucontrol->value.enumerated.item[0]);
	pr_debug("%s: mode = %d, tdm_slot_width = %d, item = %d\n", __func__,
		mode, tdm_slot[mode].width,
		ucontrol->value.enumerated.item[0]);
	return 0;
}

static int tdm_rx_slot_mapping_get(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
	unsigned int *slot_offset;
	int i;
	int mode = tdm_get_mode(kcontrol);

	if (mode < 0) {
		pr_err("%s: unsupported control: %s\n",
			__func__, kcontrol->id.name);
		return mode;
	}
	slot_offset = tdm_rx_slot_offset[mode];
	for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
		ucontrol->value.integer.value[i] = slot_offset[i];
		pr_debug("%s: offset %d, value %d\n",
			__func__, i, slot_offset[i]);
	}
	return 0;
}

static int tdm_rx_slot_mapping_put(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
	unsigned int *slot_offset;
	int i;
	int mode = tdm_get_mode(kcontrol);

	if (mode < 0) {
		pr_err("%s: unsupported control: %s\n",
			__func__, kcontrol->id.name);
		return mode;
	}
	slot_offset = tdm_rx_slot_offset[mode];
	for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
		slot_offset[i] = ucontrol->value.integer.value[i];
		pr_debug("%s: offset %d, value %d\n",
			__func__, i, slot_offset[i]);
	}
	return 0;
}

static int tdm_tx_slot_mapping_get(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
	unsigned int *slot_offset;
	int i;
	int mode = tdm_get_mode(kcontrol);

	if (mode < 0) {
		pr_err("%s: unsupported control: %s\n",
			__func__, kcontrol->id.name);
		return mode;
	}
	slot_offset = tdm_tx_slot_offset[mode];
	for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
		ucontrol->value.integer.value[i] = slot_offset[i];
		pr_debug("%s: offset %d, value %d\n",
			__func__, i, slot_offset[i]);
	}
	return 0;
}

static int tdm_tx_slot_mapping_put(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
	unsigned int *slot_offset;
	int i;
	int mode = tdm_get_mode(kcontrol);

	if (mode < 0) {
		pr_err("%s: unsupported control: %s\n",
			__func__, kcontrol->id.name);
		return mode;
	}
	slot_offset = tdm_tx_slot_offset[mode];
	for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
		slot_offset[i] = ucontrol->value.integer.value[i];
		pr_debug("%s: offset %d, value %d\n",
			__func__, i, slot_offset[i]);
	}
	return 0;
}

static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
{
	int idx;
@@ -4331,6 +4683,85 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
	SOC_ENUM_EXT("QUIN_TDM_TX_0 Channels", tdm_tx_chs,
			tdm_tx_ch_get,
			tdm_tx_ch_put),
	SOC_ENUM_EXT("SEN_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
			tdm_rx_sample_rate_get,
			tdm_rx_sample_rate_put),
	SOC_ENUM_EXT("SEN_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
			tdm_tx_sample_rate_get,
			tdm_tx_sample_rate_put),
	SOC_ENUM_EXT("SEN_TDM_RX_0 Format", tdm_rx_format,
			tdm_rx_format_get,
			tdm_rx_format_put),
	SOC_ENUM_EXT("SEN_TDM_TX_0 Format", tdm_tx_format,
			tdm_tx_format_get,
			tdm_tx_format_put),
	SOC_ENUM_EXT("SEN_TDM_RX_0 Channels", tdm_rx_chs,
			tdm_rx_ch_get,
			tdm_rx_ch_put),
	SOC_ENUM_EXT("SEN_TDM_TX_0 Channels", tdm_tx_chs,
			tdm_tx_ch_get,
			tdm_tx_ch_put),
	SOC_ENUM_EXT("PRI_TDM SlotNumber", tdm_slot_num,
			tdm_slot_num_get, tdm_slot_num_put),
	SOC_ENUM_EXT("PRI_TDM SlotWidth", tdm_slot_width,
			tdm_slot_width_get, tdm_slot_width_put),
	SOC_ENUM_EXT("SEC_TDM SlotNumber", tdm_slot_num,
			tdm_slot_num_get, tdm_slot_num_put),
	SOC_ENUM_EXT("SEC_TDM SlotWidth", tdm_slot_width,
			tdm_slot_width_get, tdm_slot_width_put),
	SOC_ENUM_EXT("TERT_TDM SlotNumber", tdm_slot_num,
			tdm_slot_num_get, tdm_slot_num_put),
	SOC_ENUM_EXT("TERT_TDM SlotWidth", tdm_slot_width,
			tdm_slot_width_get, tdm_slot_width_put),
	SOC_ENUM_EXT("QUAT_TDM SlotNumber", tdm_slot_num,
			tdm_slot_num_get, tdm_slot_num_put),
	SOC_ENUM_EXT("QUAT_TDM SlotWidth", tdm_slot_width,
			tdm_slot_width_get, tdm_slot_width_put),
	SOC_ENUM_EXT("QUIN_TDM SlotNumber", tdm_slot_num,
			tdm_slot_num_get, tdm_slot_num_put),
	SOC_ENUM_EXT("QUIN_TDM SlotWidth", tdm_slot_width,
			tdm_slot_width_get, tdm_slot_width_put),
	SOC_ENUM_EXT("SEN_TDM SlotNumber", tdm_slot_num,
			tdm_slot_num_get, tdm_slot_num_put),
	SOC_ENUM_EXT("SEN_TDM SlotWidth", tdm_slot_width,
			tdm_slot_width_get, tdm_slot_width_put),
	SOC_SINGLE_MULTI_EXT("PRI_TDM_RX SlotMapping",
		SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
		tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
	SOC_SINGLE_MULTI_EXT("SEC_TDM_RX SlotMapping",
		SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
		tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
	SOC_SINGLE_MULTI_EXT("TERT_TDM_RX SlotMapping",
		SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
		tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
	SOC_SINGLE_MULTI_EXT("QUAT_TDM_RX SlotMapping",
		SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
		tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
	SOC_SINGLE_MULTI_EXT("QUIN_TDM_RX SlotMapping",
		SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
		tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
	SOC_SINGLE_MULTI_EXT("SEN_TDM_RX SlotMapping",
		SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
		tdm_rx_slot_mapping_get, tdm_rx_slot_mapping_put),
	SOC_SINGLE_MULTI_EXT("PRI_TDM_TX SlotMapping",
		SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
		tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
	SOC_SINGLE_MULTI_EXT("SEC_TDM_TX SlotMapping",
		SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
		tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
	SOC_SINGLE_MULTI_EXT("TERT_TDM_TX SlotMapping",
		SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
		tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
	SOC_SINGLE_MULTI_EXT("QUAT_TDM_TX SlotMapping",
		SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
		tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
	SOC_SINGLE_MULTI_EXT("QUIN_TDM_TX SlotMapping",
		SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
		tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),
	SOC_SINGLE_MULTI_EXT("SEN_TDM_TX SlotMapping",
		SND_SOC_NOPM, 0, 0xFFFF, 0, TDM_SLOT_OFFSET_MAX,
		tdm_tx_slot_mapping_get, tdm_tx_slot_mapping_put),

	SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate,
			aux_pcm_rx_sample_rate_get,
			aux_pcm_rx_sample_rate_put),
@@ -5076,6 +5507,22 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
		rate->min = rate->max = tdm_tx_cfg[TDM_QUIN][TDM_0].sample_rate;
		break;

	case MSM_BACKEND_DAI_SEN_TDM_RX_0:
		channels->min = channels->max =
				tdm_rx_cfg[TDM_SEN][TDM_0].channels;
		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
			       tdm_rx_cfg[TDM_SEN][TDM_0].bit_format);
		rate->min = rate->max = tdm_rx_cfg[TDM_SEN][TDM_0].sample_rate;
		break;

	case MSM_BACKEND_DAI_SEN_TDM_TX_0:
		channels->min = channels->max =
				tdm_tx_cfg[TDM_SEN][TDM_0].channels;
		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
			       tdm_tx_cfg[TDM_SEN][TDM_0].bit_format);
		rate->min = rate->max = tdm_tx_cfg[TDM_SEN][TDM_0].sample_rate;
		break;

	case MSM_BACKEND_DAI_AUXPCM_RX:
		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
			aux_pcm_rx_cfg[PRIM_AUX_PCM].bit_format);
@@ -6168,6 +6615,13 @@ static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
			       tdm_rx_cfg[TDM_QUIN][TDM_0].bit_format);
		rate->min = rate->max = tdm_rx_cfg[TDM_QUIN][TDM_0].sample_rate;
	} else if (cpu_dai->id == AFE_PORT_ID_SENARY_TDM_RX) {
		channels->min = channels->max =
				tdm_rx_cfg[TDM_SEN][TDM_0].channels;
		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
			       tdm_rx_cfg[TDM_SEN][TDM_0].bit_format);
		rate->min = rate->max =
				tdm_rx_cfg[TDM_SEN][TDM_0].sample_rate;
	} else {
		pr_err("%s: dai id 0x%x not supported\n",
			__func__, cpu_dai->id);
@@ -6190,7 +6644,9 @@ static int qcs405_tdm_snd_hw_params(struct snd_pcm_substream *substream,
	int slot_width = 32;
	int channels, slots = 8;
	unsigned int slot_mask, rate, clk_freq;
	unsigned int slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
	unsigned int *slot_offset;
	int offset_channels = 0;
	int i;

	pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);

@@ -6198,33 +6654,75 @@ static int qcs405_tdm_snd_hw_params(struct snd_pcm_substream *substream,
	switch (cpu_dai->id) {
	case AFE_PORT_ID_PRIMARY_TDM_RX:
		channels = tdm_rx_cfg[TDM_PRI][TDM_0].channels;
		slots = tdm_slot[TDM_PRI].num;
		slot_width = tdm_slot[TDM_PRI].width;
		slot_offset = tdm_rx_slot_offset[TDM_PRI];
		break;
	case AFE_PORT_ID_SECONDARY_TDM_RX:
		channels = tdm_rx_cfg[TDM_SEC][TDM_0].channels;
		slots = tdm_slot[TDM_SEC].num;
		slot_width = tdm_slot[TDM_SEC].width;
		slot_offset = tdm_rx_slot_offset[TDM_SEC];
		break;
	case AFE_PORT_ID_TERTIARY_TDM_RX:
		channels = tdm_rx_cfg[TDM_TERT][TDM_0].channels;
		slots = tdm_slot[TDM_TERT].num;
		slot_width = tdm_slot[TDM_TERT].width;
		slot_offset = tdm_rx_slot_offset[TDM_TERT];
		break;
	case AFE_PORT_ID_QUATERNARY_TDM_RX:
		channels = tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
		slots = tdm_slot[TDM_QUAT].num;
		slot_width = tdm_slot[TDM_QUAT].width;
		slot_offset = tdm_rx_slot_offset[TDM_QUAT];
		break;
	case AFE_PORT_ID_QUINARY_TDM_RX:
		channels = tdm_rx_cfg[TDM_QUIN][TDM_0].channels;
		slots = tdm_slot[TDM_QUIN].num;
		slot_width = tdm_slot[TDM_QUIN].width;
		slot_offset = tdm_rx_slot_offset[TDM_QUIN];
		break;
	case AFE_PORT_ID_SENARY_TDM_RX:
		channels = tdm_rx_cfg[TDM_SEN][TDM_0].channels;
		slots = tdm_slot[TDM_SEN].num;
		slot_width = tdm_slot[TDM_SEN].width;
		slot_offset = tdm_rx_slot_offset[TDM_SEN];
		break;
	case AFE_PORT_ID_PRIMARY_TDM_TX:
		channels = tdm_tx_cfg[TDM_PRI][TDM_0].channels;
		slots = tdm_slot[TDM_PRI].num;
		slot_width = tdm_slot[TDM_PRI].width;
		slot_offset = tdm_tx_slot_offset[TDM_PRI];
		break;
	case AFE_PORT_ID_SECONDARY_TDM_TX:
		channels = tdm_tx_cfg[TDM_SEC][TDM_0].channels;
		slots = tdm_slot[TDM_SEC].num;
		slot_width = tdm_slot[TDM_SEC].width;
		slot_offset = tdm_tx_slot_offset[TDM_SEC];
		break;
	case AFE_PORT_ID_TERTIARY_TDM_TX:
		channels = tdm_tx_cfg[TDM_TERT][TDM_0].channels;
		slots = tdm_slot[TDM_TERT].num;
		slot_width = tdm_slot[TDM_TERT].width;
		slot_offset = tdm_tx_slot_offset[TDM_TERT];
		break;
	case AFE_PORT_ID_QUATERNARY_TDM_TX:
		channels = tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
		slots = tdm_slot[TDM_QUAT].num;
		slot_width = tdm_slot[TDM_QUAT].width;
		slot_offset = tdm_tx_slot_offset[TDM_QUAT];
		break;
	case AFE_PORT_ID_QUINARY_TDM_TX:
		channels = tdm_tx_cfg[TDM_QUIN][TDM_0].channels;
		slots = tdm_slot[TDM_QUIN].num;
		slot_width = tdm_slot[TDM_QUIN].width;
		slot_offset = tdm_tx_slot_offset[TDM_QUIN];
		break;
	case AFE_PORT_ID_SENARY_TDM_TX:
		channels = tdm_tx_cfg[TDM_SEN][TDM_0].channels;
		slots = tdm_slot[TDM_SEN].num;
		slot_width = tdm_slot[TDM_SEN].width;
		slot_offset = tdm_tx_slot_offset[TDM_SEN];
		break;
	default:
		pr_err("%s: dai id 0x%x not supported\n",
@@ -6232,9 +6730,28 @@ static int qcs405_tdm_snd_hw_params(struct snd_pcm_substream *substream,
		return -EINVAL;
	}

	for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) {
		if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID)
			offset_channels++;
		else
			break;
	}

	if (offset_channels == 0) {
		pr_err("%s: invalid offset_channels %d\n",
			__func__, offset_channels);
		return -EINVAL;
	}

	if (channels > offset_channels) {
		pr_err("%s: channels %d exceed offset_channels %d\n",
			__func__, channels, offset_channels);
		return -EINVAL;
	}

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		/*2 slot config - bits 0 and 1 set for the first two slots */
		slot_mask = 0x0000FFFF >> (16-channels);
		slot_mask = 0xFFFFFFFF >> (32 - channels);

		pr_debug("%s: tdm rx slot_width %d slots %d\n",
			__func__, slot_width, slots);
@@ -6256,7 +6773,7 @@ static int qcs405_tdm_snd_hw_params(struct snd_pcm_substream *substream,
		}
	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
		/*2 slot config - bits 0 and 1 set for the first two slots */
		slot_mask = 0x0000FFFF >> (16-channels);
		slot_mask = 0xFFFFFFFF >> (32 - channels);

		pr_debug("%s: tdm tx slot_width %d slots %d\n",
			__func__, slot_width, slots);
@@ -6285,6 +6802,12 @@ static int qcs405_tdm_snd_hw_params(struct snd_pcm_substream *substream,

	rate = params_rate(params);
	clk_freq = rate * slot_width * slots;
	if (clk_freq > TDM_MAX_CLK_FREQ) {
		ret = -EINVAL;
		pr_err("%s: clk frequency > 24.576MHz %d\n",
			__func__, clk_freq);
		goto end;
	}
	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, clk_freq, SND_SOC_CLOCK_OUT);
	if (ret < 0)
		pr_err("%s: failed to set tdm clk, err:%d\n",
@@ -6319,6 +6842,10 @@ static int msm_get_tdm_mode(u32 port_id)
	case AFE_PORT_ID_QUINARY_TDM_TX:
		tdm_mode = TDM_QUIN;
		break;
	case AFE_PORT_ID_SENARY_TDM_RX:
	case AFE_PORT_ID_SENARY_TDM_TX:
		tdm_mode = TDM_SEN;
		break;
	default:
		pr_err("%s: Invalid port id: %d\n", __func__, port_id);
		tdm_mode = -EINVAL;
@@ -8022,6 +8549,35 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
		.ops = &qcs405_tdm_be_ops,
		.ignore_suspend = 1,
	},
	{
		.name = LPASS_BE_SEN_TDM_RX_0,
		.stream_name = "Senary TDM0 Playback",
		.cpu_dai_name = "msm-dai-q6-tdm.36944",
		.platform_name = "msm-pcm-routing",
		.codec_name = "msm-stub-codec.1",
		.codec_dai_name = "msm-stub-rx",
		.no_pcm = 1,
		.dpcm_playback = 1,
		.id = MSM_BACKEND_DAI_SEN_TDM_RX_0,
		.be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
		.ops = &qcs405_tdm_be_ops,
		.ignore_suspend = 1,
		.ignore_pmdown_time = 1,
	},
	{
		.name = LPASS_BE_SEN_TDM_TX_0,
		.stream_name = "Senary TDM0 Capture",
		.cpu_dai_name = "msm-dai-q6-tdm.36945",
		.platform_name = "msm-pcm-routing",
		.codec_name = "msm-stub-codec.1",
		.codec_dai_name = "msm-stub-tx",
		.no_pcm = 1,
		.dpcm_capture = 1,
		.id = MSM_BACKEND_DAI_SEN_TDM_TX_0,
		.be_hw_params_fixup = msm_be_hw_params_fixup,
		.ops = &qcs405_tdm_be_ops,
		.ignore_suspend = 1,
	},
};

static struct snd_soc_dai_link msm_tasha_be_dai_links[] = {
@@ -10047,6 +10603,8 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
					"qcom,quat-mi2s-gpios", 0);
	pdata->mi2s_gpio_p[QUIN_MI2S] = of_parse_phandle(pdev->dev.of_node,
					"qcom,quin-mi2s-gpios", 0);
	pdata->mi2s_gpio_p[SEN_MI2S] = of_parse_phandle(pdev->dev.of_node,
					"qcom,sen-mi2s-gpios", 0);

	if (of_parse_phandle(pdev->dev.of_node, micb_supply_str, 0)) {
		pdata->tdm_micb_supply = devm_regulator_get(&pdev->dev,