Merge "ASoC: msm: Add support for DSP based DTMF generation"
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 23c1d51..bfd7208 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -157,6 +157,55 @@
u16 reserved;
} __attribute__ ((packed));
+/*
+ * Opcode for AFE to start DTMF.
+ */
+#define AFE_PORTS_CMD_DTMF_CTL 0x00010102
+
+/** DTMF payload.*/
+struct afe_dtmf_generation_command {
+ struct apr_hdr hdr;
+
+ /*
+ * Duration of the DTMF tone in ms.
+ * -1 -> continuous,
+ * 0 -> disable
+ */
+ int64_t duration_in_ms;
+
+ /*
+ * The DTMF high tone frequency.
+ */
+ uint16_t high_freq;
+
+ /*
+ * The DTMF low tone frequency.
+ */
+ uint16_t low_freq;
+
+ /*
+ * The DTMF volume setting
+ */
+ uint16_t gain;
+
+ /*
+ * The number of ports to enable/disable on.
+ */
+ uint16_t num_ports;
+
+ /*
+ * The Destination ports - array .
+ * For DTMF on multiple ports, portIds needs to
+ * be populated numPorts times.
+ */
+ uint16_t port_ids;
+
+ /*
+ * variable for 32 bit alignment of APR packet.
+ */
+ uint16_t reserved;
+} __packed;
+
#define AFE_PCM_CFG_MODE_PCM 0x0
#define AFE_PCM_CFG_MODE_AUX 0x1
#define AFE_PCM_CFG_SYNC_EXT 0x0
diff --git a/include/sound/q6afe.h b/include/sound/q6afe.h
index 8451ac6..1e12d48 100644
--- a/include/sound/q6afe.h
+++ b/include/sound/q6afe.h
@@ -88,7 +88,10 @@
int afe_cmd_memory_map_nowait(u32 dma_addr_p, u32 dma_buf_sz);
int afe_cmd_memory_unmap(u32 dma_addr_p);
int afe_cmd_memory_unmap_nowait(u32 dma_addr_p);
-
+void afe_set_dtmf_gen_rx_portid(u16 rx_port_id, int set);
+int afe_dtmf_generate_rx(int64_t duration_in_ms,
+ uint16_t high_freq,
+ uint16_t low_freq, uint16_t gain);
int afe_register_get_events(u16 port_id,
void (*cb) (uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv),
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 99302eb..a261184 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -58,7 +58,7 @@
snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
-obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o
+obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o msm-pcm-dtmf.o
snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index e91ed86..0926865 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -503,6 +503,20 @@
.ops = &msm_fe_Multimedia_dai_ops,
.name = "Pseudo",
},
+ {
+ .playback = {
+ .stream_name = "DTMF_RX Hostless Playback",
+ .aif_name = "DTMF_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "DTMF_RX_HOSTLESS",
+ },
};
static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm-pcm-dtmf.c b/sound/soc/msm/msm-pcm-dtmf.c
new file mode 100644
index 0000000..04ab7a9
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-dtmf.c
@@ -0,0 +1,100 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/q6afe.h>
+
+static int msm_dtmf_rx_generate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint16_t low_freq = ucontrol->value.integer.value[0];
+ uint16_t high_freq = ucontrol->value.integer.value[1];
+ int64_t duration = ucontrol->value.integer.value[2];
+ uint16_t gain = ucontrol->value.integer.value[3];
+
+ pr_debug("%s: low_freq=%d high_freq=%d duration=%d gain=%d\n",
+ __func__, low_freq, high_freq, (int)duration, gain);
+ afe_dtmf_generate_rx(duration, high_freq, low_freq, gain);
+ return 0;
+}
+
+static int msm_dtmf_rx_generate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s:\n", __func__);
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static struct snd_kcontrol_new msm_dtmf_controls[] = {
+ SOC_SINGLE_MULTI_EXT("DTMF_Generate Rx Low High Duration Gain",
+ SND_SOC_NOPM, 0, 5000, 0, 4,
+ msm_dtmf_rx_generate_get,
+ msm_dtmf_rx_generate_put),
+};
+
+static int msm_pcm_dtmf_probe(struct snd_soc_platform *platform)
+{
+ snd_soc_add_platform_controls(platform, msm_dtmf_controls,
+ ARRAY_SIZE(msm_dtmf_controls));
+ return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {};
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .probe = msm_pcm_dtmf_probe,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+ pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-dtmf",
+ .owner = THIS_MODULE,
+ },
+ .probe = msm_pcm_probe,
+ .remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("DTMF platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 378baf1..1ddb6c9 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -655,6 +655,14 @@
else
clear_bit(val, &msm_bedais[reg].fe_sessions);
+ if (val == MSM_FRONTEND_DAI_DTMF_RX &&
+ afe_get_port_type(msm_bedais[reg].port_id) ==
+ MSM_AFE_PORT_TYPE_RX) {
+ pr_debug("%s(): set=%d port id=0x%x for dtmf generation\n",
+ __func__, set, msm_bedais[reg].port_id);
+ afe_set_dtmf_gen_rx_portid(msm_bedais[reg].port_id, set);
+ }
+
mutex_unlock(&routing_lock);
if (afe_get_port_type(msm_bedais[reg].port_id) ==
@@ -1588,6 +1596,9 @@
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
@@ -1603,6 +1614,9 @@
SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
@@ -1618,6 +1632,9 @@
SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = {
@@ -1636,6 +1653,9 @@
SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new mi2s_rx_voice_mixer_controls[] = {
@@ -1651,6 +1671,9 @@
SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = {
@@ -1669,6 +1692,9 @@
SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new aux_pcm_rx_voice_mixer_controls[] = {
@@ -1687,6 +1713,9 @@
SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new sec_aux_pcm_rx_voice_mixer_controls[] = {
@@ -1702,6 +1731,9 @@
SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = {
@@ -1720,6 +1752,9 @@
SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
@@ -2288,6 +2323,8 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MI2S_UL_HL", "MI2S_TX_HOSTLESS Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DTMF_DL_HL", "DTMF_RX_HOSTLESS Playback",
+ 0, 0, 0, 0),
/* Backend AIF */
/* Stream name equals to backend dai link stream name
@@ -2606,48 +2643,56 @@
{"PRI_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"PRI_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"PRI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SEC_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SLIM_0_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"AFE_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"AUX_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
{"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SEC_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"HDMI_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"HDMI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"HDMI", NULL, "HDMI_RX_Voice Mixer"},
{"HDMI", NULL, "HDMI_DL_HL"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 32ab063..0c0d3b4 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -70,6 +70,7 @@
MSM_FRONTEND_DAI_VOICE_STUB,
MSM_FRONTEND_DAI_VOLTE,
MSM_FRONTEND_DAI_SGLTE,
+ MSM_FRONTEND_DAI_DTMF_RX,
MSM_FRONTEND_DAI_MAX,
};
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 9c62a2e..6cabc97 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -33,6 +33,7 @@
uint32_t token, uint32_t *payload, void *priv);
void *tx_private_data;
void *rx_private_data;
+ u16 dtmf_gen_rx_portid;
};
static struct afe_ctl this_afe;
@@ -91,6 +92,7 @@
case AFE_SERVICE_CMD_MEMORY_MAP:
case AFE_SERVICE_CMD_MEMORY_UNMAP:
case AFE_SERVICE_CMD_UNREG_RTPORT:
+ case AFE_PORTS_CMD_DTMF_CTL:
atomic_set(&this_afe.state, 0);
wake_up(&this_afe.wait);
break;
@@ -1621,6 +1623,83 @@
.write = afe_debug_write
};
#endif
+
+void afe_set_dtmf_gen_rx_portid(u16 port_id, int set)
+{
+ if (set)
+ this_afe.dtmf_gen_rx_portid = port_id;
+ else if (this_afe.dtmf_gen_rx_portid == port_id)
+ this_afe.dtmf_gen_rx_portid = -1;
+}
+
+int afe_dtmf_generate_rx(int64_t duration_in_ms,
+ uint16_t high_freq,
+ uint16_t low_freq, uint16_t gain)
+{
+ int ret = 0;
+ struct afe_dtmf_generation_command cmd_dtmf;
+
+ pr_debug("%s: DTMF AFE Gen\n", __func__);
+
+ if (afe_validate_port(this_afe.dtmf_gen_rx_portid) < 0) {
+ pr_err("%s: Failed : Invalid Port id = %d\n",
+ __func__, this_afe.dtmf_gen_rx_portid);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_debug("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ }
+
+ pr_debug("dur=%lld: hfreq=%d lfreq=%d gain=%d portid=%x\n",
+ duration_in_ms, high_freq, low_freq, gain,
+ this_afe.dtmf_gen_rx_portid);
+
+ cmd_dtmf.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cmd_dtmf.hdr.pkt_size = sizeof(cmd_dtmf);
+ cmd_dtmf.hdr.src_port = 0;
+ cmd_dtmf.hdr.dest_port = 0;
+ cmd_dtmf.hdr.token = 0;
+ cmd_dtmf.hdr.opcode = AFE_PORTS_CMD_DTMF_CTL;
+ cmd_dtmf.duration_in_ms = duration_in_ms;
+ cmd_dtmf.high_freq = high_freq;
+ cmd_dtmf.low_freq = low_freq;
+ cmd_dtmf.gain = gain;
+ cmd_dtmf.num_ports = 1;
+ cmd_dtmf.port_ids = this_afe.dtmf_gen_rx_portid;
+
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_dtmf);
+ if (ret < 0) {
+ pr_err("%s: AFE DTMF failed for num_ports:%d ids:%x\n",
+ __func__, cmd_dtmf.num_ports, cmd_dtmf.port_ids);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (ret < 0) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ return 0;
+
+fail_cmd:
+ return ret;
+}
+
int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
{
struct afe_port_sidetone_command cmd_sidetone;
@@ -1755,6 +1834,7 @@
atomic_set(&this_afe.state, 0);
atomic_set(&this_afe.status, 0);
this_afe.apr = NULL;
+ this_afe.dtmf_gen_rx_portid = -1;
#ifdef CONFIG_DEBUG_FS
debugfs_afelb = debugfs_create_file("afe_loopback",
S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",