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

Commit c06d92dd authored by Xiaojun Sang's avatar Xiaojun Sang Committed by Banajit Goswami
Browse files

ASoC: msm: add support for ADSP Stream Cmd and Callback



Add support for ADSP Stream Cmd and Callback for PCM
and compress driver. Mixer controls are added as interface
for ADSP stream cmd and callback event.

CRs-Fixed: 2023802
Change-Id: Ib2de5aebe257332171c3b1ebe3d26b3422d61c97
Signed-off-by: default avatarXiaojun Sang <xsang@codeaurora.org>
parent b840d357
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -444,6 +444,11 @@ struct adm_param_data_v5 {
	 */
} __packed;

#define ASM_STREAM_CMD_REGISTER_PP_EVENTS 0x00013213
#define ASM_STREAM_PP_EVENT 0x00013214
#define DSP_STREAM_CMD "ADSP Stream Cmd"
#define DSP_STREAM_CALLBACK "ADSP Stream Callback Event"

/* set customized mixing on matrix mixer */
#define ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5                        0x00010344
struct adm_cmd_set_pspd_mtmx_strtr_params_v5 {
+3 −0
Original line number Diff line number Diff line
@@ -618,6 +618,9 @@ int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp);
int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
				    uint32_t params_length);

int q6asm_send_stream_cmd(struct audio_client *ac, uint32_t opcode,
			void *param, uint32_t params_length);

/* Client can set the IO mode to either AIO/SIO mode */
int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode);

+209 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include <sound/msm-dts-eagle.h>

#include "msm-pcm-routing-v2.h"
#include "msm-qti-pp-config.h"

