summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/msm8x16/msm8x16-wcd.c109
-rw-r--r--sound/soc/codecs/msm8x16/msm8x16-wcd.h27
-rw-r--r--sound/soc/codecs/wcd9335.c45
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c160
-rw-r--r--sound/soc/codecs/wcd9xxx-resmgr-v2.c74
-rw-r--r--sound/soc/codecs/wcd9xxx-resmgr-v2.h2
-rw-r--r--sound/soc/msm/Kconfig76
-rw-r--r--sound/soc/msm/Makefile15
-rw-r--r--sound/soc/msm/msm-audio-pinctrl.h5
-rw-r--r--sound/soc/msm/msm-dai-fe.c32
-rw-r--r--sound/soc/msm/msmcobalt.c15
-rw-r--r--sound/soc/msm/msmfalcon-common.c1768
-rw-r--r--sound/soc/msm/msmfalcon-common.h69
-rw-r--r--sound/soc/msm/msmfalcon-ext-dai-links.c1527
-rw-r--r--sound/soc/msm/msmfalcon-external.c1700
-rw-r--r--sound/soc/msm/msmfalcon-external.h44
-rw-r--r--sound/soc/msm/msmfalcon-internal.c2453
-rw-r--r--sound/soc/msm/msmfalcon-internal.h32
-rw-r--r--sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c15
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c229
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c188
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c135
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c458
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h35
-rw-r--r--sound/soc/msm/qdsp6v2/q6afe.c14
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c27
-rw-r--r--sound/soc/msm/qdsp6v2/q6audio-v2.c84
-rw-r--r--sound/soc/msm/qdsp6v2/q6voice.h2
-rw-r--r--sound/soc/soc-compress.c10
-rw-r--r--sound/soc/soc-pcm.c2
-rw-r--r--sound/usb/usb_audio_qmi_svc.c211
31 files changed, 9233 insertions, 330 deletions
diff --git a/sound/soc/codecs/msm8x16/msm8x16-wcd.c b/sound/soc/codecs/msm8x16/msm8x16-wcd.c
index 481e1efdf015..c73414681c5a 100644
--- a/sound/soc/codecs/msm8x16/msm8x16-wcd.c
+++ b/sound/soc/codecs/msm8x16/msm8x16-wcd.c
@@ -40,9 +40,10 @@
#include <sound/tlv.h>
#include <sound/q6core.h>
#include <soc/qcom/subsystem_notif.h>
-#include "msm8x16-wcd.h"
+#include "../../msm/msmfalcon-common.h"
#include "../wcd-mbhc-v2.h"
#include "msm8916-wcd-irq.h"
+#include "msm8x16-wcd.h"
#define DRV_NAME "msm-codec"
#define MSM89XX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
@@ -253,8 +254,6 @@ static struct wcd_mbhc_register
WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT,
0x10, 4, 0),
- WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_VREF",
- 0, 0, 0, 0),
WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
MSM89XX_PMIC_ANALOG_MICB_2_EN, 0x20, 5, 0),
WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN",
@@ -295,7 +294,7 @@ static int msm8x16_wcd_dt_parse_vreg_info(struct device *dev,
const char *vreg_name, bool ondemand);
static struct msm8x16_wcd_pdata *msm8x16_wcd_populate_dt_pdata(
struct device *dev);
-static int msm8x16_wcd_enable_ext_mb_source(struct snd_soc_codec *codec,
+static int msm8x16_wcd_enable_ext_mb_source(struct wcd_mbhc *mbhc,
bool turn_on);
static void msm8x16_trim_btn_reg(struct snd_soc_codec *codec);
static void msm8x16_wcd_set_micb_v(struct snd_soc_codec *codec);
@@ -335,35 +334,28 @@ static int get_codec_version(struct msm8x16_wcd_priv *msm8x16_wcd)
static int msm_digcdc_clock_control(bool flag)
{
int ret = -EINVAL;
- struct msm8916_asoc_mach_data *pdata = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
pdata = snd_soc_card_get_drvdata(registered_codec->component.card);
if (flag) {
- mutex_lock(&pdata->cdc_mclk_mutex);
- if (atomic_read(&pdata->mclk_enabled) == false) {
- if (pdata->afe_clk_ver == AFE_CLK_VERSION_V1) {
- pdata->digital_cdc_clk.clk_val =
- pdata->mclk_freq;
- ret = afe_set_digital_codec_core_clock(
- AFE_PORT_ID_PRIMARY_MI2S_RX,
- &pdata->digital_cdc_clk);
- } else {
- pdata->digital_cdc_core_clk.enable = 1;
- ret = afe_set_lpass_clock_v2(
- AFE_PORT_ID_PRIMARY_MI2S_RX,
- &pdata->digital_cdc_core_clk);
- }
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ if (atomic_read(&pdata->int_mclk0_enabled) == false) {
+ pdata->digital_cdc_core_clk.enable = 1;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
if (ret < 0) {
- pr_err("failed to enable the MCLK\n");
- goto err;
+ pr_err("failed to enable the INT_MCLK0\n");
+ goto err_mclk;
}
pr_err("enabled digital codec core clk\n");
- atomic_set(&pdata->mclk_enabled, true);
- schedule_delayed_work(&pdata->disable_mclk_work, 50);
+ atomic_set(&pdata->int_mclk0_enabled, true);
+ schedule_delayed_work(&pdata->disable_int_mclk0_work,
+ 50);
}
-err:
- mutex_unlock(&pdata->cdc_mclk_mutex);
+err_mclk:
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
return ret;
}
return 0;
@@ -617,11 +609,12 @@ static void msm8x16_wcd_compute_impedance(struct snd_soc_codec *codec, s16 l,
}
static struct firmware_cal *msm8x16_wcd_get_hwdep_fw_cal(
- struct snd_soc_codec *codec,
+ struct wcd_mbhc *mbhc,
enum wcd_cal_type type)
{
struct msm8x16_wcd_priv *msm8x16_wcd;
struct firmware_cal *hwdep_cal;
+ struct snd_soc_codec *codec = mbhc->codec;
if (!codec) {
pr_err("%s: NULL codec pointer\n", __func__);
@@ -1063,10 +1056,11 @@ exit:
pr_err("%s: Impedance detection completed\n", __func__);
}
-static int msm8x16_register_notifier(struct snd_soc_codec *codec,
+static int msm8x16_register_notifier(struct wcd_mbhc *mbhc,
struct notifier_block *nblock,
bool enable)
{
+ struct snd_soc_codec *codec = mbhc->codec;
struct msm8x16_wcd_priv *msm8x16_wcd =
snd_soc_codec_get_drvdata(codec);
@@ -1624,7 +1618,7 @@ out:
static int msm8x16_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
int enable)
{
- struct msm8916_asoc_mach_data *pdata = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
pdata = snd_soc_card_get_drvdata(codec->component.card);
if (enable) {
@@ -1776,7 +1770,7 @@ static int msm8x16_wcd_loopback_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8916_asoc_mach_data *pdata = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
pdata = snd_soc_card_get_drvdata(codec->component.card);
dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
@@ -1789,7 +1783,7 @@ static int msm8x16_wcd_loopback_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct msm8916_asoc_mach_data *pdata = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
pdata = snd_soc_card_get_drvdata(codec->component.card);
dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
@@ -3061,7 +3055,7 @@ static int msm8x16_wcd_codec_enable_dig_clk(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
- struct msm8916_asoc_mach_data *pdata = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
pdata = snd_soc_card_get_drvdata(codec->component.card);
@@ -3202,11 +3196,12 @@ static void msm8x16_trim_btn_reg(struct snd_soc_codec *codec)
pr_err("%s: This device is trimmed at ATE\n", __func__);
}
}
-static int msm8x16_wcd_enable_ext_mb_source(struct snd_soc_codec *codec,
+static int msm8x16_wcd_enable_ext_mb_source(struct wcd_mbhc *mbhc,
bool turn_on)
{
int ret = 0;
static int count;
+ struct snd_soc_codec *codec = mbhc->codec;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
dev_err(codec->dev, "%s turn_on: %d count: %d\n", __func__, turn_on,
@@ -3405,7 +3400,7 @@ static int msm8x16_wcd_codec_enable_dec(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct msm8916_asoc_mach_data *pdata = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
unsigned int decimator;
struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
char *dec_name = NULL;
@@ -4328,14 +4323,14 @@ int msm8x16_wcd_mclk_enable(struct snd_soc_codec *codec,
dev_err(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
__func__, mclk_enable, dapm);
if (mclk_enable) {
- msm8x16_wcd->mclk_enabled = true;
+ msm8x16_wcd->int_mclk0_enabled = true;
msm8x16_wcd_codec_enable_clock_block(codec, 1);
} else {
- if (!msm8x16_wcd->mclk_enabled) {
+ if (!msm8x16_wcd->int_mclk0_enabled) {
dev_err(codec->dev, "Error, MCLK already diabled\n");
return -EINVAL;
}
- msm8x16_wcd->mclk_enabled = false;
+ msm8x16_wcd->int_mclk0_enabled = false;
msm8x16_wcd_codec_enable_clock_block(codec, 0);
}
return 0;
@@ -5178,7 +5173,7 @@ static struct regulator *wcd8x16_wcd_codec_find_regulator(
static int msm8x16_wcd_device_down(struct snd_soc_codec *codec)
{
- struct msm8916_asoc_mach_data *pdata = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
struct msm8x16_wcd_priv *msm8x16_wcd_priv =
snd_soc_codec_get_drvdata(codec);
int i;
@@ -5250,7 +5245,7 @@ static int msm8x16_wcd_device_down(struct snd_soc_codec *codec)
MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x93);
msm8x16_wcd_bringup(codec);
- atomic_set(&pdata->mclk_enabled, false);
+ atomic_set(&pdata->int_mclk0_enabled, false);
set_bit(BUS_DOWN, &msm8x16_wcd_priv->status_mask);
snd_soc_card_change_online_state(codec->component.card, 0);
return 0;
@@ -5399,7 +5394,7 @@ static void msm8x16_wcd_configure_cap(struct snd_soc_codec *codec,
bool micbias1, bool micbias2)
{
- struct msm8916_asoc_mach_data *pdata = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
pdata = snd_soc_card_get_drvdata(codec->component.card);
@@ -5553,7 +5548,7 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec)
wcd_mbhc_init(&msm8x16_wcd_priv->mbhc, codec, &mbhc_cb, &intr_ids,
wcd_mbhc_registers, true);
- msm8x16_wcd_priv->mclk_enabled = false;
+ msm8x16_wcd_priv->int_mclk0_enabled = false;
msm8x16_wcd_priv->clock_active = false;
msm8x16_wcd_priv->config_mode_active = false;
@@ -5654,33 +5649,23 @@ static int msm8x16_wcd_disable_static_supplies_to_optimum(
int msm8x16_wcd_suspend(struct snd_soc_codec *codec)
{
- struct msm8916_asoc_mach_data *pdata = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
struct msm8x16_wcd *msm8x16 = codec->control_data;
struct msm8x16_wcd_pdata *msm8x16_pdata = msm8x16->dev->platform_data;
pdata = snd_soc_card_get_drvdata(codec->component.card);
pr_err("%s: mclk cnt = %d, mclk_enabled = %d\n",
- __func__, atomic_read(&pdata->mclk_rsc_ref),
- atomic_read(&pdata->mclk_enabled));
- if (atomic_read(&pdata->mclk_enabled) == true) {
+ __func__, atomic_read(&pdata->int_mclk0_rsc_ref),
+ atomic_read(&pdata->int_mclk0_enabled));
+ if (atomic_read(&pdata->int_mclk0_enabled) == true) {
cancel_delayed_work_sync(
- &pdata->disable_mclk_work);
- mutex_lock(&pdata->cdc_mclk_mutex);
- if (atomic_read(&pdata->mclk_enabled) == true) {
- if (pdata->afe_clk_ver == AFE_CLK_VERSION_V1) {
- pdata->digital_cdc_clk.clk_val = 0;
- afe_set_digital_codec_core_clock(
- AFE_PORT_ID_PRIMARY_MI2S_RX,
- &pdata->digital_cdc_clk);
- } else {
- pdata->digital_cdc_core_clk.enable = 0;
- afe_set_lpass_clock_v2(
- AFE_PORT_ID_PRIMARY_MI2S_RX,
- &pdata->digital_cdc_core_clk);
- }
- atomic_set(&pdata->mclk_enabled, false);
- }
- mutex_unlock(&pdata->cdc_mclk_mutex);
+ &pdata->disable_int_mclk0_work);
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ pdata->digital_cdc_core_clk.enable = 0;
+ afe_set_lpass_clock_v2(AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ atomic_set(&pdata->int_mclk0_enabled, false);
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
}
msm8x16_wcd_disable_static_supplies_to_optimum(msm8x16, msm8x16_pdata);
return 0;
@@ -5688,7 +5673,7 @@ int msm8x16_wcd_suspend(struct snd_soc_codec *codec)
int msm8x16_wcd_resume(struct snd_soc_codec *codec)
{
- struct msm8916_asoc_mach_data *pdata = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
struct msm8x16_wcd *msm8x16 = codec->control_data;
struct msm8x16_wcd_pdata *msm8x16_pdata = msm8x16->dev->platform_data;
diff --git a/sound/soc/codecs/msm8x16/msm8x16-wcd.h b/sound/soc/codecs/msm8x16/msm8x16-wcd.h
index d2e782b07cb2..776090258119 100644
--- a/sound/soc/codecs/msm8x16/msm8x16-wcd.h
+++ b/sound/soc/codecs/msm8x16/msm8x16-wcd.h
@@ -221,31 +221,6 @@ struct wcd_imped_i_ref {
int offset;
};
-struct msm8916_asoc_mach_data {
- int codec_type;
- int ext_pa;
- int us_euro_gpio;
- int spk_ext_pa_gpio;
- int mclk_freq;
- int lb_mode;
- int afe_clk_ver;
- u8 micbias1_cap_mode;
- u8 micbias2_cap_mode;
- atomic_t mclk_rsc_ref;
- atomic_t mclk_enabled;
- atomic_t wsa_mclk_rsc_ref;
- struct mutex cdc_mclk_mutex;
- struct mutex wsa_mclk_mutex;
- struct delayed_work disable_mclk_work;
- struct afe_digital_clk_cfg digital_cdc_clk;
- struct afe_clk_set digital_cdc_core_clk;
- void __iomem *vaddr_gpio_mux_spkr_ctl;
- void __iomem *vaddr_gpio_mux_mic_ctl;
- void __iomem *vaddr_gpio_mux_quin_ctl;
- void __iomem *vaddr_gpio_mux_pcm_ctl;
- struct on_demand_supply wsa_switch_supply;
-};
-
struct msm8x16_wcd_pdata {
int irq;
int irq_base;
@@ -291,7 +266,7 @@ struct msm8x16_wcd_priv {
u32 rx_bias_count;
s32 dmic_1_2_clk_cnt;
u32 mute_mask;
- bool mclk_enabled;
+ bool int_mclk0_enabled;
bool clock_active;
bool config_mode_active;
u16 boost_option;
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 281db1d07f57..06e00fdfe6a1 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -714,6 +714,16 @@ struct hpf_work {
struct delayed_work dwork;
};
+#define WCD9335_SPK_ANC_EN_DELAY_MS 350
+static int spk_anc_en_delay = WCD9335_SPK_ANC_EN_DELAY_MS;
+module_param(spk_anc_en_delay, int, S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(spk_anc_en_delay, "delay to enable anc in speaker path");
+
+struct spk_anc_work {
+ struct tasha_priv *tasha;
+ struct delayed_work dwork;
+};
+
struct tx_mute_work {
struct tasha_priv *tasha;
u8 decimator;
@@ -836,6 +846,7 @@ struct tasha_priv {
int ear_spkr_gain;
struct hpf_work tx_hpf_work[TASHA_NUM_DECIMATORS];
struct tx_mute_work tx_mute_dwork[TASHA_NUM_DECIMATORS];
+ struct spk_anc_work spk_anc_dwork;
struct mutex codec_mutex;
int hph_l_gain;
int hph_r_gain;
@@ -4278,6 +4289,21 @@ static int tasha_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
return ret;
}
+static void tasha_spk_anc_update_callback(struct work_struct *work)
+{
+ struct spk_anc_work *spk_anc_dwork;
+ struct tasha_priv *tasha;
+ struct delayed_work *delayed_work;
+ struct snd_soc_codec *codec;
+
+ delayed_work = to_delayed_work(work);
+ spk_anc_dwork = container_of(delayed_work, struct spk_anc_work, dwork);
+ tasha = spk_anc_dwork->tasha;
+ codec = tasha->codec;
+
+ snd_soc_update_bits(codec, WCD9335_CDC_RX7_RX_PATH_CFG0, 0x10, 0x10);
+}
+
static int tasha_codec_enable_spk_anc(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -4295,10 +4321,11 @@ static int tasha_codec_enable_spk_anc(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
ret = tasha_codec_enable_anc(w, kcontrol, event);
- snd_soc_update_bits(codec, WCD9335_CDC_RX7_RX_PATH_CFG0,
- 0x10, 0x10);
+ schedule_delayed_work(&tasha->spk_anc_dwork.dwork,
+ msecs_to_jiffies(spk_anc_en_delay));
break;
case SND_SOC_DAPM_POST_PMD:
+ cancel_delayed_work_sync(&tasha->spk_anc_dwork.dwork);
snd_soc_update_bits(codec, WCD9335_CDC_RX7_RX_PATH_CFG0,
0x10, 0x00);
ret = tasha_codec_enable_anc(w, kcontrol, event);
@@ -11793,7 +11820,7 @@ static struct snd_soc_dai_driver tasha_dai[] = {
.capture = {
.stream_name = "AIF1 Capture",
.rates = WCD9335_RATES_MASK,
- .formats = TASHA_FORMATS,
+ .formats = TASHA_FORMATS_S16_S24_LE,
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
@@ -11821,7 +11848,7 @@ static struct snd_soc_dai_driver tasha_dai[] = {
.capture = {
.stream_name = "AIF2 Capture",
.rates = WCD9335_RATES_MASK,
- .formats = TASHA_FORMATS,
+ .formats = TASHA_FORMATS_S16_S24_LE,
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
@@ -11849,7 +11876,7 @@ static struct snd_soc_dai_driver tasha_dai[] = {
.capture = {
.stream_name = "AIF3 Capture",
.rates = WCD9335_RATES_MASK,
- .formats = TASHA_FORMATS,
+ .formats = TASHA_FORMATS_S16_S24_LE,
.rate_max = 48000,
.rate_min = 8000,
.channels_min = 1,
@@ -11950,7 +11977,7 @@ static struct snd_soc_dai_driver tasha_i2s_dai[] = {
.capture = {
.stream_name = "AIF1 Capture",
.rates = WCD9335_RATES_MASK,
- .formats = TASHA_FORMATS,
+ .formats = TASHA_FORMATS_S16_S24_LE,
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
@@ -11978,7 +12005,7 @@ static struct snd_soc_dai_driver tasha_i2s_dai[] = {
.capture = {
.stream_name = "AIF2 Capture",
.rates = WCD9335_RATES_MASK,
- .formats = TASHA_FORMATS,
+ .formats = TASHA_FORMATS_S16_S24_LE,
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
@@ -13687,6 +13714,10 @@ static int tasha_codec_probe(struct snd_soc_codec *codec)
tasha_tx_mute_update_callback);
}
+ tasha->spk_anc_dwork.tasha = tasha;
+ INIT_DELAYED_WORK(&tasha->spk_anc_dwork.dwork,
+ tasha_spk_anc_update_callback);
+
mutex_lock(&tasha->codec_mutex);
snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT1");
snd_soc_dapm_disable_pin(dapm, "ANC LINEOUT2");
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 6745aec41388..56882be12554 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -546,6 +546,16 @@ struct tx_mute_work {
struct delayed_work dwork;
};
+#define WCD934X_SPK_ANC_EN_DELAY_MS 350
+static int spk_anc_en_delay = WCD934X_SPK_ANC_EN_DELAY_MS;
+module_param(spk_anc_en_delay, int, S_IRUGO | S_IWUSR | S_IWGRP);
+MODULE_PARM_DESC(spk_anc_en_delay, "delay to enable anc in speaker path");
+
+struct spk_anc_work {
+ struct tavil_priv *tavil;
+ struct delayed_work dwork;
+};
+
struct hpf_work {
struct tavil_priv *tavil;
u8 decimator;
@@ -610,6 +620,7 @@ struct tavil_priv {
struct work_struct tavil_add_child_devices_work;
struct hpf_work tx_hpf_work[WCD934X_NUM_DECIMATORS];
struct tx_mute_work tx_mute_dwork[WCD934X_NUM_DECIMATORS];
+ struct spk_anc_work spk_anc_dwork;
unsigned int vi_feed_value;
@@ -1775,6 +1786,21 @@ static int tavil_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
return 0;
}
+static void tavil_spk_anc_update_callback(struct work_struct *work)
+{
+ struct spk_anc_work *spk_anc_dwork;
+ struct tavil_priv *tavil;
+ struct delayed_work *delayed_work;
+ struct snd_soc_codec *codec;
+
+ delayed_work = to_delayed_work(work);
+ spk_anc_dwork = container_of(delayed_work, struct spk_anc_work, dwork);
+ tavil = spk_anc_dwork->tavil;
+ codec = tavil->codec;
+
+ snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_CFG0, 0x10, 0x10);
+}
+
static int tavil_codec_enable_spkr_anc(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -1792,10 +1818,11 @@ static int tavil_codec_enable_spkr_anc(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
ret = tavil_codec_enable_anc(w, kcontrol, event);
- snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_CFG0,
- 0x10, 0x10);
+ schedule_delayed_work(&tavil->spk_anc_dwork.dwork,
+ msecs_to_jiffies(spk_anc_en_delay));
break;
case SND_SOC_DAPM_POST_PMD:
+ cancel_delayed_work_sync(&tavil->spk_anc_dwork.dwork);
snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_CFG0,
0x10, 0x00);
ret = tavil_codec_enable_anc(w, kcontrol, event);
@@ -4182,7 +4209,7 @@ int tavil_micbias_control(struct snd_soc_codec *codec,
post_dapm_on, &tavil->mbhc->wcd_mbhc);
break;
case MICB_DISABLE:
- if (tavil->pullup_ref[micb_index] > 0)
+ if (tavil->micb_ref[micb_index] > 0)
tavil->micb_ref[micb_index]--;
if ((tavil->micb_ref[micb_index] == 0) &&
(tavil->pullup_ref[micb_index] > 0))
@@ -4362,6 +4389,9 @@ static const struct reg_sequence tavil_hph_reset_tbl[] = {
{ WCD934X_HPH_RDAC_LDO_CTL, 0x33 },
{ WCD934X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 },
{ WCD934X_HPH_REFBUFF_UHQA_CTL, 0xA8 },
+};
+
+static const struct reg_sequence tavil_hph_reset_tbl_1_0[] = {
{ WCD934X_HPH_REFBUFF_LP_CTL, 0x0A },
{ WCD934X_HPH_L_DAC_CTL, 0x00 },
{ WCD934X_HPH_R_DAC_CTL, 0x00 },
@@ -4383,6 +4413,28 @@ static const struct reg_sequence tavil_hph_reset_tbl[] = {
{ WCD934X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 },
};
+static const struct reg_sequence tavil_hph_reset_tbl_1_1[] = {
+ { WCD934X_HPH_REFBUFF_LP_CTL, 0x0E },
+ { WCD934X_HPH_L_DAC_CTL, 0x00 },
+ { WCD934X_HPH_R_DAC_CTL, 0x00 },
+ { WCD934X_HPH_NEW_ANA_HPH2, 0x00 },
+ { WCD934X_HPH_NEW_ANA_HPH3, 0x00 },
+ { WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40 },
+ { WCD934X_HPH_NEW_INT_RDAC_HD2_CTL, 0x81 },
+ { WCD934X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10 },
+ { WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 },
+ { WCD934X_HPH_NEW_INT_RDAC_MISC1, 0x81 },
+ { WCD934X_HPH_NEW_INT_PA_MISC1, 0x22 },
+ { WCD934X_HPH_NEW_INT_PA_MISC2, 0x00 },
+ { WCD934X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 },
+ { WCD934X_HPH_NEW_INT_HPH_TIMER1, 0xFE },
+ { WCD934X_HPH_NEW_INT_HPH_TIMER2, 0x2 },
+ { WCD934X_HPH_NEW_INT_HPH_TIMER3, 0x4e},
+ { WCD934X_HPH_NEW_INT_HPH_TIMER4, 0x54 },
+ { WCD934X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00 },
+ { WCD934X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 },
+};
+
static const struct tavil_reg_mask_val tavil_pa_disable[] = {
{ WCD934X_CDC_RX1_RX_PATH_CTL, 0x30, 0x10 }, /* RX1 mute enable */
{ WCD934X_CDC_RX2_RX_PATH_CTL, 0x30, 0x10 }, /* RX2 mute enable */
@@ -4408,6 +4460,7 @@ static const struct tavil_reg_mask_val tavil_ocp_en_seq_1[] = {
/* LO-HIFI */
static const struct tavil_reg_mask_val tavil_pre_pa_en_lohifi[] = {
{ WCD934X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00 },
+ { WCD934X_FLYBACK_VNEG_CTRL_4, 0xf0, 0x80 },
{ WCD934X_HPH_NEW_INT_PA_MISC2, 0x20, 0x20 },
{ WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xf0, 0x40 },
{ WCD934X_HPH_CNP_WG_CTL, 0x80, 0x00 },
@@ -4449,6 +4502,7 @@ static void tavil_codec_hph_reg_recover(struct tavil_priv *tavil,
struct regmap *map, int pa_status)
{
int i;
+ unsigned int reg;
blocking_notifier_call_chain(&tavil->mbhc->notifier,
WCD_EVENT_OCP_OFF,
@@ -4470,6 +4524,12 @@ static void tavil_codec_hph_reg_recover(struct tavil_priv *tavil,
/* Restore to HW defaults */
regmap_multi_reg_write(map, tavil_hph_reset_tbl,
ARRAY_SIZE(tavil_hph_reset_tbl));
+ if (TAVIL_IS_1_1(tavil->wcd9xxx))
+ regmap_multi_reg_write(map, tavil_hph_reset_tbl_1_1,
+ ARRAY_SIZE(tavil_hph_reset_tbl_1_1));
+ if (TAVIL_IS_1_0(tavil->wcd9xxx))
+ regmap_multi_reg_write(map, tavil_hph_reset_tbl_1_0,
+ ARRAY_SIZE(tavil_hph_reset_tbl_1_0));
for (i = 0; i < ARRAY_SIZE(tavil_ocp_en_seq); i++)
regmap_write_bits(map, tavil_ocp_en_seq[i].reg,
@@ -4483,13 +4543,23 @@ pa_en_restore:
__func__, pa_status);
/* Disable PA and other registers before restoring */
- for (i = 0; i < ARRAY_SIZE(tavil_pa_disable); i++)
+ for (i = 0; i < ARRAY_SIZE(tavil_pa_disable); i++) {
+ if (TAVIL_IS_1_1(tavil->wcd9xxx) &&
+ (tavil_pa_disable[i].reg == WCD934X_HPH_CNP_WG_CTL))
+ continue;
regmap_write_bits(map, tavil_pa_disable[i].reg,
tavil_pa_disable[i].mask,
tavil_pa_disable[i].val);
+ }
regmap_multi_reg_write(map, tavil_hph_reset_tbl,
ARRAY_SIZE(tavil_hph_reset_tbl));
+ if (TAVIL_IS_1_1(tavil->wcd9xxx))
+ regmap_multi_reg_write(map, tavil_hph_reset_tbl_1_1,
+ ARRAY_SIZE(tavil_hph_reset_tbl_1_1));
+ if (TAVIL_IS_1_0(tavil->wcd9xxx))
+ regmap_multi_reg_write(map, tavil_hph_reset_tbl_1_0,
+ ARRAY_SIZE(tavil_hph_reset_tbl_1_0));
for (i = 0; i < ARRAY_SIZE(tavil_ocp_en_seq_1); i++)
regmap_write_bits(map, tavil_ocp_en_seq_1[i].reg,
@@ -4497,17 +4567,37 @@ pa_en_restore:
tavil_ocp_en_seq_1[i].val);
if (tavil->hph_mode == CLS_H_LOHIFI) {
- for (i = 0; i < ARRAY_SIZE(tavil_pre_pa_en_lohifi); i++)
+ for (i = 0; i < ARRAY_SIZE(tavil_pre_pa_en_lohifi); i++) {
+ reg = tavil_pre_pa_en_lohifi[i].reg;
+ if ((TAVIL_IS_1_1(tavil->wcd9xxx)) &&
+ ((reg == WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL) ||
+ (reg == WCD934X_HPH_CNP_WG_CTL) ||
+ (reg == WCD934X_HPH_REFBUFF_LP_CTL)))
+ continue;
regmap_write_bits(map,
tavil_pre_pa_en_lohifi[i].reg,
tavil_pre_pa_en_lohifi[i].mask,
tavil_pre_pa_en_lohifi[i].val);
+ }
} else {
- for (i = 0; i < ARRAY_SIZE(tavil_pre_pa_en); i++)
+ for (i = 0; i < ARRAY_SIZE(tavil_pre_pa_en); i++) {
+ reg = tavil_pre_pa_en[i].reg;
+ if ((TAVIL_IS_1_1(tavil->wcd9xxx)) &&
+ ((reg == WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL) ||
+ (reg == WCD934X_HPH_CNP_WG_CTL) ||
+ (reg == WCD934X_HPH_REFBUFF_LP_CTL)))
+ continue;
regmap_write_bits(map, tavil_pre_pa_en[i].reg,
tavil_pre_pa_en[i].mask,
tavil_pre_pa_en[i].val);
+ }
}
+
+ if (TAVIL_IS_1_1(tavil->wcd9xxx)) {
+ regmap_write(map, WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x84);
+ regmap_write(map, WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x84);
+ }
+
regmap_write_bits(map, WCD934X_ANA_HPH, 0x0C, pa_status & 0x0C);
regmap_write_bits(map, WCD934X_ANA_HPH, 0x30, 0x30);
/* wait for 100usec after HPH DAC is enabled */
@@ -4516,10 +4606,14 @@ pa_en_restore:
/* Sleep for 7msec after PA is enabled */
usleep_range(7000, 7100);
- for (i = 0; i < ARRAY_SIZE(tavil_post_pa_en); i++)
+ for (i = 0; i < ARRAY_SIZE(tavil_post_pa_en); i++) {
+ if ((TAVIL_IS_1_1(tavil->wcd9xxx)) &&
+ (tavil_post_pa_en[i].reg == WCD934X_HPH_CNP_WG_CTL))
+ continue;
regmap_write_bits(map, tavil_post_pa_en[i].reg,
tavil_post_pa_en[i].mask,
tavil_post_pa_en[i].val);
+ }
end:
tavil->mbhc->is_hph_recover = true;
@@ -5049,14 +5143,18 @@ static int tavil_mad_input_put(struct snd_kcontrol *kcontrol,
u32 adc, i, mic_bias_found = 0;
int ret = 0;
char *mad_input;
+ bool is_adc2_input = false;
tavil_mad_input = ucontrol->value.integer.value[0];
if (strnstr(tavil_conn_mad_text[tavil_mad_input], "NOTUSED",
sizeof("NOTUSED"))) {
- dev_err(codec->dev,
+ dev_dbg(codec->dev,
"%s: Unsupported tavil_mad_input = %s\n",
__func__, tavil_conn_mad_text[tavil_mad_input]);
+ /* Make sure the MAD register is updated */
+ snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
+ 0x88, 0x00);
return -EINVAL;
}
@@ -5085,14 +5183,16 @@ static int tavil_mad_input_put(struct snd_kcontrol *kcontrol,
snprintf(mad_amic_input_widget, 6, "%s%u", "AMIC", adc);
mad_input_widget = mad_amic_input_widget;
+ if (adc == 2)
+ is_adc2_input = true;
} else {
/* DMIC type input widget*/
mad_input_widget = tavil_conn_mad_text[tavil_mad_input];
}
dev_dbg(codec->dev,
- "%s: tavil input widget = %s\n", __func__,
- mad_input_widget);
+ "%s: tavil input widget = %s, adc_input = %s\n", __func__,
+ mad_input_widget, is_adc2_input ? "true" : "false");
for (i = 0; i < card->num_of_dapm_routes; i++) {
if (!strcmp(card->of_dapm_routes[i].sink, mad_input_widget)) {
@@ -5137,7 +5237,13 @@ static int tavil_mad_input_put(struct snd_kcontrol *kcontrol,
0x0F, tavil_mad_input);
snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
0x07, mic_bias_found);
-
+ /* for adc2 input, mad should be in micbias mode with BG enabled */
+ if (is_adc2_input)
+ snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
+ 0x88, 0x88);
+ else
+ snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
+ 0x88, 0x00);
return 0;
}
@@ -8492,21 +8598,6 @@ done:
return rc;
}
-static void tavil_enable_sido_buck(struct snd_soc_codec *codec)
-{
- struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
-
- snd_soc_update_bits(codec, WCD934X_ANA_RCO, 0x80, 0x80);
- usleep_range(100, 110);
- snd_soc_update_bits(codec, WCD934X_ANA_BUCK_CTL, 0x02, 0x02);
- usleep_range(100, 110);
- snd_soc_update_bits(codec, WCD934X_ANA_BUCK_CTL, 0x01, 0x01);
- usleep_range(100, 110);
- snd_soc_update_bits(codec, WCD934X_ANA_BUCK_CTL, 0x04, 0x04);
- usleep_range(100, 110);
- tavil->resmgr->sido_input_src = SIDO_SOURCE_RCO_BG;
-}
-
static void tavil_cdc_vote_svs(struct snd_soc_codec *codec, bool vote)
{
struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
@@ -8609,7 +8700,8 @@ static int tavil_device_down(struct wcd9xxx *wcd9xxx)
for (count = 0; count < NUM_CODEC_DAIS; count++)
priv->dai[count].bus_down_in_recovery = true;
wcd_dsp_ssr_event(priv->wdsp_cntl, WCD_CDC_DOWN_EVENT);
- priv->resmgr->sido_input_src = SIDO_SOURCE_INTERNAL;
+ wcd_resmgr_set_sido_input_src_locked(priv->resmgr,
+ SIDO_SOURCE_INTERNAL);
return 0;
}
@@ -8781,7 +8873,6 @@ static int tavil_soc_codec_probe(struct snd_soc_codec *codec)
tavil->comp_enabled[i] = 0;
tavil_codec_init_reg(tavil);
- tavil_enable_sido_buck(codec);
pdata = dev_get_platdata(codec->dev->parent);
ret = tavil_handle_pdata(tavil, pdata);
@@ -8837,6 +8928,10 @@ static int tavil_soc_codec_probe(struct snd_soc_codec *codec)
tavil_tx_mute_update_callback);
}
+ tavil->spk_anc_dwork.tavil = tavil;
+ INIT_DELAYED_WORK(&tavil->spk_anc_dwork.dwork,
+ tavil_spk_anc_update_callback);
+
tavil_mclk2_reg_defaults(tavil);
/* DSD initialization */
@@ -9352,7 +9447,6 @@ err_mem:
static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil)
{
int val, rc;
- struct snd_soc_codec *codec;
__tavil_cdc_mclk_enable(tavil, true);
@@ -9372,14 +9466,6 @@ static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil)
WARN(1, "%s: Efuse sense is not complete val=%x, ret=%d\n",
__func__, val, rc);
- codec = tavil->codec;
- if (!codec) {
- pr_debug("%s: codec is not yet registered\n", __func__);
- goto done;
- }
- tavil_enable_sido_buck(codec);
-
-done:
__tavil_cdc_mclk_enable(tavil, false);
return rc;
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.c b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
index 39ca965e791e..84754b8d09b0 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
@@ -25,6 +25,8 @@
#define WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL 0x0d41
#define WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL 0x0d42
+static void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
+ int sido_src);
static const char *wcd_resmgr_clk_type_to_str(enum wcd_clock_type clk_type)
{
if (clk_type == WCD_CLK_OFF)
@@ -262,6 +264,8 @@ static int wcd_resmgr_enable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr)
0x01, 0x01);
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD934X_CODEC_RPM_CLK_GATE, 0x03, 0x00);
+ wcd_resmgr_set_sido_input_src(resmgr,
+ SIDO_SOURCE_RCO_BG);
} else {
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
@@ -315,6 +319,10 @@ static int wcd_resmgr_disable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr)
0x80, 0x00);
}
+ if ((resmgr->codec_type == WCD934X) &&
+ (resmgr->clk_type == WCD_CLK_OFF))
+ wcd_resmgr_set_sido_input_src(resmgr, SIDO_SOURCE_INTERNAL);
+
pr_debug("%s: mclk_users: %d, clk_type: %s\n", __func__,
resmgr->clk_mclk_users,
wcd_resmgr_clk_type_to_str(resmgr->clk_type));
@@ -444,6 +452,9 @@ static int wcd_resmgr_disable_clk_rco(struct wcd9xxx_resmgr_v2 *resmgr)
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD9335_ANA_RCO,
0x80, 0x00);
+ wcd_resmgr_codec_reg_update_bits(resmgr,
+ WCD934X_CLK_SYS_MCLK_PRG,
+ 0x01, 0x00);
resmgr->clk_type = WCD_CLK_OFF;
} else if ((resmgr->clk_rco_users == 0) &&
(resmgr->clk_mclk_users)) {
@@ -455,6 +466,11 @@ static int wcd_resmgr_disable_clk_rco(struct wcd9xxx_resmgr_v2 *resmgr)
WCD9335_ANA_RCO,
0x80, 0x00);
}
+
+ if ((resmgr->codec_type == WCD934X) &&
+ (resmgr->clk_type == WCD_CLK_OFF))
+ wcd_resmgr_set_sido_input_src(resmgr, SIDO_SOURCE_INTERNAL);
+
pr_debug("%s: rco clk users: %d, clk_type: %s\n", __func__,
resmgr->clk_rco_users,
wcd_resmgr_clk_type_to_str(resmgr->clk_type));
@@ -493,6 +509,64 @@ int wcd_resmgr_enable_clk_block(struct wcd9xxx_resmgr_v2 *resmgr,
return ret;
}
+static void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
+ int sido_src)
+{
+ if (!resmgr)
+ return;
+
+ if (sido_src == resmgr->sido_input_src)
+ return;
+
+ if (sido_src == SIDO_SOURCE_INTERNAL) {
+ wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+ 0x04, 0x00);
+ usleep_range(100, 110);
+ wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+ 0x03, 0x00);
+ usleep_range(100, 110);
+ wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_RCO,
+ 0x80, 0x00);
+ usleep_range(100, 110);
+ resmgr->sido_input_src = SIDO_SOURCE_INTERNAL;
+ pr_debug("%s: sido input src to internal\n", __func__);
+ } else if (sido_src == SIDO_SOURCE_RCO_BG) {
+ wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_RCO,
+ 0x80, 0x80);
+ usleep_range(100, 110);
+ wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+ 0x02, 0x02);
+ usleep_range(100, 110);
+ wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+ 0x01, 0x01);
+ usleep_range(100, 110);
+ wcd_resmgr_codec_reg_update_bits(resmgr, WCD934X_ANA_BUCK_CTL,
+ 0x04, 0x04);
+ usleep_range(100, 110);
+ resmgr->sido_input_src = SIDO_SOURCE_RCO_BG;
+ pr_debug("%s: sido input src to external\n", __func__);
+ }
+}
+
+/*
+ * wcd_resmgr_set_sido_input_src_locked:
+ * Set SIDO input in BG_CLK locked context
+ *
+ * @resmgr: handle to struct wcd9xxx_resmgr_v2
+ * @sido_src: Select the SIDO input source
+ */
+void wcd_resmgr_set_sido_input_src_locked(struct wcd9xxx_resmgr_v2 *resmgr,
+ int sido_src)
+{
+ if (!resmgr)
+ return;
+
+ WCD9XXX_V2_BG_CLK_LOCK(resmgr);
+ wcd_resmgr_set_sido_input_src(resmgr, sido_src);
+ WCD9XXX_V2_BG_CLK_UNLOCK(resmgr);
+}
+EXPORT_SYMBOL(wcd_resmgr_set_sido_input_src_locked);
+
/*
* wcd_resmgr_disable_clk_block: disable MCLK or RCO
* @resmgr: handle to struct wcd9xxx_resmgr_v2
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.h b/sound/soc/codecs/wcd9xxx-resmgr-v2.h
index c1955d31889f..f605a249a620 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.h
@@ -85,4 +85,6 @@ int wcd_resmgr_disable_clk_block(struct wcd9xxx_resmgr_v2 *resmgr,
enum wcd_clock_type type);
int wcd_resmgr_get_clk_type(struct wcd9xxx_resmgr_v2 *resmgr);
void wcd_resmgr_post_ssr_v2(struct wcd9xxx_resmgr_v2 *resmgr);
+void wcd_resmgr_set_sido_input_src_locked(struct wcd9xxx_resmgr_v2 *resmgr,
+ int sido_src);
#endif
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 64a1fa76604d..9cf69eca0028 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -98,6 +98,70 @@ config SND_SOC_CPE
The configuration includes the cpe lsm driver to enable
listen on codec.
+config SND_SOC_INT_CODEC
+ tristate "SoC Machine driver for MSMFALCON_INT"
+ depends on ARCH_QCOM
+ select SND_SOC_QDSP6V2
+ select SND_SOC_MSM_STUB
+ select SND_SOC_MSM_HOSTLESS_PCM
+ select SND_DYNAMIC_MINORS
+ select MSM_QDSP6_APRV2_GLINK
+ select MSM_QDSP6_SSR
+ select MSM_QDSP6_PDR
+ select MSM_QDSP6_NOTIFIER
+ select MSM_QDSP6V2_CODECS
+ select SND_SOC_MSM_SWR
+ select SND_SOC_MSM8X16_WCD
+ select QTI_PP
+ select DTS_SRS_TM
+ select DOLBY_DAP
+ select DOLBY_DS2
+ select SND_HWDEP
+ select MSM_ULTRASOUND
+ select DTS_EAGLE
+ select SND_SOC_MSMFALCON_COMMON
+ select SND_SOC_COMPRESS
+ help
+ To add support for SoC audio on MSM_INT.
+ This will enable sound soc drivers which
+ interfaces with DSP, also it will enable
+ the machine driver and the corresponding
+ DAI-links
+
+config SND_SOC_EXT_CODEC
+ tristate "SoC Machine driver for MSMFALCON_EXT"
+ depends on ARCH_QCOM
+ select SND_SOC_QDSP6V2
+ select SND_SOC_MSM_STUB
+ select SND_SOC_MSM_HOSTLESS_PCM
+ select SND_DYNAMIC_MINORS
+ select MSM_QDSP6_APRV2_GLINK
+ select MSM_QDSP6_SSR
+ select MSM_QDSP6_PDR
+ select MSM_QDSP6_NOTIFIER
+ select MSM_QDSP6V2_CODECS
+ select SND_SOC_WCD9335
+ select SND_SOC_WCD934X
+ select SND_SOC_WSA881X
+ select MFD_CORE
+ select QTI_PP
+ select DTS_SRS_TM
+ select DOLBY_DAP
+ select DOLBY_DS2
+ select SND_SOC_CPE
+ select SND_SOC_WCD_CPE
+ select SND_HWDEP
+ select MSM_ULTRASOUND
+ select DTS_EAGLE
+ select SND_SOC_MSMFALCON_COMMON
+ select SND_SOC_COMPRESS
+ help
+ To add support for SoC audio on MSM_EXT.
+ This will enable sound soc drivers which
+ interfaces with DSP, also it will enable
+ the machine driver and the corresponding
+ DAI-links
+
config SND_SOC_MSM8996
tristate "SoC Machine driver for MSM8996 boards"
depends on ARCH_MSM8996
@@ -157,4 +221,16 @@ config SND_SOC_MSMCOBALT
the machine driver and the corresponding
DAI-links
+config SND_SOC_FALCON
+ tristate "SoC Machine driver for MSMFALCON boards"
+ depends on ARCH_MSMFALCON
+ select SND_SOC_INT_CODEC
+ select SND_SOC_EXT_CODEC
+ help
+ To add support for SoC audio on MSMFALCON.
+ This will enable sound soc drivers which
+ interfaces with DSP, also it will enable
+ the machine driver and the corresponding
+ DAI-links
+
endmenu
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 3ad34be41578..799c9ee63d43 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -19,3 +19,18 @@ obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-msm8996.o
# for MSMCOBALT sound card driver
snd-soc-msmcobalt-objs := msmcobalt.o
obj-$(CONFIG_SND_SOC_MSMCOBALT) += snd-soc-msmcobalt.o
+
+# for MSMFALCON sound card driver
+snd-soc-msmfalcon-common-objs := msm-audio-pinctrl.o msmfalcon-common.o
+obj-$(CONFIG_SND_SOC_MSMFALCON_COMMON) += snd-soc-msmfalcon-common.o
+
+# for MSMFALCON sound card driver
+snd-soc-int-codec-objs := msmfalcon-internal.o
+obj-$(CONFIG_SND_SOC_INT_CODEC) += snd-soc-msmfalcon-common.o
+obj-$(CONFIG_SND_SOC_INT_CODEC) += snd-soc-int-codec.o
+
+# for MSMFALCON sound card driver
+snd-soc-ext-codec-objs := msmfalcon-external.o msmfalcon-ext-dai-links.o
+obj-$(CONFIG_SND_SOC_EXT_CODEC) += snd-soc-msmfalcon-common.o
+obj-$(CONFIG_SND_SOC_EXT_CODEC) += snd-soc-ext-codec.o
+
diff --git a/sound/soc/msm/msm-audio-pinctrl.h b/sound/soc/msm/msm-audio-pinctrl.h
index 0b5395520b1b..73eeaff39bfd 100644
--- a/sound/soc/msm/msm-audio-pinctrl.h
+++ b/sound/soc/msm/msm-audio-pinctrl.h
@@ -1,4 +1,4 @@
- /* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ /* Copyright (c) 2015-2016, 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
@@ -14,8 +14,7 @@
#define __MSM_AUDIO_PINCTRL_H
enum pinctrl_client {
- CLIENT_WCD_INT,
- CLIENT_WCD_EXT,
+ CLIENT_WCD,
CLIENT_WSA_BONGO_1,
CLIENT_WSA_BONGO_2,
MAX_PINCTRL_CLIENT,
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index ee9dcacdd5c9..aa036d352f40 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -870,6 +870,38 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
.name = "QUAT_MI2S_RX_HOSTLESS",
.probe = fe_dai_probe,
},
+ {
+ .playback = {
+ .stream_name = "INT0 MI2S_RX Hostless Playback",
+ .aif_name = "INT0_MI2S_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "INT0_MI2S_RX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "INT4 MI2S_RX Hostless Playback",
+ .aif_name = "INT4_MI2S_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "INT4_MI2S_RX_HOSTLESS",
+ .probe = fe_dai_probe,
+ },
/* TDM Hostless */
{
.capture = {
diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c
index c295c26a6fd7..9c392f3d4ddc 100644
--- a/sound/soc/msm/msmcobalt.c
+++ b/sound/soc/msm/msmcobalt.c
@@ -3258,20 +3258,23 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_ignore_suspend(dapm, "EAR");
snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1");
snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
- snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
- snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
snd_soc_dapm_ignore_suspend(dapm, "ANC EAR");
snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
snd_soc_dapm_ignore_suspend(dapm, "HPHL");
snd_soc_dapm_ignore_suspend(dapm, "HPHR");
- snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
- snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
- snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
- snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
+ if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) {
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
+ }
+
snd_soc_dapm_sync(dapm);
snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
diff --git a/sound/soc/msm/msmfalcon-common.c b/sound/soc/msm/msmfalcon-common.c
new file mode 100644
index 000000000000..6c96a0778b52
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-common.c
@@ -0,0 +1,1768 @@
+/* Copyright (c) 2015-2016, 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/input.h>
+#include <linux/of_gpio.h>
+#include <linux/mfd/msm-cdc-pinctrl.h>
+#include <sound/pcm_params.h>
+#include <sound/q6afe-v2.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "msm-audio-pinctrl.h"
+#include "msmfalcon-common.h"
+#include "msmfalcon-internal.h"
+#include "msmfalcon-external.h"
+#include "../codecs/msm8x16/msm8x16-wcd.h"
+#include "../codecs/wsa881x.h"
+
+#define DRV_NAME "msmfalcon-asoc-snd"
+
+#define DEV_NAME_STR_LEN 32
+#define DEFAULT_MCLK_RATE 9600000
+
+enum {
+ PRIM_MI2S = 0,
+ SEC_MI2S,
+ TERT_MI2S,
+ QUAT_MI2S,
+ MI2S_MAX,
+};
+
+enum {
+ PRIM_AUX_PCM = 0,
+ SEC_AUX_PCM,
+ TERT_AUX_PCM,
+ QUAT_AUX_PCM,
+ AUX_PCM_MAX,
+};
+
+enum {
+ PCM_I2S_SEL_PRIM = 0,
+ PCM_I2S_SEL_SEC,
+ PCM_I2S_SEL_TERT,
+ PCM_I2S_SEL_QUAT,
+ PCM_I2S_SEL_MAX,
+};
+
+struct mi2s_aux_pcm_common_conf {
+ struct mutex lock;
+ void *pcm_i2s_sel_vt_addr;
+};
+
+struct mi2s_conf {
+ struct mutex lock;
+ u32 ref_cnt;
+ u32 msm_is_mi2s_master;
+};
+
+struct auxpcm_conf {
+ struct mutex lock;
+ u32 ref_cnt;
+};
+
+struct dev_config {
+ u32 sample_rate;
+ u32 bit_format;
+ u32 channels;
+};
+
+struct msm_wsa881x_dev_info {
+ struct device_node *of_node;
+ u32 index;
+};
+static struct snd_soc_aux_dev *msm_aux_dev;
+static struct snd_soc_codec_conf *msm_codec_conf;
+
+static bool msm_swap_gnd_mic(struct snd_soc_codec *codec);
+
+static struct wcd_mbhc_config mbhc_cfg = {
+ .read_fw_bin = false,
+ .calibration = NULL,
+ .detect_extn_cable = true,
+ .mono_stero_detection = false,
+ .swap_gnd_mic = NULL,
+ .hs_ext_micbias = false,
+ .key_code[0] = KEY_MEDIA,
+ .key_code[1] = KEY_VOICECOMMAND,
+ .key_code[2] = KEY_VOLUMEUP,
+ .key_code[3] = KEY_VOLUMEDOWN,
+ .key_code[4] = 0,
+ .key_code[5] = 0,
+ .key_code[6] = 0,
+ .key_code[7] = 0,
+ .linein_th = 5000,
+ .moisture_en = false,
+ .mbhc_micbias = 0,
+ .anc_micbias = 0,
+ .enable_anc_mic_detect = false,
+};
+
+static struct dev_config proxy_rx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 2,
+};
+
+static struct dev_config btsco_cfg = {
+ .sample_rate = SAMPLING_RATE_8KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 1,
+};
+
+/* Default configuration of MI2S channels */
+static struct dev_config mi2s_rx_cfg[] = {
+ [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+static struct dev_config mi2s_tx_cfg[] = {
+ [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static struct dev_config aux_pcm_rx_cfg[] = {
+ [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static struct dev_config aux_pcm_tx_cfg[] = {
+ [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static char const *ch_text[] = {"Two", "Three", "Four", "Five",
+ "Six", "Seven", "Eight"};
+static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
+static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_96", "KHZ_192"};
+static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven",
+ "Eight"};
+
+static SOC_ENUM_SINGLE_EXT_DECL(btsco_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_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);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text);
+
+static struct afe_clk_set mi2s_clk[MI2S_MAX] = {
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ }
+};
+
+static struct mi2s_aux_pcm_common_conf mi2s_auxpcm_conf[PCM_I2S_SEL_MAX];
+static struct mi2s_conf mi2s_intf_conf[MI2S_MAX];
+static struct auxpcm_conf auxpcm_intf_conf[AUX_PCM_MAX];
+
+static int proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: proxy_rx channels = %d\n",
+ __func__, proxy_rx_cfg.channels);
+ ucontrol->value.integer.value[0] = proxy_rx_cfg.channels - 2;
+
+ return 0;
+}
+
+static int proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ proxy_rx_cfg.channels = ucontrol->value.integer.value[0] + 2;
+ pr_debug("%s: proxy_rx channels = %d\n",
+ __func__, proxy_rx_cfg.channels);
+
+ return 1;
+}
+
+static int aux_pcm_get_sample_rate(int value)
+{
+ int sample_rate;
+
+ switch (value) {
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 0:
+ default:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int aux_pcm_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int idx;
+
+ if (strnstr(kcontrol->id.name, "PRIM_AUX_PCM",
+ sizeof("PRIM_AUX_PCM")))
+ idx = PRIM_AUX_PCM;
+ else if (strnstr(kcontrol->id.name, "SEC_AUX_PCM",
+ sizeof("SEC_AUX_PCM")))
+ idx = SEC_AUX_PCM;
+ else if (strnstr(kcontrol->id.name, "TERT_AUX_PCM",
+ sizeof("TERT_AUX_PCM")))
+ idx = TERT_AUX_PCM;
+ else if (strnstr(kcontrol->id.name, "QUAT_AUX_PCM",
+ sizeof("QUAT_AUX_PCM")))
+ idx = QUAT_AUX_PCM;
+ else {
+ pr_err("%s: unsupported port: %s",
+ __func__, kcontrol->id.name);
+ idx = -EINVAL;
+ }
+
+ return idx;
+}
+
+static int btsco_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ btsco_cfg.sample_rate =
+ aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: btsco_sample_rate = %d, item = %d\n", __func__,
+ btsco_cfg.sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int btsco_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] =
+ aux_pcm_get_sample_rate_val(btsco_cfg.sample_rate);
+
+ pr_debug("%s: btsco_sample_rate = %d, item = %d\n", __func__,
+ btsco_cfg.sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ aux_pcm_rx_cfg[idx].sample_rate =
+ aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ aux_pcm_get_sample_rate_val(aux_pcm_rx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ aux_pcm_tx_cfg[idx].sample_rate =
+ aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ aux_pcm_get_sample_rate_val(aux_pcm_tx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int idx;
+
+ if (strnstr(kcontrol->id.name, "PRIM_MI2S_RX",
+ sizeof("PRIM_MI2S_RX")))
+ idx = PRIM_MI2S;
+ else if (strnstr(kcontrol->id.name, "SEC_MI2S_RX",
+ sizeof("SEC_MI2S_RX")))
+ idx = SEC_MI2S;
+ else if (strnstr(kcontrol->id.name, "TERT_MI2S_RX",
+ sizeof("TERT_MI2S_RX")))
+ idx = TERT_MI2S;
+ else if (strnstr(kcontrol->id.name, "QUAT_MI2S_RX",
+ sizeof("QUAT_MI2S_RX")))
+ idx = QUAT_MI2S;
+ else if (strnstr(kcontrol->id.name, "PRIM_MI2S_TX",
+ sizeof("PRIM_MI2S_TX")))
+ idx = PRIM_MI2S;
+ else if (strnstr(kcontrol->id.name, "SEC_MI2S_TX",
+ sizeof("SEC_MI2S_TX")))
+ idx = SEC_MI2S;
+ else if (strnstr(kcontrol->id.name, "TERT_MI2S_TX",
+ sizeof("TERT_MI2S_TX")))
+ idx = TERT_MI2S;
+ else if (strnstr(kcontrol->id.name, "QUAT_MI2S_TX",
+ sizeof("QUAT_MI2S_TX")))
+ idx = QUAT_MI2S;
+ else {
+ pr_err("%s: unsupported channel: %s",
+ __func__, kcontrol->id.name);
+ idx = -EINVAL;
+ }
+
+ return idx;
+}
+
+static int mi2s_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 6;
+ break;
+ default:
+ sample_rate_val = 4;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int mi2s_get_sample_rate(int value)
+{
+ int sample_rate;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int mi2s_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_rx_cfg[idx].sample_rate =
+ mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_get_sample_rate_val(mi2s_rx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_tx_cfg[idx].sample_rate =
+ mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_get_sample_rate_val(mi2s_tx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].channels);
+ ucontrol->value.enumerated.item[0] = mi2s_rx_cfg[idx].channels - 1;
+
+ return 0;
+}
+
+static int msm_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_rx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].channels);
+
+ return 1;
+}
+
+static int msm_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].channels);
+ ucontrol->value.enumerated.item[0] = mi2s_tx_cfg[idx].channels - 1;
+
+ return 0;
+}
+
+static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_tx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].channels);
+
+ return 1;
+}
+
+const struct snd_kcontrol_new msm_common_snd_controls[] = {
+ SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs,
+ proxy_rx_ch_get, proxy_rx_ch_put),
+ SOC_ENUM_EXT("BTSCO SampleRate", btsco_sample_rate,
+ btsco_sample_rate_get,
+ btsco_sample_rate_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),
+ SOC_ENUM_EXT("SEC_AUX_PCM_RX SampleRate", sec_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_AUX_PCM_RX SampleRate", tert_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_AUX_PCM_RX SampleRate", quat_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_TX SampleRate", prim_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_AUX_PCM_TX SampleRate", sec_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_AUX_PCM_TX SampleRate", tert_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_AUX_PCM_TX SampleRate", quat_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_MI2S_RX SampleRate", prim_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_MI2S_RX SampleRate", sec_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_MI2S_RX SampleRate", tert_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_MI2S_RX SampleRate", quat_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_MI2S_TX SampleRate", prim_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_MI2S_TX SampleRate", sec_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_MI2S_TX SampleRate", tert_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_MI2S_TX SampleRate", quat_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_MI2S_RX Channels", prim_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("PRIM_MI2S_TX Channels", prim_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("SEC_MI2S_RX Channels", sec_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("SEC_MI2S_TX Channels", sec_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("TERT_MI2S_RX Channels", tert_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("TERT_MI2S_TX Channels", tert_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("QUAT_MI2S_RX Channels", quat_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("QUAT_MI2S_TX Channels", quat_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+};
+
+/**
+ * msm_common_be_hw_params_fixup - updates settings of ALSA BE hw params.
+ *
+ * @rtd: runtime dailink instance
+ * @params: HW params of associated backend dailink.
+ *
+ * Returns 0.
+ */
+int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ int rc = 0;
+
+ pr_debug("%s: format = %d, rate = %d\n",
+ __func__, params_format(params), params_rate(params));
+
+ switch (dai_link->be_id) {
+ case MSM_BACKEND_DAI_INT_BT_SCO_RX:
+ case MSM_BACKEND_DAI_INT_BT_SCO_TX:
+ channels->min = channels->max = btsco_cfg.channels;
+ rate->min = rate->max = 1;
+ break;
+
+ case MSM_BACKEND_DAI_AFE_PCM_RX:
+ channels->min = channels->max = proxy_rx_cfg.channels;
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+
+ case MSM_BACKEND_DAI_AUXPCM_RX:
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[PRIM_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_AUXPCM_TX:
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[PRIM_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[PRIM_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_AUXPCM_RX:
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[SEC_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[SEC_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_AUXPCM_TX:
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[SEC_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[SEC_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_AUXPCM_RX:
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[TERT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[TERT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_AUXPCM_TX:
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[TERT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[TERT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_AUXPCM_RX:
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[QUAT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[QUAT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_AUXPCM_TX:
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[QUAT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[QUAT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_MI2S_RX:
+ rate->min = rate->max = mi2s_rx_cfg[PRIM_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[PRIM_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_MI2S_TX:
+ rate->min = rate->max = mi2s_tx_cfg[PRIM_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[PRIM_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_RX:
+ rate->min = rate->max = mi2s_rx_cfg[SEC_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[SEC_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_TX:
+ rate->min = rate->max = mi2s_tx_cfg[SEC_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[SEC_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_RX:
+ rate->min = rate->max = mi2s_rx_cfg[TERT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[TERT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_TX:
+ rate->min = rate->max = mi2s_tx_cfg[TERT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[TERT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX:
+ rate->min = rate->max = mi2s_rx_cfg[QUAT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[QUAT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX:
+ rate->min = rate->max = mi2s_tx_cfg[QUAT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[QUAT_MI2S].channels;
+ break;
+
+ default:
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return rc;
+}
+EXPORT_SYMBOL(msm_common_be_hw_params_fixup);
+
+/**
+ * msm_aux_pcm_snd_startup - startup ops of auxpcm.
+ *
+ * @substream: PCM stream pointer of associated backend dailink
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int msm_aux_pcm_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int index = cpu_dai->id - 1;
+ return ret = 0;
+
+ dev_dbg(rtd->card->dev,
+ "%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
+ __func__, substream->name, substream->stream,
+ cpu_dai->name, cpu_dai->id);
+
+ if (index < PRIM_AUX_PCM || index > QUAT_AUX_PCM) {
+ ret = -EINVAL;
+ dev_err(rtd->card->dev,
+ "%s: CPU DAI id (%d) out of range\n",
+ __func__, cpu_dai->id);
+ goto done;
+ }
+
+ mutex_lock(&auxpcm_intf_conf[index].lock);
+ if (++auxpcm_intf_conf[index].ref_cnt == 1) {
+ if (mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr != NULL) {
+ mutex_lock(&mi2s_auxpcm_conf[index].lock);
+ iowrite32(1,
+ mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr);
+ mutex_unlock(&mi2s_auxpcm_conf[index].lock);
+ } else {
+ dev_err(rtd->card->dev,
+ "%s lpaif_tert_muxsel_virt_addr is NULL\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ }
+ if (IS_ERR_VALUE(ret))
+ auxpcm_intf_conf[index].ref_cnt--;
+
+ mutex_unlock(&auxpcm_intf_conf[index].lock);
+
+done:
+ return ret;
+}
+EXPORT_SYMBOL(msm_aux_pcm_snd_startup);
+
+/**
+ * msm_aux_pcm_snd_shutdown - shutdown ops of auxpcm.
+ *
+ * @substream: PCM stream pointer of associated backend dailink
+ */
+void msm_aux_pcm_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int index = rtd->cpu_dai->id - 1;
+
+ dev_dbg(rtd->card->dev,
+ "%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
+ __func__,
+ substream->name, substream->stream,
+ rtd->cpu_dai->name, rtd->cpu_dai->id);
+
+ if (index < PRIM_AUX_PCM || index > QUAT_AUX_PCM) {
+ dev_err(rtd->card->dev,
+ "%s: CPU DAI id (%d) out of range\n",
+ __func__, rtd->cpu_dai->id);
+ return;
+ }
+
+ mutex_lock(&auxpcm_intf_conf[index].lock);
+ if (--auxpcm_intf_conf[index].ref_cnt == 0) {
+ if (mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr != NULL) {
+ mutex_lock(&mi2s_auxpcm_conf[index].lock);
+ iowrite32(0,
+ mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr);
+ mutex_unlock(&mi2s_auxpcm_conf[index].lock);
+ } else {
+ dev_err(rtd->card->dev,
+ "%s lpaif_tert_muxsel_virt_addr is NULL\n",
+ __func__);
+ auxpcm_intf_conf[index].ref_cnt++;
+ }
+ }
+ mutex_unlock(&auxpcm_intf_conf[index].lock);
+}
+EXPORT_SYMBOL(msm_aux_pcm_snd_shutdown);
+
+static int msm_get_port_id(int be_id)
+{
+ int afe_port_id;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_PRI_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_PRI_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ break;
+ default:
+ pr_err("%s: Invalid be_id: %d\n", __func__, be_id);
+ afe_port_id = -EINVAL;
+ }
+
+ return afe_port_id;
+}
+
+static u32 get_mi2s_bits_per_sample(u32 bit_format)
+{
+ u32 bit_per_sample;
+
+ switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bit_per_sample = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bit_per_sample = 16;
+ break;
+ }
+
+ return bit_per_sample;
+}
+
+static void update_mi2s_clk_val(int dai_id, int stream)
+{
+ u32 bit_per_sample;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ bit_per_sample =
+ get_mi2s_bits_per_sample(mi2s_rx_cfg[dai_id].bit_format);
+ mi2s_clk[dai_id].clk_freq_in_hz =
+ mi2s_rx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
+ } else {
+ bit_per_sample =
+ get_mi2s_bits_per_sample(mi2s_tx_cfg[dai_id].bit_format);
+ mi2s_clk[dai_id].clk_freq_in_hz =
+ mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
+ }
+
+ if (!mi2s_intf_conf[dai_id].msm_is_mi2s_master)
+ mi2s_clk[dai_id].clk_freq_in_hz = 0;
+}
+
+static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int port_id = 0;
+ int index = cpu_dai->id;
+
+ port_id = msm_get_port_id(rtd->dai_link->be_id);
+ if (IS_ERR_VALUE(port_id)) {
+ dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__);
+ ret = port_id;
+ goto done;
+ }
+
+ if (enable) {
+ update_mi2s_clk_val(index, substream->stream);
+ dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__,
+ mi2s_clk[index].clk_freq_in_hz);
+ }
+
+ mi2s_clk[index].enable = enable;
+ ret = afe_set_lpass_clock_v2(port_id,
+ &mi2s_clk[index]);
+ if (ret < 0) {
+ dev_err(rtd->card->dev,
+ "%s: afe lpass clock failed for port 0x%x , err:%d\n",
+ __func__, port_id, ret);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+/**
+ * msm_mi2s_snd_startup - startup ops of mi2s.
+ *
+ * @substream: PCM stream pointer of associated backend dailink
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int index = cpu_dai->id;
+ unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+
+ dev_dbg(rtd->card->dev,
+ "%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
+ __func__, substream->name, substream->stream,
+ cpu_dai->name, cpu_dai->id);
+
+ if (index < PRIM_MI2S || index > QUAT_MI2S) {
+ ret = -EINVAL;
+ dev_err(rtd->card->dev,
+ "%s: CPU DAI id (%d) out of range\n",
+ __func__, cpu_dai->id);
+ goto done;
+ }
+ /*
+ * Muxtex protection in case the same MI2S
+ * interface using for both TX and RX so
+ * that the same clock won't be enable twice.
+ */
+ mutex_lock(&mi2s_intf_conf[index].lock);
+ if (++mi2s_intf_conf[index].ref_cnt == 1) {
+ ret = msm_mi2s_set_sclk(substream, true);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(rtd->card->dev,
+ "%s: afe lpass clock failed to enable MI2S clock, err:%d\n",
+ __func__, ret);
+ goto clean_up;
+ }
+ if (mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr != NULL) {
+ mutex_lock(&mi2s_auxpcm_conf[index].lock);
+ iowrite32(0,
+ mi2s_auxpcm_conf[index].pcm_i2s_sel_vt_addr);
+ mutex_unlock(&mi2s_auxpcm_conf[index].lock);
+ } else {
+ dev_err(rtd->card->dev,
+ "%s lpaif_muxsel_virt_addr is NULL for dai %d\n",
+ __func__, index);
+ ret = -EINVAL;
+ goto clk_off;
+ }
+ /* Check if msm needs to provide the clock to the interface */
+ if (!mi2s_intf_conf[index].msm_is_mi2s_master)
+ fmt = SND_SOC_DAIFMT_CBM_CFM;
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(rtd->card->dev,
+ "%s: set fmt cpu dai failed for MI2S (%d), err:%d\n",
+ __func__, index, ret);
+ goto clk_off;
+ }
+ }
+clk_off:
+ if (IS_ERR_VALUE(ret))
+ msm_mi2s_set_sclk(substream, false);
+clean_up:
+ if (IS_ERR_VALUE(ret))
+ mi2s_intf_conf[index].ref_cnt--;
+ mutex_unlock(&mi2s_intf_conf[index].lock);
+done:
+ return ret;
+}
+EXPORT_SYMBOL(msm_mi2s_snd_startup);
+
+/**
+ * msm_mi2s_snd_shutdown - shutdown ops of mi2s.
+ *
+ * @substream: PCM stream pointer of associated backend dailink
+ */
+void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int index = rtd->cpu_dai->id;
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+ if (index < PRIM_MI2S || index > QUAT_MI2S) {
+ pr_err("%s:invalid MI2S DAI(%d)\n", __func__, index);
+ return;
+ }
+
+ mutex_lock(&mi2s_intf_conf[index].lock);
+ if (--mi2s_intf_conf[index].ref_cnt == 0) {
+ ret = msm_mi2s_set_sclk(substream, false);
+ if (ret < 0) {
+ pr_err("%s:clock disable failed for MI2S (%d); ret=%d\n",
+ __func__, index, ret);
+ mi2s_intf_conf[index].ref_cnt++;
+ }
+ }
+ mutex_unlock(&mi2s_intf_conf[index].lock);
+}
+EXPORT_SYMBOL(msm_mi2s_snd_shutdown);
+
+/* Validate whether US EU switch is present or not */
+static int msm_prepare_us_euro(struct snd_soc_card *card)
+{
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+ int ret = 0;
+
+ if (pdata->us_euro_gpio >= 0) {
+ dev_dbg(card->dev, "%s: us_euro gpio request %d", __func__,
+ pdata->us_euro_gpio);
+ ret = gpio_request(pdata->us_euro_gpio, "TASHA_CODEC_US_EURO");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request codec US/EURO gpio %d error %d\n",
+ __func__, pdata->us_euro_gpio, ret);
+ }
+ }
+
+ return ret;
+}
+
+static bool msm_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+ struct snd_soc_card *card = codec->component.card;
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+ int value = 0;
+
+ if (pdata->us_euro_gpio_p) {
+ value = msm_cdc_pinctrl_get_state(pdata->us_euro_gpio_p);
+ if (value)
+ msm_cdc_pinctrl_select_sleep_state(
+ pdata->us_euro_gpio_p);
+ else
+ msm_cdc_pinctrl_select_active_state(
+ pdata->us_euro_gpio_p);
+ } else if (pdata->us_euro_gpio >= 0) {
+ value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+ gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
+ }
+ pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+ return true;
+}
+
+static int msm_populate_dai_link_component_of_node(
+ struct snd_soc_card *card)
+{
+ int i, index, ret = 0;
+ struct device *cdev = card->dev;
+ struct snd_soc_dai_link *dai_link = card->dai_link;
+ struct device_node *phandle;
+
+ if (!cdev) {
+ pr_err("%s: Sound card device memory NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < card->num_links; i++) {
+ if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node)
+ continue;
+
+ /* populate platform_of_node for snd card dai links */
+ if (dai_link[i].platform_name &&
+ !dai_link[i].platform_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-platform-names",
+ dai_link[i].platform_name);
+ if (index < 0) {
+ pr_err("%s: No match found for platform name: %s\n",
+ __func__, dai_link[i].platform_name);
+ ret = index;
+ goto cpu_dai;
+ }
+ phandle = of_parse_phandle(cdev->of_node,
+ "asoc-platform",
+ index);
+ if (!phandle) {
+ pr_err("%s: retrieving phandle for platform %s, index %d failed\n",
+ __func__, dai_link[i].platform_name,
+ index);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].platform_of_node = phandle;
+ dai_link[i].platform_name = NULL;
+ }
+cpu_dai:
+ /* populate cpu_of_node for snd card dai links */
+ if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-cpu-names",
+ dai_link[i].cpu_dai_name);
+ if (index < 0)
+ goto codec_dai;
+ phandle = of_parse_phandle(cdev->of_node, "asoc-cpu",
+ index);
+ if (!phandle) {
+ pr_err("%s: retrieving phandle for cpu dai %s failed\n",
+ __func__, dai_link[i].cpu_dai_name);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].cpu_of_node = phandle;
+ dai_link[i].cpu_dai_name = NULL;
+ }
+codec_dai:
+ /* populate codec_of_node for snd card dai links */
+ if (dai_link[i].codec_name && !dai_link[i].codec_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-codec-names",
+ dai_link[i].codec_name);
+ if (index < 0)
+ continue;
+ phandle = of_parse_phandle(cdev->of_node, "asoc-codec",
+ index);
+ if (!phandle) {
+ pr_err("%s: retrieving phandle for codec dai %s failed\n",
+ __func__, dai_link[i].codec_name);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].codec_of_node = phandle;
+ dai_link[i].codec_name = NULL;
+ }
+ }
+err:
+ return ret;
+}
+
+static int msm_wsa881x_init(struct snd_soc_component *component)
+{
+ u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {100, 101, 102, 106};
+ u8 spkright_ports[WSA881X_MAX_SWR_PORTS] = {103, 104, 105, 107};
+ unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200};
+ unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3};
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+ struct msm_asoc_mach_data *pdata;
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_codec_get_dapm(codec);
+
+ if (!codec) {
+ pr_err("%s codec is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!strcmp(component->name_prefix, "SpkrLeft")) {
+ dev_dbg(codec->dev, "%s: setting left ch map to codec %s\n",
+ __func__, codec->component.name);
+ wsa881x_set_channel_map(codec, &spkleft_ports[0],
+ WSA881X_MAX_SWR_PORTS, &ch_mask[0],
+ &ch_rate[0]);
+ if (dapm->component) {
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN");
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR");
+ }
+ } else if (!strcmp(component->name_prefix, "SpkrRight")) {
+ dev_dbg(codec->dev, "%s: setting right ch map to codec %s\n",
+ __func__, codec->component.name);
+ wsa881x_set_channel_map(codec, &spkright_ports[0],
+ WSA881X_MAX_SWR_PORTS, &ch_mask[0],
+ &ch_rate[0]);
+ if (dapm->component) {
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN");
+ snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR");
+ }
+ } else {
+ dev_err(codec->dev, "%s: wrong codec name %s\n", __func__,
+ codec->component.name);
+ return -EINVAL;
+ }
+
+
+ pdata = snd_soc_card_get_drvdata(component->card);
+ if (pdata && pdata->codec_root)
+ wsa881x_codec_info_create_codec_entry(pdata->codec_root,
+ codec);
+ return 0;
+}
+
+
+static int msm_init_wsa_dev(struct platform_device *pdev,
+ struct snd_soc_card *card)
+{
+ struct device_node *wsa_of_node;
+ u32 wsa_max_devs;
+ u32 wsa_dev_cnt;
+ char *dev_name_str = NULL;
+ struct msm_wsa881x_dev_info *wsa881x_dev_info;
+ const char *wsa_auxdev_name_prefix[1];
+ int found = 0;
+ int i;
+ int ret;
+
+ /* Get maximum WSA device count for this platform */
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,wsa-max-devs", &wsa_max_devs);
+ if (ret) {
+ dev_dbg(&pdev->dev,
+ "%s: wsa-max-devs property missing in DT %s, ret = %d\n",
+ __func__, pdev->dev.of_node->full_name, ret);
+ goto err_dt;
+ }
+ if (wsa_max_devs == 0) {
+ dev_warn(&pdev->dev,
+ "%s: Max WSA devices is 0 for this target?\n",
+ __func__);
+ goto err_dt;
+ }
+
+ /* Get count of WSA device phandles for this platform */
+ wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node,
+ "qcom,wsa-devs", NULL);
+ if (wsa_dev_cnt == -ENOENT) {
+ dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n",
+ __func__);
+ goto err_dt;
+ } else if (wsa_dev_cnt <= 0) {
+ dev_err(&pdev->dev,
+ "%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n",
+ __func__, wsa_dev_cnt);
+ ret = -EINVAL;
+ goto err_dt;
+ }
+
+ /*
+ * Expect total phandles count to be NOT less than maximum possible
+ * WSA count. However, if it is less, then assign same value to
+ * max count as well.
+ */
+ if (wsa_dev_cnt < wsa_max_devs) {
+ dev_dbg(&pdev->dev,
+ "%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n",
+ __func__, wsa_max_devs, wsa_dev_cnt);
+ wsa_max_devs = wsa_dev_cnt;
+ }
+
+ /* Make sure prefix string passed for each WSA device */
+ ret = of_property_count_strings(pdev->dev.of_node,
+ "qcom,wsa-aux-dev-prefix");
+ if (ret != wsa_dev_cnt) {
+ dev_err(&pdev->dev,
+ "%s: expecting %d wsa prefix. Defined only %d in DT\n",
+ __func__, wsa_dev_cnt, ret);
+ ret = -EINVAL;
+ goto err_dt;
+ }
+
+ /*
+ * Alloc mem to store phandle and index info of WSA device, if already
+ * registered with ALSA core
+ */
+ wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs,
+ sizeof(struct msm_wsa881x_dev_info),
+ GFP_KERNEL);
+ if (!wsa881x_dev_info) {
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+
+ /*
+ * search and check whether all WSA devices are already
+ * registered with ALSA core or not. If found a node, store
+ * the node and the index in a local array of struct for later
+ * use.
+ */
+ for (i = 0; i < wsa_dev_cnt; i++) {
+ wsa_of_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,wsa-devs", i);
+ if (unlikely(!wsa_of_node)) {
+ /* we should not be here */
+ dev_err(&pdev->dev,
+ "%s: wsa dev node is not present\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_dev_node;
+ }
+ if (soc_find_component(wsa_of_node, NULL)) {
+ /* WSA device registered with ALSA core */
+ wsa881x_dev_info[found].of_node = wsa_of_node;
+ wsa881x_dev_info[found].index = i;
+ found++;
+ if (found == wsa_max_devs)
+ break;
+ }
+ }
+
+ if (found < wsa_max_devs) {
+ dev_dbg(&pdev->dev,
+ "%s: failed to find %d components. Found only %d\n",
+ __func__, wsa_max_devs, found);
+ return -EPROBE_DEFER;
+ }
+ dev_info(&pdev->dev,
+ "%s: found %d wsa881x devices registered with ALSA core\n",
+ __func__, found);
+
+ card->num_aux_devs = wsa_max_devs;
+ card->num_configs = wsa_max_devs;
+
+ /* Alloc array of AUX devs struct */
+ msm_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs,
+ sizeof(struct snd_soc_aux_dev),
+ GFP_KERNEL);
+ if (!msm_aux_dev) {
+ ret = -ENOMEM;
+ goto err_auxdev_mem;
+ }
+
+ /* Alloc array of codec conf struct */
+ msm_codec_conf = devm_kcalloc(&pdev->dev, card->num_aux_devs,
+ sizeof(struct snd_soc_codec_conf),
+ GFP_KERNEL);
+ if (!msm_codec_conf) {
+ ret = -ENOMEM;
+ goto err_codec_conf;
+ }
+
+ for (i = 0; i < card->num_aux_devs; i++) {
+ dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN,
+ GFP_KERNEL);
+ if (!dev_name_str) {
+ ret = -ENOMEM;
+ goto err_dev_str;
+ }
+
+ ret = of_property_read_string_index(pdev->dev.of_node,
+ "qcom,wsa-aux-dev-prefix",
+ wsa881x_dev_info[i].index,
+ wsa_auxdev_name_prefix);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: failed to read wsa aux dev prefix, ret = %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto err_dt_prop;
+ }
+
+ snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i);
+ msm_aux_dev[i].name = dev_name_str;
+ msm_aux_dev[i].codec_name = NULL;
+ msm_aux_dev[i].codec_of_node =
+ wsa881x_dev_info[i].of_node;
+ msm_aux_dev[i].init = msm_wsa881x_init;
+ msm_codec_conf[i].dev_name = NULL;
+ msm_codec_conf[i].name_prefix = wsa_auxdev_name_prefix[0];
+ msm_codec_conf[i].of_node = wsa881x_dev_info[i].of_node;
+ }
+ card->codec_conf = msm_codec_conf;
+ card->aux_dev = msm_aux_dev;
+
+ return 0;
+
+err_dt_prop:
+ devm_kfree(&pdev->dev, dev_name_str);
+err_dev_str:
+ devm_kfree(&pdev->dev, msm_codec_conf);
+err_codec_conf:
+ devm_kfree(&pdev->dev, msm_aux_dev);
+err_auxdev_mem:
+err_dev_node:
+ devm_kfree(&pdev->dev, wsa881x_dev_info);
+err_mem:
+err_dt:
+ return ret;
+}
+
+static void msm_free_auxdev_mem(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ int i;
+
+ if (card->num_aux_devs > 0) {
+ for (i = 0; i < card->num_aux_devs; i++) {
+ kfree(msm_aux_dev[i].codec_name);
+ kfree(msm_codec_conf[i].dev_name);
+ kfree(msm_codec_conf[i].name_prefix);
+ }
+ }
+}
+
+static void i2s_auxpcm_init(struct platform_device *pdev)
+{
+ struct resource *muxsel;
+ int count;
+ u32 mi2s_master_slave[MI2S_MAX];
+ int ret;
+ char *str[PCM_I2S_SEL_MAX] = {
+ "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel"
+ };
+
+ for (count = 0; count < MI2S_MAX; count++) {
+ mutex_init(&mi2s_intf_conf[count].lock);
+ mi2s_intf_conf[count].ref_cnt = 0;
+ }
+
+ for (count = 0; count < AUX_PCM_MAX; count++) {
+ mutex_init(&auxpcm_intf_conf[count].lock);
+ auxpcm_intf_conf[count].ref_cnt = 0;
+ }
+
+ for (count = 0; count < PCM_I2S_SEL_MAX; count++) {
+ mutex_init(&mi2s_auxpcm_conf[count].lock);
+ mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr = NULL;
+ }
+
+ for (count = 0; count < PCM_I2S_SEL_MAX; count++) {
+ muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ str[count]);
+ if (muxsel) {
+ mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr
+ = ioremap(muxsel->start, resource_size(muxsel));
+ }
+ }
+
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-mi2s-master",
+ mi2s_master_slave, MI2S_MAX);
+ if (ret) {
+ dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-master in DT node\n",
+ __func__);
+ } else {
+ for (count = 0; count < MI2S_MAX; count++) {
+ mi2s_intf_conf[count].msm_is_mi2s_master =
+ mi2s_master_slave[count];
+ }
+ }
+}
+
+static void i2s_auxpcm_deinit(void)
+{
+ int count;
+
+ for (count = 0; count < PCM_I2S_SEL_MAX; count++)
+ if (mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr !=
+ NULL)
+ iounmap(
+ mi2s_auxpcm_conf[count].pcm_i2s_sel_vt_addr);
+}
+
+static const struct of_device_id msmfalcon_asoc_machine_of_match[] = {
+ { .compatible = "qcom,msmfalcon-asoc-snd",
+ .data = "internal_codec"},
+ { .compatible = "qcom,msmfalcon-asoc-snd-tasha",
+ .data = "tasha_codec"},
+ { .compatible = "qcom,msmfalcon-asoc-snd-tavil",
+ .data = "tavil_codec"},
+ {},
+};
+
+static int msm_asoc_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
+ const char *mclk = "qcom,msm-mclk-freq";
+ int ret = -EINVAL, id;
+ const struct of_device_id *match;
+
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm_asoc_mach_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ match = of_match_node(msmfalcon_asoc_machine_of_match,
+ pdev->dev.of_node);
+ if (!match)
+ goto err;
+
+ ret = of_property_read_u32(pdev->dev.of_node, mclk, &id);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: missing %s in dt node\n", __func__, mclk);
+ id = DEFAULT_MCLK_RATE;
+ }
+ pdata->mclk_freq = id;
+
+ if (!strcmp(match->data, "tasha_codec") ||
+ !strcmp(match->data, "tavil_codec")) {
+ ret = msm_ext_cdc_init(pdev, pdata, &card, &mbhc_cfg);
+ if (ret)
+ goto err;
+ } else if (!strcmp(match->data, "internal_codec")) {
+ pdata->int_codec = 1;
+ ret = msm_int_cdc_init(pdev, pdata, &card, &mbhc_cfg);
+ if (ret)
+ goto err;
+ } else {
+ dev_err(&pdev->dev,
+ "%s: Not a matching DT sound node\n", __func__);
+ goto err;
+ }
+ if (!card)
+ goto err;
+
+ /*reading the gpio configurations from dtsi file*/
+ ret = msm_gpioset_initialize(CLIENT_WCD, &pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "%s: error reading dtsi files%d\n", __func__, ret);
+ goto err;
+ }
+
+ /*
+ * Parse US-Euro gpio info from DT. Report no error if us-euro
+ * entry is not found in DT file as some targets do not support
+ * US-Euro detection
+ */
+ pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,us-euro-gpios", 0);
+ if (!gpio_is_valid(pdata->us_euro_gpio))
+ pdata->us_euro_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,us-euro-gpios", 0);
+ if (!gpio_is_valid(pdata->us_euro_gpio) && (!pdata->us_euro_gpio_p)) {
+ dev_dbg(&pdev->dev, "property %s not detected in node %s",
+ "qcom,us-euro-gpios", pdev->dev.of_node->full_name);
+ } else {
+ dev_dbg(&pdev->dev, "%s detected",
+ "qcom,us-euro-gpios");
+ mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic;
+ }
+
+ ret = msm_prepare_us_euro(card);
+ if (ret)
+ dev_dbg(&pdev->dev, "msm_prepare_us_euro failed (%d)\n",
+ ret);
+
+ i2s_auxpcm_init(pdev);
+
+ ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing");
+ if (ret)
+ goto err;
+
+ ret = msm_populate_dai_link_component_of_node(card);
+ if (ret) {
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+ ret = msm_init_wsa_dev(pdev, card);
+ if (ret)
+ goto err;
+
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err;
+ }
+ return 0;
+err:
+ if (pdata->us_euro_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
+ __func__, pdata->us_euro_gpio);
+ pdata->us_euro_gpio = 0;
+ }
+ if (pdata->hph_en1_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free hph_en1_gpio %d\n",
+ __func__, pdata->hph_en1_gpio);
+ gpio_free(pdata->hph_en1_gpio);
+ pdata->hph_en1_gpio = 0;
+ }
+ if (pdata->hph_en0_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free hph_en0_gpio %d\n",
+ __func__, pdata->hph_en0_gpio);
+ gpio_free(pdata->hph_en0_gpio);
+ pdata->hph_en0_gpio = 0;
+ }
+ devm_kfree(&pdev->dev, pdata);
+ return ret;
+}
+
+static int msm_asoc_machine_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+ if (pdata->int_codec)
+ mutex_destroy(&pdata->cdc_int_mclk0_mutex);
+ msm_free_auxdev_mem(pdev);
+
+ gpio_free(pdata->us_euro_gpio);
+ gpio_free(pdata->hph_en1_gpio);
+ gpio_free(pdata->hph_en0_gpio);
+ i2s_auxpcm_deinit();
+ snd_soc_unregister_card(card);
+ return 0;
+}
+
+static struct platform_driver msmfalcon_asoc_machine_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = msmfalcon_asoc_machine_of_match,
+ },
+ .probe = msm_asoc_machine_probe,
+ .remove = msm_asoc_machine_remove,
+};
+module_platform_driver(msmfalcon_asoc_machine_driver);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, msmfalcon_asoc_machine_of_match);
diff --git a/sound/soc/msm/msmfalcon-common.h b/sound/soc/msm/msmfalcon-common.h
new file mode 100644
index 000000000000..ff8232d6fcbb
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-common.h
@@ -0,0 +1,69 @@
+/* Copyright (c) 2015-2016, 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.
+ */
+
+#ifndef __MSM_COMMON
+#define __MSM_COMMON
+
+#include <sound/soc.h>
+#include <sound/q6afe-v2.h>
+#include "../codecs/wcd-mbhc-v2.h"
+
+#define SAMPLING_RATE_8KHZ 8000
+#define SAMPLING_RATE_11P025KHZ 11025
+#define SAMPLING_RATE_16KHZ 16000
+#define SAMPLING_RATE_22P05KHZ 22050
+#define SAMPLING_RATE_32KHZ 32000
+#define SAMPLING_RATE_44P1KHZ 44100
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_88P2KHZ 88200
+#define SAMPLING_RATE_96KHZ 96000
+#define SAMPLING_RATE_176P4KHZ 176400
+#define SAMPLING_RATE_192KHZ 192000
+#define SAMPLING_RATE_352P8KHZ 352800
+#define SAMPLING_RATE_384KHZ 384000
+
+extern const struct snd_kcontrol_new msm_common_snd_controls[];
+struct msmfalcon_codec {
+ void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
+ enum afe_config_type config_type);
+};
+
+struct msm_asoc_mach_data {
+ int us_euro_gpio; /* used by gpio driver API */
+ int hph_en1_gpio;
+ int hph_en0_gpio;
+ struct device_node *us_euro_gpio_p; /* used by pinctrl API */
+ struct device_node *hph_en1_gpio_p; /* used by pinctrl API */
+ struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
+ struct snd_soc_codec *codec;
+ struct msmfalcon_codec msmfalcon_codec_fn;
+ struct snd_info_entry *codec_root;
+ int spk_ext_pa_gpio;
+ int mclk_freq;
+ int lb_mode;
+ u8 micbias1_cap_mode;
+ u8 micbias2_cap_mode;
+ atomic_t int_mclk0_rsc_ref;
+ atomic_t int_mclk0_enabled;
+ struct mutex cdc_int_mclk0_mutex;
+ struct delayed_work disable_int_mclk0_work;
+ struct afe_clk_set digital_cdc_core_clk;
+ bool int_codec;
+};
+
+int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+int msm_aux_pcm_snd_startup(struct snd_pcm_substream *substream);
+void msm_aux_pcm_snd_shutdown(struct snd_pcm_substream *substream);
+int msm_mi2s_snd_startup(struct snd_pcm_substream *substream);
+void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream);
+#endif
diff --git a/sound/soc/msm/msmfalcon-ext-dai-links.c b/sound/soc/msm/msmfalcon-ext-dai-links.c
new file mode 100644
index 000000000000..4dca7908c108
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-ext-dai-links.c
@@ -0,0 +1,1527 @@
+/* Copyright (c) 2015-2016, 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/mfd/wcd9xxx/core.h>
+#include <linux/of.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "../codecs/wcd9335.h"
+#include "msmfalcon-common.h"
+#include "msmfalcon-external.h"
+
+#define DEV_NAME_STR_LEN 32
+#define __CHIPSET__ "MSMFALCON "
+#define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
+
+static struct snd_soc_card snd_soc_card_msm_card;
+
+static struct snd_soc_ops msm_ext_slimbus_be_ops = {
+ .hw_params = msm_snd_hw_params,
+};
+
+static struct snd_soc_ops msm_ext_cpe_ops = {
+ .hw_params = msm_snd_cpe_hw_params,
+};
+
+static struct snd_soc_ops msm_ext_slimbus_2_be_ops = {
+ .hw_params = msm_ext_slimbus_2_hw_params,
+};
+
+static struct snd_soc_ops msm_mi2s_be_ops = {
+ .startup = msm_mi2s_snd_startup,
+ .shutdown = msm_mi2s_snd_shutdown,
+};
+
+static struct snd_soc_ops msm_aux_pcm_be_ops = {
+ .startup = msm_aux_pcm_snd_startup,
+ .shutdown = msm_aux_pcm_snd_shutdown,
+};
+
+static struct snd_soc_dai_link msm_ext_tasha_fe_dai[] = {
+ /* tasha_vifeedback for speaker protection */
+ {
+ .name = LPASS_BE_SLIMBUS_4_TX,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* Ultrasound RX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_rx2",
+ .ignore_suspend = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_ext_slimbus_2_be_ops,
+ },
+ /* Ultrasound TX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16389",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx2",
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_ext_slimbus_2_be_ops,
+ },
+ /* CPE LSM direct dai-link */
+ {
+ .name = "CPE Listen service",
+ .stream_name = "CPE Listen Audio Service",
+ .cpu_dai_name = "msm-dai-slim",
+ .platform_name = "msm-cpe-lsm",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "tasha_mad1",
+ .codec_name = "tasha_codec",
+ .ops = &msm_ext_cpe_ops,
+ },
+ {
+ .name = "SLIMBUS_6 Hostless Playback",
+ .stream_name = "SLIMBUS_6 Hostless",
+ .cpu_dai_name = "SLIMBUS6_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ /* CPE LSM EC PP direct dai-link */
+ {
+ .name = "CPE Listen service ECPP",
+ .stream_name = "CPE Listen Audio Service ECPP",
+ .cpu_dai_name = "CPE_LSM_NOHOST",
+ .platform_name = "msm-cpe-lsm.3",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "tasha_cpe",
+ .codec_name = "tasha_codec",
+ },
+};
+
+static struct snd_soc_dai_link msm_ext_tavil_fe_dai[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_4_TX,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* Ultrasound RX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_ext_slimbus_2_be_ops,
+ },
+ /* Ultrasound TX DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16389",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_tx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_ext_slimbus_2_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link msm_ext_tasha_be_dai[] = {
+ /* Backend DAI Links */
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_ext_slimbus_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_ext_slimbus_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_RX,
+ .stream_name = "Slimbus1 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16386",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_TX,
+ .stream_name = "Slimbus1 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16387",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx3",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_RX,
+ .stream_name = "Slimbus4 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16392",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mix_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_5_RX,
+ .stream_name = "Slimbus5 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16394",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_rx3",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ /* MAD BE */
+ {
+ .name = LPASS_BE_SLIMBUS_5_TX,
+ .stream_name = "Slimbus5 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16395",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_mad1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_6_RX,
+ .stream_name = "Slimbus6 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16396",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_rx4",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_ext_tavil_be_dai[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_ext_slimbus_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_ext_slimbus_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_RX,
+ .stream_name = "Slimbus1 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16386",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_TX,
+ .stream_name = "Slimbus1 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16387",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_tx3",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_2_RX,
+ .stream_name = "Slimbus2 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx2",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_2_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_RX,
+ .stream_name = "Slimbus4 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16392",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_5_RX,
+ .stream_name = "Slimbus5 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16394",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx3",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ /* MAD BE */
+ {
+ .name = LPASS_BE_SLIMBUS_5_TX,
+ .stream_name = "Slimbus5 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16395",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_mad1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_6_RX,
+ .stream_name = "Slimbus6 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16396",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_rx4",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_6_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ops = &msm_ext_slimbus_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_ext_common_fe_dai[] = {
+ /* FrontEnd DAI Links */
+ {/* hw:x,0 */
+ .name = MSM_DAILINK_NAME(Media1),
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 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,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+ {/* hw:x,1 */
+ .name = MSM_DAILINK_NAME(Media2),
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
+ {/* hw:x,2 */
+ .name = "VoiceMMode1",
+ .stream_name = "VoiceMMode1",
+ .cpu_dai_name = "VoiceMMode1",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICEMMODE1,
+ },
+ {/* hw:x,3 */
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {/* hw:x,4 */
+ .name = MSM_DAILINK_NAME(ULL),
+ .stream_name = "ULL",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-dsp.2",
+ .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,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ /* Hostless PCM purpose */
+ {/* hw:x,5 */
+ .name = "SLIMBUS_0 Hostless",
+ .stream_name = "SLIMBUS_0 Hostless",
+ .cpu_dai_name = "SLIMBUS0_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* This dai link has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,6 */
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {/* hw:x,7 */
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {/* hw:x,8 */
+ .name = MSM_DAILINK_NAME(Compress1),
+ .stream_name = "Compress1",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {/* hw:x,9*/
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,10 */
+ .name = "SLIMBUS_1 Hostless",
+ .stream_name = "SLIMBUS_1 Hostless",
+ .cpu_dai_name = "SLIMBUS1_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,11 */
+ .name = "SLIMBUS_3 Hostless",
+ .stream_name = "SLIMBUS_3 Hostless",
+ .cpu_dai_name = "SLIMBUS3_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,12 */
+ .name = "SLIMBUS_4 Hostless",
+ .stream_name = "SLIMBUS_4 Hostless",
+ .cpu_dai_name = "SLIMBUS4_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,13 */
+ .name = MSM_DAILINK_NAME(LowLatency),
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
+ /* LSM FE */
+ {/* hw:x,14 */
+ .name = "Listen 1 Audio Service",
+ .stream_name = "Listen 1 Audio Service",
+ .cpu_dai_name = "LSM1",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM1,
+ },
+ {/* hw:x,15 */
+ .name = MSM_DAILINK_NAME(Compress2),
+ .stream_name = "Compress2",
+ .cpu_dai_name = "MultiMedia7",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
+ },
+ {/* hw:x,16 */
+ .name = MSM_DAILINK_NAME(Compress3),
+ .stream_name = "Compress3",
+ .cpu_dai_name = "MultiMedia10",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA10,
+ },
+ {/* hw:x,17 */
+ .name = MSM_DAILINK_NAME(ULL_NOIRQ),
+ .stream_name = "MM_NOIRQ",
+ .cpu_dai_name = "MultiMedia8",
+ .platform_name = "msm-pcm-dsp-noirq",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+ },
+ {/* hw:x,18 */
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,19 */
+ .name = "VoiceMMode2",
+ .stream_name = "VoiceMMode2",
+ .cpu_dai_name = "VoiceMMode2",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICEMMODE2,
+ },
+ {/* hw:x,20 */
+ .name = "Listen 2 Audio Service",
+ .stream_name = "Listen 2 Audio Service",
+ .cpu_dai_name = "LSM2",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM2,
+ },
+ {/* hw:x,21 */
+ .name = "Listen 3 Audio Service",
+ .stream_name = "Listen 3 Audio Service",
+ .cpu_dai_name = "LSM3",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM3,
+ },
+ {/* hw:x,22 */
+ .name = "Listen 4 Audio Service",
+ .stream_name = "Listen 4 Audio Service",
+ .cpu_dai_name = "LSM4",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM4,
+ },
+ {/* hw:x,23 */
+ .name = "Listen 5 Audio Service",
+ .stream_name = "Listen 5 Audio Service",
+ .cpu_dai_name = "LSM5",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM5,
+ },
+ {/* hw:x,24 */
+ .name = "Listen 6 Audio Service",
+ .stream_name = "Listen 6 Audio Service",
+ .cpu_dai_name = "LSM6",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM6
+ },
+ {/* hw:x,25 */
+ .name = "Listen 7 Audio Service",
+ .stream_name = "Listen 7 Audio Service",
+ .cpu_dai_name = "LSM7",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM7,
+ },
+ {/* hw:x,26 */
+ .name = "Listen 8 Audio Service",
+ .stream_name = "Listen 8 Audio Service",
+ .cpu_dai_name = "LSM8",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM8,
+ },
+ {/* hw:x,27 */
+ .name = MSM_DAILINK_NAME(Media9),
+ .stream_name = "MultiMedia9",
+ .cpu_dai_name = "MultiMedia9",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
+ },
+ {/* hw:x,28 */
+ .name = MSM_DAILINK_NAME(Compress4),
+ .stream_name = "Compress4",
+ .cpu_dai_name = "MultiMedia11",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA11,
+ },
+ {/* hw:x,29 */
+ .name = MSM_DAILINK_NAME(Compress5),
+ .stream_name = "Compress5",
+ .cpu_dai_name = "MultiMedia12",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA12,
+ },
+ {/* hw:x,30 */
+ .name = MSM_DAILINK_NAME(Compress6),
+ .stream_name = "Compress6",
+ .cpu_dai_name = "MultiMedia13",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA13,
+ },
+ {/* hw:x,31 */
+ .name = MSM_DAILINK_NAME(Compress7),
+ .stream_name = "Compress7",
+ .cpu_dai_name = "MultiMedia14",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA14,
+ },
+ {/* hw:x,32 */
+ .name = MSM_DAILINK_NAME(Compress8),
+ .stream_name = "Compress8",
+ .cpu_dai_name = "MultiMedia15",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15,
+ },
+ {/* hw:x,33 */
+ .name = MSM_DAILINK_NAME(Compress9),
+ .stream_name = "Compress9",
+ .cpu_dai_name = "MultiMedia16",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA16,
+ },
+ {/* hw:x,34 */
+ .name = "SLIMBUS_8 Hostless",
+ .stream_name = "SLIMBUS8_HOSTLESS Capture",
+ .cpu_dai_name = "SLIMBUS8_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+};
+
+static struct snd_soc_dai_link msm_ext_common_be_dai[] = {
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music 2 BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE2_PLAYBACK_TX,
+ .stream_name = "Voice2 Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32770",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_ext_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = {
+ {
+ .name = LPASS_BE_PRI_MI2S_RX,
+ .stream_name = "Primary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_MI2S_TX,
+ .stream_name = "Primary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_MI2S_RX,
+ .stream_name = "Secondary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_MI2S_TX,
+ .stream_name = "Secondary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_RX,
+ .stream_name = "Tertiary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_TX,
+ .stream_name = "Tertiary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_MI2S_RX,
+ .stream_name = "Quaternary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_MI2S_TX,
+ .stream_name = "Quaternary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = {
+ /* Primary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Secondary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_SEC_AUXPCM_RX,
+ .stream_name = "Sec AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SEC_AUXPCM_TX,
+ .stream_name = "Sec AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Tertiary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_TERT_AUXPCM_RX,
+ .stream_name = "Tert AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_TERT_AUXPCM_TX,
+ .stream_name = "Tert AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Quaternary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_QUAT_AUXPCM_RX,
+ .stream_name = "Quat AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.4",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_QUAT_AUXPCM_TX,
+ .stream_name = "Quat AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.4",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link msm_ext_tasha_dai_links[
+ARRAY_SIZE(msm_ext_common_fe_dai) +
+ARRAY_SIZE(msm_ext_tasha_fe_dai) +
+ARRAY_SIZE(msm_ext_common_be_dai) +
+ARRAY_SIZE(msm_ext_tasha_be_dai) +
+ARRAY_SIZE(msm_mi2s_be_dai_links) +
+ARRAY_SIZE(msm_auxpcm_be_dai_links)];
+
+static struct snd_soc_dai_link msm_ext_tavil_dai_links[
+ARRAY_SIZE(msm_ext_common_fe_dai) +
+ARRAY_SIZE(msm_ext_tavil_fe_dai) +
+ARRAY_SIZE(msm_ext_common_be_dai) +
+ARRAY_SIZE(msm_ext_tavil_be_dai) +
+ARRAY_SIZE(msm_mi2s_be_dai_links) +
+ARRAY_SIZE(msm_auxpcm_be_dai_links)];
+
+/**
+ * populate_snd_card_dailinks - prepares dailink array and initializes card.
+ *
+ * @dev: device handle
+ *
+ * Returns card on success or NULL on failure.
+ */
+struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
+{
+ struct snd_soc_card *card = &snd_soc_card_msm_card;
+ struct snd_soc_dai_link *msm_ext_dai_links = NULL;
+ int ret, len1, len2, len3, len4;
+ enum codec_variant codec_ver = 0;
+
+ card->dev = dev;
+ ret = snd_soc_of_parse_card_name(card, "qcom,model");
+ if (ret) {
+ dev_err(dev, "%s: parse card name failed, err:%d\n",
+ __func__, ret);
+ return NULL;
+ }
+
+ if (strnstr(card->name, "tasha", strlen(card->name))) {
+ codec_ver = tasha_codec_ver();
+ if (codec_ver == WCD9326)
+ card->name = "msmfalcon-tashalite-snd-card";
+
+ len1 = ARRAY_SIZE(msm_ext_common_fe_dai);
+ len2 = len1 + ARRAY_SIZE(msm_ext_tasha_fe_dai);
+ len3 = len2 + ARRAY_SIZE(msm_ext_common_be_dai);
+ memcpy(msm_ext_tasha_dai_links, msm_ext_common_fe_dai,
+ sizeof(msm_ext_common_fe_dai));
+ memcpy(msm_ext_tasha_dai_links + len1,
+ msm_ext_tasha_fe_dai, sizeof(msm_ext_tasha_fe_dai));
+ memcpy(msm_ext_tasha_dai_links + len2,
+ msm_ext_common_be_dai, sizeof(msm_ext_common_be_dai));
+ memcpy(msm_ext_tasha_dai_links + len3,
+ msm_ext_tasha_be_dai, sizeof(msm_ext_tasha_be_dai));
+ len4 = len3 + ARRAY_SIZE(msm_ext_tasha_be_dai);
+ if (of_property_read_bool(dev->of_node,
+ "qcom,mi2s-audio-intf")) {
+ memcpy(msm_ext_tasha_dai_links + len4,
+ msm_mi2s_be_dai_links,
+ sizeof(msm_mi2s_be_dai_links));
+ len4 += ARRAY_SIZE(msm_mi2s_be_dai_links);
+ }
+ if (of_property_read_bool(dev->of_node,
+ "qcom,auxpcm-audio-intf")) {
+ memcpy(msm_ext_tasha_dai_links + len4,
+ msm_auxpcm_be_dai_links,
+ sizeof(msm_auxpcm_be_dai_links));
+ len4 += ARRAY_SIZE(msm_auxpcm_be_dai_links);
+ }
+ msm_ext_dai_links = msm_ext_tasha_dai_links;
+ } else if (strnstr(card->name, "tavil", strlen(card->name))) {
+ len1 = ARRAY_SIZE(msm_ext_common_fe_dai);
+ len2 = len1 + ARRAY_SIZE(msm_ext_tavil_fe_dai);
+ len3 = len2 + ARRAY_SIZE(msm_ext_common_be_dai);
+ memcpy(msm_ext_tavil_dai_links, msm_ext_common_fe_dai,
+ sizeof(msm_ext_common_fe_dai));
+ memcpy(msm_ext_tavil_dai_links + len1,
+ msm_ext_tavil_fe_dai, sizeof(msm_ext_tavil_fe_dai));
+ memcpy(msm_ext_tavil_dai_links + len2,
+ msm_ext_common_be_dai, sizeof(msm_ext_common_be_dai));
+ memcpy(msm_ext_tavil_dai_links + len3,
+ msm_ext_tavil_be_dai, sizeof(msm_ext_tavil_be_dai));
+ len4 = len3 + ARRAY_SIZE(msm_ext_tavil_be_dai);
+ if (of_property_read_bool(dev->of_node,
+ "qcom,mi2s-audio-intf")) {
+ memcpy(msm_ext_tavil_dai_links + len4,
+ msm_mi2s_be_dai_links,
+ sizeof(msm_mi2s_be_dai_links));
+ len4 += ARRAY_SIZE(msm_mi2s_be_dai_links);
+ }
+ if (of_property_read_bool(dev->of_node,
+ "qcom,auxpcm-audio-intf")) {
+ memcpy(msm_ext_tavil_dai_links + len4,
+ msm_auxpcm_be_dai_links,
+ sizeof(msm_auxpcm_be_dai_links));
+ len4 += ARRAY_SIZE(msm_auxpcm_be_dai_links);
+ }
+ msm_ext_dai_links = msm_ext_tavil_dai_links;
+ } else {
+ dev_err(dev, "%s: failing as no matching card name\n",
+ __func__);
+ return NULL;
+ }
+ card->dai_link = msm_ext_dai_links;
+ card->num_links = len4;
+ card->dev = dev;
+
+ return card;
+}
+EXPORT_SYMBOL(populate_snd_card_dailinks);
diff --git a/sound/soc/msm/msmfalcon-external.c b/sound/soc/msm/msmfalcon-external.c
new file mode 100644
index 000000000000..046c63bb73cf
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-external.c
@@ -0,0 +1,1700 @@
+/* Copyright (c) 2015-2016, 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/delay.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/q6core.h>
+#include <linux/qdsp6v2/audio_notifier.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "msm-audio-pinctrl.h"
+#include "msmfalcon-common.h"
+#include "msmfalcon-external.h"
+#include "../codecs/wcd9335.h"
+#include "../codecs/wcd934x/wcd934x.h"
+#include "../codecs/wcd934x/wcd934x-mbhc.h"
+
+#define MSMFALCON_SPK_ON 1
+#define MSMFALCON_SPK_OFF 0
+
+#define WCD9XXX_MBHC_DEF_BUTTONS 8
+#define WCD9XXX_MBHC_DEF_RLOADS 5
+#define CODEC_EXT_CLK_RATE 9600000
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+
+#define WSA8810_NAME_1 "wsa881x.20170211"
+#define WSA8810_NAME_2 "wsa881x.20170212"
+
+static int msm_ext_spk_control = 1;
+static struct wcd_mbhc_config *wcd_mbhc_cfg_ptr;
+
+struct msm_asoc_wcd93xx_codec {
+ void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
+ enum afe_config_type config_type);
+ void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
+};
+
+static struct msm_asoc_wcd93xx_codec msm_codec_fn;
+static struct platform_device *spdev;
+
+static bool is_initial_boot;
+
+static void *def_ext_mbhc_cal(void);
+
+enum {
+ SLIM_RX_0 = 0,
+ SLIM_RX_1,
+ SLIM_RX_2,
+ SLIM_RX_3,
+ SLIM_RX_4,
+ SLIM_RX_5,
+ SLIM_RX_6,
+ SLIM_RX_7,
+ SLIM_RX_MAX,
+};
+
+enum {
+ SLIM_TX_0 = 0,
+ SLIM_TX_1,
+ SLIM_TX_2,
+ SLIM_TX_3,
+ SLIM_TX_4,
+ SLIM_TX_5,
+ SLIM_TX_6,
+ SLIM_TX_7,
+ SLIM_TX_8,
+ SLIM_TX_MAX,
+};
+
+struct dev_config {
+ u32 sample_rate;
+ u32 bit_format;
+ u32 channels;
+};
+
+/* Default configuration of slimbus channels */
+static struct dev_config slim_rx_cfg[] = {
+ [SLIM_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static struct dev_config slim_tx_cfg[] = {
+ [SLIM_TX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+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",
+ "Five", "Six", "Seven",
+ "Eight"};
+static const char *const vi_feed_ch_text[] = {"One", "Two"};
+static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
+ "S32_LE"};
+static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_88P2", "KHZ_96", "KHZ_176P4",
+ "KHZ_192", "KHZ_352P8", "KHZ_384"};
+static const char *const spk_function_text[] = {"Off", "On"};
+
+static SOC_ENUM_SINGLE_EXT_DECL(spk_func_en, spk_function_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_chs, slim_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_1_tx_chs, slim_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_chs, slim_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text);
+
+static int slim_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val = 0;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_88P2KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 10;
+ break;
+ default:
+ sample_rate_val = 4;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int slim_get_sample_rate(int value)
+{
+ int sample_rate = 0;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 7:
+ sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 8:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 9:
+ sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 10:
+ sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int slim_get_bit_format_val(int bit_format)
+{
+ int val = 0;
+
+ switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ val = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ val = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ val = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ val = 0;
+ break;
+ }
+ return val;
+}
+
+static int slim_get_bit_format(int val)
+{
+ int bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+
+ switch (val) {
+ case 0:
+ bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 1:
+ bit_fmt = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 2:
+ bit_fmt = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 3:
+ bit_fmt = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ default:
+ bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return bit_fmt;
+}
+
+static int slim_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int port_id = 0;
+
+ if (strnstr(kcontrol->id.name, "SLIM_0_RX", sizeof("SLIM_0_RX")))
+ port_id = SLIM_RX_0;
+ else if (strnstr(kcontrol->id.name, "SLIM_2_RX", sizeof("SLIM_2_RX")))
+ port_id = SLIM_RX_2;
+ else if (strnstr(kcontrol->id.name, "SLIM_5_RX", sizeof("SLIM_5_RX")))
+ port_id = SLIM_RX_5;
+ else if (strnstr(kcontrol->id.name, "SLIM_6_RX", sizeof("SLIM_6_RX")))
+ port_id = SLIM_RX_6;
+ else if (strnstr(kcontrol->id.name, "SLIM_0_TX", sizeof("SLIM_0_TX")))
+ port_id = SLIM_TX_0;
+ else if (strnstr(kcontrol->id.name, "SLIM_1_TX", sizeof("SLIM_1_TX")))
+ port_id = SLIM_TX_1;
+ else {
+ pr_err("%s: unsupported channel: %s",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ return port_id;
+}
+
+static int slim_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ slim_get_sample_rate_val(slim_rx_cfg[ch_num].sample_rate);
+
+ pr_debug("%s: slim[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ ch_num, slim_rx_cfg[ch_num].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_rx_cfg[ch_num].sample_rate =
+ slim_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: slim[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ ch_num, slim_rx_cfg[ch_num].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ slim_get_sample_rate_val(slim_tx_cfg[ch_num].sample_rate);
+
+ pr_debug("%s: slim[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ ch_num, slim_tx_cfg[ch_num].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate = 0;
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ sample_rate = slim_get_sample_rate(ucontrol->value.enumerated.item[0]);
+ if (sample_rate == SAMPLING_RATE_44P1KHZ) {
+ pr_err("%s: Unsupported sample rate %d: for Tx path\n",
+ __func__, sample_rate);
+ return -EINVAL;
+ }
+ slim_tx_cfg[ch_num].sample_rate = sample_rate;
+
+ pr_debug("%s: slim[%d]_tx_sample_rate = %d, value = %d\n", __func__,
+ ch_num, slim_tx_cfg[ch_num].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ slim_get_bit_format_val(slim_rx_cfg[ch_num].bit_format);
+
+ pr_debug("%s: slim[%d]_rx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, slim_rx_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_rx_cfg[ch_num].bit_format =
+ slim_get_bit_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: slim[%d]_rx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, slim_rx_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_tx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ slim_get_bit_format_val(slim_tx_cfg[ch_num].bit_format);
+
+ pr_debug("%s: slim[%d]_tx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, slim_tx_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int slim_tx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_tx_cfg[ch_num].bit_format =
+ slim_get_bit_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: slim[%d]_tx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, slim_tx_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_slim_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ pr_debug("%s: msm_slim_[%d]_rx_ch = %d\n", __func__,
+ ch_num, slim_rx_cfg[ch_num].channels);
+ ucontrol->value.enumerated.item[0] = slim_rx_cfg[ch_num].channels - 1;
+
+ return 0;
+}
+
+static int msm_slim_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_rx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_slim_[%d]_rx_ch = %d\n", __func__,
+ ch_num, slim_rx_cfg[ch_num].channels);
+
+ return 1;
+}
+
+static int msm_slim_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__,
+ ch_num, slim_tx_cfg[ch_num].channels);
+ ucontrol->value.enumerated.item[0] = slim_tx_cfg[ch_num].channels - 1;
+
+ return 0;
+}
+
+static int msm_slim_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = slim_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ slim_tx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__,
+ ch_num, slim_tx_cfg[ch_num].channels);
+
+ return 1;
+}
+
+static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_vi_feed_tx_ch - 1;
+ pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_vi_feed_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch);
+ return 1;
+}
+
+static void *def_ext_mbhc_cal(void)
+{
+ void *tavil_wcd_cal;
+ struct wcd_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_high;
+
+ tavil_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
+ WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL);
+ if (!tavil_wcd_cal)
+ return NULL;
+
+#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tavil_wcd_cal)->X) = (Y))
+ S(v_hs_max, 1600);
+#undef S
+#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tavil_wcd_cal)->X) = (Y))
+ S(num_btn, WCD_MBHC_DEF_BUTTONS);
+#undef S
+
+ btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(tavil_wcd_cal);
+ btn_high = ((void *)&btn_cfg->_v_btn_low) +
+ (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
+
+ btn_high[0] = 75;
+ btn_high[1] = 150;
+ btn_high[2] = 237;
+ btn_high[3] = 500;
+ btn_high[4] = 500;
+ btn_high[5] = 500;
+ btn_high[6] = 500;
+ btn_high[7] = 500;
+
+ return tavil_wcd_cal;
+}
+
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+
+static void msm_ext_control(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_codec_get_dapm(codec);
+
+ pr_debug("%s: msm_ext_spk_control = %d", __func__, msm_ext_spk_control);
+ if (msm_ext_spk_control == MSMFALCON_SPK_ON) {
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ } else {
+ snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_3 amp");
+ }
+ snd_soc_dapm_sync(dapm);
+}
+
+static int msm_ext_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_ext_spk_control = %d\n",
+ __func__, msm_ext_spk_control);
+ ucontrol->value.integer.value[0] = msm_ext_spk_control;
+ return 0;
+}
+
+static int msm_ext_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s()\n", __func__);
+ if (msm_ext_spk_control == ucontrol->value.integer.value[0])
+ return 0;
+
+ msm_ext_spk_control = ucontrol->value.integer.value[0];
+ msm_ext_control(codec);
+ return 1;
+}
+
+
+int msm_ext_enable_codec_mclk(struct snd_soc_codec *codec, int enable,
+ bool dapm)
+{
+ int ret;
+
+ pr_debug("%s: enable = %d\n", __func__, enable);
+
+ if (!strcmp(dev_name(codec->dev), "tasha_codec"))
+ ret = tasha_cdc_mclk_enable(codec, enable, dapm);
+ else if (!strcmp(dev_name(codec->dev), "tavil_codec"))
+ ret = tavil_cdc_mclk_enable(codec, enable);
+ else {
+ dev_err(codec->dev, "%s: unknown codec to enable ext clk\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+ SOC_ENUM_EXT("Speaker Function", spk_func_en, msm_ext_get_spk,
+ msm_ext_set_spk),
+ SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs,
+ msm_slim_rx_ch_get, msm_slim_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_2_RX Channels", slim_2_rx_chs,
+ msm_slim_rx_ch_get, msm_slim_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_TX Channels", slim_0_tx_chs,
+ msm_slim_tx_ch_get, msm_slim_tx_ch_put),
+ SOC_ENUM_EXT("SLIM_1_TX Channels", slim_1_tx_chs,
+ msm_slim_tx_ch_get, msm_slim_tx_ch_put),
+ SOC_ENUM_EXT("SLIM_5_RX Channels", slim_5_rx_chs,
+ msm_slim_rx_ch_get, msm_slim_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_6_RX Channels", slim_6_rx_chs,
+ msm_slim_rx_ch_get, msm_slim_rx_ch_put),
+ SOC_ENUM_EXT("VI_FEED_TX Channels", vi_feed_tx_chs,
+ msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_RX Format", slim_0_rx_format,
+ slim_rx_bit_format_get, slim_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_5_RX Format", slim_5_rx_format,
+ slim_rx_bit_format_get, slim_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_6_RX Format", slim_6_rx_format,
+ slim_rx_bit_format_get, slim_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_0_TX Format", slim_0_tx_format,
+ slim_tx_bit_format_get, slim_tx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate,
+ slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_2_RX SampleRate", slim_2_rx_sample_rate,
+ slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_0_TX SampleRate", slim_0_tx_sample_rate,
+ slim_tx_sample_rate_get, slim_tx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_5_RX SampleRate", slim_5_rx_sample_rate,
+ slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("SLIM_6_RX SampleRate", slim_6_rx_sample_rate,
+ slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+};
+
+static int msm_slim_get_ch_from_beid(int32_t be_id)
+{
+ int ch_id = 0;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_SLIMBUS_0_RX:
+ ch_id = SLIM_RX_0;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_1_RX:
+ ch_id = SLIM_RX_1;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_2_RX:
+ ch_id = SLIM_RX_2;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_3_RX:
+ ch_id = SLIM_RX_3;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_4_RX:
+ ch_id = SLIM_RX_4;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_6_RX:
+ ch_id = SLIM_RX_6;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_0_TX:
+ ch_id = SLIM_TX_0;
+ break;
+ case MSM_BACKEND_DAI_SLIMBUS_3_TX:
+ ch_id = SLIM_TX_3;
+ break;
+ default:
+ ch_id = SLIM_RX_0;
+ break;
+ }
+
+ return ch_id;
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+/**
+ * msm_ext_be_hw_params_fixup - updates settings of ALSA BE hw params.
+ *
+ * @rtd: runtime dailink instance
+ * @params: HW params of associated backend dailink.
+ *
+ * Returns 0 on success or rc on failure.
+ */
+int msm_ext_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ int rc = 0;
+ int idx;
+ void *config = NULL;
+ struct snd_soc_codec *codec = rtd->codec;
+
+ pr_debug("%s: format = %d, rate = %d\n",
+ __func__, params_format(params), params_rate(params));
+
+ switch (dai_link->be_id) {
+ case MSM_BACKEND_DAI_SLIMBUS_0_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_1_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_2_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_3_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_4_RX:
+ case MSM_BACKEND_DAI_SLIMBUS_6_RX:
+ idx = msm_slim_get_ch_from_beid(dai_link->be_id);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_rx_cfg[idx].bit_format);
+ rate->min = rate->max = slim_rx_cfg[idx].sample_rate;
+ channels->min = channels->max = slim_rx_cfg[idx].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_0_TX:
+ case MSM_BACKEND_DAI_SLIMBUS_3_TX:
+ idx = msm_slim_get_ch_from_beid(dai_link->be_id);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_tx_cfg[idx].bit_format);
+ rate->min = rate->max = slim_tx_cfg[idx].sample_rate;
+ channels->min = channels->max = slim_tx_cfg[idx].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_1_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_tx_cfg[1].bit_format);
+ rate->min = rate->max = slim_tx_cfg[1].sample_rate;
+ channels->min = channels->max = slim_tx_cfg[1].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_4_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FORMAT_S32_LE);
+ rate->min = rate->max = SAMPLING_RATE_8KHZ;
+ channels->min = channels->max = msm_vi_feed_tx_ch;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_5_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_rx_cfg[5].bit_format);
+ rate->min = rate->max = slim_rx_cfg[5].sample_rate;
+ channels->min = channels->max = slim_rx_cfg[5].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_5_TX:
+ rate->min = rate->max = SAMPLING_RATE_16KHZ;
+ channels->min = channels->max = 1;
+
+ config = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_SLIMBUS_SLAVE_PORT_CONFIG);
+ if (config) {
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG,
+ config, SLIMBUS_5_TX);
+ if (rc)
+ pr_err("%s: Failed to set slimbus slave port config %d\n",
+ __func__, rc);
+ }
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_7_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_rx_cfg[SLIM_RX_7].bit_format);
+ rate->min = rate->max = slim_rx_cfg[SLIM_RX_7].sample_rate;
+ channels->min = channels->max =
+ slim_rx_cfg[SLIM_RX_7].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_7_TX:
+ rate->min = rate->max = slim_tx_cfg[SLIM_TX_7].sample_rate;
+ channels->min = channels->max =
+ slim_tx_cfg[SLIM_TX_7].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_8_TX:
+ rate->min = rate->max = slim_tx_cfg[SLIM_TX_8].sample_rate;
+ channels->min = channels->max =
+ slim_tx_cfg[SLIM_TX_8].channels;
+ break;
+
+ default:
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return rc;
+}
+EXPORT_SYMBOL(msm_ext_be_hw_params_fixup);
+
+/**
+ * msm_snd_hw_params - hw params ops of backend dailink.
+ *
+ * @substream: PCM stream of associated backend dailink.
+ * @params: HW params of associated backend dailink.
+ *
+ * Returns 0 on success or ret on failure.
+ */
+int msm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+
+ int ret = 0;
+ u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ u32 user_set_tx_ch = 0;
+ u32 rx_ch_count;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_5_RX) {
+ pr_debug("%s: rx_5_ch=%d\n", __func__,
+ slim_rx_cfg[5].channels);
+ rx_ch_count = slim_rx_cfg[5].channels;
+ } else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_2_RX) {
+ pr_debug("%s: rx_2_ch=%d\n", __func__,
+ slim_rx_cfg[2].channels);
+ rx_ch_count = slim_rx_cfg[2].channels;
+ } else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_6_RX) {
+ pr_debug("%s: rx_6_ch=%d\n", __func__,
+ slim_rx_cfg[6].channels);
+ rx_ch_count = slim_rx_cfg[6].channels;
+ } else {
+ pr_debug("%s: rx_0_ch=%d\n", __func__,
+ slim_rx_cfg[0].channels);
+ rx_ch_count = slim_rx_cfg[0].channels;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ rx_ch_count, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ } else {
+ pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
+ codec_dai->name, codec_dai->id, user_set_tx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto err_ch_map;
+ }
+ /* For <codec>_tx1 case */
+ if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_0_TX)
+ user_set_tx_ch = slim_tx_cfg[0].channels;
+ /* For <codec>_tx3 case */
+ else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_1_TX)
+ user_set_tx_ch = slim_tx_cfg[1].channels;
+ else if (dai_link->be_id == MSM_BACKEND_DAI_SLIMBUS_4_TX)
+ user_set_tx_ch = msm_vi_feed_tx_ch;
+ else
+ user_set_tx_ch = tx_ch_cnt;
+
+ pr_debug("%s: msm_slim_0_tx_ch(%d) user_set_tx_ch(%d) tx_ch_cnt(%d), be_id (%d)\n",
+ __func__, slim_tx_cfg[0].channels, user_set_tx_ch,
+ tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ user_set_tx_ch, tx_ch, 0, 0);
+ if (ret < 0)
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ }
+
+err_ch_map:
+ return ret;
+}
+EXPORT_SYMBOL(msm_snd_hw_params);
+
+/**
+ * msm_ext_slimbus_2_hw_params - hw params ops of slimbus_2 BE.
+ *
+ * @substream: PCM stream of associated backend dailink.
+ * @params: HW params of associated backend dailink.
+ *
+ * Returns 0 on success or ret on failure.
+ */
+int msm_ext_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+ unsigned int num_tx_ch = 0;
+ unsigned int num_rx_ch = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ num_rx_ch = params_channels(params);
+ pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_rx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ num_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ num_tx_ch = params_channels(params);
+ pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_tx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ num_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+EXPORT_SYMBOL(msm_ext_slimbus_2_hw_params);
+
+/**
+ * msm_snd_cpe_hw_params - hw params ops of CPE backend.
+ *
+ * @substream: PCM stream of associated backend dailink.
+ * @params: HW params of associated backend dailink.
+ *
+ * Returns 0 on success or ret on failure.
+ */
+int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ int ret = 0;
+ u32 tx_ch[SLIM_MAX_TX_PORTS];
+ u32 tx_ch_cnt = 0;
+
+ if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) {
+ pr_err("%s: Invalid stream type %d\n",
+ __func__, substream->stream);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ pr_debug("%s: %s_tx_dai_id_%d\n", __func__,
+ codec_dai->name, codec_dai->id);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, NULL, NULL);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ pr_debug("%s: tx_ch_cnt(%d) be_id %d\n",
+ __func__, tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ tx_ch_cnt, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+end:
+ return ret;
+}
+EXPORT_SYMBOL(msm_snd_cpe_hw_params);
+
+static int msm_afe_set_config(struct snd_soc_codec *codec)
+{
+ int rc;
+ void *config_data;
+
+ pr_debug("%s: enter\n", __func__);
+
+ if (!msm_codec_fn.get_afe_config_fn) {
+ dev_err(codec->dev, "%s: codec get afe config not init'ed\n",
+ __func__);
+ return -EINVAL;
+ }
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_REGISTERS_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set codec registers config %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_REGISTER_PAGE_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data,
+ 0);
+ if (rc)
+ pr_err("%s: Failed to set cdc register page config\n",
+ __func__);
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_SLIMBUS_SLAVE_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave config %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_AANC_VERSION);
+ if (config_data) {
+ rc = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set AANC version %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_CLIP_REGISTERS_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+ config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set clip registers %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CLIP_BANK_SEL);
+ if (config_data) {
+ rc = afe_set_config(AFE_CLIP_BANK_SEL,
+ config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set AFE bank selection %d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_REGISTER_PAGE_CONFIG);
+ if (config_data) {
+ rc = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data,
+ 0);
+ if (rc)
+ pr_err("%s: Failed to set cdc register page config\n",
+ __func__);
+ }
+
+ return 0;
+}
+
+static void msm_afe_clear_config(void)
+{
+ afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
+ afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
+}
+
+static int msm_adsp_power_up_config(struct snd_soc_codec *codec)
+{
+ int ret = 0;
+ unsigned long timeout;
+ int adsp_ready = 0;
+
+ timeout = jiffies +
+ msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+
+ do {
+ if (q6core_is_adsp_ready()) {
+ pr_debug("%s: ADSP Audio is ready\n", __func__);
+ adsp_ready = 1;
+ break;
+ }
+ /*
+ * ADSP will be coming up after subsystem restart and
+ * it might not be fully up when the control reaches
+ * here. So, wait for 50msec before checking ADSP state
+ */
+ msleep(50);
+ } while (time_after(timeout, jiffies));
+
+ if (!adsp_ready) {
+ pr_err("%s: timed out waiting for ADSP Audio\n", __func__);
+ ret = -ETIMEDOUT;
+ goto err_fail;
+ }
+
+ ret = msm_afe_set_config(codec);
+ if (ret)
+ pr_err("%s: Failed to set AFE config. err %d\n",
+ __func__, ret);
+
+ return 0;
+
+err_fail:
+ return ret;
+}
+
+static int msmfalcon_notifier_service_cb(struct notifier_block *this,
+ unsigned long opcode, void *ptr)
+{
+ int ret;
+ struct snd_soc_card *card = NULL;
+ const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_codec *codec;
+
+ pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
+
+ switch (opcode) {
+ case AUDIO_NOTIFIER_SERVICE_DOWN:
+ /*
+ * Use flag to ignore initial boot notifications
+ * On initial boot msm_adsp_power_up_config is
+ * called on init. There is no need to clear
+ * and set the config again on initial boot.
+ */
+ if (is_initial_boot)
+ break;
+ msm_afe_clear_config();
+ break;
+ case AUDIO_NOTIFIER_SERVICE_UP:
+ if (is_initial_boot) {
+ is_initial_boot = false;
+ break;
+ }
+ if (!spdev)
+ return -EINVAL;
+
+ card = platform_get_drvdata(spdev);
+ rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
+ if (!rtd) {
+ dev_err(card->dev,
+ "%s: snd_soc_get_pcm_runtime for %s failed!\n",
+ __func__, be_dl_name);
+ ret = -EINVAL;
+ goto done;
+ }
+ codec = rtd->codec;
+
+ ret = msm_adsp_power_up_config(codec);
+ if (ret < 0) {
+ dev_err(card->dev,
+ "%s: msm_adsp_power_up_config failed ret = %d!\n",
+ __func__, ret);
+ goto done;
+ }
+ break;
+ default:
+ break;
+ }
+done:
+ return NOTIFY_OK;
+}
+
+static struct notifier_block service_nb = {
+ .notifier_call = msmfalcon_notifier_service_cb,
+ .priority = -INT_MAX,
+};
+
+static int msm_config_hph_en0_gpio(struct snd_soc_codec *codec, bool high)
+{
+ struct snd_soc_card *card = codec->component.card;
+ struct msm_asoc_mach_data *pdata;
+ int val;
+
+ if (!card)
+ return 0;
+
+ pdata = snd_soc_card_get_drvdata(card);
+ if (!pdata || !gpio_is_valid(pdata->hph_en0_gpio))
+ return 0;
+
+ val = gpio_get_value_cansleep(pdata->hph_en0_gpio);
+ if ((!!val) == high)
+ return 0;
+
+ gpio_direction_output(pdata->hph_en0_gpio, (int)high);
+
+ return 1;
+}
+
+static int msm_snd_enable_codec_ext_tx_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm)
+{
+ int ret = 0;
+
+ if (!strcmp(dev_name(codec->dev), "tasha_codec"))
+ ret = tasha_cdc_mclk_tx_enable(codec, enable, dapm);
+ else {
+ dev_err(codec->dev, "%s: unknown codec to enable ext clk\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int msm_ext_mclk_tx_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm_snd_enable_codec_ext_tx_clk(codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm_snd_enable_codec_ext_tx_clk(codec, 0, true);
+ }
+ return 0;
+}
+
+static int msm_ext_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm_ext_enable_codec_mclk(codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm_ext_enable_codec_mclk(codec, 0, true);
+ }
+ return 0;
+}
+
+static int msm_ext_prepare_hifi(struct msm_asoc_mach_data *pdata)
+{
+ int ret = 0;
+
+ if (gpio_is_valid(pdata->hph_en1_gpio)) {
+ pr_debug("%s: hph_en1_gpio request %d\n", __func__,
+ pdata->hph_en1_gpio);
+ ret = gpio_request(pdata->hph_en1_gpio, "hph_en1_gpio");
+ if (ret) {
+ pr_err("%s: hph_en1_gpio request failed, ret:%d\n",
+ __func__, ret);
+ goto err;
+ }
+ }
+ if (gpio_is_valid(pdata->hph_en0_gpio)) {
+ pr_debug("%s: hph_en0_gpio request %d\n", __func__,
+ pdata->hph_en0_gpio);
+ ret = gpio_request(pdata->hph_en0_gpio, "hph_en0_gpio");
+ if (ret)
+ pr_err("%s: hph_en0_gpio request failed, ret:%d\n",
+ __func__, ret);
+ }
+
+err:
+ return ret;
+}
+
+static const struct snd_soc_dapm_widget msm_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY_S("MCLK", -1, SND_SOC_NOPM, 0, 0,
+ msm_ext_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("MCLK TX", -1, SND_SOC_NOPM, 0, 0,
+ msm_ext_mclk_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SPK("Lineout_1 amp", NULL),
+ SND_SOC_DAPM_SPK("Lineout_3 amp", NULL),
+ SND_SOC_DAPM_SPK("Lineout_2 amp", NULL),
+ SND_SOC_DAPM_SPK("Lineout_4 amp", NULL),
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Secondary Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic4", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic6", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic7", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic8", NULL),
+
+ SND_SOC_DAPM_MIC("Digital Mic0", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+};
+
+static struct snd_soc_dapm_route wcd_audio_paths_tasha[] = {
+ {"MIC BIAS1", NULL, "MCLK TX"},
+ {"MIC BIAS2", NULL, "MCLK TX"},
+ {"MIC BIAS3", NULL, "MCLK TX"},
+ {"MIC BIAS4", NULL, "MCLK TX"},
+};
+
+static struct snd_soc_dapm_route wcd_audio_paths[] = {
+ {"MIC BIAS1", NULL, "MCLK"},
+ {"MIC BIAS2", NULL, "MCLK"},
+ {"MIC BIAS3", NULL, "MCLK"},
+ {"MIC BIAS4", NULL, "MCLK"},
+};
+
+/**
+ * msm_audrx_init - Audio init function of sound card instantiate.
+ *
+ * @rtd: runtime dailink instance
+ *
+ * Returns 0 on success or ret on failure.
+ */
+int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+ void *config_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_codec_get_dapm(codec);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_pcm_runtime *rtd_aux = rtd->card->rtd_aux;
+ struct snd_card *card;
+ struct snd_info_entry *entry;
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(rtd->card);
+
+ /* Codec SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch[TASHA_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
+ 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[TASHA_TX_MAX] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+
+ pr_debug("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+ rtd->pmdown_time = 0;
+
+ ret = snd_soc_add_codec_controls(codec, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+ if (ret < 0) {
+ pr_err("%s: add_codec_controls failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ snd_soc_dapm_new_controls(dapm, msm_dapm_widgets,
+ ARRAY_SIZE(msm_dapm_widgets));
+
+ if (!strcmp(dev_name(codec_dai->dev), "tasha_codec"))
+ snd_soc_dapm_add_routes(dapm, wcd_audio_paths_tasha,
+ ARRAY_SIZE(wcd_audio_paths_tasha));
+ else
+ snd_soc_dapm_add_routes(dapm, wcd_audio_paths,
+ ARRAY_SIZE(wcd_audio_paths));
+
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+
+ snd_soc_dapm_ignore_suspend(dapm, "MADINPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_INPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Secondary Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Lineout_1 amp");
+ snd_soc_dapm_ignore_suspend(dapm, "Lineout_3 amp");
+ snd_soc_dapm_ignore_suspend(dapm, "Lineout_2 amp");
+ snd_soc_dapm_ignore_suspend(dapm, "Lineout_4 amp");
+ snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic5");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic6");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic7");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic8");
+
+ snd_soc_dapm_ignore_suspend(dapm, "EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
+ snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC5");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC6");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC0");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC5");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HEADPHONE");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
+ snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
+ snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
+ snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
+
+ snd_soc_dapm_sync(dapm);
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+ if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
+ msm_codec_fn.get_afe_config_fn = tavil_get_afe_config;
+ } else {
+ msm_codec_fn.get_afe_config_fn = tasha_get_afe_config;
+ msm_codec_fn.mbhc_hs_detect_exit = tasha_mbhc_hs_detect_exit;
+ }
+
+ ret = msm_adsp_power_up_config(codec);
+ if (ret) {
+ pr_err("%s: Failed to set AFE config %d\n", __func__, ret);
+ goto err_afe_cfg;
+ }
+
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_AANC_VERSION);
+ if (config_data) {
+ ret = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+ if (ret) {
+ pr_err("%s: Failed to set aanc version %d\n",
+ __func__, ret);
+ goto err_afe_cfg;
+ }
+ }
+
+ if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) {
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CDC_CLIP_REGISTERS_CONFIG);
+ if (config_data) {
+ ret = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+ config_data, 0);
+ if (ret) {
+ pr_err("%s: Failed to set clip registers %d\n",
+ __func__, ret);
+ goto err_afe_cfg;
+ }
+ }
+ config_data = msm_codec_fn.get_afe_config_fn(codec,
+ AFE_CLIP_BANK_SEL);
+ if (config_data) {
+ ret = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
+ if (ret) {
+ pr_err("%s: Failed to set AFE bank selection %d\n",
+ __func__, ret);
+ goto err_afe_cfg;
+ }
+ }
+ }
+
+ /*
+ * Send speaker configuration only for WSA8810.
+ * Defalut configuration is for WSA8815.
+ */
+ if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
+ if (rtd_aux && rtd_aux->component)
+ if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) ||
+ !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) {
+ tavil_set_spkr_mode(rtd->codec, SPKR_MODE_1);
+ tavil_set_spkr_gain_offset(rtd->codec,
+ RX_GAIN_OFFSET_M1P5_DB);
+ }
+ card = rtd->card->snd_card;
+ entry = snd_register_module_info(card->module, "codecs",
+ card->proc_root);
+ if (!entry) {
+ pr_debug("%s: Cannot create codecs module entry\n",
+ __func__);
+ pdata->codec_root = NULL;
+ goto done;
+ }
+ pdata->codec_root = entry;
+ tavil_codec_info_create_codec_entry(pdata->codec_root, codec);
+ } else {
+ if (rtd_aux && rtd_aux->component)
+ if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) ||
+ !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) {
+ tasha_set_spkr_mode(rtd->codec, SPKR_MODE_1);
+ tasha_set_spkr_gain_offset(rtd->codec,
+ RX_GAIN_OFFSET_M1P5_DB);
+ }
+ card = rtd->card->snd_card;
+ entry = snd_register_module_info(card->module, "codecs",
+ card->proc_root);
+ if (!entry) {
+ pr_debug("%s: Cannot create codecs module entry\n",
+ __func__);
+ ret = 0;
+ goto err_snd_module;
+ }
+ pdata->codec_root = entry;
+ tasha_codec_info_create_codec_entry(pdata->codec_root, codec);
+ tasha_mbhc_zdet_gpio_ctrl(msm_config_hph_en0_gpio, rtd->codec);
+ }
+
+ wcd_mbhc_cfg_ptr->calibration = def_ext_mbhc_cal();
+ if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) {
+ if (wcd_mbhc_cfg_ptr->calibration) {
+ pdata->codec = codec;
+ ret = tavil_mbhc_hs_detect(codec, wcd_mbhc_cfg_ptr);
+ if (ret < 0)
+ pr_err("%s: Failed to intialise mbhc %d\n",
+ __func__, ret);
+ } else {
+ pr_err("%s: wcd_mbhc_cfg calibration is NULL\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_mbhc_cal;
+ }
+ } else {
+ if (wcd_mbhc_cfg_ptr->calibration) {
+ pdata->codec = codec;
+ ret = tasha_mbhc_hs_detect(codec, wcd_mbhc_cfg_ptr);
+ if (ret < 0)
+ pr_err("%s: Failed to intialise mbhc %d\n",
+ __func__, ret);
+ } else {
+ pr_err("%s: wcd_mbhc_cfg calibration is NULL\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_mbhc_cal;
+ }
+
+ }
+done:
+ return 0;
+
+err_snd_module:
+err_afe_cfg:
+err_mbhc_cal:
+ return ret;
+}
+EXPORT_SYMBOL(msm_audrx_init);
+
+/**
+ * msm_ext_cdc_init - external codec machine specific init.
+ *
+ * @pdev: platform device handle
+ * @pdata: private data of machine driver
+ * @card: sound card pointer reference
+ * @mbhc_cfg: MBHC config reference
+ *
+ * Returns 0 on success or ret on failure.
+ */
+int msm_ext_cdc_init(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata,
+ struct snd_soc_card **card,
+ struct wcd_mbhc_config *wcd_mbhc_cfg_ptr1)
+{
+ int ret = 0;
+
+ wcd_mbhc_cfg_ptr = wcd_mbhc_cfg_ptr1;
+ pdev->id = 0;
+ wcd_mbhc_cfg_ptr->moisture_en = true;
+ wcd_mbhc_cfg_ptr->mbhc_micbias = MIC_BIAS_2;
+ wcd_mbhc_cfg_ptr->anc_micbias = MIC_BIAS_2;
+ wcd_mbhc_cfg_ptr->enable_anc_mic_detect = false;
+
+ *card = populate_snd_card_dailinks(&pdev->dev);
+ if (!(*card)) {
+ dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+ (*card)->dev = &pdev->dev;
+ spdev = pdev;
+ platform_set_drvdata(pdev, *card);
+ snd_soc_card_set_drvdata(*card, pdata);
+ is_initial_boot = true;
+ ret = audio_notifier_register("msmfalcon", AUDIO_NOTIFIER_ADSP_DOMAIN,
+ &service_nb);
+ if (ret < 0) {
+ pr_err("%s: Audio notifier register failed ret = %d\n",
+ __func__, ret);
+ goto err;
+ }
+ pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,hph-en1-gpio", 0);
+ if (!gpio_is_valid(pdata->hph_en1_gpio))
+ pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,hph-en1-gpio", 0);
+ if (!gpio_is_valid(pdata->hph_en1_gpio) && (!pdata->hph_en1_gpio_p)) {
+ dev_dbg(&pdev->dev, "property %s not detected in node %s",
+ "qcom,hph-en1-gpio", pdev->dev.of_node->full_name);
+ }
+
+ pdata->hph_en0_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,hph-en0-gpio", 0);
+ if (!gpio_is_valid(pdata->hph_en0_gpio))
+ pdata->hph_en0_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,hph-en0-gpio", 0);
+ if (!gpio_is_valid(pdata->hph_en0_gpio) && (!pdata->hph_en0_gpio_p)) {
+ dev_dbg(&pdev->dev, "property %s not detected in node %s",
+ "qcom,hph-en0-gpio", pdev->dev.of_node->full_name);
+ }
+
+ ret = msm_ext_prepare_hifi(pdata);
+ if (ret) {
+ dev_dbg(&pdev->dev, "msm_ext_prepare_hifi failed (%d)\n",
+ ret);
+ ret = 0;
+ }
+err:
+ return ret;
+}
+EXPORT_SYMBOL(msm_ext_cdc_init);
diff --git a/sound/soc/msm/msmfalcon-external.h b/sound/soc/msm/msmfalcon-external.h
new file mode 100644
index 000000000000..24aa7ea53a09
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-external.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2015-2016, 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.
+ */
+
+#ifndef __MSMFALCON_EXTERNAL
+#define __MSMFALCON_EXTERNAL
+
+int msm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params);
+int msm_ext_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params);
+int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+int msm_audrx_init(struct snd_soc_pcm_runtime *rtd);
+int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params);
+struct snd_soc_card *populate_snd_card_dailinks(struct device *dev);
+int msm_ext_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+#ifdef CONFIG_SND_SOC_EXT_CODEC
+int msm_ext_cdc_init(struct platform_device *, struct msm_asoc_mach_data *,
+ struct snd_soc_card **, struct wcd_mbhc_config *);
+#else
+inline int msm_ext_cdc_init(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata,
+ struct snd_soc_card **card,
+ struct wcd_mbhc_config *wcd_mbhc_cfg_ptr1)
+{
+ return 0;
+}
+#endif
+#endif
diff --git a/sound/soc/msm/msmfalcon-internal.c b/sound/soc/msm/msmfalcon-internal.c
new file mode 100644
index 000000000000..3a8b88cdfb64
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-internal.c
@@ -0,0 +1,2453 @@
+/* Copyright (c) 2015-2016, 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/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <sound/pcm_params.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "msm-audio-pinctrl.h"
+#include "msmfalcon-common.h"
+#include "../codecs/msm8x16/msm8x16-wcd.h"
+
+#define __CHIPSET__ "MSMFALCON "
+#define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
+
+#define DEFAULT_MCLK_RATE 9600000
+#define NATIVE_MCLK_RATE 11289600
+
+#define WCD_MBHC_DEF_RLOADS 5
+
+enum {
+ INT0_MI2S = 0,
+ INT1_MI2S,
+ INT2_MI2S,
+ INT3_MI2S,
+ INT4_MI2S,
+ INT5_MI2S,
+ INT6_MI2S,
+ INT_MI2S_MAX,
+};
+
+static struct afe_clk_set int_mi2s_clk[INT_MI2S_MAX] = {
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT0_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT1_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT2_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT3_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT4_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT5_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_INT6_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+};
+
+struct dev_config {
+ u32 sample_rate;
+ u32 bit_format;
+ u32 channels;
+};
+
+/* Default configuration of MI2S channels */
+static struct dev_config int_mi2s_cfg[] = {
+ [INT0_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [INT1_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [INT2_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [INT3_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [INT4_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [INT5_MI2S] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [INT6_MI2S] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+static char const *int_mi2s_rate_text[] = {"KHZ_8", "KHZ_16",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_96", "KHZ_192"};
+static const char *const int_mi2s_ch_text[] = {"One", "Two"};
+static const char *const int_mi2s_tx_ch_text[] = {"One", "Two",
+ "Three", "Four"};
+static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
+static const char *const loopback_mclk_text[] = {"DISABLE", "ENABLE"};
+
+static SOC_ENUM_SINGLE_EXT_DECL(int0_mi2s_rx_sample_rate, int_mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int0_mi2s_rx_chs, int_mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int0_mi2s_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int2_mi2s_tx_sample_rate, int_mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int2_mi2s_tx_chs, int_mi2s_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int2_mi2s_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int3_mi2s_tx_sample_rate, int_mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int3_mi2s_tx_chs, int_mi2s_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int3_mi2s_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int4_mi2s_rx_sample_rate, int_mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int4_mi2s_rx_chs, int_mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int4_mi2s_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(int5_mi2s_tx_chs, int_mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(loopback_mclk_en, loopback_mclk_text);
+
+static int msm_dmic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+static int msm_int_enable_dig_cdc_clk(struct snd_soc_codec *codec, int enable,
+ bool dapm);
+static int msm_int_mclk0_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+static int msm_int_mi2s_snd_startup(struct snd_pcm_substream *substream);
+static void msm_int_mi2s_snd_shutdown(struct snd_pcm_substream *substream);
+
+static struct wcd_mbhc_config *mbhc_cfg_ptr;
+
+static int int_mi2s_get_bit_format_val(int bit_format)
+{
+ int val = 0;
+
+ switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ val = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ val = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ val = 0;
+ break;
+ }
+ return val;
+}
+
+static int int_mi2s_get_bit_format(int val)
+{
+ int bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+
+ switch (val) {
+ case 0:
+ bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 1:
+ bit_fmt = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 2:
+ bit_fmt = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ default:
+ bit_fmt = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return bit_fmt;
+}
+
+static int int_mi2s_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int port_id = 0;
+
+ if (strnstr(kcontrol->id.name, "INT0_MI2S", sizeof("INT0_MI2S")))
+ port_id = INT0_MI2S;
+ else if (strnstr(kcontrol->id.name, "INT2_MI2S", sizeof("INT2_MI2S")))
+ port_id = INT2_MI2S;
+ else if (strnstr(kcontrol->id.name, "INT3_MI2S", sizeof("INT3_MI2S")))
+ port_id = INT3_MI2S;
+ else if (strnstr(kcontrol->id.name, "INT4_MI2S", sizeof("INT4_MI2S")))
+ port_id = INT4_MI2S;
+ else {
+ pr_err("%s: unsupported channel: %s",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ return port_id;
+}
+
+static int int_mi2s_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = int_mi2s_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ ucontrol->value.enumerated.item[0] =
+ int_mi2s_get_bit_format_val(int_mi2s_cfg[ch_num].bit_format);
+
+ pr_debug("%s: int_mi2s[%d]_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, int_mi2s_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int int_mi2s_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = int_mi2s_get_port_idx(kcontrol);
+
+ if (ch_num < 0)
+ return ch_num;
+
+ int_mi2s_cfg[ch_num].bit_format =
+ int_mi2s_get_bit_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: int_mi2s[%d]_rx_bit_format = %d, ucontrol value = %d\n",
+ __func__, ch_num, int_mi2s_cfg[ch_num].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p,
+ int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+static int int_mi2s_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 6;
+ break;
+ default:
+ sample_rate_val = 4;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int int_mi2s_get_sample_rate(int value)
+{
+ int sample_rate;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int int_mi2s_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = int_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ int_mi2s_cfg[idx].sample_rate =
+ int_mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_sample_rate = %d, item = %d\n", __func__,
+ idx, int_mi2s_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int int_mi2s_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = int_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ int_mi2s_get_sample_rate_val(int_mi2s_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_sample_rate = %d, item = %d\n", __func__,
+ idx, int_mi2s_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int int_mi2s_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = int_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ pr_debug("%s: int_mi2s_[%d]_rx_ch = %d\n", __func__,
+ idx, int_mi2s_cfg[idx].channels);
+ ucontrol->value.enumerated.item[0] = int_mi2s_cfg[idx].channels - 1;
+
+ return 0;
+}
+
+static int int_mi2s_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = int_mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ int_mi2s_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: int_mi2s_[%d]_ch = %d\n", __func__,
+ idx, int_mi2s_cfg[idx].channels);
+
+ return 1;
+}
+
+static const struct snd_soc_dapm_widget msm_int_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY_S("INT_MCLK0", -1, SND_SOC_NOPM, 0, 0,
+ msm_int_mclk0_event, SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Secondary Mic", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic1", msm_dmic_event),
+ SND_SOC_DAPM_MIC("Digital Mic2", msm_dmic_event),
+ SND_SOC_DAPM_MIC("Digital Mic3", msm_dmic_event),
+ SND_SOC_DAPM_MIC("Digital Mic4", msm_dmic_event),
+};
+
+static int msm_config_hph_compander_gpio(bool enable)
+{
+ int ret = 0;
+
+ pr_debug("%s: %s HPH Compander\n", __func__,
+ enable ? "Enable" : "Disable");
+
+ if (enable) {
+ ret = msm_gpioset_activate(CLIENT_WCD, "comp_gpio");
+ if (ret) {
+ pr_err("%s: gpio set cannot be activated %s\n",
+ __func__, "comp_gpio");
+ goto done;
+ }
+ } else {
+ ret = msm_gpioset_suspend(CLIENT_WCD, "comp_gpio");
+ if (ret) {
+ pr_err("%s: gpio set cannot be de-activated %s\n",
+ __func__, "comp_gpio");
+ goto done;
+ }
+ }
+
+done:
+ return ret;
+}
+
+static int is_ext_spk_gpio_support(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata)
+{
+ const char *spk_ext_pa = "qcom,msm-spk-ext-pa";
+
+ pr_debug("%s:Enter\n", __func__);
+
+ pdata->spk_ext_pa_gpio = of_get_named_gpio(pdev->dev.of_node,
+ spk_ext_pa, 0);
+
+ if (pdata->spk_ext_pa_gpio < 0) {
+ dev_dbg(&pdev->dev,
+ "%s: missing %s in dt node\n", __func__, spk_ext_pa);
+ } else {
+ if (!gpio_is_valid(pdata->spk_ext_pa_gpio)) {
+ pr_err("%s: Invalid external speaker gpio: %d",
+ __func__, pdata->spk_ext_pa_gpio);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int enable_spk_ext_pa(struct snd_soc_codec *codec, int enable)
+{
+ struct snd_soc_card *card = codec->component.card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ if (!gpio_is_valid(pdata->spk_ext_pa_gpio)) {
+ pr_err("%s: Invalid gpio: %d\n", __func__,
+ pdata->spk_ext_pa_gpio);
+ return false;
+ }
+
+ pr_debug("%s: %s external speaker PA\n", __func__,
+ enable ? "Enable" : "Disable");
+
+ if (enable) {
+ ret = msm_gpioset_activate(CLIENT_WCD, "ext_spk_gpio");
+ if (ret) {
+ pr_err("%s: gpio set cannot be de-activated %s\n",
+ __func__, "ext_spk_gpio");
+ return ret;
+ }
+ gpio_set_value_cansleep(pdata->spk_ext_pa_gpio, enable);
+ } else {
+ gpio_set_value_cansleep(pdata->spk_ext_pa_gpio, enable);
+ ret = msm_gpioset_suspend(CLIENT_WCD, "ext_spk_gpio");
+ if (ret) {
+ pr_err("%s: gpio set cannot be de-activated %s\n",
+ __func__, "ext_spk_gpio");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int int_mi2s_get_idx_from_beid(int32_t be_id)
+{
+ int idx = 0;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_INT0_MI2S_RX:
+ idx = INT0_MI2S;
+ break;
+ case MSM_BACKEND_DAI_INT2_MI2S_TX:
+ idx = INT2_MI2S;
+ break;
+ case MSM_BACKEND_DAI_INT3_MI2S_TX:
+ idx = INT3_MI2S;
+ break;
+ case MSM_BACKEND_DAI_INT4_MI2S_RX:
+ idx = INT4_MI2S;
+ break;
+ case MSM_BACKEND_DAI_INT5_MI2S_TX:
+ idx = INT5_MI2S;
+ break;
+ default:
+ idx = INT0_MI2S;
+ break;
+ }
+
+ return idx;
+}
+
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ return 0;
+}
+
+int int_mi2s_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ int idx;
+
+ pr_debug("%s: format = %d, rate = %d\n",
+ __func__, params_format(params), params_rate(params));
+
+ switch (dai_link->be_id) {
+ case MSM_BACKEND_DAI_INT0_MI2S_RX:
+ case MSM_BACKEND_DAI_INT2_MI2S_TX:
+ case MSM_BACKEND_DAI_INT3_MI2S_TX:
+ case MSM_BACKEND_DAI_INT4_MI2S_RX:
+ case MSM_BACKEND_DAI_INT5_MI2S_TX:
+ idx = int_mi2s_get_idx_from_beid(dai_link->be_id);
+ rate->min = rate->max = int_mi2s_cfg[idx].sample_rate;
+ channels->min = channels->max =
+ int_mi2s_cfg[idx].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ int_mi2s_cfg[idx].bit_format);
+ break;
+ default:
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return 0;
+}
+
+static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] =
+ (int_mi2s_cfg[INT5_MI2S].channels/2 - 1);
+ pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int_mi2s_cfg[INT5_MI2S].channels =
+ roundup_pow_of_two(ucontrol->value.integer.value[0] + 2);
+
+ pr_debug("%s: msm_vi_feed_tx_ch = %d\n",
+ __func__, int_mi2s_cfg[INT5_MI2S].channels);
+ return 1;
+}
+
+static int msm_int_enable_dig_cdc_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm)
+{
+ int ret = 0;
+ struct msm_asoc_mach_data *pdata = NULL;
+ int clk_freq_in_hz;
+ bool int_mclk0_freq_chg = false;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ pr_debug("%s: enable %d mclk ref counter %d\n",
+ __func__, enable,
+ atomic_read(&pdata->int_mclk0_rsc_ref));
+ if (enable) {
+ if (int_mi2s_cfg[INT0_MI2S].sample_rate ==
+ SAMPLING_RATE_44P1KHZ)
+ clk_freq_in_hz = NATIVE_MCLK_RATE;
+ else
+ clk_freq_in_hz = pdata->mclk_freq;
+
+ if (pdata->digital_cdc_core_clk.clk_freq_in_hz
+ != clk_freq_in_hz)
+ int_mclk0_freq_chg = true;
+ if (!atomic_read(&pdata->int_mclk0_rsc_ref) ||
+ int_mclk0_freq_chg) {
+ cancel_delayed_work_sync(
+ &pdata->disable_int_mclk0_work);
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ if (atomic_read(&pdata->int_mclk0_enabled) == false ||
+ int_mclk0_freq_chg) {
+ pdata->digital_cdc_core_clk.clk_freq_in_hz =
+ clk_freq_in_hz;
+ pdata->digital_cdc_core_clk.enable = 1;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0) {
+ pr_err("%s: failed to enable CCLK\n",
+ __func__);
+ mutex_unlock(
+ &pdata->cdc_int_mclk0_mutex);
+ return ret;
+ }
+ pr_debug("enabled digital codec core clk\n");
+ atomic_set(&pdata->int_mclk0_enabled, true);
+ }
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ }
+ atomic_inc(&pdata->int_mclk0_rsc_ref);
+ } else {
+ cancel_delayed_work_sync(&pdata->disable_int_mclk0_work);
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ if (atomic_read(&pdata->int_mclk0_enabled) == true) {
+ pdata->digital_cdc_core_clk.enable = 0;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0)
+ pr_err("%s: failed to disable CCLK\n",
+ __func__);
+ atomic_set(&pdata->int_mclk0_enabled, false);
+ }
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ }
+ return ret;
+}
+
+static int loopback_mclk_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+
+static int loopback_mclk_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = -EINVAL;
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ pr_debug("%s: mclk_rsc_ref %d enable %ld\n",
+ __func__, atomic_read(&pdata->int_mclk0_rsc_ref),
+ ucontrol->value.integer.value[0]);
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ ret = msm_gpioset_activate(CLIENT_WCD, "int_pdm");
+ if (ret) {
+ pr_err("%s: failed to enable the pri gpios: %d\n",
+ __func__, ret);
+ break;
+ }
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ if ((!atomic_read(&pdata->int_mclk0_rsc_ref)) &&
+ (!atomic_read(&pdata->int_mclk0_enabled))) {
+ pdata->digital_cdc_core_clk.enable = 1;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0) {
+ pr_err("%s: failed to enable the MCLK: %d\n",
+ __func__, ret);
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ ret = msm_gpioset_suspend(CLIENT_WCD,
+ "int_pdm");
+ if (ret)
+ pr_err("%s: failed to disable the pri gpios: %d\n",
+ __func__, ret);
+ break;
+ }
+ atomic_set(&pdata->int_mclk0_enabled, true);
+ }
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ atomic_inc(&pdata->int_mclk0_rsc_ref);
+ msm8x16_wcd_mclk_enable(codec, 1, true);
+ break;
+ case 0:
+ if (atomic_read(&pdata->int_mclk0_rsc_ref) <= 0)
+ break;
+ msm8x16_wcd_mclk_enable(codec, 0, true);
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ if ((!atomic_dec_return(&pdata->int_mclk0_rsc_ref)) &&
+ (atomic_read(&pdata->int_mclk0_enabled))) {
+ pdata->digital_cdc_core_clk.enable = 0;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0) {
+ pr_err("%s: failed to disable the CCLK: %d\n",
+ __func__, ret);
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ break;
+ }
+ atomic_set(&pdata->int_mclk0_enabled, false);
+ }
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ ret = msm_gpioset_suspend(CLIENT_WCD, "int_pdm");
+ if (ret)
+ pr_err("%s: failed to disable the pri gpios: %d\n",
+ __func__, ret);
+ break;
+ default:
+ pr_err("%s: Unexpected input value\n", __func__);
+ break;
+ }
+ return ret;
+}
+
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+ SOC_ENUM_EXT("INT0_MI2S_RX Format", int0_mi2s_rx_format,
+ int_mi2s_bit_format_get, int_mi2s_bit_format_put),
+ SOC_ENUM_EXT("INT2_MI2S_TX Format", int2_mi2s_tx_format,
+ int_mi2s_bit_format_get, int_mi2s_bit_format_put),
+ SOC_ENUM_EXT("INT3_MI2S_TX Format", int3_mi2s_tx_format,
+ int_mi2s_bit_format_get, int_mi2s_bit_format_put),
+ SOC_ENUM_EXT("INT0_MI2S_RX SampleRate", int0_mi2s_rx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT2_MI2S_TX SampleRate", int2_mi2s_tx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT3_MI2S_TX SampleRate", int3_mi2s_tx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT0_MI2S_RX SampleRate", int0_mi2s_rx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT2_MI2S_TX SampleRate", int2_mi2s_tx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT3_MI2S_TX SampleRate", int3_mi2s_tx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT0_MI2S_RX Channels", int0_mi2s_rx_chs,
+ int_mi2s_ch_get, int_mi2s_ch_put),
+ SOC_ENUM_EXT("INT2_MI2S_TX Channels", int2_mi2s_tx_chs,
+ int_mi2s_ch_get, int_mi2s_ch_put),
+ SOC_ENUM_EXT("INT3_MI2S_TX Channels", int3_mi2s_tx_chs,
+ int_mi2s_ch_get, int_mi2s_ch_put),
+ SOC_ENUM_EXT("Loopback MCLK", loopback_mclk_en,
+ loopback_mclk_get, loopback_mclk_put),
+};
+
+static const struct snd_kcontrol_new msm_swr_controls[] = {
+ SOC_ENUM_EXT("INT4_MI2S_RX Format", int4_mi2s_rx_format,
+ int_mi2s_bit_format_get, int_mi2s_bit_format_put),
+ SOC_ENUM_EXT("INT4_MI2S_RX SampleRate", int4_mi2s_rx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT4_MI2S_RX SampleRate", int4_mi2s_rx_sample_rate,
+ int_mi2s_sample_rate_get,
+ int_mi2s_sample_rate_put),
+ SOC_ENUM_EXT("INT4_MI2S_RX Channels", int4_mi2s_rx_chs,
+ int_mi2s_ch_get, int_mi2s_ch_put),
+ SOC_ENUM_EXT("VI_FEED_TX Channels", int5_mi2s_tx_chs,
+ msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
+};
+
+static int msm_dmic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ int ret = 0;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ pr_debug("%s: event = %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = msm_gpioset_activate(CLIENT_WCD, "dmic_gpio");
+ if (ret < 0) {
+ pr_err("%s: gpio set cannot be activated %sd",
+ __func__, "dmic_gpio");
+ return ret;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ ret = msm_gpioset_suspend(CLIENT_WCD, "dmic_gpio");
+ if (ret < 0) {
+ pr_err("%s: gpio set cannot be de-activated %sd",
+ __func__, "dmic_gpio");
+ return ret;
+ }
+ break;
+ default:
+ pr_err("%s: invalid DAPM event %d\n", __func__, event);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int msm_int_mclk0_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ int ret = 0;
+
+ pdata = snd_soc_card_get_drvdata(codec->component.card);
+ pr_debug("%s: event = %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMD:
+ pr_debug("%s: mclk_res_ref = %d\n",
+ __func__, atomic_read(&pdata->int_mclk0_rsc_ref));
+ ret = msm_gpioset_suspend(CLIENT_WCD, "int_pdm");
+ if (ret < 0) {
+ pr_err("%s: gpio set cannot be de-activated %sd",
+ __func__, "int_pdm");
+ return ret;
+ }
+ if (atomic_read(&pdata->int_mclk0_rsc_ref) == 0) {
+ pr_debug("%s: disabling MCLK\n", __func__);
+ /* disable the codec mclk config*/
+ msm8x16_wcd_mclk_enable(codec, 0, true);
+ msm_int_enable_dig_cdc_clk(codec, 0, true);
+ }
+ break;
+ default:
+ pr_err("%s: invalid DAPM event %d\n", __func__, event);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int int_mi2s_get_port_id(int be_id)
+{
+ int afe_port_id;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_INT0_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_INT0_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_INT2_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_INT2_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_INT3_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_INT3_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_INT4_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_INT4_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_INT5_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_INT5_MI2S_TX;
+ break;
+ default:
+ pr_err("%s: Invalid be_id: %d\n", __func__, be_id);
+ afe_port_id = -EINVAL;
+ }
+
+ return afe_port_id;
+}
+
+static int int_mi2s_get_index(int port_id)
+{
+ int index;
+
+ switch (port_id) {
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ index = INT0_MI2S;
+ break;
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ index = INT2_MI2S;
+ break;
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ index = INT3_MI2S;
+ break;
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ index = INT4_MI2S;
+ break;
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ index = INT5_MI2S;
+ break;
+ default:
+ pr_err("%s: Invalid port_id: %d\n", __func__, port_id);
+ index = -EINVAL;
+ }
+
+ return index;
+}
+
+static u32 get_int_mi2s_bits_per_sample(u32 bit_format)
+{
+ u32 bit_per_sample;
+
+ switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bit_per_sample = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bit_per_sample = 16;
+ break;
+ }
+
+ return bit_per_sample;
+}
+
+static void update_int_mi2s_clk_val(int idx, int stream)
+{
+ u32 bit_per_sample;
+
+ bit_per_sample =
+ get_int_mi2s_bits_per_sample(int_mi2s_cfg[idx].bit_format);
+ int_mi2s_clk[idx].clk_freq_in_hz =
+ (int_mi2s_cfg[idx].sample_rate * int_mi2s_cfg[idx].channels
+ * bit_per_sample);
+}
+
+static int int_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int port_id = 0;
+ int index;
+
+ port_id = int_mi2s_get_port_id(rtd->dai_link->be_id);
+ if (IS_ERR_VALUE(port_id)) {
+ dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__);
+ ret = port_id;
+ goto done;
+ }
+ index = int_mi2s_get_index(port_id);
+ if (index < 0) {
+ dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__);
+ ret = port_id;
+ goto done;
+ }
+ if (enable) {
+ update_int_mi2s_clk_val(index, substream->stream);
+ dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__,
+ int_mi2s_clk[index].clk_freq_in_hz);
+ }
+
+ int_mi2s_clk[index].enable = enable;
+ ret = afe_set_lpass_clock_v2(port_id,
+ &int_mi2s_clk[index]);
+ if (ret < 0) {
+ dev_err(rtd->card->dev,
+ "%s: afe lpass clock failed for port 0x%x , err:%d\n",
+ __func__, port_id, ret);
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static int msm_swr_mi2s_snd_startup(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;
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ ret = int_mi2s_set_sclk(substream, true);
+ if (ret < 0) {
+ pr_err("%s: failed to enable sclk %d\n",
+ __func__, ret);
+ return ret;
+ }
+ /* Enable the codec mclk config */
+ ret = msm_gpioset_activate(CLIENT_WCD, "swr_pin");
+ if (ret < 0) {
+ pr_err("%s: gpio set cannot be activated %sd",
+ __func__, "swr_pin");
+ return ret;
+ }
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("%s: set fmt cpu dai failed; ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static void msm_swr_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret;
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ ret = int_mi2s_set_sclk(substream, false);
+ if (ret < 0)
+ pr_err("%s:clock disable failed; ret=%d\n", __func__,
+ ret);
+}
+
+static int msm_int_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ ret = int_mi2s_set_sclk(substream, true);
+ if (ret < 0) {
+ pr_err("%s: failed to enable sclk %d\n",
+ __func__, ret);
+ return ret;
+ }
+ ret = msm_int_enable_dig_cdc_clk(codec, 1, true);
+ if (ret < 0) {
+ pr_err("failed to enable mclk\n");
+ return ret;
+ }
+ /* Enable the codec mclk config */
+ ret = msm_gpioset_activate(CLIENT_WCD, "int_pdm");
+ if (ret < 0) {
+ pr_err("%s: gpio set cannot be activated %s\n",
+ __func__, "int_pdm");
+ return ret;
+ }
+ msm8x16_wcd_mclk_enable(codec, 1, true);
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("%s: set fmt cpu dai failed; ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static void msm_int_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ ret = int_mi2s_set_sclk(substream, false);
+ if (ret < 0)
+ pr_err("%s:clock disable failed; ret=%d\n", __func__,
+ ret);
+ if (atomic_read(&pdata->int_mclk0_rsc_ref) > 0) {
+ atomic_dec(&pdata->int_mclk0_rsc_ref);
+ pr_debug("%s: decrementing mclk_res_ref %d\n",
+ __func__,
+ atomic_read(&pdata->int_mclk0_rsc_ref));
+ }
+}
+
+static void *def_msm_int_wcd_mbhc_cal(void)
+{
+ void *msm_int_wcd_cal;
+ struct wcd_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_low, *btn_high;
+
+ msm_int_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
+ WCD_MBHC_DEF_RLOADS), GFP_KERNEL);
+ if (!msm_int_wcd_cal)
+ return NULL;
+
+#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(msm_int_wcd_cal)->X) = (Y))
+ S(v_hs_max, 1500);
+#undef S
+#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(msm_int_wcd_cal)->X) = (Y))
+ S(num_btn, WCD_MBHC_DEF_BUTTONS);
+#undef S
+
+
+ btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(msm_int_wcd_cal);
+ btn_low = btn_cfg->_v_btn_low;
+ btn_high = ((void *)&btn_cfg->_v_btn_low) +
+ (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
+
+ /*
+ * In SW we are maintaining two sets of threshold register
+ * one for current source and another for Micbias.
+ * all btn_low corresponds to threshold for current source
+ * all bt_high corresponds to threshold for Micbias
+ * Below thresholds are based on following resistances
+ * 0-70 == Button 0
+ * 110-180 == Button 1
+ * 210-290 == Button 2
+ * 360-680 == Button 3
+ */
+ btn_low[0] = 75;
+ btn_high[0] = 75;
+ btn_low[1] = 150;
+ btn_high[1] = 150;
+ btn_low[2] = 225;
+ btn_high[2] = 225;
+ btn_low[3] = 450;
+ btn_high[3] = 450;
+ btn_low[4] = 500;
+ btn_high[4] = 500;
+
+ return msm_int_wcd_cal;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_codec_get_dapm(codec);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = -ENOMEM;
+
+ pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+ snd_soc_add_codec_controls(codec, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+
+ snd_soc_add_codec_controls(codec, msm_common_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+
+ snd_soc_dapm_new_controls(dapm, msm_int_dapm_widgets,
+ ARRAY_SIZE(msm_int_dapm_widgets));
+
+ snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Secondary Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
+
+ snd_soc_dapm_ignore_suspend(dapm, "EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "HEADPHONE");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK_OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC4");
+
+ snd_soc_dapm_sync(dapm);
+
+ msm8x16_wcd_spk_ext_pa_cb(enable_spk_ext_pa, codec);
+ msm8x16_wcd_hph_comp_cb(msm_config_hph_compander_gpio, codec);
+
+ mbhc_cfg_ptr->calibration = def_msm_int_wcd_mbhc_cal();
+ if (mbhc_cfg_ptr->calibration) {
+ ret = msm8x16_wcd_hs_detect(codec, mbhc_cfg_ptr);
+ if (ret) {
+ pr_err("%s: msm8x16_wcd_hs_detect failed\n", __func__);
+ kfree(mbhc_cfg_ptr->calibration);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int msm_swr_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_codec_get_dapm(codec);
+
+ snd_soc_add_codec_controls(codec, msm_swr_controls,
+ ARRAY_SIZE(msm_swr_controls));
+
+ snd_soc_dapm_ignore_suspend(dapm, "AIF1_SWR Playback");
+ snd_soc_dapm_ignore_suspend(dapm, "VIfeed_SWR");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
+ snd_soc_dapm_ignore_suspend(dapm, "AIF1_SWR VI");
+ snd_soc_dapm_ignore_suspend(dapm, "VIINPUT_SWR");
+
+ snd_soc_dapm_sync(dapm);
+
+ return 0;
+}
+
+static struct snd_soc_ops msm_mi2s_be_ops = {
+ .startup = msm_mi2s_snd_startup,
+ .shutdown = msm_mi2s_snd_shutdown,
+};
+
+static struct snd_soc_ops msm_aux_pcm_be_ops = {
+ .startup = msm_aux_pcm_snd_startup,
+ .shutdown = msm_aux_pcm_snd_shutdown,
+};
+
+static struct snd_soc_ops msm_int_mi2s_be_ops = {
+ .startup = msm_int_mi2s_snd_startup,
+ .shutdown = msm_int_mi2s_snd_shutdown,
+};
+
+static struct snd_soc_ops msm_swr_mi2s_be_ops = {
+ .startup = msm_swr_mi2s_snd_startup,
+ .shutdown = msm_swr_mi2s_snd_shutdown,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_int_dai[] = {
+ /* FrontEnd DAI Links */
+ {/* hw:x,0 */
+ .name = MSM_DAILINK_NAME(Media1),
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 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,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+ {/* hw:x,1 */
+ .name = MSM_DAILINK_NAME(Media2),
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
+ {/* hw:x,2 */
+ .name = "VoiceMMode1",
+ .stream_name = "VoiceMMode1",
+ .cpu_dai_name = "VoiceMMode1",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICEMMODE1,
+ },
+ {/* hw:x,3 */
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {/* hw:x,4 */
+ .name = MSM_DAILINK_NAME(ULL),
+ .stream_name = "ULL",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-dsp.2",
+ .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,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ /* Hostless PCM purpose */
+ {/* hw:x,5 */
+ .name = "INT4 MI2S_RX Hostless",
+ .stream_name = "INT4 MI2S_RX Hostless",
+ .cpu_dai_name = "INT4_MI2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,6 */
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {/* hw:x,7 */
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {/* hw:x,8 */
+ .name = MSM_DAILINK_NAME(Compress1),
+ .stream_name = "Compress1",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {/* hw:x,9*/
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,10 */
+ .name = "SLIMBUS_1 Hostless",
+ .stream_name = "SLIMBUS_1 Hostless",
+ .cpu_dai_name = "SLIMBUS1_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,11 */
+ .name = "SLIMBUS_3 Hostless",
+ .stream_name = "SLIMBUS_3 Hostless",
+ .cpu_dai_name = "SLIMBUS3_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,12 */
+ .name = "SLIMBUS_4 Hostless",
+ .stream_name = "SLIMBUS_4 Hostless",
+ .cpu_dai_name = "SLIMBUS4_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,13 */
+ .name = MSM_DAILINK_NAME(LowLatency),
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
+ /* LSM FE */
+ {/* hw:x,14 */
+ .name = "Listen 1 Audio Service",
+ .stream_name = "Listen 1 Audio Service",
+ .cpu_dai_name = "LSM1",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM1,
+ },
+ {/* hw:x,15 */
+ .name = MSM_DAILINK_NAME(Compress2),
+ .stream_name = "Compress2",
+ .cpu_dai_name = "MultiMedia7",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
+ },
+ {/* hw:x,16 */
+ .name = MSM_DAILINK_NAME(Compress3),
+ .stream_name = "Compress3",
+ .cpu_dai_name = "MultiMedia10",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA10,
+ },
+ {/* hw:x,17 */
+ .name = MSM_DAILINK_NAME(ULL_NOIRQ),
+ .stream_name = "MM_NOIRQ",
+ .cpu_dai_name = "MultiMedia8",
+ .platform_name = "msm-pcm-dsp-noirq",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+ },
+ {/* hw:x,18 */
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,19 */
+ .name = "VoiceMMode2",
+ .stream_name = "VoiceMMode2",
+ .cpu_dai_name = "VoiceMMode2",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOICEMMODE2,
+ },
+ {/* hw:x,20 */
+ .name = "Listen 2 Audio Service",
+ .stream_name = "Listen 2 Audio Service",
+ .cpu_dai_name = "LSM2",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM2,
+ },
+ {/* hw:x,21 */
+ .name = "Listen 3 Audio Service",
+ .stream_name = "Listen 3 Audio Service",
+ .cpu_dai_name = "LSM3",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM3,
+ },
+ {/* hw:x,22 */
+ .name = "Listen 4 Audio Service",
+ .stream_name = "Listen 4 Audio Service",
+ .cpu_dai_name = "LSM4",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM4,
+ },
+ {/* hw:x,23 */
+ .name = "Listen 5 Audio Service",
+ .stream_name = "Listen 5 Audio Service",
+ .cpu_dai_name = "LSM5",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM5,
+ },
+ {/* hw:x,24 */
+ .name = "Listen 6 Audio Service",
+ .stream_name = "Listen 6 Audio Service",
+ .cpu_dai_name = "LSM6",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM6
+ },
+ {/* hw:x,25 */
+ .name = "Listen 7 Audio Service",
+ .stream_name = "Listen 7 Audio Service",
+ .cpu_dai_name = "LSM7",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM7,
+ },
+ {/* hw:x,26 */
+ .name = "Listen 8 Audio Service",
+ .stream_name = "Listen 8 Audio Service",
+ .cpu_dai_name = "LSM8",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM8,
+ },
+ {/* hw:x,27 */
+ .name = MSM_DAILINK_NAME(Media9),
+ .stream_name = "MultiMedia9",
+ .cpu_dai_name = "MultiMedia9",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
+ },
+ {/* hw:x,28 */
+ .name = MSM_DAILINK_NAME(Compress4),
+ .stream_name = "Compress4",
+ .cpu_dai_name = "MultiMedia11",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA11,
+ },
+ {/* hw:x,29 */
+ .name = MSM_DAILINK_NAME(Compress5),
+ .stream_name = "Compress5",
+ .cpu_dai_name = "MultiMedia12",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA12,
+ },
+ {/* hw:x,30 */
+ .name = MSM_DAILINK_NAME(Compress6),
+ .stream_name = "Compress6",
+ .cpu_dai_name = "MultiMedia13",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA13,
+ },
+ {/* hw:x,31 */
+ .name = MSM_DAILINK_NAME(Compress7),
+ .stream_name = "Compress7",
+ .cpu_dai_name = "MultiMedia14",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA14,
+ },
+ {/* hw:x,32 */
+ .name = MSM_DAILINK_NAME(Compress8),
+ .stream_name = "Compress8",
+ .cpu_dai_name = "MultiMedia15",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA15,
+ },
+ {/* hw:x,33 */
+ .name = MSM_DAILINK_NAME(Compress9),
+ .stream_name = "Compress9",
+ .cpu_dai_name = "MultiMedia16",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_capture = 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,
+ /* this dai link has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA16,
+ },
+ {/* hw:x,34 */
+ .name = "SLIMBUS_8 Hostless",
+ .stream_name = "SLIMBUS8_HOSTLESS Capture",
+ .cpu_dai_name = "SLIMBUS8_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,35 */
+ .name = LPASS_BE_INT5_MI2S_TX,
+ .stream_name = "INT5_mi2s Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.12",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "msm_swr_codec",
+ .codec_dai_name = "msm_swr_vifeedback",
+ .be_id = MSM_BACKEND_DAI_INT5_MI2S_TX,
+ .be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+ .ops = &msm_swr_mi2s_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .dpcm_capture = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {/* hw:x,36 */
+ .name = "Primary MI2S_RX Hostless",
+ .stream_name = "Primary MI2S_RX Hostless",
+ .cpu_dai_name = "PRI_MI2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,37 */
+ .name = "Secondary MI2S_RX Hostless",
+ .stream_name = "Secondary MI2S_RX Hostless",
+ .cpu_dai_name = "SEC_MI2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,38 */
+ .name = "Tertiary MI2S_RX Hostless",
+ .stream_name = "Tertiary MI2S_RX Hostless",
+ .cpu_dai_name = "TERT_MI2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,39 */
+ .name = "INT0 MI2S_RX Hostless",
+ .stream_name = "INT0 MI2S_RX Hostless",
+ .cpu_dai_name = "INT0_MI2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ /* Backend I2S DAI Links */
+ {
+ .name = LPASS_BE_INT0_MI2S_RX,
+ .stream_name = "INT0 MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.7",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "cajon_codec",
+ .codec_dai_name = "msm8x16_wcd_i2s_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE |
+ ASYNC_DPCM_SND_SOC_HW_PARAMS,
+ .be_id = MSM_BACKEND_DAI_INT0_MI2S_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+ .ops = &msm_int_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT4_MI2S_RX,
+ .stream_name = "INT4 MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.11",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm_swr_codec",
+ .codec_dai_name = "msm_swr_i2s_rx1",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_INT4_MI2S_RX,
+ .init = &msm_swr_audrx_init,
+ .be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+ .ops = &msm_swr_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT2_MI2S_TX,
+ .stream_name = "INT2 MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.9",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "cajon_codec",
+ .codec_dai_name = "msm8x16_wcd_i2s_tx2",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE |
+ ASYNC_DPCM_SND_SOC_HW_PARAMS,
+ .be_id = MSM_BACKEND_DAI_INT2_MI2S_TX,
+ .be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+ .ops = &msm_int_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT3_MI2S_TX,
+ .stream_name = "INT3 MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.10",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "cajon_codec",
+ .codec_dai_name = "msm8x16_wcd_i2s_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE |
+ ASYNC_DPCM_SND_SOC_HW_PARAMS,
+ .be_id = MSM_BACKEND_DAI_INT3_MI2S_TX,
+ .be_hw_params_fixup = int_mi2s_be_hw_params_fixup,
+ .ops = &msm_int_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music 2 BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE2_PLAYBACK_TX,
+ .stream_name = "Voice2 Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32770",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = {
+ {
+ .name = LPASS_BE_PRI_MI2S_RX,
+ .stream_name = "Primary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_MI2S_TX,
+ .stream_name = "Primary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_MI2S_RX,
+ .stream_name = "Secondary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_MI2S_TX,
+ .stream_name = "Secondary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_RX,
+ .stream_name = "Tertiary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_TX,
+ .stream_name = "Tertiary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_MI2S_RX,
+ .stream_name = "Quaternary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_MI2S_TX,
+ .stream_name = "Quaternary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = {
+ /* Primary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Secondary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_SEC_AUXPCM_RX,
+ .stream_name = "Sec AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SEC_AUXPCM_TX,
+ .stream_name = "Sec AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Tertiary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_TERT_AUXPCM_RX,
+ .stream_name = "Tert AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_TERT_AUXPCM_TX,
+ .stream_name = "Tert AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ /* Quaternary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_QUAT_AUXPCM_RX,
+ .stream_name = "Quat AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.4",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_QUAT_AUXPCM_TX,
+ .stream_name = "Quat AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.4",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .ops = &msm_aux_pcm_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link msm_int_dai_links[
+ARRAY_SIZE(msm_int_dai) +
+ARRAY_SIZE(msm_mi2s_be_dai_links) +
+ARRAY_SIZE(msm_auxpcm_be_dai_links)];
+
+static struct snd_soc_card msmfalcon_card = {
+ /* snd_soc_card_msmfalcon */
+ .name = "msmfalcon-snd-card",
+ .dai_link = msm_int_dai,
+ .num_links = ARRAY_SIZE(msm_int_dai),
+};
+
+static void msm_disable_int_mclk0(struct work_struct *work)
+{
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct delayed_work *dwork;
+ int ret = 0;
+
+ dwork = to_delayed_work(work);
+ pdata = container_of(dwork, struct msm_asoc_mach_data,
+ disable_int_mclk0_work);
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ pr_debug("%s: mclk_enabled %d mclk_rsc_ref %d\n", __func__,
+ atomic_read(&pdata->int_mclk0_enabled),
+ atomic_read(&pdata->int_mclk0_rsc_ref));
+
+ if (atomic_read(&pdata->int_mclk0_enabled) == true
+ && atomic_read(&pdata->int_mclk0_rsc_ref) == 0) {
+ pr_debug("Disable the mclk\n");
+ pdata->digital_cdc_core_clk.enable = 0;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0)
+ pr_err("%s failed to disable the CCLK\n", __func__);
+ atomic_set(&pdata->int_mclk0_enabled, false);
+ }
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+}
+
+static void msm_int_dt_parse_cap_info(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata)
+{
+ const char *ext1_cap = "qcom,msm-micbias1-ext-cap";
+ const char *ext2_cap = "qcom,msm-micbias2-ext-cap";
+
+ pdata->micbias1_cap_mode =
+ (of_property_read_bool(pdev->dev.of_node, ext1_cap) ?
+ MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+
+ pdata->micbias2_cap_mode =
+ (of_property_read_bool(pdev->dev.of_node, ext2_cap) ?
+ MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+}
+
+static struct snd_soc_card *msm_int_populate_sndcard_dailinks(
+ struct device *dev)
+{
+ struct snd_soc_card *card = &msmfalcon_card;
+ struct snd_soc_dai_link *dailink;
+ int len1;
+
+ card->name = dev_name(dev);
+ len1 = ARRAY_SIZE(msm_int_dai);
+ memcpy(msm_int_dai_links, msm_int_dai, sizeof(msm_int_dai));
+ dailink = msm_int_dai_links;
+ if (of_property_read_bool(dev->of_node,
+ "qcom,mi2s-audio-intf")) {
+ memcpy(dailink + len1,
+ msm_mi2s_be_dai_links,
+ sizeof(msm_mi2s_be_dai_links));
+ len1 += ARRAY_SIZE(msm_mi2s_be_dai_links);
+ }
+ if (of_property_read_bool(dev->of_node,
+ "qcom,auxpcm-audio-intf")) {
+ memcpy(dailink + len1,
+ msm_auxpcm_be_dai_links,
+ sizeof(msm_auxpcm_be_dai_links));
+ len1 += ARRAY_SIZE(msm_auxpcm_be_dai_links);
+ }
+ card->dai_link = dailink;
+ card->num_links = len1;
+ return card;
+}
+
+static int msm_internal_init(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata,
+ struct snd_soc_card *card)
+{
+ const char *type = NULL;
+ const char *hs_micbias_type = "qcom,msm-hs-micbias-type";
+ int ret;
+
+ ret = is_ext_spk_gpio_support(pdev, pdata);
+ if (ret < 0)
+ dev_dbg(&pdev->dev,
+ "%s: doesn't support external speaker pa\n",
+ __func__);
+
+ ret = of_property_read_string(pdev->dev.of_node,
+ hs_micbias_type, &type);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: missing %s in dt node\n",
+ __func__, hs_micbias_type);
+ goto err;
+ }
+ if (!strcmp(type, "external")) {
+ dev_dbg(&pdev->dev, "Headset is using external micbias\n");
+ mbhc_cfg_ptr->hs_ext_micbias = true;
+ } else {
+ dev_dbg(&pdev->dev, "Headset is using internal micbias\n");
+ mbhc_cfg_ptr->hs_ext_micbias = false;
+ }
+
+ /* initialize the int_mclk0 */
+ pdata->digital_cdc_core_clk.clk_set_minor_version =
+ AFE_API_VERSION_I2S_CONFIG;
+ pdata->digital_cdc_core_clk.clk_id =
+ Q6AFE_LPASS_CLK_ID_INT_MCLK_0;
+ pdata->digital_cdc_core_clk.clk_freq_in_hz =
+ pdata->mclk_freq;
+ pdata->digital_cdc_core_clk.clk_attri =
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO;
+ pdata->digital_cdc_core_clk.clk_root =
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT;
+ pdata->digital_cdc_core_clk.enable = 1;
+
+ /* Initialize loopback mode to false */
+ pdata->lb_mode = false;
+
+ msm_int_dt_parse_cap_info(pdev, pdata);
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, pdata);
+ ret = snd_soc_of_parse_card_name(card, "qcom,model");
+ if (ret)
+ goto err;
+ /* initialize timer */
+ INIT_DELAYED_WORK(&pdata->disable_int_mclk0_work,
+ msm_disable_int_mclk0);
+ mutex_init(&pdata->cdc_int_mclk0_mutex);
+ atomic_set(&pdata->int_mclk0_rsc_ref, 0);
+ atomic_set(&pdata->int_mclk0_enabled, false);
+
+ dev_info(&pdev->dev, "%s: default codec configured\n", __func__);
+
+ return 0;
+err:
+ return ret;
+}
+
+/**
+ * msm_int_cdc_init - internal codec machine specific init.
+ *
+ * @pdev: platform device handle
+ * @pdata: private data of machine driver
+ * @card: sound card pointer reference
+ * @mbhc_cfg: MBHC config reference
+ *
+ * Returns 0.
+ */
+int msm_int_cdc_init(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata,
+ struct snd_soc_card **card,
+ struct wcd_mbhc_config *mbhc_cfg)
+{
+ mbhc_cfg_ptr = mbhc_cfg;
+
+ *card = msm_int_populate_sndcard_dailinks(&pdev->dev);
+ msm_internal_init(pdev, pdata, *card);
+ return 0;
+}
+EXPORT_SYMBOL(msm_int_cdc_init);
diff --git a/sound/soc/msm/msmfalcon-internal.h b/sound/soc/msm/msmfalcon-internal.h
new file mode 100644
index 000000000000..e5e3e7c66246
--- /dev/null
+++ b/sound/soc/msm/msmfalcon-internal.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2016, 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.
+ */
+
+#ifndef __MSMFALCON_INTERNAL
+#define __MSMFALCON_INTERNAL
+
+#include <sound/soc.h>
+
+#ifdef CONFIG_SND_SOC_INT_CODEC
+int msm_int_cdc_init(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata,
+ struct snd_soc_card **card,
+ struct wcd_mbhc_config *mbhc_cfg);
+#else
+int msm_int_cdc_init(struct platform_device *pdev,
+ struct msm_asoc_mach_data *pdata,
+ struct snd_soc_card **card,
+ struct wcd_mbhc_config *mbhc_cfg)
+{
+ return 0;
+}
+#endif
+#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 770bd12eb501..a2cd6c6f98db 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -2779,10 +2779,10 @@ static int msm_compr_app_type_cfg_put(struct snd_kcontrol *kcontrol,
acdb_dev_id = ucontrol->value.integer.value[1];
if (0 != ucontrol->value.integer.value[2])
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate);
+ pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
+ __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate);
+ acdb_dev_id, sample_rate, SESSION_TYPE_RX);
return 0;
}
@@ -2804,8 +2804,8 @@ static int msm_compr_app_type_cfg_get(struct snd_kcontrol *kcontrol,
goto done;
}
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, &app_type,
- &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
+ &app_type, &acdb_dev_id, &sample_rate);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -2815,8 +2815,9 @@ static int msm_compr_app_type_cfg_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = app_type;
ucontrol->value.integer.value[1] = acdb_dev_id;
ucontrol->value.integer.value[2] = sample_rate;
- pr_debug("%s: fedai_id %llu, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fe_id, app_type, acdb_dev_id, sample_rate);
+ pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, SESSION_TYPE_RX,
+ app_type, acdb_dev_id, sample_rate);
done:
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 7eb4a10b83c7..718f7017342b 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -3481,12 +3481,32 @@ static int msm_mi2s_get_port_id(u32 mi2s_id, int stream, u16 *port_id)
case MSM_QUIN_MI2S:
*port_id = AFE_PORT_ID_QUINARY_MI2S_RX;
break;
- break;
+ case MSM_INT0_MI2S:
+ *port_id = AFE_PORT_ID_INT0_MI2S_RX;
+ break;
+ case MSM_INT1_MI2S:
+ *port_id = AFE_PORT_ID_INT1_MI2S_RX;
+ break;
+ case MSM_INT2_MI2S:
+ *port_id = AFE_PORT_ID_INT2_MI2S_RX;
+ break;
+ case MSM_INT3_MI2S:
+ *port_id = AFE_PORT_ID_INT3_MI2S_RX;
+ break;
+ case MSM_INT4_MI2S:
+ *port_id = AFE_PORT_ID_INT4_MI2S_RX;
+ break;
+ case MSM_INT5_MI2S:
+ *port_id = AFE_PORT_ID_INT5_MI2S_RX;
+ break;
+ case MSM_INT6_MI2S:
+ *port_id = AFE_PORT_ID_INT6_MI2S_RX;
+ break;
default:
pr_err("%s: playback err id 0x%x\n",
__func__, mi2s_id);
ret = -1;
- break;
+ break;
}
break;
case SNDRV_PCM_STREAM_CAPTURE:
@@ -3509,10 +3529,31 @@ static int msm_mi2s_get_port_id(u32 mi2s_id, int stream, u16 *port_id)
case MSM_SENARY_MI2S:
*port_id = AFE_PORT_ID_SENARY_MI2S_TX;
break;
+ case MSM_INT0_MI2S:
+ *port_id = AFE_PORT_ID_INT0_MI2S_TX;
+ break;
+ case MSM_INT1_MI2S:
+ *port_id = AFE_PORT_ID_INT1_MI2S_TX;
+ break;
+ case MSM_INT2_MI2S:
+ *port_id = AFE_PORT_ID_INT2_MI2S_TX;
+ break;
+ case MSM_INT3_MI2S:
+ *port_id = AFE_PORT_ID_INT3_MI2S_TX;
+ break;
+ case MSM_INT4_MI2S:
+ *port_id = AFE_PORT_ID_INT4_MI2S_TX;
+ break;
+ case MSM_INT5_MI2S:
+ *port_id = AFE_PORT_ID_INT5_MI2S_TX;
+ break;
+ case MSM_INT6_MI2S:
+ *port_id = AFE_PORT_ID_INT6_MI2S_TX;
+ break;
default:
pr_err("%s: capture err id 0x%x\n", __func__, mi2s_id);
ret = -1;
- break;
+ break;
}
break;
default:
@@ -3968,6 +4009,188 @@ static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai[] = {
.probe = msm_dai_q6_dai_mi2s_probe,
.remove = msm_dai_q6_dai_mi2s_remove,
},
+ {
+ .playback = {
+ .stream_name = "INT0 MI2S Playback",
+ .aif_name = "INT0_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_44100,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT0 MI2S Capture",
+ .aif_name = "INT0_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT0_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT1 MI2S Playback",
+ .aif_name = "INT1_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT1 MI2S Capture",
+ .aif_name = "INT1_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT1_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT2 MI2S Playback",
+ .aif_name = "INT2_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT2 MI2S Capture",
+ .aif_name = "INT2_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT2_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT3 MI2S Playback",
+ .aif_name = "INT3_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT3 MI2S Capture",
+ .aif_name = "INT3_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT3_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT4 MI2S Playback",
+ .aif_name = "INT4_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT4 MI2S Capture",
+ .aif_name = "INT4_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT4_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT5 MI2S Playback",
+ .aif_name = "INT5_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT5 MI2S Capture",
+ .aif_name = "INT5_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT5_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
+ {
+ .playback = {
+ .stream_name = "INT6 MI2S Playback",
+ .aif_name = "INT6_MI2S_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "INT6 MI2S Capture",
+ .aif_name = "INT6_MI2S_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_mi2s_ops,
+ .id = MSM_INT6_MI2S,
+ .probe = msm_dai_q6_dai_mi2s_probe,
+ .remove = msm_dai_q6_dai_mi2s_remove,
+ },
};
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
index ff7cf5812c0c..82458275b892 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -516,7 +516,7 @@ exit:
return rc;
}
-static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
+static int msm_pcm_add_volume_controls(struct snd_soc_pcm_runtime *rtd)
{
struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
struct snd_pcm_volume *volume_info;
@@ -537,6 +537,192 @@ static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate = 48000;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ return -EINVAL;
+ }
+
+ app_type = ucontrol->value.integer.value[0];
+ acdb_dev_id = ucontrol->value.integer.value[1];
+ if (ucontrol->value.integer.value[2] != 0)
+ sample_rate = ucontrol->value.integer.value[2];
+ pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
+ __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+ msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
+ acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+
+ return 0;
+}
+
+static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
+ &app_type, &acdb_dev_id, &sample_rate);
+ if (ret < 0) {
+ pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ucontrol->value.integer.value[0] = app_type;
+ ucontrol->value.integer.value[1] = acdb_dev_id;
+ ucontrol->value.integer.value[2] = sample_rate;
+ pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, SESSION_TYPE_RX,
+ app_type, acdb_dev_id, sample_rate);
+done:
+ return ret;
+}
+
+static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate = 48000;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ return -EINVAL;
+ }
+
+ app_type = ucontrol->value.integer.value[0];
+ acdb_dev_id = ucontrol->value.integer.value[1];
+ if (ucontrol->value.integer.value[2] != 0)
+ sample_rate = ucontrol->value.integer.value[2];
+ pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
+ __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
+ acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+
+ return 0;
+}
+
+static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
+ &app_type, &acdb_dev_id, &sample_rate);
+ if (ret < 0) {
+ pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ucontrol->value.integer.value[0] = app_type;
+ ucontrol->value.integer.value[1] = acdb_dev_id;
+ ucontrol->value.integer.value[2] = sample_rate;
+ pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, SESSION_TYPE_TX,
+ app_type, acdb_dev_id, sample_rate);
+done:
+ return ret;
+}
+
+static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm_usr *app_type_info;
+ struct snd_kcontrol *kctl;
+ const char *playback_mixer_ctl_name = "Audio Stream";
+ const char *capture_mixer_ctl_name = "Audio Stream Capture";
+ const char *deviceNo = "NN";
+ const char *suffix = "App Type Cfg";
+ int ctl_len, ret = 0;
+
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+ ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+ strlen(deviceNo) + 1 + strlen(suffix) + 1;
+ pr_debug("%s: Playback app type cntrl add\n", __func__);
+ ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1, ctl_len, rtd->dai_link->be_id,
+ &app_type_info);
+ if (ret < 0)
+ return ret;
+ kctl = app_type_info->kctl;
+ snprintf(kctl->id.name, ctl_len, "%s %d %s",
+ playback_mixer_ctl_name, rtd->pcm->device, suffix);
+ kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
+ kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
+ }
+
+ if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+ ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+ strlen(deviceNo) + 1 + strlen(suffix) + 1;
+ pr_debug("%s: Capture app type cntrl add\n", __func__);
+ ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ NULL, 1, ctl_len, rtd->dai_link->be_id,
+ &app_type_info);
+ if (ret < 0)
+ return ret;
+ kctl = app_type_info->kctl;
+ snprintf(kctl->id.name, ctl_len, "%s %d %s",
+ capture_mixer_ctl_name, rtd->pcm->device, suffix);
+ kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
+ kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
+ }
+
+ return 0;
+}
+
+static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+ ret = msm_pcm_add_volume_controls(rtd);
+ if (ret)
+ pr_err("%s: pcm add volume controls failed:%d\n",
+ __func__, ret);
+ ret = msm_pcm_add_app_type_controls(rtd);
+ if (ret)
+ pr_err("%s: pcm add app type controls failed:%d\n",
+ __func__, ret);
+ return ret;
+}
+
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index c5baf0e63732..920e7324f14a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -1178,7 +1178,7 @@ static int msm_pcm_add_chmap_controls(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int msm_pcm_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
@@ -1197,15 +1197,15 @@ static int msm_pcm_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
acdb_dev_id = ucontrol->value.integer.value[1];
if (0 != ucontrol->value.integer.value[2])
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate);
+ pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
+ __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate);
+ acdb_dev_id, sample_rate, SESSION_TYPE_RX);
return 0;
}
-static int msm_pcm_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
@@ -1222,8 +1222,8 @@ static int msm_pcm_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
goto done;
}
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, &app_type,
- &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
+ &app_type, &acdb_dev_id, &sample_rate);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -1233,8 +1233,71 @@ static int msm_pcm_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = app_type;
ucontrol->value.integer.value[1] = acdb_dev_id;
ucontrol->value.integer.value[2] = sample_rate;
- pr_debug("%s: fedai_id %llu, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fe_id, app_type, acdb_dev_id, sample_rate);
+ pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, SESSION_TYPE_RX,
+ app_type, acdb_dev_id, sample_rate);
+done:
+ return ret;
+}
+
+static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate = 48000;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ return -EINVAL;
+ }
+
+ app_type = ucontrol->value.integer.value[0];
+ acdb_dev_id = ucontrol->value.integer.value[1];
+ if (ucontrol->value.integer.value[2] != 0)
+ sample_rate = ucontrol->value.integer.value[2];
+ pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
+ __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
+ acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+
+ return 0;
+}
+
+static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
+ &app_type, &acdb_dev_id, &sample_rate);
+ if (ret < 0) {
+ pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ucontrol->value.integer.value[0] = app_type;
+ ucontrol->value.integer.value[1] = acdb_dev_id;
+ ucontrol->value.integer.value[2] = sample_rate;
+ pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, SESSION_TYPE_TX,
+ app_type, acdb_dev_id, sample_rate);
done:
return ret;
}
@@ -1244,27 +1307,49 @@ static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
struct snd_pcm *pcm = rtd->pcm;
struct snd_pcm_usr *app_type_info;
struct snd_kcontrol *kctl;
- const char *mixer_ctl_name = "Audio Stream";
+ const char *playback_mixer_ctl_name = "Audio Stream";
+ const char *capture_mixer_ctl_name = "Audio Stream Capture";
const char *deviceNo = "NN";
const char *suffix = "App Type Cfg";
int ctl_len, ret = 0;
- ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 +
- strlen(suffix) + 1;
- pr_debug("%s, App type cntrl add\n", __func__);
- ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- NULL, 1, ctl_len, rtd->dai_link->be_id,
- &app_type_info);
- if (ret < 0) {
- pr_err("%s, app type cntrl add failed:%d\n", __func__, ret);
- return ret;
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+ ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+ strlen(deviceNo) + 1 + strlen(suffix) + 1;
+ pr_debug("%s: Playback app type cntrl add\n", __func__);
+ ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1, ctl_len, rtd->dai_link->be_id,
+ &app_type_info);
+ if (ret < 0) {
+ pr_err("%s: playback app type cntrl add failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ kctl = app_type_info->kctl;
+ snprintf(kctl->id.name, ctl_len, "%s %d %s",
+ playback_mixer_ctl_name, rtd->pcm->device, suffix);
+ kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
+ kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
+ }
+
+ if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+ ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+ strlen(deviceNo) + 1 + strlen(suffix) + 1;
+ pr_debug("%s: Capture app type cntrl add\n", __func__);
+ ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ NULL, 1, ctl_len, rtd->dai_link->be_id,
+ &app_type_info);
+ if (ret < 0) {
+ pr_err("%s: capture app type cntrl add failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ kctl = app_type_info->kctl;
+ snprintf(kctl->id.name, ctl_len, "%s %d %s",
+ capture_mixer_ctl_name, rtd->pcm->device, suffix);
+ kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
+ kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
}
- kctl = app_type_info->kctl;
- snprintf(kctl->id.name, ctl_len, "%s %d %s", mixer_ctl_name,
- rtd->pcm->device, suffix);
- kctl = app_type_info->kctl;
- kctl->put = msm_pcm_app_type_cfg_ctl_put;
- kctl->get = msm_pcm_app_type_cfg_ctl_get;
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 13d4ba27d990..9681330be33b 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -466,6 +466,34 @@ struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
LPASS_BE_QUAT_AUXPCM_RX},
{ AFE_PORT_ID_QUATERNARY_PCM_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
LPASS_BE_QUAT_AUXPCM_TX},
+ { AFE_PORT_ID_INT0_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT0_MI2S_RX},
+ { AFE_PORT_ID_INT0_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT0_MI2S_TX},
+ { AFE_PORT_ID_INT1_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT1_MI2S_RX},
+ { AFE_PORT_ID_INT1_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT1_MI2S_TX},
+ { AFE_PORT_ID_INT2_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT2_MI2S_RX},
+ { AFE_PORT_ID_INT2_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT2_MI2S_TX},
+ { AFE_PORT_ID_INT3_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT3_MI2S_RX},
+ { AFE_PORT_ID_INT3_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT3_MI2S_TX},
+ { AFE_PORT_ID_INT4_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT4_MI2S_RX},
+ { AFE_PORT_ID_INT4_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT4_MI2S_TX},
+ { AFE_PORT_ID_INT5_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT5_MI2S_RX},
+ { AFE_PORT_ID_INT5_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT5_MI2S_TX},
+ { AFE_PORT_ID_INT6_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT6_MI2S_RX},
+ { AFE_PORT_ID_INT6_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0,
+ LPASS_BE_INT6_MI2S_TX},
};
/* Track ASM playback & capture sessions of DAI */
@@ -525,7 +553,7 @@ static unsigned long session_copp_map[MSM_FRONTEND_DAI_MM_SIZE][2]
[MSM_BACKEND_DAI_MAX];
static struct msm_pcm_routing_app_type_data app_type_cfg[MAX_APP_TYPES];
static struct msm_pcm_stream_app_type_cfg
- fe_dai_app_type_cfg[MSM_FRONTEND_DAI_MM_SIZE];
+ fe_dai_app_type_cfg[MSM_FRONTEND_DAI_MM_SIZE][2];
/* The caller of this should aqcuire routing lock */
void msm_pcm_routing_get_bedai_info(int be_idx,
@@ -569,34 +597,43 @@ static int msm_pcm_routing_get_app_type_idx(int app_type)
}
void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type,
- int acdb_dev_id, int sample_rate)
+ int acdb_dev_id, int sample_rate, int session_type)
{
- pr_debug("%s: fedai_id %d, app_type %d, sample_rate %d\n",
- __func__, fedai_id, app_type, sample_rate);
+ pr_debug("%s: fedai_id %d, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fedai_id, session_type, app_type,
+ acdb_dev_id, sample_rate);
if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
pr_err("%s: Invalid machine driver ID %d\n",
__func__, fedai_id);
return;
}
- fe_dai_app_type_cfg[fedai_id].app_type = app_type;
- fe_dai_app_type_cfg[fedai_id].acdb_dev_id = acdb_dev_id;
- fe_dai_app_type_cfg[fedai_id].sample_rate = sample_rate;
+ if (session_type != SESSION_TYPE_RX &&
+ session_type != SESSION_TYPE_TX) {
+ pr_err("%s: Invalid session type %d\n",
+ __func__, session_type);
+ return;
+ }
+ fe_dai_app_type_cfg[fedai_id][session_type].app_type = app_type;
+ fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id = acdb_dev_id;
+ fe_dai_app_type_cfg[fedai_id][session_type].sample_rate = sample_rate;
}
/**
* msm_pcm_routing_get_stream_app_type_cfg
*
- * Receives fedai_id and populates app_type, acdb_dev_id, &
+ * Receives fedai_id, session_type and populates app_type, acdb_dev_id, &
* sample rate. Returns 0 on success. On failure returns
* -EINVAL and does not alter passed values.
*
* fedai_id - Passed value, front end ID for which app type config is wanted
+ * session_type - Passed value, session type for which app type config
+ * is wanted
* app_type - Returned value, app type used by app type config
* acdb_dev_id - Returned value, ACDB device ID used by app type config
* sample_rate - Returned value, sample rate used by app type config
*/
-int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int *app_type,
- int *acdb_dev_id, int *sample_rate)
+int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
+ int *app_type, int *acdb_dev_id, int *sample_rate)
{
int ret = 0;
@@ -617,13 +654,20 @@ int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int *app_type,
__func__, fedai_id);
ret = -EINVAL;
goto done;
+ } else if (session_type != SESSION_TYPE_RX &&
+ session_type != SESSION_TYPE_TX) {
+ pr_err("%s: Invalid session type %d\n",
+ __func__, session_type);
+ ret = -EINVAL;
+ goto done;
}
- *app_type = fe_dai_app_type_cfg[fedai_id].app_type;
- *acdb_dev_id = fe_dai_app_type_cfg[fedai_id].acdb_dev_id;
- *sample_rate = fe_dai_app_type_cfg[fedai_id].sample_rate;
+ *app_type = fe_dai_app_type_cfg[fedai_id][session_type].app_type;
+ *acdb_dev_id = fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
+ *sample_rate = fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
- pr_debug("%s: fedai_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fedai_id, *app_type, *acdb_dev_id, *sample_rate);
+ pr_debug("%s: fedai_id %d, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fedai_id, session_type,
+ *app_type, *acdb_dev_id, *sample_rate);
done:
return ret;
}
@@ -680,7 +724,8 @@ static struct cal_block_data *msm_routing_find_topology(int path,
return msm_routing_find_topology_by_path(path);
}
-static int msm_routing_get_adm_topology(int path, int fedai_id)
+static int msm_routing_get_adm_topology(int path, int fedai_id,
+ int session_type)
{
int topology = NULL_COPP_TOPOLOGY;
struct cal_block_data *cal_block = NULL;
@@ -693,11 +738,10 @@ static int msm_routing_get_adm_topology(int path, int fedai_id)
mutex_lock(&cal_data->lock);
- if (path == RX_DEVICE) {
- app_type = fe_dai_app_type_cfg[fedai_id].app_type;
- acdb_dev_id = fe_dai_app_type_cfg[fedai_id].acdb_dev_id;
- sample_rate = fe_dai_app_type_cfg[fedai_id].sample_rate;
- }
+ app_type = fe_dai_app_type_cfg[fedai_id][session_type].app_type;
+ acdb_dev_id = fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
+ sample_rate = fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
+
cal_block = msm_routing_find_topology(path, app_type,
acdb_dev_id, sample_rate);
if (cal_block == NULL)
@@ -753,9 +797,12 @@ static void msm_pcm_routing_build_matrix(int fedai_id, int sess_type,
if (num_copps) {
payload.num_copps = num_copps;
payload.session_id = fe_dai_map[fedai_id][sess_type].strm_id;
- payload.app_type = fe_dai_app_type_cfg[fedai_id].app_type;
- payload.acdb_dev_id = fe_dai_app_type_cfg[fedai_id].acdb_dev_id;
- payload.sample_rate = fe_dai_app_type_cfg[fedai_id].sample_rate;
+ payload.app_type =
+ fe_dai_app_type_cfg[fedai_id][sess_type].app_type;
+ payload.acdb_dev_id =
+ fe_dai_app_type_cfg[fedai_id][sess_type].acdb_dev_id;
+ payload.sample_rate =
+ fe_dai_app_type_cfg[fedai_id][sess_type].sample_rate;
adm_matrix_map(path_type, payload, perf_mode);
msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
}
@@ -863,22 +910,23 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
bit_width = msm_routing_get_bit_width(
msm_bedais[i].format);
- app_type = (stream_type == SNDRV_PCM_STREAM_PLAYBACK) ?
- fe_dai_app_type_cfg[fe_id].app_type : 0;
+ app_type =
+ fe_dai_app_type_cfg[fe_id][session_type].app_type;
if (app_type) {
app_type_idx =
msm_pcm_routing_get_app_type_idx(
app_type);
sample_rate =
- fe_dai_app_type_cfg[fe_id].sample_rate;
+ fe_dai_app_type_cfg[fe_id][session_type].sample_rate;
bit_width =
app_type_cfg[app_type_idx].bit_width;
} else {
sample_rate = msm_bedais[i].sample_rate;
}
- acdb_dev_id = fe_dai_app_type_cfg[fe_id].acdb_dev_id;
+ acdb_dev_id =
+ fe_dai_app_type_cfg[fe_id][session_type].acdb_dev_id;
topology = msm_routing_get_adm_topology(path_type,
- fe_id);
+ fe_id, session_type);
if (compr_passthr_mode == COMPRESSED_PASSTHROUGH_DSD)
topology = COMPRESS_PASSTHROUGH_NONE_TOPOLOGY;
pr_err("%s: Before adm open topology %d\n", __func__,
@@ -928,8 +976,10 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
if (num_copps) {
payload.num_copps = num_copps;
payload.session_id = fe_dai_map[fe_id][session_type].strm_id;
- payload.app_type = fe_dai_app_type_cfg[fe_id].app_type;
- payload.acdb_dev_id = fe_dai_app_type_cfg[fe_id].acdb_dev_id;
+ payload.app_type =
+ fe_dai_app_type_cfg[fe_id][session_type].app_type;
+ payload.acdb_dev_id =
+ fe_dai_app_type_cfg[fe_id][session_type].acdb_dev_id;
adm_matrix_map(path_type, payload, perf_mode);
msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
}
@@ -1026,21 +1076,23 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
bits_per_sample = msm_routing_get_bit_width(
msm_bedais[i].format);
- app_type = (stream_type == SNDRV_PCM_STREAM_PLAYBACK) ?
- fe_dai_app_type_cfg[fedai_id].app_type : 0;
+ app_type =
+ fe_dai_app_type_cfg[fedai_id][session_type].app_type;
if (app_type) {
app_type_idx =
msm_pcm_routing_get_app_type_idx(app_type);
sample_rate =
- fe_dai_app_type_cfg[fedai_id].sample_rate;
+ fe_dai_app_type_cfg[fedai_id][session_type].
+ sample_rate;
bits_per_sample =
app_type_cfg[app_type_idx].bit_width;
} else
sample_rate = msm_bedais[i].sample_rate;
- acdb_dev_id = fe_dai_app_type_cfg[fedai_id].acdb_dev_id;
+ acdb_dev_id =
+ fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
topology = msm_routing_get_adm_topology(path_type,
- fedai_id);
+ fedai_id, session_type);
copp_idx = adm_open(msm_bedais[i].port_id, path_type,
sample_rate, channels, topology,
perf_mode, bits_per_sample,
@@ -1085,9 +1137,12 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
if (num_copps) {
payload.num_copps = num_copps;
payload.session_id = fe_dai_map[fedai_id][session_type].strm_id;
- payload.app_type = fe_dai_app_type_cfg[fedai_id].app_type;
- payload.acdb_dev_id = fe_dai_app_type_cfg[fedai_id].acdb_dev_id;
- payload.sample_rate = fe_dai_app_type_cfg[fedai_id].sample_rate;
+ payload.app_type =
+ fe_dai_app_type_cfg[fedai_id][session_type].app_type;
+ payload.acdb_dev_id =
+ fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
+ payload.sample_rate =
+ fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
adm_matrix_map(path_type, payload, perf_mode);
msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
}
@@ -1255,20 +1310,23 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
bits_per_sample = msm_routing_get_bit_width(
msm_bedais[reg].format);
- app_type = (session_type == SESSION_TYPE_RX) ?
- fe_dai_app_type_cfg[val].app_type : 0;
+ app_type =
+ fe_dai_app_type_cfg[val][session_type].app_type;
if (app_type) {
app_type_idx =
msm_pcm_routing_get_app_type_idx(app_type);
sample_rate =
- fe_dai_app_type_cfg[val].sample_rate;
+ fe_dai_app_type_cfg[val][session_type].
+ sample_rate;
bits_per_sample =
app_type_cfg[app_type_idx].bit_width;
} else
sample_rate = msm_bedais[reg].sample_rate;
- topology = msm_routing_get_adm_topology(path_type, val);
- acdb_dev_id = fe_dai_app_type_cfg[val].acdb_dev_id;
+ topology = msm_routing_get_adm_topology(path_type, val,
+ session_type);
+ acdb_dev_id =
+ fe_dai_app_type_cfg[val][session_type].acdb_dev_id;
copp_idx = adm_open(msm_bedais[reg].port_id, path_type,
sample_rate, channels, topology,
fdai->perf_mode, bits_per_sample,
@@ -2919,6 +2977,108 @@ static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new int0_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new int4_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -4358,6 +4518,12 @@ static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -4451,6 +4617,12 @@ static const struct snd_kcontrol_new mmul2_mixer_controls[] = {
SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -4526,6 +4698,12 @@ static const struct snd_kcontrol_new mmul3_mixer_controls[] = {
SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -4604,6 +4782,12 @@ static const struct snd_kcontrol_new mmul4_mixer_controls[] = {
SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -4646,6 +4830,12 @@ static const struct snd_kcontrol_new mmul5_mixer_controls[] = {
SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -4703,6 +4893,12 @@ static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -4760,6 +4956,12 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = {
SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -5113,6 +5315,42 @@ static const struct snd_kcontrol_new pri_mi2s_rx_voice_mixer_controls[] = {
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new int0_mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new int4_mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
static const struct snd_kcontrol_new tert_mi2s_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -5777,6 +6015,9 @@ static const struct snd_kcontrol_new tx_voicemmode1_mixer_controls[] = {
SOC_SINGLE_EXT("TERT_MI2S_TX_MMode1",
MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE1,
1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX_MMode1",
+ MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE1,
+ 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("SLIM_7_TX_MMode1",
MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1,
0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
@@ -5822,6 +6063,9 @@ static const struct snd_kcontrol_new tx_voicemmode2_mixer_controls[] = {
SOC_SINGLE_EXT("TERT_MI2S_TX_MMode2",
MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE2,
1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX_MMode2",
+ MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE2,
+ 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("SLIM_7_TX_MMode2",
MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1,
0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
@@ -5867,6 +6111,9 @@ static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
SOC_SINGLE_EXT("TERT_MI2S_TX_Voip", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX_Voip", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("SLIM_7_TX_Voip", MSM_BACKEND_DAI_SLIMBUS_7_TX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -5900,6 +6147,9 @@ static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
@@ -6056,6 +6306,9 @@ static const struct snd_kcontrol_new tx_qchat_mixer_controls[] = {
SOC_SINGLE_EXT("TERT_MI2S_TX_QCHAT", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX_QCHAT", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
SOC_SINGLE_EXT("SLIM_7_TX_QCHAT", MSM_BACKEND_DAI_SLIMBUS_7_TX,
MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -7877,6 +8130,12 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INT0_MI2S_DL_HL",
+ "INT0 MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INT4_MI2S_DL_HL",
+ "INT4 MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("PRI_MI2S_DL_HL",
"Primary MI2S_RX Hostless Playback",
0, 0, 0, 0),
@@ -8150,6 +8409,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("PRI_MI2S_RX", "Primary MI2S Playback",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INT0_MI2S_RX", "INT0 MI2S Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INT4_MI2S_RX", "INT4 MI2S Playback",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("QUIN_MI2S_RX", "Quinary MI2S Playback",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("PRI_I2S_TX", "Primary I2S Capture", 0, 0, 0, 0),
@@ -8160,6 +8423,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("TERT_MI2S_TX", "Tertiary MI2S Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INT2_MI2S_TX", "INT2 MI2S Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INT3_MI2S_TX", "INT3 MI2S Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SEC_MI2S_TX", "Secondary MI2S Capture",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
@@ -8444,6 +8711,12 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_MIXER("PRI_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
primary_mi2s_rx_mixer_controls,
ARRAY_SIZE(primary_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INT0_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ int0_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(int0_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INT4_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ int4_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(int4_mi2s_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("QUIN_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
quinary_mi2s_rx_mixer_controls,
ARRAY_SIZE(quinary_mi2s_rx_mixer_controls)),
@@ -8581,6 +8854,14 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_NOPM, 0, 0,
pri_mi2s_rx_voice_mixer_controls,
ARRAY_SIZE(pri_mi2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INT0_MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ int0_mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(int0_mi2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("INT4_MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ int4_mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(int4_mi2s_rx_voice_mixer_controls)),
SND_SOC_DAPM_MIXER("TERT_MI2S_RX_Voice Mixer",
SND_SOC_NOPM, 0, 0,
tert_mi2s_rx_voice_mixer_controls,
@@ -9082,6 +9363,42 @@ static const struct snd_soc_dapm_route intercon[] = {
{"PRI_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Audio Mixer"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"INT0_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"INT0_MI2S_RX", NULL, "INT0_MI2S_RX Audio Mixer"},
+
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"INT4_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"INT4_MI2S_RX", NULL, "INT4_MI2S_RX Audio Mixer"},
+
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUIN_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"QUIN_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"QUIN_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"QUIN_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -9363,6 +9680,10 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia2 Mixer", "QUIN_MI2S_TX", "QUIN_MI2S_TX"},
{"MultiMedia1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"MultiMedia2 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"MultiMedia1 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia2 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia1 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"MultiMedia2 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia3 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
@@ -9384,6 +9705,12 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia6 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"MultiMedia3 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"MultiMedia5 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"MultiMedia6 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia3 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia5 Mixer", "INT2_MI2S_TX", "INT2_MI2S_TX"},
+ {"MultiMedia6 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"MultiMedia3 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"MultiMedia5 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia6 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia6 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia6 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
@@ -9821,6 +10148,20 @@ static const struct snd_soc_dapm_route intercon[] = {
{"PRI_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_Voice Mixer"},
+ {"INT0_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"INT0_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"INT0_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"INT0_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"INT0_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"INT0_MI2S_RX", NULL, "INT0_MI2S_RX_Voice Mixer"},
+
+ {"INT4_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"INT4_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
+ {"INT4_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"INT4_MI2S_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"INT4_MI2S_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_Voice Mixer"},
+
{"TERT_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"TERT_MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"TERT_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
@@ -9992,6 +10333,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"VoiceMMode1_Tx Mixer", "PRI_MI2S_TX_MMode1", "PRI_MI2S_TX"},
{"VoiceMMode1_Tx Mixer", "MI2S_TX_MMode1", "MI2S_TX"},
{"VoiceMMode1_Tx Mixer", "TERT_MI2S_TX_MMode1", "TERT_MI2S_TX"},
+ {"VoiceMMode1_Tx Mixer", "INT3_MI2S_TX_MMode1", "INT3_MI2S_TX"},
{"VoiceMMode1_Tx Mixer", "SLIM_0_TX_MMode1", "SLIMBUS_0_TX"},
{"VoiceMMode1_Tx Mixer", "SLIM_7_TX_MMode1", "SLIMBUS_7_TX"},
{"VoiceMMode1_Tx Mixer", "SLIM_8_TX_MMode1", "SLIMBUS_8_TX"},
@@ -10008,6 +10350,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"VoiceMMode2_Tx Mixer", "PRI_MI2S_TX_MMode2", "PRI_MI2S_TX"},
{"VoiceMMode2_Tx Mixer", "MI2S_TX_MMode2", "MI2S_TX"},
{"VoiceMMode2_Tx Mixer", "TERT_MI2S_TX_MMode2", "TERT_MI2S_TX"},
+ {"VoiceMMode2_Tx Mixer", "INT3_MI2S_TX_MMode2", "INT3_MI2S_TX"},
{"VoiceMMode2_Tx Mixer", "SLIM_0_TX_MMode2", "SLIMBUS_0_TX"},
{"VoiceMMode2_Tx Mixer", "SLIM_7_TX_MMode2", "SLIMBUS_7_TX"},
{"VoiceMMode2_Tx Mixer", "SLIM_8_TX_MMode2", "SLIMBUS_8_TX"},
@@ -10023,6 +10366,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
{"Voip_Tx Mixer", "MI2S_TX_Voip", "MI2S_TX"},
{"Voip_Tx Mixer", "TERT_MI2S_TX_Voip", "TERT_MI2S_TX"},
+ {"Voip_Tx Mixer", "INT3_MI2S_TX_Voip", "INT3_MI2S_TX"},
{"Voip_Tx Mixer", "SLIM_0_TX_Voip", "SLIMBUS_0_TX"},
{"Voip_Tx Mixer", "SLIM_7_TX_Voip", "SLIMBUS_7_TX"},
{"Voip_Tx Mixer", "SLIM_8_TX_Voip", "SLIMBUS_8_TX"},
@@ -10132,6 +10476,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QCHAT_Tx Mixer", "MI2S_TX_QCHAT", "MI2S_TX"},
{"QCHAT_Tx Mixer", "PRI_MI2S_TX_QCHAT", "PRI_MI2S_TX"},
{"QCHAT_Tx Mixer", "TERT_MI2S_TX_QCHAT", "TERT_MI2S_TX"},
+ {"QCHAT_Tx Mixer", "INT3_MI2S_TX_QCHAT", "INT3_MI2S_TX"},
{"QCHAT_Tx Mixer", "USB_AUDIO_TX_QCHAT", "USB_AUDIO_TX"},
{"QCHAT_UL", NULL, "QCHAT_Tx Mixer"},
@@ -10149,6 +10494,10 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MI2S_UL_HL", NULL, "MI2S_TX"},
{"PCM_RX_DL_HL", "Switch", "SLIM0_DL_HL"},
{"PCM_RX", NULL, "PCM_RX_DL_HL"},
+ {"INT0_MI2S_RX_DL_HL", "Switch", "INT0_MI2S_DL_HL"},
+ {"INT0_MI2S_RX", NULL, "INT0_MI2S_RX_DL_HL"},
+ {"INT4_MI2S_RX_DL_HL", "Switch", "INT4_MI2S_DL_HL"},
+ {"INT4_MI2S_RX", NULL, "INT4_MI2S_RX_DL_HL"},
{"PRI_MI2S_RX_DL_HL", "Switch", "PRI_MI2S_DL_HL"},
{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_DL_HL"},
{"SEC_MI2S_RX_DL_HL", "Switch", "SEC_MI2S_DL_HL"},
@@ -10384,6 +10733,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Voice Stub Tx Mixer", "MI2S_TX", "MI2S_TX"},
{"Voice Stub Tx Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"Voice Stub Tx Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"Voice Stub Tx Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"Voice Stub Tx Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
{"Voice Stub Tx Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"Voice Stub Tx Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
@@ -10561,6 +10911,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"BE_OUT", NULL, "SEC_MI2S_RX"},
{"BE_OUT", NULL, "SEC_MI2S_RX_SD1"},
{"BE_OUT", NULL, "PRI_MI2S_RX"},
+ {"BE_OUT", NULL, "INT0_MI2S_RX"},
+ {"BE_OUT", NULL, "INT4_MI2S_RX"},
{"BE_OUT", NULL, "INT_BT_SCO_RX"},
{"BE_OUT", NULL, "INT_BT_A2DP_RX"},
{"BE_OUT", NULL, "INT_FM_RX"},
@@ -10593,6 +10945,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUIN_MI2S_TX", NULL, "BE_IN"},
{"PRI_MI2S_TX", NULL, "BE_IN"},
{"TERT_MI2S_TX", NULL, "BE_IN"},
+ {"INT2_MI2S_TX", NULL, "BE_IN"},
+ {"INT3_MI2S_TX", NULL, "BE_IN"},
{"SEC_MI2S_TX", NULL, "BE_IN"},
{"SENARY_MI2S_TX", NULL, "BE_IN" },
{"SLIMBUS_0_TX", NULL, "BE_IN" },
@@ -10726,7 +11080,6 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
int i, path_type, session_type, topology;
struct msm_pcm_routing_bdai_data *bedai;
u32 channels, sample_rate;
- bool playback, capture;
uint16_t bits_per_sample = 16, voc_path_type;
struct msm_pcm_routing_fdai_data *fdai;
u32 session_id;
@@ -10762,8 +11115,6 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
* is started.
*/
bedai->active = 1;
- playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- capture = substream->stream == SNDRV_PCM_STREAM_CAPTURE;
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
fdai = &fe_dai_map[i][session_type];
@@ -10785,13 +11136,14 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
bits_per_sample = msm_routing_get_bit_width(
bedai->format);
- app_type = playback ?
- fe_dai_app_type_cfg[i].app_type : 0;
+ app_type =
+ fe_dai_app_type_cfg[i][session_type].app_type;
if (app_type) {
app_type_idx =
msm_pcm_routing_get_app_type_idx(app_type);
sample_rate =
- fe_dai_app_type_cfg[i].sample_rate;
+ fe_dai_app_type_cfg[i][session_type].
+ sample_rate;
bits_per_sample =
app_type_cfg[app_type_idx].bit_width;
} else
@@ -10804,8 +11156,10 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
channels = bedai->channel;
else
channels = bedai->adm_override_ch;
- acdb_dev_id = fe_dai_app_type_cfg[i].acdb_dev_id;
- topology = msm_routing_get_adm_topology(path_type, i);
+ acdb_dev_id =
+ fe_dai_app_type_cfg[i][session_type].acdb_dev_id;
+ topology = msm_routing_get_adm_topology(path_type, i,
+ session_type);
copp_idx = adm_open(bedai->port_id, path_type,
sample_rate, channels, topology,
fdai->perf_mode, bits_per_sample,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 8e3086849d92..8a62e900ff28 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -143,6 +143,21 @@
#define LPASS_BE_USB_AUDIO_RX "USB_AUDIO_RX"
#define LPASS_BE_USB_AUDIO_TX "USB_AUDIO_TX"
+
+#define LPASS_BE_INT0_MI2S_RX "INT0_MI2S_RX"
+#define LPASS_BE_INT0_MI2S_TX "INT0_MI2S_TX"
+#define LPASS_BE_INT1_MI2S_RX "INT1_MI2S_RX"
+#define LPASS_BE_INT1_MI2S_TX "INT1_MI2S_TX"
+#define LPASS_BE_INT2_MI2S_RX "INT2_MI2S_RX"
+#define LPASS_BE_INT2_MI2S_TX "INT2_MI2S_TX"
+#define LPASS_BE_INT3_MI2S_RX "INT3_MI2S_RX"
+#define LPASS_BE_INT3_MI2S_TX "INT3_MI2S_TX"
+#define LPASS_BE_INT4_MI2S_RX "INT4_MI2S_RX"
+#define LPASS_BE_INT4_MI2S_TX "INT4_MI2S_TX"
+#define LPASS_BE_INT5_MI2S_RX "INT5_MI2S_RX"
+#define LPASS_BE_INT5_MI2S_TX "INT5_MI2S_TX"
+#define LPASS_BE_INT6_MI2S_RX "INT6_MI2S_RX"
+#define LPASS_BE_INT6_MI2S_TX "INT6_MI2S_TX"
/* For multimedia front-ends, asm session is allocated dynamically.
* Hence, asm session/multimedia front-end mapping has to be maintained.
* Due to this reason, additional multimedia front-end must be placed before
@@ -321,6 +336,20 @@ enum {
MSM_BACKEND_DAI_TERT_AUXPCM_TX,
MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ MSM_BACKEND_DAI_INT0_MI2S_RX,
+ MSM_BACKEND_DAI_INT0_MI2S_TX,
+ MSM_BACKEND_DAI_INT1_MI2S_RX,
+ MSM_BACKEND_DAI_INT1_MI2S_TX,
+ MSM_BACKEND_DAI_INT2_MI2S_RX,
+ MSM_BACKEND_DAI_INT2_MI2S_TX,
+ MSM_BACKEND_DAI_INT3_MI2S_RX,
+ MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_BACKEND_DAI_INT4_MI2S_RX,
+ MSM_BACKEND_DAI_INT4_MI2S_TX,
+ MSM_BACKEND_DAI_INT5_MI2S_RX,
+ MSM_BACKEND_DAI_INT5_MI2S_TX,
+ MSM_BACKEND_DAI_INT6_MI2S_RX,
+ MSM_BACKEND_DAI_INT6_MI2S_TX,
MSM_BACKEND_DAI_MAX,
};
@@ -432,7 +461,7 @@ void msm_pcm_routing_acquire_lock(void);
void msm_pcm_routing_release_lock(void);
void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type,
- int acdb_dev_id, int sample_rate);
-int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int *app_type,
- int *acdb_dev_id, int *sample_rate);
+ int acdb_dev_id, int sample_rate, int session_type);
+int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
+ int *app_type, int *acdb_dev_id, int *sample_rate);
#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 78546fef7b3b..c75f7214db1a 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -483,6 +483,13 @@ int afe_get_port_type(u16 port_id)
case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
case AFE_PORT_ID_USB_RX:
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ case AFE_PORT_ID_INT1_MI2S_RX:
+ case AFE_PORT_ID_INT2_MI2S_RX:
+ case AFE_PORT_ID_INT3_MI2S_RX:
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ case AFE_PORT_ID_INT5_MI2S_RX:
+ case AFE_PORT_ID_INT6_MI2S_RX:
ret = MSM_AFE_PORT_TYPE_RX;
break;
@@ -547,6 +554,13 @@ int afe_get_port_type(u16 port_id)
case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
case AFE_PORT_ID_USB_TX:
+ case AFE_PORT_ID_INT0_MI2S_TX:
+ case AFE_PORT_ID_INT1_MI2S_TX:
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ case AFE_PORT_ID_INT4_MI2S_TX:
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ case AFE_PORT_ID_INT6_MI2S_TX:
ret = MSM_AFE_PORT_TYPE_TX;
break;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 2874a334dfdd..22e14f431bb3 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -3015,7 +3015,8 @@ int q6asm_set_shared_circ_buff(struct audio_client *ac,
int dir)
{
struct audio_buffer *buf_circ;
- int bytes_to_alloc, rc, len;
+ int bytes_to_alloc, rc;
+ size_t len;
buf_circ = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL);
@@ -3034,7 +3035,7 @@ int q6asm_set_shared_circ_buff(struct audio_client *ac,
rc = msm_audio_ion_alloc("audio_client", &buf_circ->client,
&buf_circ->handle, bytes_to_alloc,
(ion_phys_addr_t *)&buf_circ->phys,
- (size_t *)&len, &buf_circ->data);
+ &len, &buf_circ->data);
if (rc) {
pr_err("%s: Audio ION alloc is failed, rc = %d\n", __func__,
@@ -3076,7 +3077,8 @@ int q6asm_set_shared_pos_buff(struct audio_client *ac,
int dir)
{
struct audio_buffer *buf_pos = &ac->shared_pos_buf;
- int len, rc;
+ int rc;
+ size_t len;
int bytes_to_alloc = sizeof(struct asm_shared_position_buffer);
mutex_lock(&ac->cmd_lock);
@@ -3085,7 +3087,7 @@ int q6asm_set_shared_pos_buff(struct audio_client *ac,
rc = msm_audio_ion_alloc("audio_client", &buf_pos->client,
&buf_pos->handle, bytes_to_alloc,
- (ion_phys_addr_t *)&buf_pos->phys, (size_t *)&len,
+ (ion_phys_addr_t *)&buf_pos->phys, &len,
&buf_pos->data);
if (rc) {
@@ -5848,7 +5850,7 @@ static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
struct asm_buffer_node *buffer_node = NULL;
int rc = 0;
int i = 0;
- int cmd_size = 0;
+ uint32_t cmd_size = 0;
uint32_t bufcnt_t;
uint32_t bufsz_t;
@@ -5870,10 +5872,25 @@ static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
bufsz_t = PAGE_ALIGN(bufsz_t);
}
+ if (bufcnt_t > (UINT_MAX
+ - sizeof(struct avs_cmd_shared_mem_map_regions))
+ / sizeof(struct avs_shared_map_region_payload)) {
+ pr_err("%s: Unsigned Integer Overflow. bufcnt_t = %u\n",
+ __func__, bufcnt_t);
+ return -EINVAL;
+ }
+
cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions)
+ (sizeof(struct avs_shared_map_region_payload)
* bufcnt_t);
+
+ if (bufcnt > (UINT_MAX / sizeof(struct asm_buffer_node))) {
+ pr_err("%s: Unsigned Integer Overflow. bufcnt = %u\n",
+ __func__, bufcnt);
+ return -EINVAL;
+ }
+
buffer_node = kzalloc(sizeof(struct asm_buffer_node) * bufcnt,
GFP_KERNEL);
if (!buffer_node) {
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 99f5f0e1a5a5..84e1178dc354 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -233,6 +233,34 @@ int q6audio_get_port_index(u16 port_id)
return IDX_AFE_PORT_ID_USB_RX;
case AFE_PORT_ID_USB_TX:
return IDX_AFE_PORT_ID_USB_TX;
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT0_MI2S_RX;
+ case AFE_PORT_ID_INT0_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT0_MI2S_TX;
+ case AFE_PORT_ID_INT1_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT1_MI2S_RX;
+ case AFE_PORT_ID_INT1_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT1_MI2S_TX;
+ case AFE_PORT_ID_INT2_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT2_MI2S_RX;
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT2_MI2S_TX;
+ case AFE_PORT_ID_INT3_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT3_MI2S_RX;
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT3_MI2S_TX;
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT4_MI2S_RX;
+ case AFE_PORT_ID_INT4_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT4_MI2S_TX;
+ case AFE_PORT_ID_INT5_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT5_MI2S_RX;
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT5_MI2S_TX;
+ case AFE_PORT_ID_INT6_MI2S_RX:
+ return IDX_AFE_PORT_ID_INT6_MI2S_RX;
+ case AFE_PORT_ID_INT6_MI2S_TX:
+ return IDX_AFE_PORT_ID_INT6_MI2S_TX;
default: return -EINVAL;
}
}
@@ -452,6 +480,34 @@ int q6audio_get_port_id(u16 port_id)
return AFE_PORT_ID_USB_RX;
case AFE_PORT_ID_USB_TX:
return AFE_PORT_ID_USB_TX;
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ return AFE_PORT_ID_INT0_MI2S_RX;
+ case AFE_PORT_ID_INT0_MI2S_TX:
+ return AFE_PORT_ID_INT0_MI2S_TX;
+ case AFE_PORT_ID_INT1_MI2S_RX:
+ return AFE_PORT_ID_INT1_MI2S_RX;
+ case AFE_PORT_ID_INT1_MI2S_TX:
+ return AFE_PORT_ID_INT1_MI2S_TX;
+ case AFE_PORT_ID_INT2_MI2S_RX:
+ return AFE_PORT_ID_INT2_MI2S_RX;
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ return AFE_PORT_ID_INT2_MI2S_TX;
+ case AFE_PORT_ID_INT3_MI2S_RX:
+ return AFE_PORT_ID_INT3_MI2S_RX;
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ return AFE_PORT_ID_INT3_MI2S_TX;
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ return AFE_PORT_ID_INT4_MI2S_RX;
+ case AFE_PORT_ID_INT4_MI2S_TX:
+ return AFE_PORT_ID_INT4_MI2S_TX;
+ case AFE_PORT_ID_INT5_MI2S_RX:
+ return AFE_PORT_ID_INT5_MI2S_RX;
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ return AFE_PORT_ID_INT5_MI2S_TX;
+ case AFE_PORT_ID_INT6_MI2S_RX:
+ return AFE_PORT_ID_INT6_MI2S_RX;
+ case AFE_PORT_ID_INT6_MI2S_TX:
+ return AFE_PORT_ID_INT6_MI2S_TX;
default:
pr_warn("%s: Invalid port_id %d\n", __func__, port_id);
return -EINVAL;
@@ -572,6 +628,20 @@ int q6audio_is_digital_pcm_interface(u16 port_id)
case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
case AFE_PORT_ID_SENARY_MI2S_TX:
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ case AFE_PORT_ID_INT0_MI2S_TX:
+ case AFE_PORT_ID_INT1_MI2S_RX:
+ case AFE_PORT_ID_INT1_MI2S_TX:
+ case AFE_PORT_ID_INT2_MI2S_RX:
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ case AFE_PORT_ID_INT3_MI2S_RX:
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ case AFE_PORT_ID_INT4_MI2S_TX:
+ case AFE_PORT_ID_INT5_MI2S_RX:
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ case AFE_PORT_ID_INT6_MI2S_RX:
+ case AFE_PORT_ID_INT6_MI2S_TX:
break;
default:
ret = -EINVAL;
@@ -710,6 +780,20 @@ int q6audio_validate_port(u16 port_id)
case AFE_PORT_ID_SENARY_MI2S_TX:
case AFE_PORT_ID_USB_RX:
case AFE_PORT_ID_USB_TX:
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ case AFE_PORT_ID_INT0_MI2S_TX:
+ case AFE_PORT_ID_INT1_MI2S_RX:
+ case AFE_PORT_ID_INT1_MI2S_TX:
+ case AFE_PORT_ID_INT2_MI2S_RX:
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ case AFE_PORT_ID_INT3_MI2S_RX:
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ case AFE_PORT_ID_INT4_MI2S_TX:
+ case AFE_PORT_ID_INT5_MI2S_RX:
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ case AFE_PORT_ID_INT6_MI2S_RX:
+ case AFE_PORT_ID_INT6_MI2S_TX:
{
ret = 0;
break;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 3b3e728f88f2..834fe7c05306 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -142,7 +142,7 @@ struct share_mem_buf {
struct mem_map_table {
dma_addr_t phys;
void *data;
- uint32_t size; /* size of buffer */
+ size_t size; /* size of buffer */
struct ion_handle *handle;
struct ion_client *client;
};
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index c8f45b4efa21..eb894d073c07 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -68,7 +68,8 @@ out:
static int soc_compr_open_fe(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
- struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
+ struct snd_pcm_substream *fe_substream =
+ fe->pcm->streams[cstream->direction].substream;
struct snd_soc_platform *platform = fe->platform;
struct snd_soc_dpcm *dpcm;
struct snd_soc_dapm_widget_list *list;
@@ -443,7 +444,8 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
struct snd_compr_params *params)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
- struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
+ struct snd_pcm_substream *fe_substream =
+ fe->pcm->streams[cstream->direction].substream;
struct snd_soc_platform *platform = fe->platform;
struct snd_soc_pcm_runtime *be_list[DPCM_MAX_BE_USERS];
struct snd_soc_dpcm *dpcm;
@@ -852,8 +854,8 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
}
}
- printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
- cpu_dai->name);
+ dev_dbg(rtd->card->dev, "compress asoc: %s <-> %s mapping ok\n",
+ codec_dai->name, cpu_dai->name);
return ret;
compr_err:
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 4ef20ba02cb4..13649f96b370 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -3017,7 +3017,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
pcm->private_free = platform->driver->pcm_free;
out:
- dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
+ dev_dbg(rtd->card->dev, "%s <-> %s mapping ok\n",
(rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
cpu_dai->name);
return ret;
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
index 9f7d4e2cb532..22468eee62db 100644
--- a/sound/usb/usb_audio_qmi_svc.c
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -68,6 +68,9 @@ struct intf_info {
size_t xfer_buf_size;
phys_addr_t xfer_buf_pa;
u8 *xfer_buf;
+ u8 pcm_card_num;
+ u8 pcm_dev_num;
+ u8 direction;
bool in_use;
};
@@ -115,6 +118,7 @@ struct uaudio_qmi_svc {
struct qmi_handle *uaudio_svc_hdl;
void *curr_conn;
struct work_struct recv_msg_work;
+ struct work_struct qmi_disconnect_work;
struct workqueue_struct *uaudio_wq;
ktime_t t_request_recvd;
ktime_t t_resp_sent;
@@ -385,7 +389,7 @@ static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va,
static int prepare_qmi_response(struct snd_usb_substream *subs,
struct qmi_uaudio_stream_resp_msg_v01 *resp, u32 xfer_buf_len,
- int card_num)
+ int card_num, int pcm_dev_num)
{
int ret = -ENODEV;
struct usb_interface *iface;
@@ -411,6 +415,14 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
goto err;
}
+ if (uadev[card_num].info &&
+ uadev[card_num].info[subs->interface].in_use) {
+ pr_err("%s interface# %d already in use card# %d\n", __func__,
+ subs->interface, card_num);
+ ret = -EBUSY;
+ goto err;
+ }
+
alts = &iface->altsetting[subs->altset_idx];
altsd = get_iface_desc(alts);
protocol = altsd->bInterfaceProtocol;
@@ -627,12 +639,6 @@ skip_sync:
kref_get(&uadev[card_num].kref);
}
- if (uadev[card_num].info[subs->interface].in_use) {
- pr_err("%s interface# %d already in use card# %d\n", __func__,
- subs->interface, card_num);
- goto unmap_xfer_buf;
- }
-
uadev[card_num].card_num = card_num;
/* cache intf specific info to use it for unmap and free xfer buf */
@@ -644,6 +650,9 @@ skip_sync:
uadev[card_num].info[subs->interface].xfer_buf_pa = xfer_buf_pa;
uadev[card_num].info[subs->interface].xfer_buf_size = len;
uadev[card_num].info[subs->interface].xfer_buf = xfer_buf;
+ uadev[card_num].info[subs->interface].pcm_card_num = card_num;
+ uadev[card_num].info[subs->interface].pcm_dev_num = pcm_dev_num;
+ uadev[card_num].info[subs->interface].direction = subs->direction;
uadev[card_num].info[subs->interface].in_use = true;
set_bit(card_num, &uaudio_qdev->card_slot);
@@ -665,9 +674,71 @@ err:
return ret;
}
-void uaudio_disconnect_cb(struct snd_usb_audio *chip)
+static void uaudio_dev_intf_cleanup(struct usb_device *udev,
+ struct intf_info *info)
+{
+ uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va,
+ info->data_xfer_ring_size);
+ info->data_xfer_ring_va = 0;
+ info->data_xfer_ring_size = 0;
+
+ uaudio_iommu_unmap(MEM_XFER_RING, info->sync_xfer_ring_va,
+ info->sync_xfer_ring_size);
+ info->sync_xfer_ring_va = 0;
+ info->sync_xfer_ring_size = 0;
+
+ uaudio_iommu_unmap(MEM_XFER_BUF, info->xfer_buf_va,
+ info->xfer_buf_size);
+ info->xfer_buf_va = 0;
+
+ usb_free_coherent(udev, info->xfer_buf_size,
+ info->xfer_buf, info->xfer_buf_pa);
+ info->xfer_buf_size = 0;
+ info->xfer_buf = NULL;
+ info->xfer_buf_pa = 0;
+
+ info->in_use = false;
+}
+
+static void uaudio_dev_cleanup(struct uaudio_dev *dev)
{
- int ret, if_idx;
+ int if_idx;
+
+ /* free xfer buffer and unmap xfer ring and buf per interface */
+ for (if_idx = 0; if_idx < dev->num_intf; if_idx++) {
+ if (!dev->info[if_idx].in_use)
+ continue;
+ uaudio_dev_intf_cleanup(dev->udev, &dev->info[if_idx]);
+ pr_debug("%s: release resources: intf# %d card# %d\n", __func__,
+ if_idx, dev->card_num);
+ }
+
+ /* iommu_unmap dcba iova for a usb device */
+ uaudio_iommu_unmap(MEM_DCBA, dev->dcba_iova, dev->dcba_size);
+
+ dev->dcba_iova = 0;
+ dev->dcba_size = 0;
+ dev->num_intf = 0;
+
+ /* free interface info */
+ kfree(dev->info);
+ dev->info = NULL;
+
+ clear_bit(dev->card_num, &uaudio_qdev->card_slot);
+
+ /* all audio devices are disconnected */
+ if (!uaudio_qdev->card_slot) {
+ uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+ usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
+ pr_debug("%s: all audio devices disconnected\n", __func__);
+ }
+
+ dev->udev = NULL;
+}
+
+static void uaudio_disconnect_cb(struct snd_usb_audio *chip)
+{
+ int ret;
struct uaudio_dev *dev;
int card_num = chip->card_num;
struct uaudio_qmi_svc *svc = uaudio_svc;
@@ -713,57 +784,7 @@ void uaudio_disconnect_cb(struct snd_usb_audio *chip)
mutex_lock(&chip->dev_lock);
}
- /* free xfer buffer and unmap xfer ring and buf per interface */
- for (if_idx = 0; if_idx < dev->num_intf; if_idx++) {
- if (!dev->info[if_idx].in_use)
- continue;
- usb_free_coherent(dev->udev,
- dev->info[if_idx].xfer_buf_size,
- dev->info[if_idx].xfer_buf,
- dev->info[if_idx].xfer_buf_pa);
-
- uaudio_iommu_unmap(MEM_XFER_RING,
- dev->info[if_idx].data_xfer_ring_va,
- dev->info[if_idx].data_xfer_ring_size);
- dev->info[if_idx].data_xfer_ring_va = 0;
- dev->info[if_idx].data_xfer_ring_size = 0;
-
- uaudio_iommu_unmap(MEM_XFER_RING,
- dev->info[if_idx].sync_xfer_ring_va,
- dev->info[if_idx].sync_xfer_ring_size);
- dev->info[if_idx].sync_xfer_ring_va = 0;
- dev->info[if_idx].sync_xfer_ring_size = 0;
-
- uaudio_iommu_unmap(MEM_XFER_BUF,
- dev->info[if_idx].xfer_buf_va,
- dev->info[if_idx].xfer_buf_size);
- dev->info[if_idx].xfer_buf_va = 0;
- dev->info[if_idx].xfer_buf_size = 0;
- pr_debug("%s: release resources: intf# %d card# %d\n", __func__,
- if_idx, card_num);
- }
-
- /* iommu_unmap dcba iova for a usb device */
- uaudio_iommu_unmap(MEM_DCBA, dev->dcba_iova, dev->dcba_size);
-
- dev->dcba_iova = 0;
- dev->dcba_size = 0;
- dev->num_intf = 0;
-
- /* free interface info */
- kfree(dev->info);
- dev->info = NULL;
-
- clear_bit(card_num, &uaudio_qdev->card_slot);
-
- /* all audio devices are disconnected */
- if (!uaudio_qdev->card_slot) {
- uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
- usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
- pr_debug("%s: all audio devices disconnected\n", __func__);
- }
-
- dev->udev = NULL;
+ uaudio_dev_cleanup(dev);
done:
mutex_unlock(&chip->dev_lock);
}
@@ -789,7 +810,7 @@ static void uaudio_dev_release(struct kref *kref)
}
/* maps audio format received over QMI to asound.h based pcm format */
-int map_pcm_format(unsigned int fmt_received)
+static int map_pcm_format(unsigned int fmt_received)
{
switch (fmt_received) {
case USB_QMI_PCM_FORMAT_S8:
@@ -903,7 +924,7 @@ static int handle_uaudio_stream_req(void *req_h, void *req)
if (!ret && req_msg->enable)
ret = prepare_qmi_response(subs, &resp, req_msg->xfer_buff_size,
- pcm_card_num);
+ pcm_card_num, pcm_dev_num);
mutex_unlock(&chip->dev_lock);
@@ -912,31 +933,7 @@ response:
if (intf_num >= 0) {
mutex_lock(&chip->dev_lock);
info = &uadev[pcm_card_num].info[intf_num];
- uaudio_iommu_unmap(MEM_XFER_RING,
- info->data_xfer_ring_va,
- info->data_xfer_ring_size);
- info->data_xfer_ring_va = 0;
- info->data_xfer_ring_size = 0;
-
- uaudio_iommu_unmap(MEM_XFER_RING,
- info->sync_xfer_ring_va,
- info->sync_xfer_ring_size);
- info->sync_xfer_ring_va = 0;
- info->sync_xfer_ring_size = 0;
-
- uaudio_iommu_unmap(MEM_XFER_BUF,
- info->xfer_buf_va,
- info->xfer_buf_size);
- info->xfer_buf_va = 0;
-
- usb_free_coherent(uadev[pcm_card_num].udev,
- info->xfer_buf_size,
- info->xfer_buf,
- info->xfer_buf_pa);
- info->xfer_buf_size = 0;
- info->xfer_buf = NULL;
- info->xfer_buf_pa = 0;
- info->in_use = false;
+ uaudio_dev_intf_cleanup(uadev[pcm_card_num].udev, info);
pr_debug("%s:release resources: intf# %d card# %d\n",
__func__, intf_num, pcm_card_num);
mutex_unlock(&chip->dev_lock);
@@ -980,6 +977,43 @@ static int uaudio_qmi_svc_connect_cb(struct qmi_handle *handle,
return 0;
}
+static void uaudio_qmi_disconnect_work(struct work_struct *w)
+{
+ struct intf_info *info;
+ int idx, if_idx;
+ struct snd_usb_substream *subs;
+ struct snd_usb_audio *chip = NULL;
+
+ /* find all active intf for set alt 0 and cleanup usb audio dev */
+ for (idx = 0; idx < SNDRV_CARDS; idx++) {
+ if (!atomic_read(&uadev[idx].in_use))
+ continue;
+
+ for (if_idx = 0; if_idx < uadev[idx].num_intf; if_idx++) {
+ if (!uadev[idx].info || !uadev[idx].info[if_idx].in_use)
+ continue;
+ info = &uadev[idx].info[if_idx];
+ subs = find_snd_usb_substream(info->pcm_card_num,
+ info->pcm_dev_num,
+ info->direction,
+ &chip,
+ uaudio_disconnect_cb);
+ if (!subs || !chip || atomic_read(&chip->shutdown)) {
+ pr_debug("%s:no subs for c#%u, dev#%u dir%u\n",
+ __func__, info->pcm_card_num,
+ info->pcm_dev_num,
+ info->direction);
+ continue;
+ }
+ snd_usb_enable_audio_stream(subs, 0);
+ }
+ atomic_set(&uadev[idx].in_use, 0);
+ mutex_lock(&chip->dev_lock);
+ uaudio_dev_cleanup(&uadev[idx]);
+ mutex_unlock(&chip->dev_lock);
+ }
+}
+
static int uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle,
void *conn_h)
{
@@ -991,6 +1025,8 @@ static int uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle,
}
svc->curr_conn = NULL;
+ queue_work(svc->uaudio_wq, &svc->qmi_disconnect_work);
+
return 0;
}
@@ -1195,6 +1231,7 @@ static int uaudio_qmi_svc_init(void)
}
INIT_WORK(&svc->recv_msg_work, uaudio_qmi_svc_recv_msg);
+ INIT_WORK(&svc->qmi_disconnect_work, uaudio_qmi_disconnect_work);
uaudio_svc = svc;