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

Commit f572a6f4 authored by Vignesh Kulothungan's avatar Vignesh Kulothungan
Browse files

soc: Add support for Haptics Audio



Enable frontends dais Multimedia 30 and 31.
Enable backend dai QUAT_TDM_RX_1.
Add support to configure TDM slots.

CRs-Fixed: 2419295
Change-Id: Ib06152e3c6e84ce6275fbefff54527f38877ff39
Signed-off-by: default avatarVignesh Kulothungan <vigneshk@codeaurora.org>
parent f59ba6fc
Loading
Loading
Loading
Loading
+251 −56
Original line number Diff line number Diff line
@@ -67,12 +67,14 @@
#define WSA8810_NAME_2 "wsa881x.20170212"
#define WCN_CDC_SLIM_RX_CH_MAX 2
#define WCN_CDC_SLIM_TX_CH_MAX 3
#define TDM_CHANNEL_MAX 8

#define ADSP_STATE_READY_TIMEOUT_MS 3000
#define MSM_LL_QOS_VALUE 300 /* time in us to ensure LPM doesn't go in C3/C4 */
#define MSM_HIFI_ON 1

#define TDM_MAX_SLOTS		8
#define TDM_SLOT_WIDTH_BITS	32

enum {
	SLIM_RX_0 = 0,
	SLIM_RX_1,
@@ -135,6 +137,10 @@ struct dev_config {
	u32 channels;
};

struct tdm_dev_config {
	unsigned int tdm_slot_offset[TDM_MAX_SLOTS];
};

enum {
	DP_RX_IDX = 0,
	EXT_DISP_RX_IDX_MAX,
@@ -158,6 +164,7 @@ struct msm_pinctrl_info {
	struct pinctrl_state *mi2s_active;
	struct pinctrl_state *tdm_active;
	enum pinctrl_pin_state curr_state;
	atomic_t pinctrl_ref_count;
};

struct msm_asoc_mach_data {
@@ -339,6 +346,90 @@ static struct dev_config slim_tx_cfg[] = {
	[SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
};

static struct tdm_dev_config tdm_cfg[TDM_INTERFACE_MAX * 2]
				    [TDM_PORT_MAX] = {
	{ /* PRI TDM */
		{ {0,   4, 0xFFFF} }, /* RX_0 */
		{ {8,  12, 0xFFFF} }, /* RX_1 */
		{ {16, 20, 0xFFFF} }, /* RX_2 */
		{ {24, 28, 0xFFFF} }, /* RX_3 */
		{ {0xFFFF} }, /* RX_4 */
		{ {0xFFFF} }, /* RX_5 */
		{ {0xFFFF} }, /* RX_6 */
		{ {0xFFFF} }, /* RX_7 */
	},
	{
		{ {0,   4, 0xFFFF} }, /* TX_0 */
		{ {8,  12, 0xFFFF} }, /* TX_1 */
		{ {16, 20, 0xFFFF} }, /* TX_2 */
		{ {24, 28, 0xFFFF} }, /* TX_3 */
		{ {0xFFFF} }, /* TX_4 */
		{ {0xFFFF} }, /* TX_5 */
		{ {0xFFFF} }, /* TX_6 */
		{ {0xFFFF} }, /* TX_7 */
	},
	{ /* SEC TDM */
		{ {0,   4, 0xFFFF} }, /* RX_0 */
		{ {8,  12, 0xFFFF} }, /* RX_1 */
		{ {16, 20, 0xFFFF} }, /* RX_2 */
		{ {24, 28, 0xFFFF} }, /* RX_3 */
		{ {0xFFFF} }, /* RX_4 */
		{ {0xFFFF} }, /* RX_5 */
		{ {0xFFFF} }, /* RX_6 */
		{ {0xFFFF} }, /* RX_7 */
	},
	{
		{ {0,   4, 0xFFFF} }, /* TX_0 */
		{ {8,  12, 0xFFFF} }, /* TX_1 */
		{ {16, 20, 0xFFFF} }, /* TX_2 */
		{ {24, 28, 0xFFFF} }, /* TX_3 */
		{ {0xFFFF} }, /* TX_4 */
		{ {0xFFFF} }, /* TX_5 */
		{ {0xFFFF} }, /* TX_6 */
		{ {0xFFFF} }, /* TX_7 */
	},
	{ /* TERT TDM */
		{ {0,   4, 0xFFFF} }, /* RX_0 */
		{ {8,  12, 0xFFFF} }, /* RX_1 */
		{ {16, 20, 0xFFFF} }, /* RX_2 */
		{ {24, 28, 0xFFFF} }, /* RX_3 */
		{ {0xFFFF} }, /* RX_4 */
		{ {0xFFFF} }, /* RX_5 */
		{ {0xFFFF} }, /* RX_6 */
		{ {0xFFFF} }, /* RX_7 */
	},
	{
		{ {0,   4, 0xFFFF} }, /* TX_0 */
		{ {8,  12, 0xFFFF} }, /* TX_1 */
		{ {16, 20, 0xFFFF} }, /* TX_2 */
		{ {24, 28, 0xFFFF} }, /* TX_3 */
		{ {0xFFFF} }, /* TX_4 */
		{ {0xFFFF} }, /* TX_5 */
		{ {0xFFFF} }, /* TX_6 */
		{ {0xFFFF} }, /* TX_7 */
	},
	{ /* QUAT TDM */
		{ {0,   4, 0xFFFF} }, /* RX_0 */
		{ {8,  12, 0xFFFF} }, /* RX_1 */
		{ {16, 20, 0xFFFF} }, /* RX_2 */
		{ {24, 28, 0xFFFF} }, /* RX_3 */
		{ {0xFFFF} }, /* RX_4 */
		{ {0xFFFF} }, /* RX_5 */
		{ {0xFFFF} }, /* RX_6 */
		{ {0xFFFF} }, /* RX_7 */
	},
	{
		{ {0,   4, 0xFFFF} }, /* TX_0 */
		{ {8,  12, 0xFFFF} }, /* TX_1 */
		{ {16, 20, 0xFFFF} }, /* TX_2 */
		{ {24, 28, 0xFFFF} }, /* TX_3 */
		{ {0xFFFF} }, /* TX_4 */
		{ {0xFFFF} }, /* TX_5 */
		{ {0xFFFF} }, /* TX_6 */
		{ {0xFFFF} }, /* TX_7 */
	},
};

/* Default configuration of external display BE */
static struct dev_config ext_disp_rx_cfg[] = {
	[DP_RX_IDX] =   {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
@@ -2226,6 +2317,43 @@ static int tdm_tx_ch_put(struct snd_kcontrol *kcontrol,
	return ret;
}

static int tdm_slot_map_put(struct snd_kcontrol *kcontrol,
			struct snd_ctl_elem_value *ucontrol)
{
	int interface = ucontrol->value.integer.value[0];
	int channel = ucontrol->value.integer.value[1];
	unsigned int offset_val;
	unsigned int *slot_offset;

	if (interface < 0  || interface >= (TDM_INTERFACE_MAX * 2)) {
		pr_err("%s: incorrect interface = %d", __func__, interface);
		return -EINVAL;
	}
	if (channel < 0  || channel >= TDM_PORT_MAX) {
		pr_err("%s: incorrect channel = %d", __func__, channel);
		return -EINVAL;
	}

	pr_debug("%s: interface = %d, channel = %d", __func__,
		interface, channel);

	slot_offset = tdm_cfg[interface][channel].tdm_slot_offset;

	/* Currenly can configure only two slots */
	offset_val = ucontrol->value.integer.value[2];
	/* Offset value can only be 0, 4, 8, ..28 */
	if (offset_val % 4 == 0 && offset_val <= 28)
		slot_offset[0] = offset_val;
	pr_debug("%s: slot offset[0] = %d\n", __func__, slot_offset[0]);

	offset_val = ucontrol->value.integer.value[3];
	if (offset_val % 4 == 0 && offset_val <= 28)
		slot_offset[1] = offset_val;
	pr_debug("%s: slot offset[1] = %d\n", __func__, slot_offset[1]);

	return 0;
}

static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
{
	int idx;
@@ -2943,18 +3071,27 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
	SOC_ENUM_EXT("QUAT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
			tdm_rx_sample_rate_get,
			tdm_rx_sample_rate_put),
	SOC_ENUM_EXT("QUAT_TDM_RX_1 SampleRate", tdm_rx_sample_rate,
			tdm_rx_sample_rate_get,
			tdm_rx_sample_rate_put),
	SOC_ENUM_EXT("QUAT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
			tdm_tx_sample_rate_get,
			tdm_tx_sample_rate_put),
	SOC_ENUM_EXT("QUAT_TDM_RX_0 Format", tdm_rx_format,
			tdm_rx_format_get,
			tdm_rx_format_put),
	SOC_ENUM_EXT("QUAT_TDM_RX_1 Format", tdm_rx_format,
			tdm_rx_format_get,
			tdm_rx_format_put),
	SOC_ENUM_EXT("QUAT_TDM_TX_0 Format", tdm_tx_format,
			tdm_tx_format_get,
			tdm_tx_format_put),
	SOC_ENUM_EXT("QUAT_TDM_RX_0 Channels", tdm_rx_chs,
			tdm_rx_ch_get,
			tdm_rx_ch_put),
	SOC_ENUM_EXT("QUAT_TDM_RX_1 Channels", tdm_rx_chs,
			tdm_rx_ch_get,
			tdm_rx_ch_put),
	SOC_ENUM_EXT("QUAT_TDM_TX_0 Channels", tdm_tx_chs,
			tdm_tx_ch_get,
			tdm_tx_ch_put),
@@ -3098,6 +3235,8 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
			msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
	SOC_ENUM_EXT("HiFi Function", hifi_function, msm_hifi_get,
			msm_hifi_put),
	SOC_SINGLE_MULTI_EXT("TDM Slot Map", SND_SOC_NOPM, 0, 255, 0, 4,
	NULL, tdm_slot_map_put),

};

@@ -3345,8 +3484,10 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
	void *config = NULL;
	struct snd_soc_codec *codec = NULL;

	pr_debug("%s: format = %d, rate = %d\n",
		  __func__, params_format(params), params_rate(params));
	pr_debug("%s: dai_id= %d, format = %d, rate = %d\n",
		  __func__, dai_link->id, params_format(params),
		  params_rate(params));


	switch (dai_link->id) {
	case MSM_BACKEND_DAI_SLIMBUS_0_RX:
@@ -4612,6 +4753,7 @@ static int msm_get_pinctrl(struct platform_device *pdev)
		goto err;
	}
	pinctrl_info->curr_state = STATE_DISABLE;
	atomic_set(&(pinctrl_info->pinctrl_ref_count), 0);

	return 0;

@@ -4637,6 +4779,13 @@ static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
			       tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
		rate->min = rate->max =
				tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
	} else if (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX_1) {
		channels->min = channels->max =
				tdm_rx_cfg[TDM_QUAT][TDM_1].channels;
		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
			       tdm_rx_cfg[TDM_QUAT][TDM_1].bit_format);
		rate->min = rate->max =
				tdm_rx_cfg[TDM_QUAT][TDM_1].sample_rate;
	} else if (cpu_dai->id == AFE_PORT_ID_SECONDARY_TDM_RX) {
		channels->min = channels->max =
				tdm_rx_cfg[TDM_SEC][TDM_0].channels;
@@ -4668,59 +4817,50 @@ static int sm8150_tdm_snd_hw_params(struct snd_pcm_substream *substream,
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	int ret = 0;
	int slot_width = 32;
	int channels, slots;
	int slot_width = TDM_SLOT_WIDTH_BITS;
	int channels, slots = TDM_MAX_SLOTS;
	unsigned int slot_mask, rate, clk_freq;
	unsigned int slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
	unsigned int *slot_offset;
	unsigned int path_dir = 0, interface = 0, channel_interface = 0;

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

	/* currently only supporting TDM_RX_0 and TDM_TX_0 */
	switch (cpu_dai->id) {
	case AFE_PORT_ID_PRIMARY_TDM_RX:
		slots = tdm_rx_cfg[TDM_PRI][TDM_0].channels;
		break;
	case AFE_PORT_ID_SECONDARY_TDM_RX:
		slots = tdm_rx_cfg[TDM_SEC][TDM_0].channels;
		break;
	case AFE_PORT_ID_TERTIARY_TDM_RX:
		slots = tdm_rx_cfg[TDM_TERT][TDM_0].channels;
		break;
	case AFE_PORT_ID_QUATERNARY_TDM_RX:
		slots = tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
		break;
	case AFE_PORT_ID_QUINARY_TDM_RX:
		slots = tdm_rx_cfg[TDM_QUIN][TDM_0].channels;
		break;
	case AFE_PORT_ID_PRIMARY_TDM_TX:
		slots = tdm_tx_cfg[TDM_PRI][TDM_0].channels;
		break;
	case AFE_PORT_ID_SECONDARY_TDM_TX:
		slots = tdm_tx_cfg[TDM_SEC][TDM_0].channels;
		break;
	case AFE_PORT_ID_TERTIARY_TDM_TX:
		slots = tdm_tx_cfg[TDM_TERT][TDM_0].channels;
		break;
	case AFE_PORT_ID_QUATERNARY_TDM_TX:
		slots = tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
		break;
         case AFE_PORT_ID_QUINARY_TDM_TX:
                 slots = tdm_tx_cfg[TDM_QUIN][TDM_0].channels;
                 break;
	pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);

	default:
	if (cpu_dai->id < AFE_PORT_ID_TDM_PORT_RANGE_START) {
		pr_err("%s: dai id 0x%x not supported\n",
			__func__, cpu_dai->id);
		return -EINVAL;
	}

	/* RX or TX */
	path_dir = cpu_dai->id % 2;

	/* PRI, SEC, TERT, QUAT, QUIN */
	interface = (cpu_dai->id - AFE_PORT_ID_TDM_PORT_RANGE_START)
			/ (2 * TDM_PORT_MAX);

	/* 0, 1, 2, .. 7 */
	channel_interface =
		((cpu_dai->id - AFE_PORT_ID_TDM_PORT_RANGE_START) / 2)
		% TDM_PORT_MAX;

	pr_debug("%s: interface %u, channel interface %u\n", __func__,
		interface, channel_interface);

	slot_offset = tdm_cfg[(interface * 2) + path_dir][channel_interface]
			.tdm_slot_offset;

	if (path_dir)
		channels = tdm_tx_cfg[interface][channel_interface].channels;
	else
		channels = tdm_rx_cfg[interface][channel_interface].channels;

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

		pr_debug("%s: tdm rx slot_width %d slots %d\n",
			__func__, slot_width, slots);
		pr_debug("%s: tdm rx slot_width %d slots %d slot_mask %x\n",
			__func__, slot_width, slots, slot_mask);

		ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
			slots, slot_width);
@@ -4730,6 +4870,9 @@ static int sm8150_tdm_snd_hw_params(struct snd_pcm_substream *substream,
			goto end;
		}

		pr_debug("%s: tdm rx slot_offset[0]: %d, slot_offset[1]: %d\n",
			__func__, slot_offset[0], slot_offset[1]);

		ret = snd_soc_dai_set_channel_map(cpu_dai,
			0, NULL, channels, slot_offset);
		if (ret < 0) {
@@ -4740,7 +4883,6 @@ static int sm8150_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-slots);
		channels = slots;

		pr_debug("%s: tdm tx slot_width %d slots %d\n",
			__func__, slot_width, slots);
@@ -4787,14 +4929,18 @@ static int sm8150_tdm_snd_startup(struct snd_pcm_substream *substream)
	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;

	/* currently only supporting TDM_RX_0 and TDM_TX_0 */
	/* currently only supporting TDM_RX_0/TDM_RX_1 and TDM_TX_0 */
	if ((cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) ||
		(cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_TX)) {
		(cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_TX) ||
		(cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX_1)) {
		if (atomic_read(&(pinctrl_info->pinctrl_ref_count)) == 0) {
			ret = msm_set_pinctrl(pinctrl_info, STATE_TDM_ACTIVE);
			if (ret)
				pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
					__func__, ret);
		}
		atomic_inc(&(pinctrl_info->pinctrl_ref_count));
	}

	return ret;
}
@@ -4808,15 +4954,19 @@ static void sm8150_tdm_snd_shutdown(struct snd_pcm_substream *substream)
	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;