#define DSP_PP_BUFFERING_IN_MSEC	25
#define PARTIAL_DRAIN_ACK_EARLY_BY_MSEC	150
@@ -545,12 +546,19 @@ static void compr_event_handler(uint32_t opcode,
	unsigned long flags;
	uint64_t read_size;
	uint32_t *buff_addr;
	struct snd_soc_pcm_runtime *rtd;
	int ret = 0;

	if (!prtd) {
		pr_err("%s: prtd is NULL\n", __func__);
		return;
	}
	cstream = prtd->cstream;
	if (!cstream) {
		pr_err("%s: cstream is NULL\n", __func__);
		return;
	}

	ac = prtd->audio_client;

	/*
@@ -717,6 +725,23 @@ static void compr_event_handler(uint32_t opcode,
		if (prtd->gapless_state.gapless_transition)
			prtd->gapless_state.gapless_transition = 0;
		spin_unlock_irqrestore(&prtd->lock, flags);
		break;
	case ASM_STREAM_PP_EVENT:
		pr_debug("%s: ASM_STREAM_PP_EVENT\n", __func__);
		rtd = cstream->private_data;
		if (!rtd) {
			pr_err("%s: rtd is NULL\n", __func__);
			return;
		}

		ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK,
					payload);
		if (ret) {
			pr_err("%s: failed to inform mixer ctrl. err = %d\n",
				__func__, ret);
			return;
		}

		break;
	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
	case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: {
@@ -821,6 +846,10 @@ static void compr_event_handler(uint32_t opcode,
			}
			atomic_set(&prtd->close, 0);
			break;
		case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
			pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
				__func__);
			break;
		default:
			break;
		}
@@ -3589,6 +3618,65 @@ static int msm_compr_channel_map_get(struct snd_kcontrol *kcontrol,
	return rc;
}

static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
	unsigned long fe_id = kcontrol->private_value;
	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
				snd_soc_component_get_drvdata(comp);
	struct snd_compr_stream *cstream = NULL;
	struct msm_compr_audio *prtd;
	int ret = 0, param_length = 0;

	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
		pr_err("%s Received invalid fe_id %lu\n",
			__func__, fe_id);
		ret = -EINVAL;
		goto done;
	}

	cstream = pdata->cstream[fe_id];
	if (cstream == NULL) {
		pr_err("%s cstream is null.\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	prtd = cstream->runtime->private_data;
	if (!prtd) {
		pr_err("%s: prtd is null.\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	if (prtd->audio_client == NULL) {
		pr_err("%s: audio_client is null.\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	memcpy(&param_length, ucontrol->value.bytes.data,
		sizeof(param_length));
	if ((param_length + sizeof(param_length))
		>= sizeof(ucontrol->value.bytes.data)) {
		pr_err("%s param length=%d  exceeds limit",
			__func__, param_length);
		ret = -EINVAL;
		goto done;
	}

	ret = q6asm_send_stream_cmd(prtd->audio_client,
			ASM_STREAM_CMD_REGISTER_PP_EVENTS,
			ucontrol->value.bytes.data + sizeof(param_length),
			param_length);
	if (ret < 0)
		pr_err("%s: failed to register pp event. err = %d\n",
			__func__, ret);
done:
	return ret;
}

static int msm_compr_gapless_put(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
@@ -3863,6 +3951,117 @@ static int msm_compr_add_query_audio_effect_control(
	return 0;
}

static int msm_compr_add_audio_adsp_stream_cmd_control(
			struct snd_soc_pcm_runtime *rtd)
{
	const char *mixer_ctl_name = DSP_STREAM_CMD;
	const char *deviceNo = "NN";
	char *mixer_str = NULL;
	int ctl_len = 0, ret = 0;
	struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
		{
		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
		.name = "?",
		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
		.info = msm_adsp_stream_cmd_info,
		.put = msm_compr_adsp_stream_cmd_put,
		.private_value = 0,
		}
	};

	if (!rtd) {
		pr_err("%s NULL rtd\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
	if (!mixer_str) {
		ret = -ENOMEM;
		goto done;
	}

	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
	fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
	fe_audio_adsp_stream_cmd_config_control[0].private_value =
				rtd->dai_link->id;
	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
	ret = snd_soc_add_platform_controls(rtd->platform,
		fe_audio_adsp_stream_cmd_config_control,
		ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
	if (ret < 0)
		pr_err("%s: failed to add ctl %s. err = %d\n",
			__func__, mixer_str, ret);

	kfree(mixer_str);
done:
	return ret;
}

static int msm_compr_add_audio_adsp_stream_callback_control(
			struct snd_soc_pcm_runtime *rtd)
{
	const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
	const char *deviceNo = "NN";
	char *mixer_str = NULL;
	int ctl_len = 0, ret = 0;
	struct snd_kcontrol *kctl;

	struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
		{
		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
		.name = "?",
		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
		.info = msm_adsp_stream_callback_info,
		.get = msm_adsp_stream_callback_get,
		.put = msm_adsp_stream_callback_put,
		.private_value = 0,
		}
	};

	if (!rtd) {
		pr_err("%s: rtd is  NULL\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
	if (!mixer_str) {
		ret = -ENOMEM;
		goto done;
	}

	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
	fe_audio_adsp_callback_config_control[0].name = mixer_str;
	fe_audio_adsp_callback_config_control[0].private_value =
					rtd->dai_link->id;
	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
	ret = snd_soc_add_platform_controls(rtd->platform,
			fe_audio_adsp_callback_config_control,
			ARRAY_SIZE(fe_audio_adsp_callback_config_control));
	if (ret < 0) {
		pr_err("%s: failed to add ctl %s. err = %d\n",
			__func__, mixer_str, ret);
		ret = -EINVAL;
		goto free_mixer_str;
	}

	kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
	if (!kctl) {
		pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
		ret = -EINVAL;
		goto free_mixer_str;
	}

	kctl->private_data = NULL;
free_mixer_str:
	kfree(mixer_str);
done:
	return ret;
}

static int msm_compr_add_dec_runtime_params_control(
						struct snd_soc_pcm_runtime *rtd)
{
@@ -4050,6 +4249,16 @@ static int msm_compr_new(struct snd_soc_pcm_runtime *rtd)
		pr_err("%s: Could not add Compr Audio Effects Control\n",
			__func__);

	rc = msm_compr_add_audio_adsp_stream_cmd_control(rtd);
	if (rc)
		pr_err("%s: Could not add Compr ADSP Stream Cmd Control\n",
			__func__);

	rc = msm_compr_add_audio_adsp_stream_callback_control(rtd);
	if (rc)
		pr_err("%s: Could not add Compr ADSP Stream Callback Control\n",
			__func__);

	rc = msm_compr_add_query_audio_effect_control(rtd);
	if (rc)
		pr_err("%s: Could not add Compr Query Audio Effect Control\n",
+211 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@

#include "msm-pcm-q6-v2.h"
#include "msm-pcm-routing-v2.h"
#include "msm-qti-pp-config.h"

enum stream_state {
	IDLE = 0,
@@ -148,6 +149,8 @@ static void event_handler(uint32_t opcode,
	uint32_t idx = 0;
	uint32_t size = 0;
	uint8_t buf_index;
	struct snd_soc_pcm_runtime *rtd;
	int ret = 0;

	switch (opcode) {
	case ASM_DATA_EVENT_WRITE_DONE_V2: {
@@ -224,6 +227,29 @@ static void event_handler(uint32_t opcode,
		}
		break;
	}
	case ASM_STREAM_PP_EVENT: {
		pr_debug("%s: ASM_STREAM_PP_EVENT\n", __func__);
		if (!substream) {
			pr_err("%s: substream is NULL.\n", __func__);
			return;
		}

		rtd = substream->private_data;
		if (!rtd) {
			pr_err("%s: rtd is NULL\n", __func__);
			return;
		}

		ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK,
					payload);
		if (ret) {
			pr_err("%s: failed to inform mixer ctl. err = %d\n",
				__func__, ret);
			return;
		}

		break;
	}
	case APR_BASIC_RSP_RESULT: {
		switch (payload[0]) {
		case ASM_SESSION_CMD_RUN_V2:
@@ -253,6 +279,10 @@ static void event_handler(uint32_t opcode,
			}
			atomic_set(&prtd->start, 1);
			break;
		case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
			pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
				__func__);
			break;
		default:
			pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
				__func__, payload[0], payload[1]);
@@ -1036,6 +1066,177 @@ static const struct snd_pcm_ops msm_pcm_ops = {
	.mmap		= msm_pcm_mmap,
};

static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
	struct snd_soc_platform *platform = snd_soc_component_to_platform(pcm);
	struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
	struct snd_pcm_substream *substream;
	struct msm_audio *prtd;
	int ret = 0, param_length = 0;

	if (!pdata) {
		pr_err("%s pdata is NULL\n", __func__);
		ret = -ENODEV;
		goto done;
	}

	substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
	if (!substream) {
		pr_err("%s substream not found\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	if (!substream->runtime) {
		pr_err("%s substream runtime not found\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	prtd = substream->runtime->private_data;
	if (prtd->audio_client == NULL) {
		pr_err("%s prtd is null.\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	memcpy(&param_length, ucontrol->value.bytes.data,
		sizeof(param_length));
	if ((param_length + sizeof(param_length))
		>= sizeof(ucontrol->value.bytes.data)) {
		pr_err("%s param length=%d  exceeds limit",
			__func__, param_length);
		ret = -EINVAL;
		goto done;
	}

	ret = q6asm_send_stream_cmd(prtd->audio_client,
			ASM_STREAM_CMD_REGISTER_PP_EVENTS,
			ucontrol->value.bytes.data + sizeof(param_length),
			param_length);
	if (ret < 0)
		pr_err("%s: failed to register pp event. err = %d\n",
			__func__, ret);
done:
	return ret;
}

static int msm_pcm_add_audio_adsp_stream_cmd_control(
			struct snd_soc_pcm_runtime *rtd)
{
	const char *mixer_ctl_name = DSP_STREAM_CMD;
	const char *deviceNo = "NN";
	char *mixer_str = NULL;
	int ctl_len = 0, ret = 0;
	struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
		{
		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
		.name = "?",
		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
		.info = msm_adsp_stream_cmd_info,
		.put = msm_pcm_adsp_stream_cmd_put,
		.private_value = 0,
		}
	};

	if (!rtd) {
		pr_err("%s rtd is NULL\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
	if (!mixer_str) {
		ret = -ENOMEM;
		goto done;
	}

	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
	fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
	fe_audio_adsp_stream_cmd_config_control[0].private_value =
		rtd->dai_link->id;
	pr_debug("Registering new mixer ctl %s\n", mixer_str);
	ret = snd_soc_add_platform_controls(rtd->platform,
		fe_audio_adsp_stream_cmd_config_control,
		ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
	if (ret < 0)
		pr_err("%s: failed add ctl %s. err = %d\n",
			__func__, mixer_str, ret);

	kfree(mixer_str);
done:
	return ret;
}

static int msm_pcm_add_audio_adsp_stream_callback_control(
			struct snd_soc_pcm_runtime *rtd)
{
	const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
	const char *deviceNo = "NN";
	char *mixer_str = NULL;
	int ctl_len = 0, ret = 0;
	struct snd_kcontrol *kctl;

	struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
		{
		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
		.name = "?",
		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
		.info = msm_adsp_stream_callback_info,
		.get = msm_adsp_stream_callback_get,
		.put = msm_adsp_stream_callback_put,
		.private_value = 0,
		}
	};

	if (!rtd) {
		pr_err("%s NULL rtd\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
		 __func__, rtd->dai_link->name, rtd->dai_link->id,
		 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
	if (!mixer_str) {
		ret = -ENOMEM;
		goto done;
	}

	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
	fe_audio_adsp_callback_config_control[0].name = mixer_str;
	fe_audio_adsp_callback_config_control[0].private_value =
		rtd->dai_link->id;
	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
	ret = snd_soc_add_platform_controls(rtd->platform,
			fe_audio_adsp_callback_config_control,
			ARRAY_SIZE(fe_audio_adsp_callback_config_control));
	if (ret < 0) {
		pr_err("%s: failed to add ctl %s. err = %d\n",
			__func__, mixer_str, ret);
		ret = -EINVAL;
		goto free_mixer_str;
	}

	kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
	if (!kctl) {
		pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
		ret = -EINVAL;
		goto free_mixer_str;
	}

	kctl->private_data = NULL;
free_mixer_str:
	kfree(mixer_str);
done:
	return ret;
}

static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
{
	int rc = 0;
@@ -1550,6 +1751,16 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
		pr_err("%s: Could not add pcm Compress Control %d\n",
			__func__, ret);

	ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd);
	if (ret)
		pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n",
			__func__);

	ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd);
	if (ret)
		pr_err("%s: Could not add pcm ADSP Stream Callback Control\n",
			__func__);

	return ret;
}

+130 −0
Original line number Diff line number Diff line
@@ -821,6 +821,136 @@ static int msm_qti_pp_asphere_set(struct snd_kcontrol *kcontrol,
	return 0;
}


int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
			const char *mixer_ctl_name,
			uint32_t *payload)
{
	/* adsp pp event notifier */
	struct snd_kcontrol *kctl;
	struct snd_ctl_elem_value control;
	uint32_t payload_size = 0;
	const char *deviceNo = "NN";
	char *mixer_str = NULL;
	int ctl_len = 0, ret = 0;

	if (!rtd || !payload) {
		pr_err("%s: %s is NULL\n", __func__,
			(!rtd) ? "rtd" : "payload");
		ret = -EINVAL;
		goto done;
	}

	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
	mixer_str = kzalloc(ctl_len, GFP_ATOMIC);
	if (!mixer_str) {
		ret = -EINVAL;
		goto done;
	}

	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name,
		rtd->pcm->device);
	kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
	kfree(mixer_str);
	if (!kctl) {
		pr_err("%s: failed to get kctl.\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	control.id = kctl->id;
	payload_size = payload[0];
	/* Copy complete payload */
	memcpy(control.value.bytes.data, (void *)payload,
		sizeof(payload_size) + payload_size);
	kctl->put(kctl, &control);
	if (rtd->card->snd_card == NULL) {
		pr_err("%s: snd_card is null.\n", __func__);
		ret = -EINVAL;
		goto done;
	}

	snd_ctl_notify(rtd->card->snd_card,
			SNDRV_CTL_EVENT_MASK_INFO,
			&control.id);
done:
	return ret;
}

int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol,
			struct snd_ctl_elem_info *uinfo)
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
	uinfo->count = 512;

	return 0;
}

