Merge changes into audio-drivers.lnx.3.0
diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c
index fbacdc0..006f863 100644
--- a/asoc/codecs/bolero/rx-macro.c
+++ b/asoc/codecs/bolero/rx-macro.c
@@ -44,6 +44,11 @@
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S24_3LE)
+#define SAMPLING_RATE_44P1KHZ 44100
+#define SAMPLING_RATE_88P2KHZ 88200
+#define SAMPLING_RATE_176P4KHZ 176400
+#define SAMPLING_RATE_352P8KHZ 352800
+
#define RX_MACRO_MAX_OFFSET 0x1000
#define RX_MACRO_MAX_DMA_CH_PER_PORT 2
@@ -312,10 +317,6 @@
"ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB"
};
-static const char *const rx_macro_native_text[] = {"OFF", "ON"};
-static const struct soc_enum rx_macro_native_enum =
- SOC_ENUM_SINGLE_EXT(2, rx_macro_native_text);
-
static const char *const rx_macro_ear_mode_text[] = {"OFF", "ON"};
static const struct soc_enum rx_macro_ear_mode_enum =
SOC_ENUM_SINGLE_EXT(2, rx_macro_ear_mode_text);
@@ -642,16 +643,40 @@
return 0;
}
+static bool rx_macro_is_fractional_sample_rate(u32 sample_rate)
+{
+ switch (sample_rate) {
+ case SAMPLING_RATE_44P1KHZ:
+ case SAMPLING_RATE_88P2KHZ:
+ case SAMPLING_RATE_176P4KHZ:
+ case SAMPLING_RATE_352P8KHZ:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
static int rx_macro_set_interpolator_rate(struct snd_soc_dai *dai,
u32 sample_rate)
{
struct snd_soc_codec *codec = dai->codec;
int rate_val = 0;
int i = 0, ret = 0;
+ struct device *rx_dev = NULL;
+ struct rx_macro_priv *rx_priv = NULL;
+
+ if (!rx_macro_get_data(codec, &rx_dev, &rx_priv, __func__))
+ return -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(sr_val_tbl); i++) {
if (sample_rate == sr_val_tbl[i].sample_rate) {
rate_val = sr_val_tbl[i].rate_val;
+ if (rx_macro_is_fractional_sample_rate(sample_rate))
+ rx_priv->is_native_on = true;
+ else
+ rx_priv->is_native_on = false;
break;
}
}
@@ -748,7 +773,7 @@
dev_dbg(rx_priv->dev, "%s: mclk_enable = %u, dapm = %d clk_users= %d\n",
__func__, mclk_enable, dapm, rx_priv->rx_mclk_users);
- if(rx_priv->is_native_on)
+ if (rx_priv->is_native_on)
mclk_mux = MCLK_MUX1;
mutex_lock(&rx_priv->mclk_lock);
if (mclk_enable) {
@@ -809,6 +834,7 @@
int ret = 0;
struct device *rx_dev = NULL;
struct rx_macro_priv *rx_priv = NULL;
+ int mclk_freq = MCLK_FREQ;
if (!rx_macro_get_data(codec, &rx_dev, &rx_priv, __func__))
return -EINVAL;
@@ -820,13 +846,18 @@
if (rx_priv->swr_clk_users > 0) {
if ((rx_priv->mclk_mux == MCLK_MUX0 &&
rx_priv->is_native_on) ||
- (rx_priv->mclk_mux == MCLK_MUX1 &&
+ (rx_priv->mclk_mux == MCLK_MUX1 &&
!rx_priv->is_native_on)) {
swrm_wcd_notify(
rx_priv->swr_ctrl_data[0].rx_swr_pdev,
SWR_DEVICE_DOWN, NULL);
}
}
+ if (rx_priv->is_native_on)
+ mclk_freq = MCLK_FREQ_NATIVE;
+ swrm_wcd_notify(
+ rx_priv->swr_ctrl_data[0].rx_swr_pdev,
+ SWR_CLK_FREQ, &mclk_freq);
ret = rx_macro_mclk_enable(rx_priv, 1, true);
break;
case SND_SOC_DAPM_POST_PMD:
@@ -1331,36 +1362,6 @@
return -EINVAL;
}
-static int rx_macro_get_native(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct device *rx_dev = NULL;
- struct rx_macro_priv *rx_priv = NULL;
-
- if (!rx_macro_get_data(codec, &rx_dev, &rx_priv, __func__))
- return -EINVAL;
-
- ucontrol->value.integer.value[0] =
- (rx_priv->is_native_on == true ? 1 : 0);
- return 0;
-}
-
-static int rx_macro_put_native(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct device *rx_dev = NULL;
- struct rx_macro_priv *rx_priv = NULL;
-
- if (!rx_macro_get_data(codec, &rx_dev, &rx_priv, __func__))
- return -EINVAL;
-
- rx_priv->is_native_on =
- (!ucontrol->value.integer.value[0] ? false : true);
- return 0;
-}
-
static int rx_macro_get_ear_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1877,9 +1878,6 @@
SOC_SINGLE_EXT("RX_COMP2 Switch", SND_SOC_NOPM, RX_MACRO_COMP2, 1, 0,
rx_macro_get_compander, rx_macro_set_compander),
- SOC_ENUM_EXT("RX_Native", rx_macro_native_enum, rx_macro_get_native,
- rx_macro_put_native),
-
SOC_ENUM_EXT("RX_EAR Mode", rx_macro_ear_mode_enum,
rx_macro_get_ear_mode, rx_macro_put_ear_mode),
diff --git a/asoc/codecs/wcd9335.c b/asoc/codecs/wcd9335.c
index 3ec94fe..854fb92 100644
--- a/asoc/codecs/wcd9335.c
+++ b/asoc/codecs/wcd9335.c
@@ -613,6 +613,8 @@
WCD9335_MBHC_CTL_2, 0x03, 0, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
WCD9335_ANA_MBHC_RESULT_3, 0x08, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_IN2P_CLAMP_STATE",
+ WCD9335_ANA_MBHC_RESULT_3, 0x10, 4, 0),
WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
WCD9335_ANA_MBHC_RESULT_3, 0x20, 5, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index 19952c8..742457c 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -1212,6 +1212,29 @@
return rc;
}
+/*
+ * For single CPU DAI registration, the dai id needs to be
+ * set explicitly in the dai probe as ASoC does not read
+ * the cpu->driver->id field rather it assigns the dai id
+ * from the device name that is in the form %s.%d. This dai
+ * id should be assigned to back-end AFE port id and used
+ * during dai prepare. For multiple dai registration, it
+ * is not required to call this function, however the dai->
+ * driver->id field must be defined and set to corresponding
+ * AFE Port id.
+ */
+static inline void msm_dai_q6_set_dai_id(struct snd_soc_dai *dai)
+{
+ if (!dai->driver) {
+ dev_err(dai->dev, "DAI driver is not set\n");
+ return;
+ }
+ if (!dai->driver->id) {
+ dev_dbg(dai->dev, "DAI driver id is not set\n");
+ return;
+ }
+ dai->id = dai->driver->id;
+}
static int msm_dai_q6_aux_pcm_probe(struct snd_soc_dai *dai)
{
@@ -1226,11 +1249,8 @@
pr_err("%s: Invalid params dai dev\n", __func__);
return -EINVAL;
}
- if (!dai->driver->id) {
- dev_warn(dai->dev, "DAI driver id is not set\n");
- return -EINVAL;
- }
- dai->id = dai->driver->id;
+
+ msm_dai_q6_set_dai_id(dai);
dai_data = dev_get_drvdata(dai->dev);
if (dai_data->is_island_dai)
@@ -1725,15 +1745,20 @@
pr_err("%s: dai not found!!\n", __func__);
return -EINVAL;
}
+ if (!dai->dev) {
+ pr_err("%s: Invalid params dai dev\n", __func__);
+ return -EINVAL;
+ }
+
dai_data = kzalloc(sizeof(struct msm_dai_q6_spdif_dai_data),
GFP_KERNEL);
- if (!dai_data) {
- rc = -ENOMEM;
- } else
+ if (!dai_data)
+ return -ENOMEM;
+ else
dev_set_drvdata(dai->dev, dai_data);
- dai->id = dai->driver->id;
+ msm_dai_q6_set_dai_id(dai);
dai_data->port_id = dai->id;
switch (dai->id) {
@@ -2530,26 +2555,6 @@
.set_channel_map = msm_dai_q6_set_channel_map,
};
-/*
- * For single CPU DAI registration, the dai id needs to be
- * set explicitly in the dai probe as ASoC does not read
- * the cpu->driver->id field rather it assigns the dai id
- * from the device name that is in the form %s.%d. This dai
- * id should be assigned to back-end AFE port id and used
- * during dai prepare. For multiple dai registration, it
- * is not required to call this function, however the dai->
- * driver->id field must be defined and set to corresponding
- * AFE Port id.
- */
-static inline void msm_dai_q6_set_dai_id(struct snd_soc_dai *dai)
-{
- if (!dai->driver->id) {
- dev_warn(dai->dev, "DAI driver id is not set\n");
- return;
- }
- dai->id = dai->driver->id;
-}
-
static int msm_dai_q6_cal_info_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -3188,7 +3193,7 @@
dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
if (!dai_data)
- rc = -ENOMEM;
+ return -ENOMEM;
else
dev_set_drvdata(dai->dev, dai_data);
@@ -6978,8 +6983,7 @@
static int msm_dai_q6_dai_tdm_probe(struct snd_soc_dai *dai)
{
int rc = 0;
- struct msm_dai_q6_tdm_dai_data *tdm_dai_data =
- dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_tdm_dai_data *tdm_dai_data = NULL;
struct snd_kcontrol *data_format_kcontrol = NULL;
struct snd_kcontrol *header_type_kcontrol = NULL;
struct snd_kcontrol *header_kcontrol = NULL;
@@ -6988,6 +6992,8 @@
const struct snd_kcontrol_new *header_type_ctrl = NULL;
const struct snd_kcontrol_new *header_ctrl = NULL;
+ tdm_dai_data = dev_get_drvdata(dai->dev);
+
msm_dai_q6_set_dai_id(dai);
port_idx = msm_dai_q6_get_port_idx(dai->id);
diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c
index 8ae85b7..f40769b 100644
--- a/asoc/msm-pcm-q6-v2.c
+++ b/asoc/msm-pcm-q6-v2.c
@@ -704,7 +704,10 @@
prtd->set_channel_map = false;
prtd->reset_event = false;
runtime->private_data = prtd;
- msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd);
+
/* Vote to update the Rx thread priority to RT Thread for playback */
if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
(pdata->perf_mode == LOW_LATENCY_PCM_MODE))
diff --git a/asoc/msm-pcm-voice-v2.c b/asoc/msm-pcm-voice-v2.c
index 0a4aa05..38da7e7 100644
--- a/asoc/msm-pcm-voice-v2.c
+++ b/asoc/msm-pcm-voice-v2.c
@@ -519,6 +519,22 @@
return ret;
}
+static int msm_voice_mbd_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = voc_get_mbd_enable();
+ return 0;
+}
+
+static int msm_voice_mbd_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ bool enable = ucontrol->value.integer.value[0];
+
+ voc_set_mbd_enable(enable);
+
+ return 0;
+}
static const char * const tty_mode[] = {"OFF", "HCO", "VCO", "FULL"};
@@ -664,6 +680,8 @@
},
SOC_SINGLE_MULTI_EXT("Voice Sidetone Enable", SND_SOC_NOPM, 0, 1, 0, 1,
msm_voice_sidetone_get, msm_voice_sidetone_put),
+ SOC_SINGLE_BOOL_EXT("Voice Mic Break Enable", 0, msm_voice_mbd_get,
+ msm_voice_mbd_put),
};
static const struct snd_pcm_ops msm_pcm_ops = {
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index 353df6a..f5e7267 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -2292,7 +2292,7 @@
goto exit;
}
}
- pr_err("%s: no matching cal_block found\n", __func__);
+ pr_debug("%s: no matching cal_block found\n", __func__);
cal_block = NULL;
exit:
diff --git a/dsp/q6voice.c b/dsp/q6voice.c
index 32e85f9..ce86564 100644
--- a/dsp/q6voice.c
+++ b/dsp/q6voice.c
@@ -72,6 +72,9 @@
static int voice_send_mvm_cal_network_cmd(struct voice_data *v);
static int voice_send_mvm_media_type_cmd(struct voice_data *v);
static int voice_send_mvm_cvd_version_cmd(struct voice_data *v);
+static int voice_send_mvm_event_class_cmd(struct voice_data *v,
+ uint32_t event_id,
+ uint32_t class_id);
static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v);
static int voice_send_cvs_packet_exchange_config_cmd(struct voice_data *v);
static int voice_set_packet_exchange_mode_and_config(uint32_t session_id,
@@ -767,6 +770,70 @@
return ret;
}
+static int voice_send_mvm_event_class_cmd(struct voice_data *v,
+ uint32_t event_id,
+ uint32_t class_id)
+{
+ struct vss_inotify_cmd_event_class_t mvm_event;
+ int ret = 0;
+ void *apr_mvm = NULL;
+ u16 mvm_handle = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ apr_mvm = common.apr_q6_mvm;
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&mvm_event, 0, sizeof(mvm_event));
+ mvm_handle = voice_get_mvm_handle(v);
+ mvm_event.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_event.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_event) - APR_HDR_SIZE);
+ mvm_event.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_event.hdr.dest_port = mvm_handle;
+ mvm_event.hdr.token = 0;
+ mvm_event.hdr.opcode = event_id;
+ mvm_event.class_id = class_id;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_event);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending %x event\n", __func__, ret,
+ event_id);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+ ret = -ETIMEDOUT;
+ goto fail;
+ }
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ v->async_err));
+ ret = adsp_err_get_lnx_err_code(
+ v->async_err);
+ goto fail;
+ }
+ return 0;
+fail:
+ return ret;
+}
+
static int voice_send_dual_control_cmd(struct voice_data *v)
{
int ret = 0;
@@ -4243,6 +4310,23 @@
return ret;
}
+static void voice_mic_break_work_fn(struct work_struct *work)
+{
+ int ret = 0;
+ char event[25] = "";
+ struct voice_data *v = container_of(work, struct voice_data,
+ voice_mic_break_work);
+
+ snprintf(event, sizeof(event), "MIC_BREAK_STATUS=%s",
+ v->mic_break_status ? "TRUE" : "FALSE");
+
+ mutex_lock(&common.common_lock);
+ ret = q6core_send_uevent(common.uevent_data, event);
+ if (ret)
+ pr_err("%s: Send UEvent %s failed :%d\n", __func__, event, ret);
+ mutex_unlock(&common.common_lock);
+}
+
static int voice_setup_vocproc(struct voice_data *v)
{
struct module_instance_info mod_inst_info;
@@ -4341,6 +4425,11 @@
if (v->hd_enable)
voice_send_hd_cmd(v, v->hd_enable);
+ if (common.mic_break_enable)
+ voice_send_mvm_event_class_cmd(v,
+ VSS_INOTIFY_CMD_LISTEN_FOR_EVENT_CLASS,
+ VSS_ICOMMON_EVENT_CLASS_VOICE_ACTIVITY_UPDATE);
+
rtac_add_voice(voice_get_cvs_handle(v),
voice_get_cvp_handle(v),
v->dev_rx.port_id, v->dev_tx.port_id,
@@ -5034,6 +5123,11 @@
/* Unload topology modules */
voice_unload_topo_modules();
+ if (common.mic_break_enable)
+ voice_send_mvm_event_class_cmd(v,
+ VSS_INOTIFY_CMD_CANCEL_EVENT_CLASS,
+ VSS_ICOMMON_EVENT_CLASS_VOICE_ACTIVITY_UPDATE);
+
/* destrop cvp session */
cvp_destroy_session_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -6626,6 +6720,70 @@
EXPORT_SYMBOL(voc_get_route_flag);
/**
+ * voc_get_mbd_enable -
+ * Retrieve mic break detection enable state
+ *
+ * Returns true if mic break detection is enabled or false if disabled
+ */
+bool voc_get_mbd_enable(void)
+{
+ bool enable = false;
+
+ mutex_lock(&common.common_lock);
+ enable = common.mic_break_enable;
+ mutex_unlock(&common.common_lock);
+
+ return enable;
+}
+EXPORT_SYMBOL(voc_get_mbd_enable);
+
+/**
+ * voc_set_mbd_enable -
+ * Set mic break detection enable state
+ *
+ * @enable: mic break detection state to set
+ *
+ * Returns 0
+ */
+uint8_t voc_set_mbd_enable(bool enable)
+{
+ struct voice_data *v = NULL;
+ struct voice_session_itr itr;
+ bool check_and_send_event = false;
+ uint32_t event_id = VSS_INOTIFY_CMD_LISTEN_FOR_EVENT_CLASS;
+ uint32_t class_id = VSS_ICOMMON_EVENT_CLASS_VOICE_ACTIVITY_UPDATE;
+
+ mutex_lock(&common.common_lock);
+ if (common.mic_break_enable != enable)
+ check_and_send_event = true;
+ common.mic_break_enable = enable;
+ mutex_unlock(&common.common_lock);
+
+ if (!check_and_send_event)
+ return 0;
+
+ if (!enable)
+ event_id = VSS_INOTIFY_CMD_CANCEL_EVENT_CLASS;
+
+ memset(&itr, 0, sizeof(itr));
+
+ voice_itr_init(&itr, ALL_SESSION_VSID);
+ while (voice_itr_get_next_session(&itr, &v)) {
+ if (v != NULL) {
+ mutex_lock(&v->lock);
+ if (is_voc_state_active(v->voc_state)) {
+ voice_send_mvm_event_class_cmd(v, event_id,
+ class_id);
+ }
+ mutex_unlock(&v->lock);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(voc_set_mbd_enable);
+
+/**
* voc_end_voice_call -
* command to end voice call
*
@@ -7171,6 +7329,7 @@
uint32_t *ptr = NULL;
struct common_data *c = NULL;
struct voice_data *v = NULL;
+ struct vss_evt_voice_activity *voice_act_update = NULL;
int i = 0;
struct vss_iversion_rsp_get_t *version_rsp = NULL;
@@ -7276,6 +7435,8 @@
case VSS_IMVM_CMD_STANDBY_VOICE:
case VSS_IHDVOICE_CMD_ENABLE:
case VSS_IHDVOICE_CMD_DISABLE:
+ case VSS_INOTIFY_CMD_LISTEN_FOR_EVENT_CLASS:
+ case VSS_INOTIFY_CMD_CANCEL_EVENT_CLASS:
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
v->mvm_state = CMD_STATUS_SUCCESS;
v->async_err = ptr[1];
@@ -7380,7 +7541,33 @@
v->mvm_state = CMD_STATUS_SUCCESS;
wake_up(&v->mvm_wait);
}
+ } else if (data->opcode == VSS_ICOMMON_EVT_VOICE_ACTIVITY_UPDATE) {
+ if (data->payload_size == sizeof(struct vss_evt_voice_activity)) {
+ voice_act_update =
+ (struct vss_evt_voice_activity *)
+ data->payload;
+
+ /* Drop notifications other than Mic Break */
+ if ((voice_act_update->activity
+ != VSS_ICOMMON_VOICE_ACTIVITY_MIC_BREAK)
+ && (voice_act_update->activity
+ != VSS_ICOMMON_VOICE_ACITIVTY_MIC_UNBREAK))
+ return 0;
+
+ switch (voice_act_update->activity) {
+ case VSS_ICOMMON_VOICE_ACTIVITY_MIC_BREAK:
+ v->mic_break_status = true;
+ break;
+ case VSS_ICOMMON_VOICE_ACITIVTY_MIC_UNBREAK:
+ v->mic_break_status = false;
+ break;
+ }
+
+ if (c->mic_break_enable)
+ schedule_work(&(v->voice_mic_break_work));
+ }
}
+
return 0;
}
@@ -9642,6 +9829,14 @@
return ret;
}
+static void voc_release_uevent_data(struct kobject *kobj)
+{
+ struct audio_uevent_data *data = container_of(kobj,
+ struct audio_uevent_data,
+ kobj);
+ kfree(data);
+}
+
/**
* is_voc_initialized:
*
@@ -9694,6 +9889,18 @@
mutex_init(&common.common_lock);
+ common.uevent_data = kzalloc(sizeof(*(common.uevent_data)), GFP_KERNEL);
+ if (!common.uevent_data)
+ return -ENOMEM;
+
+ /*
+ * Set release function to cleanup memory related to kobject
+ * before initializing the kobject.
+ */
+ common.uevent_data->ktype.release = voc_release_uevent_data;
+ q6core_init_uevent_data(common.uevent_data, "q6voice_uevent");
+ common.mic_break_enable = false;
+
/* Initialize session id with vsid */
init_session_id();
@@ -9734,6 +9941,9 @@
common.voice[i].voc_state = VOC_INIT;
+ INIT_WORK(&common.voice[i].voice_mic_break_work,
+ voice_mic_break_work_fn);
+
init_waitqueue_head(&common.voice[i].mvm_wait);
init_waitqueue_head(&common.voice[i].cvs_wait);
init_waitqueue_head(&common.voice[i].cvp_wait);
@@ -9754,6 +9964,7 @@
void voice_exit(void)
{
+ q6core_destroy_uevent_data(common.uevent_data);
voice_delete_cal_data();
free_cal_map_table();
}
diff --git a/dsp/rtac.c b/dsp/rtac.c
index 7102ae2..c6bca98 100644
--- a/dsp/rtac.c
+++ b/dsp/rtac.c
@@ -54,6 +54,7 @@
struct rtac_common_data {
atomic_t usage_count;
atomic_t apr_err_code;
+ struct mutex rtac_fops_mutex;
};
static struct rtac_common_data rtac_common;
@@ -122,10 +123,6 @@
struct mutex rtac_voice_mutex;
struct mutex rtac_voice_apr_mutex;
struct mutex rtac_afe_apr_mutex;
-struct mutex rtac_asm_cal_mutex;
-struct mutex rtac_adm_cal_mutex;
-struct mutex rtac_afe_cal_mutex;
-struct mutex rtac_voice_cal_mutex;
int rtac_clear_mapping(uint32_t cal_type)
{
@@ -322,7 +319,9 @@
pr_debug("%s\n", __func__);
+ mutex_lock(&rtac_common.rtac_fops_mutex);
atomic_inc(&rtac_common.usage_count);
+ mutex_unlock(&rtac_common.rtac_fops_mutex);
return result;
}
@@ -334,12 +333,15 @@
pr_debug("%s\n", __func__);
+ mutex_lock(&rtac_common.rtac_fops_mutex);
atomic_dec(&rtac_common.usage_count);
pr_debug("%s: ref count %d!\n", __func__,
atomic_read(&rtac_common.usage_count));
- if (atomic_read(&rtac_common.usage_count) > 0)
+ if (atomic_read(&rtac_common.usage_count) > 0) {
+ mutex_unlock(&rtac_common.rtac_fops_mutex);
goto done;
+ }
for (i = 0; i < MAX_RTAC_BLOCKS; i++) {
result2 = rtac_unmap_cal_buffer(i);
@@ -356,6 +358,7 @@
result = result2;
}
}
+ mutex_unlock(&rtac_common.rtac_fops_mutex);
done:
return result;
}
@@ -1807,84 +1810,64 @@
}
case AUDIO_GET_RTAC_ADM_CAL:
- mutex_lock(&rtac_adm_cal_mutex);
opcode = q6common_is_instance_id_supported() ?
ADM_CMD_GET_PP_PARAMS_V6 :
ADM_CMD_GET_PP_PARAMS_V5;
result = send_adm_apr((void *) arg, opcode);
- mutex_unlock(&rtac_adm_cal_mutex);
break;
case AUDIO_SET_RTAC_ADM_CAL:
- mutex_lock(&rtac_adm_cal_mutex);
opcode = q6common_is_instance_id_supported() ?
ADM_CMD_SET_PP_PARAMS_V6 :
ADM_CMD_SET_PP_PARAMS_V5;
result = send_adm_apr((void *) arg, opcode);
- mutex_unlock(&rtac_adm_cal_mutex);
break;
case AUDIO_GET_RTAC_ASM_CAL:
- mutex_lock(&rtac_asm_cal_mutex);
opcode = q6common_is_instance_id_supported() ?
ASM_STREAM_CMD_GET_PP_PARAMS_V3 :
ASM_STREAM_CMD_GET_PP_PARAMS_V2;
result = send_rtac_asm_apr((void *) arg, opcode);
- mutex_unlock(&rtac_asm_cal_mutex);
break;
case AUDIO_SET_RTAC_ASM_CAL:
- mutex_lock(&rtac_asm_cal_mutex);
opcode = q6common_is_instance_id_supported() ?
ASM_STREAM_CMD_SET_PP_PARAMS_V3 :
ASM_STREAM_CMD_SET_PP_PARAMS_V2;
result = send_rtac_asm_apr((void *) arg, opcode);
- mutex_unlock(&rtac_asm_cal_mutex);
break;
case AUDIO_GET_RTAC_CVS_CAL:
- mutex_lock(&rtac_voice_cal_mutex);
opcode = q6common_is_instance_id_supported() ?
VSS_ICOMMON_CMD_GET_PARAM_V3 :
VSS_ICOMMON_CMD_GET_PARAM_V2;
result = send_voice_apr(RTAC_CVS, (void *) arg, opcode);
- mutex_unlock(&rtac_voice_cal_mutex);
break;
case AUDIO_SET_RTAC_CVS_CAL:
- mutex_lock(&rtac_voice_cal_mutex);
opcode = q6common_is_instance_id_supported() ?
VSS_ICOMMON_CMD_SET_PARAM_V3 :
VSS_ICOMMON_CMD_SET_PARAM_V2;
result = send_voice_apr(RTAC_CVS, (void *) arg, opcode);
- mutex_unlock(&rtac_voice_cal_mutex);
break;
case AUDIO_GET_RTAC_CVP_CAL:
- mutex_lock(&rtac_voice_cal_mutex);
opcode = q6common_is_instance_id_supported() ?
VSS_ICOMMON_CMD_GET_PARAM_V3 :
VSS_ICOMMON_CMD_GET_PARAM_V2;
result = send_voice_apr(RTAC_CVP, (void *) arg, opcode);
- mutex_unlock(&rtac_voice_cal_mutex);
break;
case AUDIO_SET_RTAC_CVP_CAL:
- mutex_lock(&rtac_voice_cal_mutex);
opcode = q6common_is_instance_id_supported() ?
VSS_ICOMMON_CMD_SET_PARAM_V3 :
VSS_ICOMMON_CMD_SET_PARAM_V2;
result = send_voice_apr(RTAC_CVP, (void *) arg, opcode);
- mutex_unlock(&rtac_voice_cal_mutex);
break;
case AUDIO_GET_RTAC_AFE_CAL:
- mutex_lock(&rtac_afe_cal_mutex);
opcode = q6common_is_instance_id_supported() ?
AFE_PORT_CMD_GET_PARAM_V3 :
AFE_PORT_CMD_GET_PARAM_V2;
result = send_rtac_afe_apr((void __user *) arg, opcode);
- mutex_unlock(&rtac_afe_cal_mutex);
break;
case AUDIO_SET_RTAC_AFE_CAL:
- mutex_lock(&rtac_afe_cal_mutex);
opcode = q6common_is_instance_id_supported() ?
AFE_PORT_CMD_SET_PARAM_V3 :
AFE_PORT_CMD_SET_PARAM_V2;
result = send_rtac_afe_apr((void __user *) arg, opcode);
- mutex_unlock(&rtac_afe_cal_mutex);
break;
default:
pr_err("%s: Invalid IOCTL, command = %d!\n",
@@ -1900,6 +1883,7 @@
{
int result = 0;
+ mutex_lock(&rtac_common.rtac_fops_mutex);
if (!arg) {
pr_err("%s: No data sent to driver!\n", __func__);
result = -EFAULT;
@@ -1907,6 +1891,7 @@
result = rtac_ioctl_shared(f, cmd, (void __user *)arg);
}
+ mutex_unlock(&rtac_common.rtac_fops_mutex);
return result;
}
@@ -1929,6 +1914,7 @@
{
int result = 0;
+ mutex_lock(&rtac_common.rtac_fops_mutex);
if (!arg) {
pr_err("%s: No data sent to driver!\n", __func__);
result = -EINVAL;
@@ -1981,6 +1967,7 @@
break;
}
done:
+ mutex_unlock(&rtac_common.rtac_fops_mutex);
return result;
}
#else
@@ -2008,6 +1995,7 @@
/* Driver */
atomic_set(&rtac_common.usage_count, 0);
atomic_set(&rtac_common.apr_err_code, 0);
+ mutex_init(&rtac_common.rtac_fops_mutex);
/* ADM */
memset(&rtac_adm_data, 0, sizeof(rtac_adm_data));
@@ -2016,7 +2004,6 @@
init_waitqueue_head(&rtac_adm_apr_data.cmd_wait);
mutex_init(&rtac_adm_mutex);
mutex_init(&rtac_adm_apr_mutex);
- mutex_init(&rtac_adm_cal_mutex);
rtac_adm_buffer = kzalloc(
rtac_cal[ADM_RTAC_CAL].map_data.map_size, GFP_KERNEL);
@@ -2030,7 +2017,6 @@
init_waitqueue_head(&rtac_asm_apr_data[i].cmd_wait);
}
mutex_init(&rtac_asm_apr_mutex);
- mutex_init(&rtac_asm_cal_mutex);
rtac_asm_buffer = kzalloc(
rtac_cal[ASM_RTAC_CAL].map_data.map_size, GFP_KERNEL);
@@ -2044,7 +2030,6 @@
atomic_set(&rtac_afe_apr_data.cmd_state, 0);
init_waitqueue_head(&rtac_afe_apr_data.cmd_wait);
mutex_init(&rtac_afe_apr_mutex);
- mutex_init(&rtac_afe_cal_mutex);
rtac_afe_buffer = kzalloc(
rtac_cal[AFE_RTAC_CAL].map_data.map_size, GFP_KERNEL);
@@ -2063,7 +2048,6 @@
}
mutex_init(&rtac_voice_mutex);
mutex_init(&rtac_voice_apr_mutex);
- mutex_init(&rtac_voice_cal_mutex);
rtac_voice_buffer = kzalloc(
rtac_cal[VOICE_RTAC_CAL].map_data.map_size, GFP_KERNEL);
diff --git a/include/dsp/q6voice.h b/include/dsp/q6voice.h
index d0ba990..ca42508 100644
--- a/include/dsp/q6voice.h
+++ b/include/dsp/q6voice.h
@@ -15,6 +15,7 @@
#include <linux/msm_ion.h>
#include <sound/voice_params.h>
#include <dsp/rtac.h>
+#include <dsp/q6core.h>
#include <ipc/apr.h>
#define MAX_VOC_PKT_SIZE 642
@@ -494,6 +495,19 @@
#define VSS_IHDVOICE_CMD_ENABLE 0x000130A2
#define VSS_IHDVOICE_CMD_DISABLE 0x000130A3
+/* To listen for events from MVM module */
+#define VSS_INOTIFY_CMD_LISTEN_FOR_EVENT_CLASS 0x00012E56
+/* To cancel listening for events from MVM module */
+#define VSS_INOTIFY_CMD_CANCEL_EVENT_CLASS 0x00012E57
+/* To receive ongoing voice activity notification */
+#define VSS_ICOMMON_EVENT_CLASS_VOICE_ACTIVITY_UPDATE 0x000131EF
+/* Voice activity notification from MVM */
+#define VSS_ICOMMON_EVT_VOICE_ACTIVITY_UPDATE 0x000131F0
+/* Mic path is broken. */
+#define VSS_ICOMMON_VOICE_ACTIVITY_MIC_BREAK 0x000131F3
+/* Mic path is restored. */
+#define VSS_ICOMMON_VOICE_ACITIVTY_MIC_UNBREAK 0x000131F4
+
enum msm_audio_voc_rate {
VOC_0_RATE, /* Blank frame */
VOC_8_RATE, /* 1/8 rate */
@@ -719,6 +733,33 @@
uint32_t mem_handle;
} __packed;
+/*
+ * Payload structure for VSS_INOTIFY_CMD_LISTEN_FOR_EVENT_CLASS and
+ * VSS_INOTIFY_CMD_CANCEL_EVENT_CLASS commands.
+ */
+struct vss_inotify_cmd_event_class_t {
+ struct apr_hdr hdr;
+ /* Event class ID to listen for. */
+ uint32_t class_id;
+} __packed;
+
+/* Payload structure for the VSS_ICOMMOM_EVT_VOICE_ACTIVITY_UPDATE event. */
+struct vss_evt_voice_activity {
+ uint32_t activity;
+ /*
+ * Specifies the voice acitivity.
+ * @values
+ * #VSS_ICOMMON_VOICE_ACTIVITY_VPTX_MUTE
+ * #VSS_ICOMMON_VOICE_ACTIVITY_VPTX_UNMUTE
+ * #VSS_ICOMMON_VOICE_ACTIVITY_MIC_BREAK
+ * #VSS_ICOMMON_VOICE_ACITIVTY_MIC_UNBREAK
+ * #VSS_ICOMMON_VOICE_ACTIVITY_UI_STREAM_TX_MUTE
+ * #VSS_ICOMMON_VOICE_ACTIVITY_UI_STREAM_TX_UNMUTE
+ * #VSS_ICOMMON_VOICE_ACTIVITY_UI_VOCPROC_TX_MUTE
+ * #VSS_ICOMMON_VOICE_ACTIVITY_UI_VOCPROC_TX_UNMUTE
+ */
+} __packed;
+
/* TO CVS commands */
#define VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION 0x00011140
/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
@@ -1854,6 +1895,9 @@
struct incall_music_info music_info;
struct voice_rec_route_state rec_route_state;
+
+ bool mic_break_status;
+ struct work_struct voice_mic_break_work;
};
#define MAX_VOC_SESSIONS 8
@@ -1907,6 +1951,8 @@
struct shared_mem_info source_tracking_sh_mem;
struct vss_isourcetrack_activity_data_t sourceTrackingResponse;
bool sidetone_enable;
+ bool mic_break_enable;
+ struct audio_uevent_data *uevent_data;
};
struct voice_session_itr {
@@ -1998,6 +2044,8 @@
int voc_get_rx_device_mute(uint32_t session_id);
int voc_set_route_flag(uint32_t session_id, uint8_t path_dir, uint8_t set);
uint8_t voc_get_route_flag(uint32_t session_id, uint8_t path_dir);
+bool voc_get_mbd_enable(void);
+uint8_t voc_set_mbd_enable(bool enable);
int voc_enable_dtmf_rx_detection(uint32_t session_id, uint32_t enable);
void voc_disable_dtmf_det_on_active_sessions(void);
int voc_alloc_cal_shared_memory(void);
diff --git a/include/soc/swr-wcd.h b/include/soc/swr-wcd.h
index 3608150..75d0e65 100644
--- a/include/soc/swr-wcd.h
+++ b/include/soc/swr-wcd.h
@@ -23,6 +23,7 @@
SWR_DEVICE_UP,
SWR_SUBSYS_RESTART,
SWR_SET_NUM_RX_CH,
+ SWR_CLK_FREQ,
};
struct swr_mstr_port {
@@ -30,6 +31,9 @@
u8 *port;
};
+#define MCLK_FREQ 9600000
+#define MCLK_FREQ_NATIVE 11289600
+
#if (IS_ENABLED(CONFIG_SOUNDWIRE_WCD_CTRL) || \
IS_ENABLED(CONFIG_SOUNDWIRE_MSTR_CTRL))
extern int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data);
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index 26cc1f4..d3fb087 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -956,7 +956,15 @@
n_col = SWR_MAX_COL;
}
/* Use default 50 * x, frame shape. Change based on mclk */
- n_row = SWR_ROW_50;
+ if (swrm->mclk_freq == MCLK_FREQ_NATIVE) {
+ dev_dbg(swrm->dev, "setting 64 x %d frameshape\n",
+ n_col ? 16 : 2);
+ n_row = SWR_ROW_64;
+ } else {
+ dev_dbg(swrm->dev, "setting 50 x %d frameshape\n",
+ n_col ? 16 : 2);
+ n_row = SWR_ROW_50;
+ }
value = swr_master_read(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank));
value &= (~mask);
value |= ((n_row << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT) |
@@ -1630,6 +1638,7 @@
swrm->slave_status = 0;
swrm->num_rx_chs = 0;
swrm->clk_ref_count = 0;
+ swrm->mclk_freq = MCLK_FREQ;
swrm->state = SWR_MSTR_RESUME;
init_completion(&swrm->reset);
init_completion(&swrm->broadcast);
@@ -1940,6 +1949,16 @@
mstr = &swrm->master;
switch (id) {
+ case SWR_CLK_FREQ:
+ if (!data) {
+ dev_err(swrm->dev, "%s: data is NULL\n", __func__);
+ ret = -EINVAL;
+ } else {
+ mutex_lock(&swrm->mlock);
+ swrm->mclk_freq = *(int *)data;
+ mutex_unlock(&swrm->mlock);
+ }
+ break;
case SWR_DEVICE_DOWN:
dev_dbg(swrm->dev, "%s: swr master down called\n", __func__);
mutex_lock(&swrm->mlock);
diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h
index fd13392..b3dfd7d 100644
--- a/soc/swr-mstr-ctrl.h
+++ b/soc/swr-mstr-ctrl.h
@@ -129,6 +129,7 @@
void *data), void *swr_handle, int type);
int irq;
int version;
+ int mclk_freq;
u32 num_dev;
int slave_status;
struct swrm_mports mport_cfg[SWR_MAX_MSTR_PORT_NUM];