	/* currently only supporting TDM_RX_0 and TDM_TX_0 */
	/* currently only supporting TDM_RX_0/TDM_RX_1 and TDM_TX_0 */
	if ((cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) ||
		(cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_TX)) {
		(cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_TX) ||
		(cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX_1)) {
		atomic_dec(&(pinctrl_info->pinctrl_ref_count));
		if (atomic_read(&(pinctrl_info->pinctrl_ref_count)) == 0) {
			ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
			if (ret)
				pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
					__func__, ret);
		}
	}
}

static struct snd_soc_ops sm8150_tdm_be_ops = {
	.hw_params = sm8150_tdm_snd_hw_params,
@@ -5686,6 +5836,36 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
		.ignore_pmdown_time = 1,
		.id = MSM_FRONTEND_DAI_MULTIMEDIA17,
	},
	{
		.name = "MultiMedia30 Playback",
		.stream_name = "MultiMedia30",
		.cpu_dai_name = "MultiMedia30",
		.platform_name = "msm-pcm-dsp.1",
		.dynamic = 1,
		.dpcm_playback = 1,
		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
			    SND_SOC_DPCM_TRIGGER_POST},
		.codec_dai_name = "snd-soc-dummy-dai",
		.codec_name = "snd-soc-dummy",
		.ignore_suspend = 1,
		.ignore_pmdown_time = 1,
		.id = MSM_FRONTEND_DAI_MULTIMEDIA30,
	},
	{
		.name = "MultiMedia31 Playback",
		.stream_name = "MultiMedia31",
		.cpu_dai_name = "MultiMedia31",
		.platform_name = "msm-pcm-dsp.1",
		.dynamic = 1,
		.dpcm_playback = 1,
		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
			    SND_SOC_DPCM_TRIGGER_POST},
		.codec_dai_name = "snd-soc-dummy-dai",
		.codec_name = "snd-soc-dummy",
		.ignore_suspend = 1,
		.ignore_pmdown_time = 1,
		.id = MSM_FRONTEND_DAI_MULTIMEDIA31,
	},
};

static struct snd_soc_dai_link msm_common_be_dai_links[] = {
@@ -5919,6 +6099,21 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
		.ops = &sm8150_tdm_be_ops,
		.ignore_suspend = 1,
	},
	{
		.name = LPASS_BE_QUAT_TDM_RX_1,
		.stream_name = "Quaternary TDM1 Playback",
		.cpu_dai_name = "msm-dai-q6-tdm.36914",
		.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_QUAT_TDM_RX_1,
		.be_hw_params_fixup = msm_be_hw_params_fixup,
		.ops = &sm8150_tdm_be_ops,
		.ignore_suspend = 1,
		.ignore_pmdown_time = 1,
	},
};

static struct snd_soc_dai_link msm_pahu_be_dai_links[] = {