int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol,
			struct snd_ctl_elem_value *ucontrol)
{
	uint32_t payload_size = 0, last_payload_size = 0;

	/* fetch payload size in first four bytes */
	memcpy(&payload_size, ucontrol->value.bytes.data, sizeof(uint32_t));

	if (kcontrol->private_data == NULL) {
		/* buffer is empty */
		kcontrol->private_data =
			kzalloc(payload_size + sizeof(payload_size),
				GFP_ATOMIC);
		if (kcontrol->private_data == NULL)
			return -ENOMEM;
	} else {
		memcpy(&last_payload_size, kcontrol->private_data,
			sizeof(uint32_t));
		if (last_payload_size < payload_size) {
			/* new payload size exceeds old one.
			 * reallocate buffer
			 */
			kfree(kcontrol->private_data);
			kcontrol->private_data =
				kzalloc(payload_size + sizeof(payload_size),
					GFP_ATOMIC);
			if (kcontrol->private_data == NULL)
				return -ENOMEM;
		}
	}

	memcpy(kcontrol->private_data, ucontrol->value.bytes.data,
			sizeof(uint32_t) + payload_size);

	return 0;
}

int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol,
			struct snd_ctl_elem_value *ucontrol)
{
	uint32_t payload_size = 0;

	if (kcontrol->private_data == NULL) {
		pr_err("%s: ASM Stream PP Event Data Unavailable\n", __func__);
		return -EINVAL;
	}

	memcpy(&payload_size, kcontrol->private_data, sizeof(uint32_t));
	memcpy(ucontrol->value.bytes.data, kcontrol->private_data,
		sizeof(uint32_t) + payload_size);
	kfree(kcontrol->private_data);
	kcontrol->private_data = NULL;

	return 0;
}

int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol,
			struct snd_ctl_elem_info *uinfo)
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
	uinfo->count = 512;

	return 0;
}

static int msm_multichannel_ec_primary_mic_ch_put(struct snd_kcontrol *kcontrol,
			struct snd_ctl_elem_value *ucontrol)
{
Loading