Merge "asoc: qcs405: add support for dsd input"
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..4422132
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,18 @@
+gensrcs {
+ name: "qcom-audio-kernel-includes",
+ cmd: "$(location headers_install.sh) `dirname $(out)` `dirname $(in)` `basename $(in)`",
+ tools: ["headers_install.sh"],
+ export_include_dirs: ["include/uapi"],
+ srcs: [
+ "include/uapi/**/*.h",
+ ],
+ output_extension: "h",
+}
+
+cc_library_headers {
+ name: "qcom_audio_kernel_headers",
+ generated_headers: ["qcom-audio-kernel-includes"],
+ export_generated_headers: ["qcom-audio-kernel-includes"],
+ vendor: true,
+ recovery_available: true,
+}
diff --git a/Android.mk b/Android.mk
index cac7388..6c43c4e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -52,4 +52,6 @@
include $(MY_LOCAL_PATH)/asoc/codecs/bolero/Android.mk
$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd938x/Module.symvers)
include $(MY_LOCAL_PATH)/asoc/codecs/wcd938x/Android.mk
+$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/Module.symvers)
+include $(MY_LOCAL_PATH)/asoc/codecs/wcd937x/Android.mk
endif
diff --git a/Makefile.am b/Makefile.am
index 9d263f2..14e8a8c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -37,6 +37,11 @@
obj-m += asoc/codecs/wcd937x/
endif
+ifeq ($(TARGET_SUPPORT), qrb5165)
+obj-m += asoc/codecs/bolero/
+obj-m += asoc/codecs/wcd938x/
+endif
+
ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), sa8155 sa8155ivi sa6155 sa8195 qtiquingvm))
obj-m := ipc/
obj-m += dsp/
@@ -49,6 +54,9 @@
ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), sa6155))
KBUILD_OPTIONS += CONFIG_SND_SOC_SA6155=m
endif
+ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), qrb5165))
+KBUILD_OPTIONS += CONFIG_SND_SOC_KONA=m
+endif
endif
all:
diff --git a/asoc/bengal-port-config.h b/asoc/bengal-port-config.h
index 4ac7e10..a20a6d5 100644
--- a/asoc/bengal-port-config.h
+++ b/asoc/bengal-port-config.h
@@ -31,9 +31,9 @@
/* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */
static struct port_params tx_frame_params_default[SWR_MSTR_PORT_LEN] = {
- {1, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX1 */
- {1, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1}, /* TX2 */
- {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX3 */
+ {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX1 */
+ {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX2 */
+ {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX3 */
};
static struct swr_mstr_port_map sm_port_map[] = {
diff --git a/asoc/bengal.c b/asoc/bengal.c
index c500a17..dcdf1ed 100644
--- a/asoc/bengal.c
+++ b/asoc/bengal.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
@@ -14,6 +14,7 @@
#include <linux/input.h>
#include <linux/of_device.h>
#include <linux/soc/qcom/fsa4480-i2c.h>
+#include <linux/nvmem-consumer.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -155,6 +156,7 @@
struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
bool is_afe_config_done;
struct device_node *fsa_handle;
+ bool va_disable;
};
struct tdm_port {
@@ -3465,6 +3467,8 @@
break;
case MSM_BACKEND_DAI_SLIMBUS_7_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_tx_cfg[SLIM_TX_7].bit_format);
rate->min = rate->max = slim_tx_cfg[SLIM_TX_7].sample_rate;
channels->min = channels->max =
slim_tx_cfg[SLIM_TX_7].channels;
@@ -3811,11 +3815,17 @@
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
switch (dai_link->id) {
case MSM_BACKEND_DAI_VA_CDC_DMA_TX_0:
case MSM_BACKEND_DAI_VA_CDC_DMA_TX_1:
case MSM_BACKEND_DAI_VA_CDC_DMA_TX_2:
+ if (pdata->va_disable) {
+ pr_debug("%s: SVA not supported\n", __func__);
+ return -EINVAL;
+ }
ret = bengal_send_island_va_config(dai_link->id);
if (ret)
pr_err("%s: send island va cfg failed, err: %d\n",
@@ -4835,7 +4845,7 @@
};
static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
- {/* hw:x,34 */
+ {/* hw:x,33 */
.name = MSM_DAILINK_NAME(ASM Loopback),
.stream_name = "MultiMedia6",
.cpu_dai_name = "MultiMedia6",
@@ -4852,7 +4862,7 @@
.ignore_pmdown_time = 1,
.id = MSM_FRONTEND_DAI_MULTIMEDIA6,
},
- {/* hw:x,35 */
+ {/* hw:x,34 */
.name = "USB Audio Hostless",
.stream_name = "USB Audio Hostless",
.cpu_dai_name = "USBAUDIO_HOSTLESS",
@@ -4868,7 +4878,7 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
- {/* hw:x,36 */
+ {/* hw:x,35 */
.name = "SLIMBUS_7 Hostless",
.stream_name = "SLIMBUS_7 Hostless",
.cpu_dai_name = "SLIMBUS7_HOSTLESS",
@@ -4884,7 +4894,7 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
- {/* hw:x,37 */
+ {/* hw:x,36 */
.name = "Compress Capture",
.stream_name = "Compress9",
.cpu_dai_name = "MultiMedia17",
@@ -4899,7 +4909,7 @@
.ignore_pmdown_time = 1,
.id = MSM_FRONTEND_DAI_MULTIMEDIA17,
},
- {/* hw:x,38 */
+ {/* hw:x,37 */
.name = "SLIMBUS_8 Hostless",
.stream_name = "SLIMBUS_8 Hostless",
.cpu_dai_name = "SLIMBUS8_HOSTLESS",
@@ -4915,7 +4925,7 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
- {/* hw:x,39 */
+ {/* hw:x,38 */
.name = LPASS_BE_TX_CDC_DMA_TX_5,
.stream_name = "TX CDC DMA5 Capture",
.cpu_dai_name = "msm-dai-cdc-dma-dev.45115",
@@ -6443,6 +6453,10 @@
const char *mbhc_audio_jack_type = NULL;
int ret = 0;
uint index = 0;
+ struct nvmem_cell *cell;
+ size_t len;
+ u32 *buf;
+ u32 adsp_var_idx = 0;
if (!pdev->dev.of_node) {
dev_err(&pdev->dev,
@@ -6592,7 +6606,23 @@
__func__, ret);
is_initial_boot = true;
+ /* get adsp variant idx */
+ cell = nvmem_cell_get(&pdev->dev, "adsp_variant");
+ if (IS_ERR_OR_NULL(cell)) {
+ dev_dbg(&pdev->dev, "%s: FAILED to get nvmem cell \n", __func__);
+ goto ret;
+ }
+ buf = nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+ if (IS_ERR_OR_NULL(buf) || len <= 0 || len > sizeof(32)) {
+ dev_dbg(&pdev->dev, "%s: FAILED to read nvmem cell \n", __func__);
+ goto ret;
+ }
+ memcpy(&adsp_var_idx, buf, len);
+ kfree(buf);
+ pdata->va_disable = adsp_var_idx;
+ret:
return 0;
err:
devm_kfree(&pdev->dev, pdata);
diff --git a/asoc/codecs/audio-ext-clk-up.c b/asoc/codecs/audio-ext-clk-up.c
index 632f674..fc3cb38 100644
--- a/asoc/codecs/audio-ext-clk-up.c
+++ b/asoc/codecs/audio-ext-clk-up.c
@@ -70,6 +70,8 @@
if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS) &&
(clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) {
clk_priv->clk_cfg.enable = 1;
+ trace_printk("%s: vote for %d clock\n",
+ __func__, clk_priv->clk_src);
ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk_priv->clk_cfg);
if (ret < 0) {
pr_err_ratelimited("%s afe_set_digital_codec_core_clock failed\n",
@@ -112,6 +114,8 @@
if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS) &&
(clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) {
clk_priv->clk_cfg.enable = 0;
+ trace_printk("%s: unvote for %d clock\n",
+ __func__, clk_priv->clk_src);
ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk_priv->clk_cfg);
if (ret < 0)
pr_err_ratelimited("%s: afe_set_lpass_clk_cfg failed, ret = %d\n",
@@ -146,6 +150,8 @@
int ret;
if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE) {
+ trace_printk("%s: vote for %d clock\n",
+ __func__, clk_priv->clk_src);
ret = afe_vote_lpass_core_hw(AFE_LPASS_CORE_HW_MACRO_BLOCK,
"LPASS_HW_MACRO",
&clk_priv->lpass_core_hwvote_client_handle);
@@ -157,6 +163,8 @@
}
if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_AUDIO_HW_VOTE) {
+ trace_printk("%s: vote for %d clock\n",
+ __func__, clk_priv->clk_src);
ret = afe_vote_lpass_core_hw(AFE_LPASS_CORE_HW_DCODEC_BLOCK,
"LPASS_HW_DCODEC",
&clk_priv->lpass_audio_hwvote_client_handle);
@@ -176,6 +184,8 @@
int ret = 0;
if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE) {
+ trace_printk("%s: unvote for %d clock\n",
+ __func__, clk_priv->clk_src);
ret = afe_unvote_lpass_core_hw(
AFE_LPASS_CORE_HW_MACRO_BLOCK,
clk_priv->lpass_core_hwvote_client_handle);
@@ -186,6 +196,8 @@
}
if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_AUDIO_HW_VOTE) {
+ trace_printk("%s: unvote for %d clock\n",
+ __func__, clk_priv->clk_src);
ret = afe_unvote_lpass_core_hw(
AFE_LPASS_CORE_HW_DCODEC_BLOCK,
clk_priv->lpass_audio_hwvote_client_handle);
diff --git a/asoc/codecs/bolero/bolero-cdc-regmap.c b/asoc/codecs/bolero/bolero-cdc-regmap.c
index 77f5420..e6f03fc 100644
--- a/asoc/codecs/bolero/bolero-cdc-regmap.c
+++ b/asoc/codecs/bolero/bolero-cdc-regmap.c
@@ -797,6 +797,14 @@
case BOLERO_CDC_VA_TOP_CSR_CORE_ID_1:
case BOLERO_CDC_VA_TOP_CSR_CORE_ID_2:
case BOLERO_CDC_VA_TOP_CSR_CORE_ID_3:
+ case BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL:
+ case BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL:
+ case BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL:
+ case BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL:
+ case BOLERO_CDC_TX_TOP_CSR_SWR_DMIC0_CTL:
+ case BOLERO_CDC_TX_TOP_CSR_SWR_DMIC1_CTL:
+ case BOLERO_CDC_TX_TOP_CSR_SWR_DMIC2_CTL:
+ case BOLERO_CDC_TX_TOP_CSR_SWR_DMIC3_CTL:
case BOLERO_CDC_WSA_VBAT_BCL_VBAT_GAIN_MON_VAL:
case BOLERO_CDC_WSA_VBAT_BCL_VBAT_DECODE_ST:
case BOLERO_CDC_WSA_INTR_CTRL_PIN1_STATUS0:
diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c
index d307c21..2db0c5b 100644
--- a/asoc/codecs/bolero/bolero-cdc.c
+++ b/asoc/codecs/bolero/bolero-cdc.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/of_platform.h>
@@ -101,8 +101,11 @@
goto ssr_err;
}
- if (priv->macro_params[VA_MACRO].dev)
+ if (priv->macro_params[VA_MACRO].dev) {
pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
+ if (!bolero_check_core_votes(priv->macro_params[VA_MACRO].dev))
+ goto ssr_err;
+ }
if (priv->version < BOLERO_VERSION_2_0) {
/* Request Clk before register access */
@@ -149,8 +152,11 @@
ret = -EINVAL;
goto ssr_err;
}
- if (priv->macro_params[VA_MACRO].dev)
+ if (priv->macro_params[VA_MACRO].dev) {
pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
+ if (!bolero_check_core_votes(priv->macro_params[VA_MACRO].dev))
+ goto ssr_err;
+ }
if (priv->version < BOLERO_VERSION_2_0) {
/* Request Clk before register access */
@@ -470,6 +476,129 @@
}
EXPORT_SYMBOL(bolero_unregister_res_clk);
+static u8 bolero_dmic_clk_div_get(struct snd_soc_component *component,
+ int mode)
+{
+ struct bolero_priv* priv = snd_soc_component_get_drvdata(component);
+ int macro = (mode ? VA_MACRO : TX_MACRO);
+ int ret = 0;
+
+ if (priv->macro_params[macro].clk_div_get) {
+ ret = priv->macro_params[macro].clk_div_get(component);
+ if (ret > 0)
+ return ret;
+ }
+
+ return 1;
+}
+
+int bolero_dmic_clk_enable(struct snd_soc_component *component,
+ u32 dmic, u32 tx_mode, bool enable)
+{
+ struct bolero_priv* priv = snd_soc_component_get_drvdata(component);
+ u8 dmic_clk_en = 0x01;
+ u16 dmic_clk_reg = 0;
+ s32 *dmic_clk_cnt = NULL;
+ u8 *dmic_clk_div = NULL;
+ u8 freq_change_mask = 0;
+ u8 clk_div = 0;
+
+ dev_dbg(component->dev, "%s: enable: %d, tx_mode:%d, dmic: %d\n",
+ __func__, enable, tx_mode, dmic);
+
+ switch (dmic) {
+ case 0:
+ case 1:
+ dmic_clk_cnt = &(priv->dmic_0_1_clk_cnt);
+ dmic_clk_div = &(priv->dmic_0_1_clk_div);
+ dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL;
+ freq_change_mask = 0x01;
+ break;
+ case 2:
+ case 3:
+ dmic_clk_cnt = &(priv->dmic_2_3_clk_cnt);
+ dmic_clk_div = &(priv->dmic_2_3_clk_div);
+ dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL;
+ freq_change_mask = 0x02;
+ break;
+ case 4:
+ case 5:
+ dmic_clk_cnt = &(priv->dmic_4_5_clk_cnt);
+ dmic_clk_div = &(priv->dmic_4_5_clk_div);
+ dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL;
+ freq_change_mask = 0x04;
+ break;
+ case 6:
+ case 7:
+ dmic_clk_cnt = &(priv->dmic_6_7_clk_cnt);
+ dmic_clk_div = &(priv->dmic_6_7_clk_div);
+ dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL;
+ freq_change_mask = 0x08;
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid DMIC Selection\n",
+ __func__);
+ return -EINVAL;
+ }
+ dev_dbg(component->dev, "%s: DMIC%d dmic_clk_cnt %d\n",
+ __func__, dmic, *dmic_clk_cnt);
+ if (enable) {
+ clk_div = bolero_dmic_clk_div_get(component, tx_mode);
+ (*dmic_clk_cnt)++;
+ if (*dmic_clk_cnt == 1) {
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
+ 0x80, 0x00);
+ snd_soc_component_update_bits(component, dmic_clk_reg,
+ 0x0E, clk_div << 0x1);
+ snd_soc_component_update_bits(component, dmic_clk_reg,
+ dmic_clk_en, dmic_clk_en);
+ } else {
+ if (*dmic_clk_div > clk_div) {
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
+ freq_change_mask, freq_change_mask);
+ snd_soc_component_update_bits(component, dmic_clk_reg,
+ 0x0E, clk_div << 0x1);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
+ freq_change_mask, 0x00);
+ } else {
+ clk_div = *dmic_clk_div;
+ }
+ }
+ *dmic_clk_div = clk_div;
+ } else {
+ (*dmic_clk_cnt)--;
+ if (*dmic_clk_cnt == 0) {
+ snd_soc_component_update_bits(component, dmic_clk_reg,
+ dmic_clk_en, 0);
+ clk_div = 0;
+ snd_soc_component_update_bits(component, dmic_clk_reg,
+ 0x0E, clk_div << 0x1);
+ } else {
+ clk_div = bolero_dmic_clk_div_get(component, tx_mode);
+ if (*dmic_clk_div > clk_div) {
+ clk_div = bolero_dmic_clk_div_get(component, !tx_mode);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
+ freq_change_mask, freq_change_mask);
+ snd_soc_component_update_bits(component, dmic_clk_reg,
+ 0x0E, clk_div << 0x1);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
+ freq_change_mask, 0x00);
+ } else {
+ clk_div = *dmic_clk_div;
+ }
+ }
+ *dmic_clk_div = clk_div;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(bolero_dmic_clk_enable);
+
/**
* bolero_register_macro - Registers macro to bolero
*
@@ -517,7 +646,11 @@
priv->macro_params[macro_id].clk_switch = ops->clk_switch;
priv->macro_params[macro_id].reg_evt_listener =
ops->reg_evt_listener;
+ priv->macro_params[macro_id].clk_enable = ops->clk_enable;
}
+ if (macro_id == TX_MACRO || macro_id == VA_MACRO)
+ priv->macro_params[macro_id].clk_div_get = ops->clk_div_get;
+
if (priv->version == BOLERO_VERSION_2_1) {
if (macro_id == VA_MACRO)
priv->macro_params[macro_id].reg_wake_irq =
@@ -527,7 +660,7 @@
priv->num_macros_registered++;
priv->macros_supported[macro_id] = true;
- dev_dbg(dev, "%s: register macro successful:%d\n", macro_id);
+ dev_dbg(dev, "%s: register macro successful:%d\n", __func__, macro_id);
if (priv->num_macros_registered == priv->num_macros) {
ret = bolero_copy_dais_from_macro(priv);
@@ -587,7 +720,10 @@
priv->macro_params[macro_id].reg_wake_irq = NULL;
priv->macro_params[macro_id].clk_switch = NULL;
priv->macro_params[macro_id].reg_evt_listener = NULL;
+ priv->macro_params[macro_id].clk_enable = NULL;
}
+ if (macro_id == TX_MACRO || macro_id == VA_MACRO)
+ priv->macro_params[macro_id].clk_div_get = NULL;
priv->num_dais -= priv->macro_params[macro_id].num_dais;
priv->num_macros_registered--;
@@ -698,6 +834,11 @@
priv->component,
BOLERO_MACRO_EVT_CLK_RESET, 0x0);
}
+
+ if (priv->rsc_clk_cb)
+ priv->rsc_clk_cb(priv->clk_dev, BOLERO_MACRO_EVT_SSR_GFMUX_UP);
+
+ trace_printk("%s: clk count reset\n", __func__);
regcache_cache_only(priv->regmap, false);
mutex_lock(&priv->clk_lock);
priv->dev_up = true;
@@ -708,6 +849,7 @@
/* Add a 100usec sleep to ensure last register write is done */
usleep_range(100,110);
bolero_clk_rsc_enable_all_clocks(priv->clk_dev, false);
+ trace_printk("%s: regcache_sync done\n", __func__);
/* call ssr event for supported macros */
for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) {
if (!priv->macro_params[macro_idx].event_handler)
@@ -716,6 +858,7 @@
priv->component,
BOLERO_MACRO_EVT_SSR_UP, 0x0);
}
+ trace_printk("%s: SSR up events processed by all macros\n", __func__);
bolero_cdc_notifier_call(priv, BOLERO_WCD_EVT_SSR_UP);
return 0;
}
@@ -725,6 +868,12 @@
struct bolero_priv *priv = data;
int macro_idx;
+ if (!priv->dev_up) {
+ dev_err_ratelimited(priv->dev,
+ "%s: already disabled\n", __func__);
+ return;
+ }
+
bolero_cdc_notifier_call(priv, BOLERO_WCD_EVT_PA_OFF_PRE_SSR);
regcache_cache_only(priv->regmap, true);
@@ -855,9 +1004,11 @@
*
* @component: pointer to codec component instance.
*
+ * @clk_src: 0 for TX_RCG and 1 for VA_RCG
+ *
* Returns 0 on success or -EINVAL on error.
*/
-int bolero_tx_clk_switch(struct snd_soc_component *component)
+int bolero_tx_clk_switch(struct snd_soc_component *component, int clk_src)
{
struct bolero_priv *priv = NULL;
int ret = 0;
@@ -875,13 +1026,48 @@
}
if (priv->macro_params[TX_MACRO].clk_switch)
- ret = priv->macro_params[TX_MACRO].clk_switch(component);
+ ret = priv->macro_params[TX_MACRO].clk_switch(component,
+ clk_src);
return ret;
}
EXPORT_SYMBOL(bolero_tx_clk_switch);
/**
+ * bolero_tx_mclk_enable - Enable/Disable TX Macro mclk
+ *
+ * @component: pointer to codec component instance.
+ * @enable: set true to enable, otherwise false.
+ *
+ * Returns 0 on success or -EINVAL on error.
+ */
+int bolero_tx_mclk_enable(struct snd_soc_component *component,
+ bool enable)
+{
+ struct bolero_priv *priv = NULL;
+ int ret = 0;
+
+ if (!component)
+ return -EINVAL;
+
+ priv = snd_soc_component_get_drvdata(component);
+ if (!priv)
+ return -EINVAL;
+
+ if (!bolero_is_valid_codec_dev(priv->dev)) {
+ dev_err(component->dev, "%s: invalid codec\n", __func__);
+ return -EINVAL;
+ }
+
+ if (priv->macro_params[TX_MACRO].clk_enable)
+ ret = priv->macro_params[TX_MACRO].clk_enable(component,
+ enable);
+
+ return ret;
+}
+EXPORT_SYMBOL(bolero_tx_mclk_enable);
+
+/**
* bolero_register_event_listener - Register/Deregister to event listener
*
* @component: pointer to codec component instance.
@@ -1043,10 +1229,9 @@
pdev->dev.parent = priv->dev;
pdev->dev.of_node = node;
- if (split_codec) {
- priv->dev->platform_data = platdata;
+ priv->dev->platform_data = platdata;
+ if (split_codec)
priv->wcd_dev = &pdev->dev;
- }
ret = platform_device_add(pdev);
if (ret) {
@@ -1202,6 +1387,8 @@
}
}
priv->core_hw_vote_count++;
+ trace_printk("%s: hw vote count %d\n",
+ __func__, priv->core_hw_vote_count);
audio_vote:
if (priv->lpass_audio_hw_vote == NULL) {
@@ -1218,6 +1405,8 @@
}
}
priv->core_audio_vote_count++;
+ trace_printk("%s: audio vote count %d\n",
+ __func__, priv->core_audio_vote_count);
done:
mutex_unlock(&priv->vote_lock);
@@ -1240,6 +1429,8 @@
dev_dbg(dev, "%s: Invalid lpass core hw node\n",
__func__);
}
+ trace_printk("%s: hw vote count %d\n",
+ __func__, priv->core_hw_vote_count);
if (priv->lpass_audio_hw_vote != NULL) {
if (--priv->core_audio_vote_count == 0)
@@ -1250,6 +1441,8 @@
dev_dbg(dev, "%s: Invalid lpass audio hw node\n",
__func__);
}
+ trace_printk("%s: audio vote count %d\n",
+ __func__, priv->core_audio_vote_count);
mutex_unlock(&priv->vote_lock);
return 0;
diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h
index 2ec4617..b37eeae 100644
--- a/asoc/codecs/bolero/bolero-cdc.h
+++ b/asoc/codecs/bolero/bolero-cdc.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#ifndef BOLERO_CDC_H
@@ -38,6 +38,11 @@
};
enum {
+ CLK_SRC_TX_RCG = 0,
+ CLK_SRC_VA_RCG,
+};
+
+enum {
BOLERO_MACRO_EVT_RX_MUTE = 1, /* for RX mute/unmute */
BOLERO_MACRO_EVT_IMPED_TRUE, /* for imped true */
BOLERO_MACRO_EVT_IMPED_FALSE, /* for imped false */
@@ -47,7 +52,26 @@
BOLERO_MACRO_EVT_CLK_RESET,
BOLERO_MACRO_EVT_REG_WAKE_IRQ,
BOLERO_MACRO_EVT_RX_COMPANDER_SOFT_RST,
- BOLERO_MACRO_EVT_BCS_CLK_OFF
+ BOLERO_MACRO_EVT_BCS_CLK_OFF,
+ BOLERO_MACRO_EVT_SSR_GFMUX_UP,
+};
+
+enum {
+ DMIC_TX = 0,
+ DMIC_VA = 1,
+
+};
+
+enum {
+ DMIC0 = 0,
+ DMIC1,
+ DMIC2,
+ DMIC3,
+ DMIC4,
+ DMIC5,
+ DMIC6,
+ DMIC7,
+ DMIC_MAX
};
struct macro_ops {
@@ -62,8 +86,10 @@
int (*reg_wake_irq)(struct snd_soc_component *component, u32 data);
int (*set_port_map)(struct snd_soc_component *component, u32 uc,
u32 size, void *data);
- int (*clk_switch)(struct snd_soc_component *component);
+ int (*clk_div_get)(struct snd_soc_component *component);
+ int (*clk_switch)(struct snd_soc_component *component, int clk_src);
int (*reg_evt_listener)(struct snd_soc_component *component, bool en);
+ int (*clk_enable)(struct snd_soc_component *c, bool en);
char __iomem *io_base;
u16 clk_id_req;
u16 default_clk_id;
@@ -87,12 +113,15 @@
int bolero_runtime_resume(struct device *dev);
int bolero_runtime_suspend(struct device *dev);
int bolero_set_port_map(struct snd_soc_component *component, u32 size, void *data);
-int bolero_tx_clk_switch(struct snd_soc_component *component);
+int bolero_tx_clk_switch(struct snd_soc_component *component, int clk_src);
int bolero_register_event_listener(struct snd_soc_component *component,
bool enable);
void bolero_wsa_pa_on(struct device *dev);
bool bolero_check_core_votes(struct device *dev);
+int bolero_tx_mclk_enable(struct snd_soc_component *c, bool enable);
int bolero_get_version(struct device *dev);
+int bolero_dmic_clk_enable(struct snd_soc_component *component,
+ u32 dmic, u32 tx_mode, bool enable);
#else
static inline int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb)
{
@@ -152,7 +181,8 @@
return 0;
}
-static inline int bolero_tx_clk_switch(struct snd_soc_component *component)
+static inline int bolero_tx_clk_switch(struct snd_soc_component *component,
+ int clk_src)
{
return 0;
}
@@ -177,5 +207,15 @@
{
return 0;
}
+
+static int bolero_dmic_clk_enable(struct snd_soc_component *component,
+ u32 dmic, u32 tx_mode, bool enable)
+{
+ return 0;
+}
+static int bolero_tx_mclk_enable(struct snd_soc_component *c, bool enable)
+{
+ return 0;
+}
#endif /* CONFIG_SND_SOC_BOLERO */
#endif /* BOLERO_CDC_H */
diff --git a/asoc/codecs/bolero/bolero-clk-rsc.c b/asoc/codecs/bolero/bolero-clk-rsc.c
index b80a267..9cc9b1c 100644
--- a/asoc/codecs/bolero/bolero-clk-rsc.c
+++ b/asoc/codecs/bolero/bolero-clk-rsc.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/of_platform.h>
@@ -32,11 +32,13 @@
struct bolero_clk_rsc {
struct device *dev;
struct mutex rsc_clk_lock;
+ struct mutex fs_gen_lock;
struct clk *clk[MAX_CLK];
int clk_cnt[MAX_CLK];
int reg_seq_en_cnt;
int va_tx_clk_cnt;
bool dev_up;
+ bool dev_up_gfmux;
u32 num_fs_reg;
u32 *fs_gen_seq;
int default_clk_id[MAX_CLK];
@@ -64,10 +66,14 @@
}
mutex_lock(&priv->rsc_clk_lock);
- if (event == BOLERO_MACRO_EVT_SSR_UP)
+ if (event == BOLERO_MACRO_EVT_SSR_UP) {
priv->dev_up = true;
- else if (event == BOLERO_MACRO_EVT_SSR_DOWN)
+ } else if (event == BOLERO_MACRO_EVT_SSR_DOWN) {
priv->dev_up = false;
+ priv->dev_up_gfmux = false;
+ } else if (event == BOLERO_MACRO_EVT_SSR_GFMUX_UP) {
+ priv->dev_up_gfmux = true;
+ }
mutex_unlock(&priv->rsc_clk_lock);
return 0;
@@ -99,7 +105,7 @@
int count = 0;
if (!dev) {
- pr_err("%s: dev is null %d\n", __func__);
+ pr_err("%s: dev is null\n", __func__);
return -EINVAL;
}
@@ -128,6 +134,8 @@
}
dev_dbg(priv->dev,
"%s: clock reset after ssr, count %d\n", __func__, count);
+
+ trace_printk("%s: clock reset after ssr, count %d\n", __func__, count);
while (count--) {
clk_prepare_enable(priv->clk[clk_id]);
clk_prepare_enable(priv->clk[clk_id + NPL_CLK_OFFSET]);
@@ -144,7 +152,7 @@
int i = 0;
if (!dev) {
- pr_err("%s: dev is null %d\n", __func__);
+ pr_err("%s: dev is null\n", __func__);
return;
}
@@ -237,6 +245,7 @@
char __iomem *clk_muxsel = NULL;
int ret = 0;
int default_clk_id = priv->default_clk_id[clk_id];
+ u32 muxsel = 0;
clk_muxsel = bolero_clk_rsc_get_clk_muxsel(priv, clk_id);
if (!clk_muxsel) {
@@ -246,10 +255,13 @@
if (enable) {
if (priv->clk_cnt[clk_id] == 0) {
- ret = bolero_clk_rsc_mux0_clk_request(priv, default_clk_id,
+ if (clk_id != VA_CORE_CLK) {
+ ret = bolero_clk_rsc_mux0_clk_request(priv,
+ default_clk_id,
true);
- if (ret < 0)
- goto done;
+ if (ret < 0)
+ goto done;
+ }
ret = clk_prepare_enable(priv->clk[clk_id]);
if (ret < 0) {
@@ -267,9 +279,24 @@
goto err_npl_clk;
}
}
- iowrite32(0x1, clk_muxsel);
- bolero_clk_rsc_mux0_clk_request(priv, default_clk_id,
+
+ /*
+ * Temp SW workaround to address a glitch issue of
+ * VA GFMux instance responsible for switching from
+ * TX MCLK to VA MCLK. This configuration would be taken
+ * care in DSP itself
+ */
+ if (clk_id != VA_CORE_CLK) {
+ if (priv->dev_up_gfmux) {
+ iowrite32(0x1, clk_muxsel);
+ muxsel = ioread32(clk_muxsel);
+ trace_printk("%s: muxsel value after enable: %d\n",
+ __func__, muxsel);
+ }
+ bolero_clk_rsc_mux0_clk_request(priv,
+ default_clk_id,
false);
+ }
}
priv->clk_cnt[clk_id]++;
} else {
@@ -281,20 +308,36 @@
}
priv->clk_cnt[clk_id]--;
if (priv->clk_cnt[clk_id] == 0) {
- ret = bolero_clk_rsc_mux0_clk_request(priv,
+ if (clk_id != VA_CORE_CLK) {
+ ret = bolero_clk_rsc_mux0_clk_request(priv,
default_clk_id, true);
- if (!ret)
- iowrite32(0x0, clk_muxsel);
-
+ if (!ret) {
+ /*
+ * Temp SW workaround to address a glitch issue
+ * of VA GFMux instance responsible for
+ * switching from TX MCLK to VA MCLK.
+ * This configuration would be taken
+ * care in DSP itself.
+ */
+ if (priv->dev_up_gfmux) {
+ iowrite32(0x0, clk_muxsel);
+ muxsel = ioread32(clk_muxsel);
+ trace_printk("%s: muxsel value after disable: %d\n",
+ __func__, muxsel);
+ }
+ }
+ }
if (priv->clk[clk_id + NPL_CLK_OFFSET])
clk_disable_unprepare(
priv->clk[clk_id + NPL_CLK_OFFSET]);
clk_disable_unprepare(priv->clk[clk_id]);
- if (!ret)
- bolero_clk_rsc_mux0_clk_request(priv,
+ if (clk_id != VA_CORE_CLK) {
+ if (!ret)
+ bolero_clk_rsc_mux0_clk_request(priv,
default_clk_id, false);
+ }
}
}
return ret;
@@ -303,7 +346,8 @@
clk_disable_unprepare(priv->clk[clk_id]);
err_clk:
- bolero_clk_rsc_mux0_clk_request(priv, default_clk_id, false);
+ if (clk_id != VA_CORE_CLK)
+ bolero_clk_rsc_mux0_clk_request(priv, default_clk_id, false);
done:
return ret;
}
@@ -404,7 +448,7 @@
struct bolero_clk_rsc *priv = NULL;
if (!dev) {
- pr_err("%s: dev is null %d\n", __func__);
+ pr_err("%s: dev is null\n", __func__);
return;
}
clk_dev = bolero_get_rsc_clk_device_ptr(dev->parent);
@@ -422,6 +466,7 @@
pr_err("%s: regmap is null\n", __func__);
return;
}
+ mutex_lock(&priv->fs_gen_lock);
if (enable) {
if (priv->reg_seq_en_cnt++ == 0) {
for (i = 0; i < (priv->num_fs_reg * 2); i += 2) {
@@ -439,6 +484,7 @@
dev_err_ratelimited(priv->dev, "%s: req_seq_cnt: %d is already disabled\n",
__func__, priv->reg_seq_en_cnt);
priv->reg_seq_en_cnt = 0;
+ mutex_unlock(&priv->fs_gen_lock);
return;
}
if (--priv->reg_seq_en_cnt == 0) {
@@ -451,6 +497,7 @@
}
}
}
+ mutex_unlock(&priv->fs_gen_lock);
}
EXPORT_SYMBOL(bolero_clk_rsc_fs_gen_request);
@@ -476,7 +523,7 @@
bool mux_switch = false;
if (!dev) {
- pr_err("%s: dev is null %d\n", __func__);
+ pr_err("%s: dev is null\n", __func__);
return -EINVAL;
}
if ((clk_id_req < 0 || clk_id_req >= MAX_CLK) &&
@@ -500,6 +547,7 @@
if (!priv->dev_up && enable) {
dev_err_ratelimited(priv->dev, "%s: SSR is in progress..\n",
__func__);
+ trace_printk("%s: SSR is in progress..\n", __func__);
ret = -EINVAL;
goto err;
}
@@ -529,6 +577,9 @@
dev_dbg(priv->dev, "%s: clk_cnt: %d for requested clk: %d, enable: %d\n",
__func__, priv->clk_cnt[clk_id_req], clk_id_req,
enable);
+ trace_printk("%s: clk_cnt: %d for requested clk: %d, enable: %d\n",
+ __func__, priv->clk_cnt[clk_id_req], clk_id_req,
+ enable);
mutex_unlock(&priv->rsc_clk_lock);
@@ -664,7 +715,9 @@
}
priv->dev = &pdev->dev;
priv->dev_up = true;
+ priv->dev_up_gfmux = true;
mutex_init(&priv->rsc_clk_lock);
+ mutex_init(&priv->fs_gen_lock);
dev_set_drvdata(&pdev->dev, priv);
err:
@@ -680,6 +733,7 @@
if (!priv)
return -EINVAL;
mutex_destroy(&priv->rsc_clk_lock);
+ mutex_destroy(&priv->fs_gen_lock);
return 0;
}
diff --git a/asoc/codecs/bolero/internal.h b/asoc/codecs/bolero/internal.h
index d18568b..5b3dd49 100644
--- a/asoc/codecs/bolero/internal.h
+++ b/asoc/codecs/bolero/internal.h
@@ -82,6 +82,14 @@
struct blocking_notifier_head notifier;
struct device *clk_dev;
rsc_clk_cb_t rsc_clk_cb;
+ s32 dmic_0_1_clk_cnt;
+ s32 dmic_2_3_clk_cnt;
+ s32 dmic_4_5_clk_cnt;
+ s32 dmic_6_7_clk_cnt;
+ u8 dmic_0_1_clk_div;
+ u8 dmic_2_3_clk_div;
+ u8 dmic_4_5_clk_div;
+ u8 dmic_6_7_clk_div;
};
struct regmap *bolero_regmap_init(struct device *dev,
diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c
index ffcd734..ea1a374 100644
--- a/asoc/codecs/bolero/rx-macro.c
+++ b/asoc/codecs/bolero/rx-macro.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -1120,7 +1120,7 @@
*rx_slot = ch_mask;
*rx_num = rx_priv->active_ch_cnt[dai->id];
dev_dbg(rx_priv->dev,
- "%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d active_mask: 0x%x\n",
+ "%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d active_mask: 0x%lx\n",
__func__, dai->id, *rx_slot, *rx_num, rx_priv->active_ch_mask[dai->id]);
break;
case RX_MACRO_AIF_ECHO:
@@ -1247,6 +1247,9 @@
0x02, 0x02);
regmap_update_bits(regmap,
BOLERO_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
+ 0x02, 0x00);
+ regmap_update_bits(regmap,
+ BOLERO_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
0x01, 0x01);
}
rx_priv->rx_mclk_users++;
@@ -1263,6 +1266,12 @@
BOLERO_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
0x01, 0x00);
regmap_update_bits(regmap,
+ BOLERO_CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
+ 0x02, 0x02);
+ regmap_update_bits(regmap,
+ BOLERO_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL,
+ 0x02, 0x00);
+ regmap_update_bits(regmap,
BOLERO_CDC_RX_CLK_RST_CTRL_MCLK_CONTROL,
0x01, 0x00);
bolero_clk_rsc_fs_gen_request(rx_priv->dev,
@@ -1275,6 +1284,8 @@
}
}
exit:
+ trace_printk("%s: mclk_enable = %u, dapm = %d clk_users= %d\n",
+ __func__, mclk_enable, dapm, rx_priv->rx_mclk_users);
mutex_unlock(&rx_priv->mclk_lock);
return ret;
}
@@ -1360,13 +1371,11 @@
rx_macro_wcd_clsh_imped_config(component, data, false);
break;
case BOLERO_MACRO_EVT_SSR_DOWN:
+ trace_printk("%s, enter SSR down\n", __func__);
rx_priv->dev_up = false;
if (rx_priv->swr_ctrl_data) {
swrm_wcd_notify(
rx_priv->swr_ctrl_data[0].rx_swr_pdev,
- SWR_DEVICE_DOWN, NULL);
- swrm_wcd_notify(
- rx_priv->swr_ctrl_data[0].rx_swr_pdev,
SWR_DEVICE_SSR_DOWN, NULL);
}
if ((!pm_runtime_enabled(rx_dev) ||
@@ -1380,6 +1389,7 @@
}
break;
case BOLERO_MACRO_EVT_SSR_UP:
+ trace_printk("%s, enter SSR up\n", __func__);
rx_priv->dev_up = true;
/* reset swr after ssr/pdr */
rx_priv->reset_swr = true;
@@ -1665,7 +1675,9 @@
int interp_n, int event)
{
int comp = 0;
- u16 comp_ctl0_reg = 0, rx_path_cfg0_reg = 0;
+ u16 comp_ctl0_reg = 0, rx_path_cfg0_reg = 0, rx_path_cfg3_reg = 0;
+ u16 rx0_path_ctl_reg = 0;
+ u8 pcm_rate = 0, val = 0;
/* AUX does not have compander */
if (interp_n == INTERP_AUX)
@@ -1682,6 +1694,20 @@
(comp * RX_MACRO_COMP_OFFSET);
rx_path_cfg0_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG0 +
(comp * RX_MACRO_RX_PATH_OFFSET);
+ rx_path_cfg3_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG3 +
+ (comp * RX_MACRO_RX_PATH_OFFSET);
+ rx0_path_ctl_reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL +
+ (comp * RX_MACRO_RX_PATH_OFFSET);
+ pcm_rate = (snd_soc_component_read32(component, rx0_path_ctl_reg)
+ & 0x0F);
+ if (pcm_rate < 0x06)
+ val = 0x03;
+ else if (pcm_rate < 0x08)
+ val = 0x01;
+ else if (pcm_rate < 0x0B)
+ val = 0x02;
+ else
+ val = 0x00;
if (SND_SOC_DAPM_EVENT_ON(event)) {
/* Enable Compander Clock */
@@ -1693,6 +1719,8 @@
0x02, 0x00);
snd_soc_component_update_bits(component, rx_path_cfg0_reg,
0x02, 0x02);
+ snd_soc_component_update_bits(component, rx_path_cfg3_reg,
+ 0x03, val);
}
if (SND_SOC_DAPM_EVENT_OFF(event)) {
@@ -1704,6 +1732,8 @@
0x01, 0x00);
snd_soc_component_update_bits(component, comp_ctl0_reg,
0x04, 0x00);
+ snd_soc_component_update_bits(component, rx_path_cfg3_reg,
+ 0x03, 0x03);
}
return 0;
@@ -3306,6 +3336,8 @@
{"RX INT0_1 MIX1 INP0", "RX5", "RX_RX5"},
{"RX INT0_1 MIX1 INP0", "IIR0", "IIR0"},
{"RX INT0_1 MIX1 INP0", "IIR1", "IIR1"},
+ {"RX INT0_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"},
+ {"RX INT0_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"},
{"RX INT0_1 MIX1 INP1", "RX0", "RX_RX0"},
{"RX INT0_1 MIX1 INP1", "RX1", "RX_RX1"},
{"RX INT0_1 MIX1 INP1", "RX2", "RX_RX2"},
@@ -3314,6 +3346,8 @@
{"RX INT0_1 MIX1 INP1", "RX5", "RX_RX5"},
{"RX INT0_1 MIX1 INP1", "IIR0", "IIR0"},
{"RX INT0_1 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX INT0_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"},
+ {"RX INT0_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"},
{"RX INT0_1 MIX1 INP2", "RX0", "RX_RX0"},
{"RX INT0_1 MIX1 INP2", "RX1", "RX_RX1"},
{"RX INT0_1 MIX1 INP2", "RX2", "RX_RX2"},
@@ -3322,6 +3356,8 @@
{"RX INT0_1 MIX1 INP2", "RX5", "RX_RX5"},
{"RX INT0_1 MIX1 INP2", "IIR0", "IIR0"},
{"RX INT0_1 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX INT0_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"},
+ {"RX INT0_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"},
{"RX INT1_1 MIX1 INP0", "RX0", "RX_RX0"},
{"RX INT1_1 MIX1 INP0", "RX1", "RX_RX1"},
@@ -3331,6 +3367,8 @@
{"RX INT1_1 MIX1 INP0", "RX5", "RX_RX5"},
{"RX INT1_1 MIX1 INP0", "IIR0", "IIR0"},
{"RX INT1_1 MIX1 INP0", "IIR1", "IIR1"},
+ {"RX INT1_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"},
+ {"RX INT1_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"},
{"RX INT1_1 MIX1 INP1", "RX0", "RX_RX0"},
{"RX INT1_1 MIX1 INP1", "RX1", "RX_RX1"},
{"RX INT1_1 MIX1 INP1", "RX2", "RX_RX2"},
@@ -3339,6 +3377,8 @@
{"RX INT1_1 MIX1 INP1", "RX5", "RX_RX5"},
{"RX INT1_1 MIX1 INP1", "IIR0", "IIR0"},
{"RX INT1_1 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX INT1_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"},
+ {"RX INT1_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"},
{"RX INT1_1 MIX1 INP2", "RX0", "RX_RX0"},
{"RX INT1_1 MIX1 INP2", "RX1", "RX_RX1"},
{"RX INT1_1 MIX1 INP2", "RX2", "RX_RX2"},
@@ -3347,6 +3387,8 @@
{"RX INT1_1 MIX1 INP2", "RX5", "RX_RX5"},
{"RX INT1_1 MIX1 INP2", "IIR0", "IIR0"},
{"RX INT1_1 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX INT1_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"},
+ {"RX INT1_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"},
{"RX INT2_1 MIX1 INP0", "RX0", "RX_RX0"},
{"RX INT2_1 MIX1 INP0", "RX1", "RX_RX1"},
@@ -3356,6 +3398,8 @@
{"RX INT2_1 MIX1 INP0", "RX5", "RX_RX5"},
{"RX INT2_1 MIX1 INP0", "IIR0", "IIR0"},
{"RX INT2_1 MIX1 INP0", "IIR1", "IIR1"},
+ {"RX INT2_1 MIX1 INP0", "DEC0", "RX_TX DEC0_INP"},
+ {"RX INT2_1 MIX1 INP0", "DEC1", "RX_TX DEC1_INP"},
{"RX INT2_1 MIX1 INP1", "RX0", "RX_RX0"},
{"RX INT2_1 MIX1 INP1", "RX1", "RX_RX1"},
{"RX INT2_1 MIX1 INP1", "RX2", "RX_RX2"},
@@ -3364,6 +3408,8 @@
{"RX INT2_1 MIX1 INP1", "RX5", "RX_RX5"},
{"RX INT2_1 MIX1 INP1", "IIR0", "IIR0"},
{"RX INT2_1 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX INT2_1 MIX1 INP1", "DEC0", "RX_TX DEC0_INP"},
+ {"RX INT2_1 MIX1 INP1", "DEC1", "RX_TX DEC1_INP"},
{"RX INT2_1 MIX1 INP2", "RX0", "RX_RX0"},
{"RX INT2_1 MIX1 INP2", "RX1", "RX_RX1"},
{"RX INT2_1 MIX1 INP2", "RX2", "RX_RX2"},
@@ -3372,6 +3418,8 @@
{"RX INT2_1 MIX1 INP2", "RX5", "RX_RX5"},
{"RX INT2_1 MIX1 INP2", "IIR0", "IIR0"},
{"RX INT2_1 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX INT2_1 MIX1 INP2", "DEC0", "RX_TX DEC0_INP"},
+ {"RX INT2_1 MIX1 INP2", "DEC1", "RX_TX DEC1_INP"},
{"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP0"},
{"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP1"},
@@ -3589,6 +3637,8 @@
mutex_lock(&rx_priv->swr_clk_lock);
+ trace_printk("%s: swrm clock %s\n",
+ __func__, (enable ? "enable" : "disable"));
dev_dbg(rx_priv->dev, "%s: swrm clock %s\n",
__func__, (enable ? "enable" : "disable"));
if (enable) {
@@ -3655,6 +3705,8 @@
}
}
}
+ trace_printk("%s: swrm clock users %d\n",
+ __func__, rx_priv->swr_clk_users);
dev_dbg(rx_priv->dev, "%s: swrm clock users %d\n",
__func__, rx_priv->swr_clk_users);
exit:
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index 31745d6..bccf0f8 100644
--- a/asoc/codecs/bolero/tx-macro.c
+++ b/asoc/codecs/bolero/tx-macro.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -40,12 +40,15 @@
#define TX_MACRO_MCLK_FREQ 9600000
#define TX_MACRO_TX_PATH_OFFSET 0x80
#define TX_MACRO_SWR_MIC_MUX_SEL_MASK 0xF
-#define TX_MACRO_ADC_MUX_CFG_OFFSET 0x2
+#define TX_MACRO_ADC_MUX_CFG_OFFSET 0x8
#define TX_MACRO_ADC_MODE_CFG0_SHIFT 1
-#define TX_MACRO_TX_UNMUTE_DELAY_MS 40
+#define TX_MACRO_DMIC_UNMUTE_DELAY_MS 40
+#define TX_MACRO_AMIC_UNMUTE_DELAY_MS 100
+#define TX_MACRO_DMIC_HPF_DELAY_MS 300
+#define TX_MACRO_AMIC_HPF_DELAY_MS 300
-static int tx_unmute_delay = TX_MACRO_TX_UNMUTE_DELAY_MS;
+static int tx_unmute_delay = TX_MACRO_DMIC_UNMUTE_DELAY_MS;
module_param(tx_unmute_delay, int, 0664);
MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path");
@@ -155,10 +158,6 @@
struct work_struct tx_macro_add_child_devices_work;
struct hpf_work tx_hpf_work[NUM_DECIMATORS];
struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS];
- s32 dmic_0_1_clk_cnt;
- s32 dmic_2_3_clk_cnt;
- s32 dmic_4_5_clk_cnt;
- s32 dmic_6_7_clk_cnt;
u16 dmic_clk_div;
u32 version;
u32 is_used_tx_swr_gpio;
@@ -222,19 +221,19 @@
mutex_lock(&tx_priv->mclk_lock);
if (mclk_enable) {
+ ret = bolero_clk_rsc_request_clock(tx_priv->dev,
+ TX_CORE_CLK,
+ TX_CORE_CLK,
+ true);
+ if (ret < 0) {
+ dev_err_ratelimited(tx_priv->dev,
+ "%s: request clock enable failed\n",
+ __func__);
+ goto exit;
+ }
+ bolero_clk_rsc_fs_gen_request(tx_priv->dev,
+ true);
if (tx_priv->tx_mclk_users == 0) {
- ret = bolero_clk_rsc_request_clock(tx_priv->dev,
- TX_CORE_CLK,
- TX_CORE_CLK,
- true);
- if (ret < 0) {
- dev_err_ratelimited(tx_priv->dev,
- "%s: request clock enable failed\n",
- __func__);
- goto exit;
- }
- bolero_clk_rsc_fs_gen_request(tx_priv->dev,
- true);
regcache_mark_dirty(regmap);
regcache_sync_region(regmap,
TX_START_OFFSET,
@@ -265,20 +264,32 @@
regmap_update_bits(regmap,
BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL,
0x01, 0x00);
- bolero_clk_rsc_fs_gen_request(tx_priv->dev,
- false);
-
- bolero_clk_rsc_request_clock(tx_priv->dev,
- TX_CORE_CLK,
- TX_CORE_CLK,
- false);
}
+
+ bolero_clk_rsc_fs_gen_request(tx_priv->dev,
+ false);
+ bolero_clk_rsc_request_clock(tx_priv->dev,
+ TX_CORE_CLK,
+ TX_CORE_CLK,
+ false);
}
exit:
mutex_unlock(&tx_priv->mclk_lock);
return ret;
}
+static int __tx_macro_mclk_enable(struct snd_soc_component *component,
+ bool enable)
+{
+ struct device *tx_dev = NULL;
+ struct tx_macro_priv *tx_priv = NULL;
+
+ if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
+ return -EINVAL;
+
+ return tx_macro_mclk_enable(tx_priv, enable);
+}
+
static int tx_macro_va_swr_clk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -362,12 +373,10 @@
switch (event) {
case BOLERO_MACRO_EVT_SSR_DOWN:
+ trace_printk("%s, enter SSR down\n", __func__);
if (tx_priv->swr_ctrl_data) {
swrm_wcd_notify(
tx_priv->swr_ctrl_data[0].tx_swr_pdev,
- SWR_DEVICE_DOWN, NULL);
- swrm_wcd_notify(
- tx_priv->swr_ctrl_data[0].tx_swr_pdev,
SWR_DEVICE_SSR_DOWN, NULL);
}
if ((!pm_runtime_enabled(tx_dev) ||
@@ -381,6 +390,7 @@
}
break;
case BOLERO_MACRO_EVT_SSR_UP:
+ trace_printk("%s, enter SSR up\n", __func__);
/* reset swr after ssr/pdr */
tx_priv->reset_swr = true;
if (tx_priv->swr_ctrl_data)
@@ -423,6 +433,33 @@
return ret;
}
+static bool is_amic_enabled(struct snd_soc_component *component, int decimator)
+{
+ u16 adc_mux_reg = 0, adc_reg = 0;
+ u16 adc_n = BOLERO_ADC_MAX;
+ bool ret = false;
+ struct device *tx_dev = NULL;
+ struct tx_macro_priv *tx_priv = NULL;
+
+ if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
+ return ret;
+
+ adc_mux_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
+ TX_MACRO_ADC_MUX_CFG_OFFSET * decimator;
+ if (snd_soc_component_read32(component, adc_mux_reg) & SWR_MIC) {
+ if (tx_priv->version == BOLERO_VERSION_2_1)
+ return true;
+ adc_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
+ TX_MACRO_ADC_MUX_CFG_OFFSET * decimator;
+ adc_n = snd_soc_component_read32(component, adc_reg) &
+ TX_MACRO_SWR_MIC_MUX_SEL_MASK;
+ if (adc_n < BOLERO_ADC_MAX)
+ return true;
+ }
+
+ return ret;
+}
+
static void tx_macro_tx_hpf_corner_freq_callback(struct work_struct *work)
{
struct delayed_work *hpf_delayed_work = NULL;
@@ -431,7 +468,7 @@
struct snd_soc_component *component = NULL;
u16 dec_cfg_reg = 0, hpf_gate_reg = 0;
u8 hpf_cut_off_freq = 0;
- u16 adc_mux_reg = 0, adc_n = 0, adc_reg = 0;
+ u16 adc_reg = 0, adc_n = 0;
hpf_delayed_work = to_delayed_work(work);
hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
@@ -447,26 +484,33 @@
dev_dbg(component->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n",
__func__, hpf_work->decimator, hpf_cut_off_freq);
- adc_mux_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
- TX_MACRO_ADC_MUX_CFG_OFFSET * hpf_work->decimator;
- if (snd_soc_component_read32(component, adc_mux_reg) & SWR_MIC) {
+ if (is_amic_enabled(component, hpf_work->decimator)) {
adc_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
TX_MACRO_ADC_MUX_CFG_OFFSET * hpf_work->decimator;
adc_n = snd_soc_component_read32(component, adc_reg) &
TX_MACRO_SWR_MIC_MUX_SEL_MASK;
- if (adc_n >= BOLERO_ADC_MAX)
- goto tx_hpf_set;
/* analog mic clear TX hold */
bolero_clear_amic_tx_hold(component->dev, adc_n);
+ snd_soc_component_update_bits(component,
+ dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK,
+ hpf_cut_off_freq << 5);
+ snd_soc_component_update_bits(component, hpf_gate_reg,
+ 0x03, 0x02);
+ /* Minimum 1 clk cycle delay is required as per HW spec */
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(component, hpf_gate_reg,
+ 0x03, 0x01);
+ } else {
+ snd_soc_component_update_bits(component,
+ dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK,
+ hpf_cut_off_freq << 5);
+ snd_soc_component_update_bits(component, hpf_gate_reg,
+ 0x02, 0x02);
+ /* Minimum 1 clk cycle delay is required as per HW spec */
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(component, hpf_gate_reg,
+ 0x02, 0x00);
}
-tx_hpf_set:
- snd_soc_component_update_bits(component,
- dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK,
- hpf_cut_off_freq << 5);
- snd_soc_component_update_bits(component, hpf_gate_reg, 0x02, 0x02);
- /* Minimum 1 clk cycle delay is required as per HW spec */
- usleep_range(1000, 1010);
- snd_soc_component_update_bits(component, hpf_gate_reg, 0x02, 0x00);
}
static void tx_macro_mute_update_callback(struct work_struct *work)
@@ -754,17 +798,9 @@
{
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
- u8 dmic_clk_en = 0x01;
- u16 dmic_clk_reg = 0;
- s32 *dmic_clk_cnt = NULL;
unsigned int dmic = 0;
int ret = 0;
char *wname = NULL;
- struct device *tx_dev = NULL;
- struct tx_macro_priv *tx_priv = NULL;
-
- if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
- return -EINVAL;
wname = strpbrk(w->name, "01234567");
if (!wname) {
@@ -779,54 +815,15 @@
return -EINVAL;
}
- switch (dmic) {
- case 0:
- case 1:
- dmic_clk_cnt = &(tx_priv->dmic_0_1_clk_cnt);
- dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL;
- break;
- case 2:
- case 3:
- dmic_clk_cnt = &(tx_priv->dmic_2_3_clk_cnt);
- dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL;
- break;
- case 4:
- case 5:
- dmic_clk_cnt = &(tx_priv->dmic_4_5_clk_cnt);
- dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL;
- break;
- case 6:
- case 7:
- dmic_clk_cnt = &(tx_priv->dmic_6_7_clk_cnt);
- dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL;
- break;
- default:
- dev_err(component->dev, "%s: Invalid DMIC Selection\n",
- __func__);
- return -EINVAL;
- }
- dev_dbg(component->dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n",
- __func__, event, dmic, *dmic_clk_cnt);
+ dev_dbg(component->dev, "%s: event %d DMIC%d\n",
+ __func__, event, dmic);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- (*dmic_clk_cnt)++;
- if (*dmic_clk_cnt == 1) {
- snd_soc_component_update_bits(component,
- BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
- 0x80, 0x00);
-
- snd_soc_component_update_bits(component, dmic_clk_reg,
- 0x0E, tx_priv->dmic_clk_div << 0x1);
- snd_soc_component_update_bits(component, dmic_clk_reg,
- dmic_clk_en, dmic_clk_en);
- }
+ bolero_dmic_clk_enable(component, dmic, DMIC_TX, true);
break;
case SND_SOC_DAPM_POST_PMD:
- (*dmic_clk_cnt)--;
- if (*dmic_clk_cnt == 0)
- snd_soc_component_update_bits(component, dmic_clk_reg,
- dmic_clk_en, 0);
+ bolero_dmic_clk_enable(component, dmic, DMIC_TX, false);
break;
}
@@ -844,8 +841,12 @@
u16 hpf_gate_reg = 0;
u16 tx_gain_ctl_reg = 0;
u8 hpf_cut_off_freq = 0;
+ int hpf_delay = TX_MACRO_DMIC_HPF_DELAY_MS;
+ int unmute_delay = TX_MACRO_DMIC_UNMUTE_DELAY_MS;
struct device *tx_dev = NULL;
struct tx_macro_priv *tx_priv = NULL;
+ u16 adc_mux_reg = 0, adc_reg = 0, adc_n = 0;
+ u16 dmic_clk_reg = 0;
if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
return -EINVAL;
@@ -866,6 +867,22 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ adc_mux_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1 +
+ TX_MACRO_ADC_MUX_CFG_OFFSET * decimator;
+ if (snd_soc_component_read32(component, adc_mux_reg) & SWR_MIC) {
+ adc_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0 +
+ TX_MACRO_ADC_MUX_CFG_OFFSET * decimator;
+ adc_n = snd_soc_component_read32(component, adc_reg) &
+ TX_MACRO_SWR_MIC_MUX_SEL_MASK;
+ if (adc_n >= BOLERO_ADC_MAX) {
+ dmic_clk_reg =
+ BOLERO_CDC_TX_TOP_CSR_SWR_DMIC0_CTL +
+ ((adc_n - 5) / 2) * 4;
+ snd_soc_component_update_bits(component,
+ dmic_clk_reg,
+ 0x0E, tx_priv->dmic_clk_div << 0x1);
+ }
+ }
snd_soc_component_update_bits(component,
dec_cfg_reg, 0x06, tx_priv->dec_mode[decimator] <<
TX_MACRO_ADC_MODE_CFG0_SHIFT);
@@ -876,13 +893,14 @@
case SND_SOC_DAPM_POST_PMU:
snd_soc_component_update_bits(component,
tx_vol_ctl_reg, 0x20, 0x20);
- snd_soc_component_update_bits(component,
- hpf_gate_reg, 0x01, 0x00);
- /*
- * Minimum 1 clk cycle delay is required as per HW spec
- */
- usleep_range(1000, 1010);
-
+ if (!is_amic_enabled(component, decimator)) {
+ snd_soc_component_update_bits(component,
+ hpf_gate_reg, 0x01, 0x00);
+ /*
+ * Minimum 1 clk cycle delay is required as per HW spec
+ */
+ usleep_range(1000, 1010);
+ }
hpf_cut_off_freq = (
snd_soc_component_read32(component, dec_cfg_reg) &
TX_HPF_CUT_OFF_FREQ_MASK) >> 5;
@@ -895,22 +913,35 @@
TX_HPF_CUT_OFF_FREQ_MASK,
CF_MIN_3DB_150HZ << 5);
+ if (is_amic_enabled(component, decimator)) {
+ hpf_delay = TX_MACRO_AMIC_HPF_DELAY_MS;
+ unmute_delay = TX_MACRO_AMIC_UNMUTE_DELAY_MS;
+ }
+ if (tx_unmute_delay < unmute_delay)
+ tx_unmute_delay = unmute_delay;
/* schedule work queue to Remove Mute */
schedule_delayed_work(&tx_priv->tx_mute_dwork[decimator].dwork,
msecs_to_jiffies(tx_unmute_delay));
if (tx_priv->tx_hpf_work[decimator].hpf_cut_off_freq !=
CF_MIN_3DB_150HZ) {
schedule_delayed_work(
- &tx_priv->tx_hpf_work[decimator].dwork,
- msecs_to_jiffies(300));
+ &tx_priv->tx_hpf_work[decimator].dwork,
+ msecs_to_jiffies(hpf_delay));
snd_soc_component_update_bits(component,
- hpf_gate_reg, 0x03, 0x03);
+ hpf_gate_reg, 0x03, 0x02);
+ if (!is_amic_enabled(component, decimator))
+ snd_soc_component_update_bits(component,
+ hpf_gate_reg, 0x03, 0x00);
/*
* Minimum 1 clk cycle delay is required as per HW spec
*/
usleep_range(1000, 1010);
snd_soc_component_update_bits(component,
- hpf_gate_reg, 0x02, 0x00);
+ hpf_gate_reg, 0x03, 0x01);
+ /*
+ * 6ms delay is required as per HW spec
+ */
+ usleep_range(6000, 6010);
}
/* apply gain after decimator is enabled */
snd_soc_component_write(component, tx_gain_ctl_reg,
@@ -938,9 +969,15 @@
component, dec_cfg_reg,
TX_HPF_CUT_OFF_FREQ_MASK,
hpf_cut_off_freq << 5);
- snd_soc_component_update_bits(component,
- hpf_gate_reg,
- 0x02, 0x02);
+ if (is_amic_enabled(component, decimator))
+ snd_soc_component_update_bits(component,
+ hpf_gate_reg,
+ 0x03, 0x02);
+ else
+ snd_soc_component_update_bits(component,
+ hpf_gate_reg,
+ 0x03, 0x03);
+
/*
* Minimum 1 clk cycle delay is required
* as per HW spec
@@ -948,7 +985,7 @@
usleep_range(1000, 1010);
snd_soc_component_update_bits(component,
hpf_gate_reg,
- 0x02, 0x00);
+ 0x03, 0x01);
}
}
cancel_delayed_work_sync(
@@ -2311,7 +2348,8 @@
"%s: priv is null for macro!\n", __func__);
return -EINVAL;
}
- if (tx_priv->swr_ctrl_data) {
+ if (tx_priv->swr_ctrl_data &&
+ (!tx_priv->tx_swr_clk_cnt || !tx_priv->va_swr_clk_cnt)) {
if (enable) {
ret = swrm_wcd_notify(
tx_priv->swr_ctrl_data[0].tx_swr_pdev,
@@ -2336,6 +2374,9 @@
{
int ret = 0, clk_tx_ret = 0;
+ trace_printk("%s: clock type %s, enable: %s tx_mclk_users: %d\n",
+ __func__, (clk_type ? "VA_MCLK" : "TX_MCLK"),
+ (enable ? "enable" : "disable"), tx_priv->tx_mclk_users);
dev_dbg(tx_priv->dev,
"%s: clock type %s, enable: %s tx_mclk_users: %d\n",
__func__, (clk_type ? "VA_MCLK" : "TX_MCLK"),
@@ -2343,6 +2384,7 @@
if (enable) {
if (tx_priv->swr_clk_users == 0) {
+ trace_printk("%s: tx swr clk users 0\n", __func__);
ret = msm_cdc_pinctrl_select_active_state(
tx_priv->tx_swr_gpio_p);
if (ret < 0) {
@@ -2358,6 +2400,7 @@
TX_CORE_CLK,
true);
if (clk_type == TX_MCLK) {
+ trace_printk("%s: requesting TX_MCLK\n", __func__);
ret = tx_macro_mclk_enable(tx_priv, 1);
if (ret < 0) {
if (tx_priv->swr_clk_users == 0)
@@ -2370,6 +2413,7 @@
}
}
if (clk_type == VA_MCLK) {
+ trace_printk("%s: requesting VA_MCLK\n", __func__);
ret = bolero_clk_rsc_request_clock(tx_priv->dev,
TX_CORE_CLK,
VA_CORE_CLK,
@@ -2390,16 +2434,19 @@
BOLERO_CDC_TX_TOP_CSR_FREQ_MCLK,
0x01, 0x01);
regmap_update_bits(regmap,
- BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL,
+ BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL,
0x01, 0x01);
regmap_update_bits(regmap,
- BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL,
+ BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL,
0x01, 0x01);
}
+ tx_priv->tx_mclk_users++;
}
if (tx_priv->swr_clk_users == 0) {
dev_dbg(tx_priv->dev, "%s: reset_swr: %d\n",
__func__, tx_priv->reset_swr);
+ trace_printk("%s: reset_swr: %d\n",
+ __func__, tx_priv->reset_swr);
if (tx_priv->reset_swr)
regmap_update_bits(regmap,
BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
@@ -2438,16 +2485,24 @@
if (clk_type == TX_MCLK)
tx_macro_mclk_enable(tx_priv, 0);
if (clk_type == VA_MCLK) {
+ if (tx_priv->tx_mclk_users <= 0) {
+ dev_err(tx_priv->dev, "%s: clock already disabled\n",
+ __func__);
+ tx_priv->tx_mclk_users = 0;
+ goto tx_clk;
+ }
+ tx_priv->tx_mclk_users--;
if (tx_priv->tx_mclk_users == 0) {
regmap_update_bits(regmap,
- BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL,
+ BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL,
0x01, 0x00);
regmap_update_bits(regmap,
- BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL,
+ BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL,
0x01, 0x00);
}
+
bolero_clk_rsc_fs_gen_request(tx_priv->dev,
- false);
+ false);
ret = bolero_clk_rsc_request_clock(tx_priv->dev,
TX_CORE_CLK,
VA_CORE_CLK,
@@ -2459,6 +2514,7 @@
goto done;
}
}
+tx_clk:
if (!clk_tx_ret)
ret = bolero_clk_rsc_request_clock(tx_priv->dev,
TX_CORE_CLK,
@@ -2484,10 +2540,22 @@
TX_CORE_CLK,
false);
exit:
+ trace_printk("%s: exit\n", __func__);
return ret;
}
-static int tx_macro_clk_switch(struct snd_soc_component *component)
+static int tx_macro_clk_div_get(struct snd_soc_component *component)
+{
+ struct device *tx_dev = NULL;
+ struct tx_macro_priv *tx_priv = NULL;
+
+ if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
+ return -EINVAL;
+
+ return tx_priv->dmic_clk_div;
+}
+
+static int tx_macro_clk_switch(struct snd_soc_component *component, int clk_src)
{
struct device *tx_dev = NULL;
struct tx_macro_priv *tx_priv = NULL;
@@ -2511,7 +2579,7 @@
if (tx_priv->swr_ctrl_data) {
ret = swrm_wcd_notify(
tx_priv->swr_ctrl_data[0].tx_swr_pdev,
- SWR_REQ_CLK_SWITCH, NULL);
+ SWR_REQ_CLK_SWITCH, &clk_src);
}
return ret;
@@ -2549,6 +2617,10 @@
}
mutex_lock(&tx_priv->swr_clk_lock);
+ trace_printk("%s: swrm clock %s tx_swr_clk_cnt: %d va_swr_clk_cnt: %d\n",
+ __func__,
+ (enable ? "enable" : "disable"),
+ tx_priv->tx_swr_clk_cnt, tx_priv->va_swr_clk_cnt);
dev_dbg(tx_priv->dev,
"%s: swrm clock %s tx_swr_clk_cnt: %d va_swr_clk_cnt: %d\n",
__func__, (enable ? "enable" : "disable"),
@@ -2611,6 +2683,9 @@
}
}
+ trace_printk("%s: swrm clock users %d tx_clk_sts_cnt: %d va_clk_sts_cnt: %d\n",
+ __func__, tx_priv->swr_clk_users, tx_priv->tx_clk_status,
+ tx_priv->va_clk_status);
dev_dbg(tx_priv->dev,
"%s: swrm clock users %d tx_clk_sts_cnt: %d va_clk_sts_cnt: %d\n",
__func__, tx_priv->swr_clk_users, tx_priv->tx_clk_status,
@@ -2671,7 +2746,7 @@
}
static const struct tx_macro_reg_mask_val tx_macro_reg_init[] = {
- {BOLERO_CDC_TX0_TX_PATH_SEC7, 0x3F, 0x02},
+ {BOLERO_CDC_TX0_TX_PATH_SEC7, 0x3F, 0x0A},
};
static int tx_macro_init(struct snd_soc_component *component)
@@ -2845,10 +2920,10 @@
if (tx_priv->version == BOLERO_VERSION_2_1)
snd_soc_component_update_bits(component,
- BOLERO_CDC_VA_TOP_CSR_SWR_CTRL, 0xF0, 0xA0);
+ BOLERO_CDC_VA_TOP_CSR_SWR_CTRL, 0x0F, 0x0A);
else if (tx_priv->version == BOLERO_VERSION_2_0)
snd_soc_component_update_bits(component,
- BOLERO_CDC_TX_TOP_CSR_SWR_CTRL, 0xF0, 0xA0);
+ BOLERO_CDC_TX_TOP_CSR_SWR_CTRL, 0x0F, 0x0A);
return 0;
}
@@ -3008,8 +3083,10 @@
ops->event_handler = tx_macro_event_handler;
ops->reg_wake_irq = tx_macro_reg_wake_irq;
ops->set_port_map = tx_macro_set_port_map;
+ ops->clk_div_get = tx_macro_clk_div_get;
ops->clk_switch = tx_macro_clk_switch;
ops->reg_evt_listener = tx_macro_register_event_listener;
+ ops->clk_enable = __tx_macro_mclk_enable;
}
static int tx_macro_probe(struct platform_device *pdev)
diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c
index c5f0ef9..85d4ae3 100644
--- a/asoc/codecs/bolero/va-macro.c
+++ b/asoc/codecs/bolero/va-macro.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -44,16 +44,19 @@
#define VA_MACRO_TX_DMIC_CLK_DIV_MASK 0x0E
#define VA_MACRO_TX_DMIC_CLK_DIV_SHFT 0x01
#define VA_MACRO_SWR_MIC_MUX_SEL_MASK 0xF
-#define VA_MACRO_ADC_MUX_CFG_OFFSET 0x2
+#define VA_MACRO_ADC_MUX_CFG_OFFSET 0x8
+#define VA_MACRO_ADC_MODE_CFG0_SHIFT 1
-#define BOLERO_CDC_VA_TX_UNMUTE_DELAY_MS 40
+#define BOLERO_CDC_VA_TX_DMIC_UNMUTE_DELAY_MS 40
+#define BOLERO_CDC_VA_TX_AMIC_UNMUTE_DELAY_MS 100
+#define BOLERO_CDC_VA_TX_DMIC_HPF_DELAY_MS 300
+#define BOLERO_CDC_VA_TX_AMIC_HPF_DELAY_MS 300
#define MAX_RETRY_ATTEMPTS 500
-
#define VA_MACRO_SWR_STRING_LEN 80
#define VA_MACRO_CHILD_DEVICES_MAX 3
static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
-static int va_tx_unmute_delay = BOLERO_CDC_VA_TX_UNMUTE_DELAY_MS;
+static int va_tx_unmute_delay = BOLERO_CDC_VA_TX_DMIC_UNMUTE_DELAY_MS;
module_param(va_tx_unmute_delay, int, 0664);
MODULE_PARM_DESC(va_tx_unmute_delay, "delay to unmute the tx path");
@@ -120,6 +123,7 @@
int (*write)(void *handle, int reg, int val);
int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
int (*clk)(void *handle, bool enable);
+ int (*core_vote)(void *handle, bool enable);
int (*handle_irq)(void *handle,
irqreturn_t (*swrm_irq_handler)(int irq,
void *data),
@@ -139,10 +143,6 @@
struct va_mute_work va_mute_dwork[VA_MACRO_NUM_DECIMATORS];
unsigned long active_ch_mask[VA_MACRO_MAX_DAIS];
unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS];
- s32 dmic_0_1_clk_cnt;
- s32 dmic_2_3_clk_cnt;
- s32 dmic_4_5_clk_cnt;
- s32 dmic_6_7_clk_cnt;
u16 dmic_clk_div;
u16 va_mclk_users;
int swr_clk_users;
@@ -169,6 +169,9 @@
int va_swr_clk_cnt;
int va_clk_status;
int tx_clk_status;
+ bool lpi_enable;
+ bool register_event_listener;
+ int dec_mode[VA_MACRO_NUM_DECIMATORS];
};
static bool va_macro_get_data(struct snd_soc_component *component,
@@ -191,6 +194,22 @@
return true;
}
+static int va_macro_clk_div_get(struct snd_soc_component *component)
+{
+ struct device *va_dev = NULL;
+ struct va_macro_priv *va_priv = NULL;
+
+ if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
+ return -EINVAL;
+
+ if ((va_priv->version >= BOLERO_VERSION_2_0)
+ && !va_priv->lpi_enable
+ && (va_priv->dmic_clk_div == VA_MACRO_CLK_DIV_16))
+ return VA_MACRO_CLK_DIV_8;
+
+ return va_priv->dmic_clk_div;
+}
+
static int va_macro_mclk_enable(struct va_macro_priv *va_priv,
bool mclk_enable, bool dapm)
{
@@ -207,19 +226,19 @@
mutex_lock(&va_priv->mclk_lock);
if (mclk_enable) {
+ ret = bolero_clk_rsc_request_clock(va_priv->dev,
+ va_priv->default_clk_id,
+ va_priv->clk_id,
+ true);
+ if (ret < 0) {
+ dev_err(va_priv->dev,
+ "%s: va request clock en failed\n",
+ __func__);
+ goto exit;
+ }
+ bolero_clk_rsc_fs_gen_request(va_priv->dev,
+ true);
if (va_priv->va_mclk_users == 0) {
- ret = bolero_clk_rsc_request_clock(va_priv->dev,
- va_priv->default_clk_id,
- va_priv->clk_id,
- true);
- if (ret < 0) {
- dev_err(va_priv->dev,
- "%s: va request clock en failed\n",
- __func__);
- goto exit;
- }
- bolero_clk_rsc_fs_gen_request(va_priv->dev,
- true);
regcache_mark_dirty(regmap);
regcache_sync_region(regmap,
VA_START_OFFSET,
@@ -234,14 +253,12 @@
goto exit;
}
va_priv->va_mclk_users--;
- if (va_priv->va_mclk_users == 0) {
- bolero_clk_rsc_fs_gen_request(va_priv->dev,
- false);
- bolero_clk_rsc_request_clock(va_priv->dev,
- va_priv->default_clk_id,
- va_priv->clk_id,
- false);
- }
+ bolero_clk_rsc_fs_gen_request(va_priv->dev,
+ false);
+ bolero_clk_rsc_request_clock(va_priv->dev,
+ va_priv->default_clk_id,
+ va_priv->clk_id,
+ false);
}
exit:
mutex_unlock(&va_priv->mclk_lock);
@@ -281,6 +298,7 @@
__func__);
break;
case BOLERO_MACRO_EVT_SSR_UP:
+ trace_printk("%s, enter SSR up\n", __func__);
/* enable&disable VA_CORE_CLK to reset GFMUX reg */
ret = bolero_clk_rsc_request_clock(va_priv->dev,
va_priv->default_clk_id,
@@ -307,9 +325,6 @@
if (va_priv->swr_ctrl_data) {
swrm_wcd_notify(
va_priv->swr_ctrl_data[0].va_swr_pdev,
- SWR_DEVICE_DOWN, NULL);
- swrm_wcd_notify(
- va_priv->swr_ctrl_data[0].va_swr_pdev,
SWR_DEVICE_SSR_DOWN, NULL);
}
if ((!pm_runtime_enabled(va_dev) ||
@@ -328,6 +343,32 @@
return 0;
}
+static int va_macro_swr_clk_event_v2(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct device *va_dev = NULL;
+ struct va_macro_priv *va_priv = NULL;
+
+ if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
+ return -EINVAL;
+
+ dev_dbg(va_dev, "%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ va_priv->va_swr_clk_cnt++;
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ va_priv->va_swr_clk_cnt--;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
static int va_macro_swr_pwr_event_v2(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -336,18 +377,24 @@
int ret = 0;
struct device *va_dev = NULL;
struct va_macro_priv *va_priv = NULL;
+ int clk_src = 0;
if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
return -EINVAL;
- dev_dbg(va_dev, "%s: event = %d\n", __func__, event);
+ dev_dbg(va_dev, "%s: event = %d, lpi_enable = %d\n",
+ __func__, event, va_priv->lpi_enable);
+
+ if (!va_priv->lpi_enable)
+ return ret;
+
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- va_priv->va_swr_clk_cnt++;
if (va_priv->swr_ctrl_data) {
+ clk_src = CLK_SRC_VA_RCG;
ret = swrm_wcd_notify(
va_priv->swr_ctrl_data[0].va_swr_pdev,
- SWR_REQ_CLK_SWITCH, NULL);
+ SWR_REQ_CLK_SWITCH, &clk_src);
if (ret)
dev_dbg(va_dev, "%s: clock switch failed\n",
__func__);
@@ -359,14 +406,14 @@
msm_cdc_pinctrl_set_wakeup_capable(
va_priv->va_swr_gpio_p, true);
if (va_priv->swr_ctrl_data) {
+ clk_src = CLK_SRC_TX_RCG;
ret = swrm_wcd_notify(
va_priv->swr_ctrl_data[0].va_swr_pdev,
- SWR_REQ_CLK_SWITCH, NULL);
+ SWR_REQ_CLK_SWITCH, &clk_src);
if (ret)
dev_dbg(va_dev, "%s: clock switch failed\n",
__func__);
}
- va_priv->va_swr_clk_cnt--;
break;
default:
dev_err(va_priv->dev,
@@ -388,7 +435,12 @@
if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
return -EINVAL;
- dev_dbg(va_dev, "%s: event = %d\n", __func__, event);
+ dev_dbg(va_dev, "%s: event = %d, lpi_enable = %d\n",
+ __func__, event, va_priv->lpi_enable);
+
+ if (!va_priv->lpi_enable)
+ return ret;
+
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (va_priv->lpass_audio_hw_vote) {
@@ -399,14 +451,20 @@
__func__);
}
if (!ret)
- if (bolero_tx_clk_switch(component))
+ if (bolero_tx_clk_switch(component, CLK_SRC_VA_RCG))
dev_dbg(va_dev, "%s: clock switch failed\n",
__func__);
- bolero_register_event_listener(component, true);
+ if (va_priv->lpi_enable) {
+ bolero_register_event_listener(component, true);
+ va_priv->register_event_listener = true;
+ }
break;
case SND_SOC_DAPM_POST_PMD:
- bolero_register_event_listener(component, false);
- if (bolero_tx_clk_switch(component))
+ if (va_priv->register_event_listener) {
+ va_priv->register_event_listener = false;
+ bolero_register_event_listener(component, false);
+ }
+ if (bolero_tx_clk_switch(component, CLK_SRC_TX_RCG))
dev_dbg(va_dev, "%s: clock switch failed\n",__func__);
if (va_priv->lpass_audio_hw_vote)
clk_disable_unprepare(va_priv->lpass_audio_hw_vote);
@@ -446,6 +504,7 @@
int ret = 0;
struct device *va_dev = NULL;
struct va_macro_priv *va_priv = NULL;
+ int clk_src = 0;
if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
return -EINVAL;
@@ -459,12 +518,35 @@
true);
if (!ret)
va_priv->tx_clk_status++;
- ret = va_macro_mclk_enable(va_priv, 1, true);
+
+ if (va_priv->lpi_enable)
+ ret = va_macro_mclk_enable(va_priv, 1, true);
+ else
+ ret = bolero_tx_mclk_enable(component, 1);
break;
case SND_SOC_DAPM_POST_PMD:
- if (bolero_tx_clk_switch(component))
- dev_dbg(va_dev, "%s: clock switch failed\n",__func__);
- va_macro_mclk_enable(va_priv, 0, true);
+ if (va_priv->lpi_enable) {
+ if (va_priv->version == BOLERO_VERSION_2_1) {
+ if (va_priv->swr_ctrl_data) {
+ clk_src = CLK_SRC_TX_RCG;
+ ret = swrm_wcd_notify(
+ va_priv->swr_ctrl_data[0].va_swr_pdev,
+ SWR_REQ_CLK_SWITCH, &clk_src);
+ if (ret)
+ dev_dbg(va_dev,
+ "%s: clock switch failed\n",
+ __func__);
+ }
+ } else if (bolero_tx_clk_switch(component,
+ CLK_SRC_TX_RCG)) {
+ dev_dbg(va_dev, "%s: clock switch failed\n",
+ __func__);
+ }
+ va_macro_mclk_enable(va_priv, 0, true);
+ } else {
+ bolero_tx_mclk_enable(component, 0);
+ }
+
if (va_priv->tx_clk_status > 0) {
bolero_clk_rsc_request_clock(va_priv->dev,
va_priv->default_clk_id,
@@ -603,6 +685,26 @@
return ret;
}
+static int va_macro_core_vote(void *handle, bool enable)
+{
+ struct va_macro_priv *va_priv = (struct va_macro_priv *) handle;
+
+ if (va_priv == NULL) {
+ pr_err("%s: va priv data is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (enable) {
+ pm_runtime_get_sync(va_priv->dev);
+ pm_runtime_put_autosuspend(va_priv->dev);
+ pm_runtime_mark_last_busy(va_priv->dev);
+ }
+
+ if (bolero_check_core_votes(va_priv->dev))
+ return 0;
+ else
+ return -EINVAL;
+}
+
static int va_macro_swrm_clock(void *handle, bool enable)
{
struct va_macro_priv *va_priv = (struct va_macro_priv *) handle;
@@ -625,14 +727,20 @@
if (va_priv->va_swr_clk_cnt && !va_priv->tx_swr_clk_cnt) {
ret = va_macro_tx_va_mclk_enable(va_priv, regmap,
VA_MCLK, enable);
- if (ret)
+ if (ret) {
+ pm_runtime_mark_last_busy(va_priv->dev);
+ pm_runtime_put_autosuspend(va_priv->dev);
goto done;
+ }
va_priv->va_clk_status++;
} else {
ret = va_macro_tx_va_mclk_enable(va_priv, regmap,
TX_MCLK, enable);
- if (ret)
+ if (ret) {
+ pm_runtime_mark_last_busy(va_priv->dev);
+ pm_runtime_put_autosuspend(va_priv->dev);
goto done;
+ }
va_priv->tx_clk_status++;
}
pm_runtime_mark_last_busy(va_priv->dev);
@@ -679,6 +787,33 @@
return ret;
}
+static bool is_amic_enabled(struct snd_soc_component *component, int decimator)
+{
+ u16 adc_mux_reg = 0, adc_reg = 0;
+ u16 adc_n = BOLERO_ADC_MAX;
+ bool ret = false;
+ struct device *va_dev = NULL;
+ struct va_macro_priv *va_priv = NULL;
+
+ if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
+ return ret;
+
+ adc_mux_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1 +
+ VA_MACRO_ADC_MUX_CFG_OFFSET * decimator;
+ if (snd_soc_component_read32(component, adc_mux_reg) & SWR_MIC) {
+ if (va_priv->version == BOLERO_VERSION_2_1)
+ return true;
+ adc_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0 +
+ VA_MACRO_ADC_MUX_CFG_OFFSET * decimator;
+ adc_n = snd_soc_component_read32(component, adc_reg) &
+ VA_MACRO_SWR_MIC_MUX_SEL_MASK;
+ if (adc_n < BOLERO_ADC_MAX)
+ return true;
+ }
+
+ return ret;
+}
+
static void va_macro_tx_hpf_corner_freq_callback(struct work_struct *work)
{
struct delayed_work *hpf_delayed_work;
@@ -687,7 +822,7 @@
struct snd_soc_component *component;
u16 dec_cfg_reg, hpf_gate_reg;
u8 hpf_cut_off_freq;
- u16 adc_mux_reg = 0, adc_n = 0, adc_reg = 0;
+ u16 adc_reg = 0, adc_n = 0;
hpf_delayed_work = to_delayed_work(work);
hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
@@ -703,26 +838,33 @@
dev_dbg(va_priv->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n",
__func__, hpf_work->decimator, hpf_cut_off_freq);
- adc_mux_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1 +
- VA_MACRO_ADC_MUX_CFG_OFFSET * hpf_work->decimator;
- if (snd_soc_component_read32(component, adc_mux_reg) & SWR_MIC) {
+ if (is_amic_enabled(component, hpf_work->decimator)) {
adc_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0 +
VA_MACRO_ADC_MUX_CFG_OFFSET * hpf_work->decimator;
adc_n = snd_soc_component_read32(component, adc_reg) &
VA_MACRO_SWR_MIC_MUX_SEL_MASK;
- if (adc_n >= BOLERO_ADC_MAX)
- goto va_hpf_set;
/* analog mic clear TX hold */
bolero_clear_amic_tx_hold(component->dev, adc_n);
+ snd_soc_component_update_bits(component,
+ dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK,
+ hpf_cut_off_freq << 5);
+ snd_soc_component_update_bits(component, hpf_gate_reg,
+ 0x03, 0x02);
+ /* Minimum 1 clk cycle delay is required as per HW spec */
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(component, hpf_gate_reg,
+ 0x03, 0x01);
+ } else {
+ snd_soc_component_update_bits(component,
+ dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK,
+ hpf_cut_off_freq << 5);
+ snd_soc_component_update_bits(component, hpf_gate_reg,
+ 0x02, 0x02);
+ /* Minimum 1 clk cycle delay is required as per HW spec */
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(component, hpf_gate_reg,
+ 0x02, 0x00);
}
-va_hpf_set:
- snd_soc_component_update_bits(component,
- dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK,
- hpf_cut_off_freq << 5);
- snd_soc_component_update_bits(component, hpf_gate_reg, 0x02, 0x02);
- /* Minimum 1 clk cycle delay is required as per HW spec */
- usleep_range(1000, 1010);
- snd_soc_component_update_bits(component, hpf_gate_reg, 0x02, 0x00);
}
static void va_macro_mute_update_callback(struct work_struct *work)
@@ -831,6 +973,38 @@
return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
}
+static int va_macro_lpi_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct device *va_dev = NULL;
+ struct va_macro_priv *va_priv = NULL;
+
+ if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
+ return -EINVAL;
+
+ ucontrol->value.integer.value[0] = va_priv->lpi_enable;
+
+ return 0;
+}
+
+static int va_macro_lpi_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct device *va_dev = NULL;
+ struct va_macro_priv *va_priv = NULL;
+
+ if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
+ return -EINVAL;
+
+ va_priv->lpi_enable = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
static int va_macro_tx_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -892,81 +1066,32 @@
{
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
- u8 dmic_clk_en = 0x01;
- u16 dmic_clk_reg;
- s32 *dmic_clk_cnt;
- unsigned int dmic;
- int ret;
+ unsigned int dmic = 0;
+ int ret = 0;
char *wname;
- struct device *va_dev = NULL;
- struct va_macro_priv *va_priv = NULL;
-
- if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
- return -EINVAL;
wname = strpbrk(w->name, "01234567");
if (!wname) {
- dev_err(va_dev, "%s: widget not found\n", __func__);
+ dev_err(component->dev, "%s: widget not found\n", __func__);
return -EINVAL;
}
ret = kstrtouint(wname, 10, &dmic);
if (ret < 0) {
- dev_err(va_dev, "%s: Invalid DMIC line on the codec\n",
+ dev_err(component->dev, "%s: Invalid DMIC line on the codec\n",
__func__);
return -EINVAL;
}
- switch (dmic) {
- case 0:
- case 1:
- dmic_clk_cnt = &(va_priv->dmic_0_1_clk_cnt);
- dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL;
- break;
- case 2:
- case 3:
- dmic_clk_cnt = &(va_priv->dmic_2_3_clk_cnt);
- dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL;
- break;
- case 4:
- case 5:
- dmic_clk_cnt = &(va_priv->dmic_4_5_clk_cnt);
- dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL;
- break;
- case 6:
- case 7:
- dmic_clk_cnt = &(va_priv->dmic_6_7_clk_cnt);
- dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL;
- break;
- default:
- dev_err(va_dev, "%s: Invalid DMIC Selection\n",
- __func__);
- return -EINVAL;
- }
- dev_dbg(va_dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n",
- __func__, event, dmic, *dmic_clk_cnt);
+ dev_dbg(component->dev, "%s: event %d DMIC%d\n",
+ __func__, event, dmic);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- (*dmic_clk_cnt)++;
- if (*dmic_clk_cnt == 1) {
- snd_soc_component_update_bits(component,
- BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
- 0x80, 0x00);
- snd_soc_component_update_bits(component, dmic_clk_reg,
- VA_MACRO_TX_DMIC_CLK_DIV_MASK,
- va_priv->dmic_clk_div <<
- VA_MACRO_TX_DMIC_CLK_DIV_SHFT);
- snd_soc_component_update_bits(component, dmic_clk_reg,
- dmic_clk_en, dmic_clk_en);
- }
+ bolero_dmic_clk_enable(component, dmic, DMIC_VA, true);
break;
case SND_SOC_DAPM_POST_PMD:
- (*dmic_clk_cnt)--;
- if (*dmic_clk_cnt == 0) {
- snd_soc_component_update_bits(component, dmic_clk_reg,
- dmic_clk_en, 0);
- }
+ bolero_dmic_clk_enable(component, dmic, DMIC_VA, false);
break;
}
@@ -984,6 +1109,8 @@
u8 hpf_cut_off_freq;
struct device *va_dev = NULL;
struct va_macro_priv *va_priv = NULL;
+ int hpf_delay = BOLERO_CDC_VA_TX_DMIC_HPF_DELAY_MS;
+ int unmute_delay = BOLERO_CDC_VA_TX_DMIC_UNMUTE_DELAY_MS;
if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
return -EINVAL;
@@ -1004,6 +1131,9 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component,
+ dec_cfg_reg, 0x06, va_priv->dec_mode[decimator] <<
+ VA_MACRO_ADC_MODE_CFG0_SHIFT);
/* Enable TX PGA Mute */
snd_soc_component_update_bits(component,
tx_vol_ctl_reg, 0x10, 0x10);
@@ -1012,13 +1142,14 @@
/* Enable TX CLK */
snd_soc_component_update_bits(component,
tx_vol_ctl_reg, 0x20, 0x20);
- snd_soc_component_update_bits(component,
+ if (!is_amic_enabled(component, decimator)) {
+ snd_soc_component_update_bits(component,
hpf_gate_reg, 0x01, 0x00);
- /*
- * Minimum 1 clk cycle delay is required as per HW spec
- */
- usleep_range(1000, 1010);
-
+ /*
+ * Minimum 1 clk cycle delay is required as per HW spec
+ */
+ usleep_range(1000, 1010);
+ }
hpf_cut_off_freq = (snd_soc_component_read32(
component, dec_cfg_reg) &
TX_HPF_CUT_OFF_FREQ_MASK) >> 5;
@@ -1029,15 +1160,28 @@
snd_soc_component_update_bits(component, dec_cfg_reg,
TX_HPF_CUT_OFF_FREQ_MASK,
CF_MIN_3DB_150HZ << 5);
- snd_soc_component_update_bits(component,
- hpf_gate_reg, 0x03, 0x03);
- /*
- * Minimum 1 clk cycle delay is required as per HW spec
- */
- usleep_range(1000, 1010);
- snd_soc_component_update_bits(component,
- hpf_gate_reg, 0x02, 0x00);
}
+ if (is_amic_enabled(component, decimator)) {
+ hpf_delay = BOLERO_CDC_VA_TX_AMIC_HPF_DELAY_MS;
+ unmute_delay = BOLERO_CDC_VA_TX_AMIC_UNMUTE_DELAY_MS;
+ if (va_tx_unmute_delay < unmute_delay)
+ va_tx_unmute_delay = unmute_delay;
+ }
+ snd_soc_component_update_bits(component,
+ hpf_gate_reg, 0x03, 0x02);
+ if (!is_amic_enabled(component, decimator))
+ snd_soc_component_update_bits(component,
+ hpf_gate_reg, 0x03, 0x00);
+ /*
+ * Minimum 1 clk cycle delay is required as per HW spec
+ */
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(component,
+ hpf_gate_reg, 0x03, 0x01);
+ /*
+ * 6ms delay is required as per HW spec
+ */
+ usleep_range(6000, 6010);
/* schedule work queue to Remove Mute */
schedule_delayed_work(&va_priv->va_mute_dwork[decimator].dwork,
msecs_to_jiffies(va_tx_unmute_delay));
@@ -1045,7 +1189,7 @@
CF_MIN_3DB_150HZ)
schedule_delayed_work(
&va_priv->va_hpf_work[decimator].dwork,
- msecs_to_jiffies(50));
+ msecs_to_jiffies(hpf_delay));
/* apply gain after decimator is enabled */
snd_soc_component_write(component, tx_gain_ctl_reg,
snd_soc_component_read32(component, tx_gain_ctl_reg));
@@ -1062,9 +1206,14 @@
dec_cfg_reg,
TX_HPF_CUT_OFF_FREQ_MASK,
hpf_cut_off_freq << 5);
- snd_soc_component_update_bits(component,
+ if (is_amic_enabled(component, decimator))
+ snd_soc_component_update_bits(component,
hpf_gate_reg,
- 0x02, 0x02);
+ 0x03, 0x02);
+ else
+ snd_soc_component_update_bits(component,
+ hpf_gate_reg,
+ 0x03, 0x03);
/*
* Minimum 1 clk cycle delay is required
* as per HW spec
@@ -1072,7 +1221,7 @@
usleep_range(1000, 1010);
snd_soc_component_update_bits(component,
hpf_gate_reg,
- 0x02, 0x00);
+ 0x03, 0x01);
}
}
cancel_delayed_work_sync(
@@ -1105,8 +1254,6 @@
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- if (bolero_tx_clk_switch(component))
- dev_dbg(va_dev, "%s: clock switch failed\n",__func__);
if (va_priv->tx_clk_status > 0) {
ret = bolero_clk_rsc_request_clock(va_priv->dev,
va_priv->default_clk_id,
@@ -1199,6 +1346,90 @@
return 0;
}
+static inline int va_macro_path_get(const char *wname,
+ unsigned int *path_num)
+{
+ int ret = 0;
+ char *widget_name = NULL;
+ char *w_name = NULL;
+ char *path_num_char = NULL;
+ char *path_name = NULL;
+
+ widget_name = kstrndup(wname, 10, GFP_KERNEL);
+ if (!widget_name)
+ return -EINVAL;
+
+ w_name = widget_name;
+
+ path_name = strsep(&widget_name, " ");
+ if (!path_name) {
+ pr_err("%s: Invalid widget name = %s\n",
+ __func__, widget_name);
+ ret = -EINVAL;
+ goto err;
+ }
+ path_num_char = strpbrk(path_name, "01234567");
+ if (!path_num_char) {
+ pr_err("%s: va path index not found\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ ret = kstrtouint(path_num_char, 10, path_num);
+ if (ret < 0)
+ pr_err("%s: Invalid tx path = %s\n",
+ __func__, w_name);
+
+err:
+ kfree(w_name);
+ return ret;
+}
+
+static int va_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct va_macro_priv *priv = NULL;
+ struct device *va_dev = NULL;
+ int ret = 0;
+ int path = 0;
+
+ if (!va_macro_get_data(component, &va_dev, &priv, __func__))
+ return -EINVAL;
+
+ ret = va_macro_path_get(kcontrol->id.name, &path);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[0] = priv->dec_mode[path];
+
+ return 0;
+}
+
+static int va_macro_dec_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct va_macro_priv *priv = NULL;
+ struct device *va_dev = NULL;
+ int value = ucontrol->value.integer.value[0];
+ int ret = 0;
+ int path = 0;
+
+ if (!va_macro_get_data(component, &va_dev, &priv, __func__))
+ return -EINVAL;
+
+ ret = va_macro_path_get(kcontrol->id.name, &path);
+ if (ret)
+ return ret;
+
+ priv->dec_mode[path] = value;
+
+ return 0;
+}
+
static int va_macro_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -1689,6 +1920,10 @@
SND_SOC_DAPM_SUPPLY_S("VA_TX_SWR_CLK", 0, SND_SOC_NOPM, 0, 0,
va_macro_tx_swr_clk_event_v2,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("VA_SWR_CLK", 0, SND_SOC_NOPM, 0, 0,
+ va_macro_swr_clk_event_v2,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
static const struct snd_soc_dapm_widget va_macro_dapm_widgets_v3[] = {
@@ -2015,6 +2250,12 @@
{"VA SMIC MUX3", "SWR_MIC11", "VA SWR_MIC11"},
};
+static const struct snd_soc_dapm_route va_audio_map_v2[] = {
+ {"VA_AIF1 CAP", NULL, "VA_SWR_CLK"},
+ {"VA_AIF2 CAP", NULL, "VA_SWR_CLK"},
+ {"VA_AIF3 CAP", NULL, "VA_SWR_CLK"},
+};
+
static const struct snd_soc_dapm_route va_audio_map[] = {
{"VA_AIF1 CAP", NULL, "VA_MCLK"},
{"VA_AIF2 CAP", NULL, "VA_MCLK"},
@@ -2247,8 +2488,24 @@
{"VA SWR_ADC1", NULL, "VA_SWR_PWR"},
{"VA SWR_ADC2", NULL, "VA_SWR_PWR"},
{"VA SWR_ADC3", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC0", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC1", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC2", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC3", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC4", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC5", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC6", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC7", NULL, "VA_SWR_PWR"},
};
+static const char * const dec_mode_mux_text[] = {
+ "ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF",
+};
+
+static const struct soc_enum dec_mode_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dec_mode_mux_text),
+ dec_mode_mux_text);
+
static const struct snd_kcontrol_new va_macro_snd_controls[] = {
SOC_SINGLE_SX_TLV("VA_DEC0 Volume",
BOLERO_CDC_VA_TX0_TX_VOL_CTL,
@@ -2274,6 +2531,20 @@
SOC_SINGLE_SX_TLV("VA_DEC7 Volume",
BOLERO_CDC_VA_TX7_TX_VOL_CTL,
0, -84, 40, digital_gain),
+ SOC_SINGLE_EXT("LPI Enable", 0, 0, 1, 0,
+ va_macro_lpi_get, va_macro_lpi_put),
+
+ SOC_ENUM_EXT("VA_DEC0 MODE", dec_mode_mux_enum,
+ va_macro_dec_mode_get, va_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("VA_DEC1 MODE", dec_mode_mux_enum,
+ va_macro_dec_mode_get, va_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("VA_DEC2 MODE", dec_mode_mux_enum,
+ va_macro_dec_mode_get, va_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("VA_DEC3 MODE", dec_mode_mux_enum,
+ va_macro_dec_mode_get, va_macro_dec_mode_put),
};
static const struct snd_kcontrol_new va_macro_snd_controls_common[] = {
@@ -2283,6 +2554,8 @@
SOC_SINGLE_SX_TLV("VA_DEC1 Volume",
BOLERO_CDC_VA_TX1_TX_VOL_CTL,
0, -84, 40, digital_gain),
+ SOC_SINGLE_EXT("LPI Enable", 0, 0, 1, 0,
+ va_macro_lpi_get, va_macro_lpi_put),
};
static const struct snd_kcontrol_new va_macro_snd_controls_v3[] = {
@@ -2365,6 +2638,9 @@
return -EINVAL;
}
+ va_priv->lpi_enable = false;
+ va_priv->register_event_listener = false;
+
if (va_priv->va_without_decimation) {
ret = snd_soc_dapm_new_controls(dapm, va_macro_wod_dapm_widgets,
ARRAY_SIZE(va_macro_wod_dapm_widgets));
@@ -2420,14 +2696,25 @@
__func__);
return ret;
}
- if (va_priv->version == BOLERO_VERSION_2_0)
+ if (va_priv->version == BOLERO_VERSION_2_0) {
ret = snd_soc_dapm_add_routes(dapm,
va_audio_map_v3,
ARRAY_SIZE(va_audio_map_v3));
- if (ret < 0) {
- dev_err(va_dev, "%s: Failed to add routes\n",
- __func__);
- return ret;
+ if (ret < 0) {
+ dev_err(va_dev, "%s: Failed to add routes\n",
+ __func__);
+ return ret;
+ }
+ }
+ if (va_priv->version == BOLERO_VERSION_2_1) {
+ ret = snd_soc_dapm_add_routes(dapm,
+ va_audio_map_v2,
+ ARRAY_SIZE(va_audio_map_v2));
+ if (ret < 0) {
+ dev_err(va_dev, "%s: Failed to add routes\n",
+ __func__);
+ return ret;
+ }
}
} else {
ret = snd_soc_dapm_add_routes(dapm, va_audio_map,
@@ -2520,6 +2807,15 @@
}
va_priv->component = component;
+ if (va_priv->version == BOLERO_VERSION_2_1) {
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL0, 0xEE, 0xCC);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL1, 0xEE, 0xCC);
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL2, 0xEE, 0xCC);
+ }
+
return 0;
}
@@ -2703,6 +2999,7 @@
ops->event_handler = va_macro_event_handler;
ops->set_port_map = va_macro_set_port_map;
ops->reg_wake_irq = va_macro_reg_wake_irq;
+ ops->clk_div_get = va_macro_clk_div_get;
}
static int va_macro_probe(struct platform_device *pdev)
@@ -2845,6 +3142,7 @@
va_priv->swr_plat_data.write = NULL;
va_priv->swr_plat_data.bulk_write = NULL;
va_priv->swr_plat_data.clk = va_macro_swrm_clock;
+ va_priv->swr_plat_data.core_vote = va_macro_core_vote;
va_priv->swr_plat_data.handle_irq = NULL;
mutex_init(&va_priv->swr_clk_lock);
}
diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c
index 03bea4e..e97d746 100644
--- a/asoc/codecs/bolero/wsa-macro.c
+++ b/asoc/codecs/bolero/wsa-macro.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -41,7 +41,7 @@
#define NUM_INTERPOLATORS 2
#define WSA_MACRO_MUX_INP_SHFT 0x3
-#define WSA_MACRO_MUX_INP_MASK1 0x38
+#define WSA_MACRO_MUX_INP_MASK1 0x07
#define WSA_MACRO_MUX_INP_MASK2 0x38
#define WSA_MACRO_MUX_CFG_OFFSET 0x8
#define WSA_MACRO_MUX_CFG1_OFFSET 0x4
@@ -620,10 +620,10 @@
inp0_sel = int_mux_cfg0_val & WSA_MACRO_MUX_INP_MASK1;
inp1_sel = (int_mux_cfg0_val >>
WSA_MACRO_MUX_INP_SHFT) &
- WSA_MACRO_MUX_INP_MASK2;
+ WSA_MACRO_MUX_INP_MASK1;
inp2_sel = (int_mux_cfg1_val >>
WSA_MACRO_MUX_INP_SHFT) &
- WSA_MACRO_MUX_INP_MASK2;
+ WSA_MACRO_MUX_INP_MASK1;
if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
(inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
(inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) {
@@ -994,12 +994,10 @@
switch (event) {
case BOLERO_MACRO_EVT_SSR_DOWN:
+ trace_printk("%s, enter SSR down\n", __func__);
if (wsa_priv->swr_ctrl_data) {
swrm_wcd_notify(
wsa_priv->swr_ctrl_data[0].wsa_swr_pdev,
- SWR_DEVICE_DOWN, NULL);
- swrm_wcd_notify(
- wsa_priv->swr_ctrl_data[0].wsa_swr_pdev,
SWR_DEVICE_SSR_DOWN, NULL);
}
if ((!pm_runtime_enabled(wsa_dev) ||
@@ -1013,6 +1011,7 @@
}
break;
case BOLERO_MACRO_EVT_SSR_UP:
+ trace_printk("%s, enter SSR up\n", __func__);
/* reset swr after ssr/pdr */
wsa_priv->reset_swr = true;
/* enable&disable WSA_CORE_CLK to reset GFMUX reg */
@@ -2832,6 +2831,9 @@
mutex_lock(&wsa_priv->swr_clk_lock);
+ trace_printk("%s: %s swrm clock %s\n",
+ dev_name(wsa_priv->dev), __func__,
+ (enable ? "enable" : "disable"));
dev_dbg(wsa_priv->dev, "%s: swrm clock %s\n",
__func__, (enable ? "enable" : "disable"));
if (enable) {
@@ -2897,6 +2899,9 @@
}
}
}
+ trace_printk("%s: %s swrm clock users: %d\n",
+ dev_name(wsa_priv->dev), __func__,
+ wsa_priv->swr_clk_users);
dev_dbg(wsa_priv->dev, "%s: swrm clock users %d\n",
__func__, wsa_priv->swr_clk_users);
exit:
diff --git a/asoc/codecs/msm-cdc-pinctrl.c b/asoc/codecs/msm-cdc-pinctrl.c
index 597be1b..dcfb57b 100644
--- a/asoc/codecs/msm-cdc-pinctrl.c
+++ b/asoc/codecs/msm-cdc-pinctrl.c
@@ -293,7 +293,7 @@
gpio_data->chip_wakeup_register[i] =
devm_ioremap(&pdev->dev, chip_wakeup_reg[i], 0x4);
}
- if (of_property_read_u32_array(pdev->dev.of_node,
+ if (!of_property_read_u32_array(pdev->dev.of_node,
"qcom,chip-wakeup-default-val",
chip_wakeup_default_val, count)) {
for (i = 0; i < count; i++) {
diff --git a/asoc/codecs/msm_hdmi_codec_rx.c b/asoc/codecs/msm_hdmi_codec_rx.c
index 5144b92..1588c56 100644
--- a/asoc/codecs/msm_hdmi_codec_rx.c
+++ b/asoc/codecs/msm_hdmi_codec_rx.c
@@ -29,8 +29,6 @@
codec_info.type = EXT_DISPLAY_TYPE_DP; \
codec_info.ctrl_id = codec_data->ctl[dai_id]; \
codec_info.stream_id = codec_data->stream[dai_id]; \
- msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, \
- &codec_info)
enum {
DP_CONTROLLER0 = 0,
@@ -94,7 +92,9 @@
mutex_lock(&codec_data->dp_ops_lock);
SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
- if (!codec_data->ext_disp_ops.get_audio_edid_blk) {
+ rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
+ &codec_info);
+ if (!codec_data->ext_disp_ops.get_audio_edid_blk || rc) {
dev_dbg(component->dev, "%s: get_audio_edid_blk() is NULL\n",
__func__);
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
@@ -139,7 +139,9 @@
mutex_lock(&codec_data->dp_ops_lock);
SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
- if (!codec_data->ext_disp_ops.get_audio_edid_blk) {
+ rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
+ &codec_info);
+ if (!codec_data->ext_disp_ops.get_audio_edid_blk || rc) {
dev_err(component->dev, "%s: codec_data or get_audio_edid_blk() is NULL\n",
__func__);
mutex_unlock(&codec_data->dp_ops_lock);
@@ -199,9 +201,11 @@
mutex_lock(&codec_data->dp_ops_lock);
SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
+ rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
+ &codec_info);
if (!codec_data->ext_disp_ops.get_audio_edid_blk ||
- !codec_data->ext_disp_ops.get_intf_id) {
+ !codec_data->ext_disp_ops.get_intf_id || rc) {
dev_err(component->dev, "%s: get_audio_edid_blk() or get_intf_id is NULL\n",
__func__);
rc = -EINVAL;
@@ -284,8 +288,10 @@
mutex_lock(&codec_data->dp_ops_lock);
SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
+ rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
+ &codec_info);
- if (!codec_data->ext_disp_ops.acknowledge) {
+ if (!codec_data->ext_disp_ops.acknowledge || rc) {
dev_err(component->dev,
"%s: codec_data ops acknowledge() is NULL\n",
__func__);
@@ -460,7 +466,7 @@
struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- int ret = 0;
+ int ret = 0, rc = 0;
struct msm_ext_disp_codec_id codec_info;
struct msm_ext_disp_audio_codec_rx_data *codec_data =
dev_get_drvdata(dai->component->dev);
@@ -477,8 +483,10 @@
mutex_lock(&codec_data->dp_ops_lock);
SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
+ rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
+ &codec_info);
- if (!codec_data->ext_disp_ops.cable_status) {
+ if (!codec_data->ext_disp_ops.cable_status || rc) {
dev_err(dai->dev, "%s() cable_status is null\n",
__func__);
mutex_unlock(&codec_data->dp_ops_lock);
@@ -532,8 +540,10 @@
mutex_lock(&codec_data->dp_ops_lock);
SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
+ rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
+ &codec_info);
- if (!codec_data->ext_disp_ops.audio_info_setup) {
+ if (!codec_data->ext_disp_ops.audio_info_setup || rc) {
dev_err(dai->dev, "%s: audio_info_setup is null\n",
__func__);
mutex_unlock(&codec_data->dp_ops_lock);
@@ -600,8 +610,13 @@
mutex_lock(&codec_data->dp_ops_lock);
SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
+ rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
+ &codec_info);
+ if (rc)
+ goto end;
rc = codec_data->ext_disp_ops.audio_info_setup(
codec_data->ext_disp_core_pdev, &audio_setup_params);
+end:
mutex_unlock(&codec_data->dp_ops_lock);
if (rc < 0) {
dev_err_ratelimited(dai->dev,
@@ -634,9 +649,11 @@
mutex_lock(&codec_data->dp_ops_lock);
SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
+ rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
+ &codec_info);
if (!codec_data->ext_disp_ops.teardown_done ||
- !codec_data->ext_disp_ops.cable_status) {
+ !codec_data->ext_disp_ops.cable_status || rc) {
dev_err(dai->dev, "%s: teardown_done or cable_status is null\n",
__func__);
mutex_unlock(&codec_data->dp_ops_lock);
diff --git a/asoc/codecs/rouleur/Android.mk b/asoc/codecs/rouleur/Android.mk
new file mode 100644
index 0000000..4fb5793
--- /dev/null
+++ b/asoc/codecs/rouleur/Android.mk
@@ -0,0 +1,65 @@
+# Android makefile for audio kernel modules
+
+# Assume no targets will be supported
+
+# Check if this driver needs be built for current target
+ifeq ($(call is-board-platform,bengal),true)
+AUDIO_SELECT := CONFIG_SND_SOC_BENGAL=m
+endif
+
+AUDIO_CHIPSET := audio
+# Build/Package only in case of supported target
+ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) bengal),true)
+
+LOCAL_PATH := $(call my-dir)
+
+# This makefile is only for DLKM
+ifneq ($(findstring vendor,$(LOCAL_PATH)),)
+
+ifneq ($(findstring opensource,$(LOCAL_PATH)),)
+ AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel
+endif # opensource
+
+DLKM_DIR := $(TOP)/device/qcom/common/dlkm
+
+# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko
+###########################################################
+# This is set once per LOCAL_PATH, not per (kernel) module
+KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR)
+
+# We are actually building audio.ko here, as per the
+# requirement we are specifying <chipset>_audio.ko as LOCAL_MODULE.
+# This means we need to rename the module to <chipset>_audio.ko
+# after audio.ko is built.
+KBUILD_OPTIONS += MODNAME=rouleur_dlkm
+KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM)
+KBUILD_OPTIONS += $(AUDIO_SELECT)
+
+###########################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(AUDIO_CHIPSET)_rouleur.ko
+LOCAL_MODULE_KBUILD_NAME := rouleur_dlkm.ko
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/AndroidKernelModule.mk
+###########################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(AUDIO_CHIPSET)_rouleur_slave.ko
+LOCAL_MODULE_KBUILD_NAME := rouleur_slave_dlkm.ko
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/AndroidKernelModule.mk
+###########################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(AUDIO_CHIPSET)_pm2250_spmi.ko
+LOCAL_MODULE_KBUILD_NAME := pm2250_spmi_dlkm.ko
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/AndroidKernelModule.mk
+###########################################################
+
+endif # DLKM check
+endif # supported target check
diff --git a/asoc/codecs/rouleur/Kbuild b/asoc/codecs/rouleur/Kbuild
new file mode 100644
index 0000000..b59bcb1
--- /dev/null
+++ b/asoc/codecs/rouleur/Kbuild
@@ -0,0 +1,120 @@
+# We can build either as part of a standalone Kernel build or as
+# an external module. Determine which mechanism is being used
+ifeq ($(MODNAME),)
+ KERNEL_BUILD := 1
+else
+ KERNEL_BUILD := 0
+endif
+
+
+
+ifeq ($(KERNEL_BUILD), 1)
+ # These are configurable via Kconfig for kernel-based builds
+ # Need to explicitly configure for Android-based builds
+ AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/kernel/msm-4.19
+ AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio
+endif
+
+ifeq ($(KERNEL_BUILD), 0)
+ ifeq ($(CONFIG_ARCH_BENGAL), y)
+ include $(AUDIO_ROOT)/config/bengalauto.conf
+ export
+ INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
+ endif
+endif
+
+# As per target team, build is done as follows:
+# Defconfig : build with default flags
+# Slub : defconfig + CONFIG_SLUB_DEBUG := y +
+# CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y
+# Perf : Using appropriate msmXXXX-perf_defconfig
+#
+# Shipment builds (user variants) should not have any debug feature
+# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds
+# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since
+# there is no other way to identify defconfig builds, QTI internal
+# representation of perf builds (identified using the string 'perf'),
+# is used to identify if the build is a slub or defconfig one. This
+# way no critical debug feature will be enabled for perf and shipment
+# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT
+# config.
+
+############ UAPI ############
+UAPI_DIR := uapi
+UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR)
+
+############ COMMON ############
+COMMON_DIR := include
+COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR)
+
+############ ROULEUR ############
+
+# for ROULEUR Codec
+ifdef CONFIG_SND_SOC_ROULEUR
+ ROULEUR_OBJS += rouleur.o
+ ROULEUR_OBJS += rouleur-regmap.o
+ ROULEUR_OBJS += rouleur-tables.o
+ ROULEUR_OBJS += rouleur-mbhc.o
+endif
+
+ifdef CONFIG_PM2250_SPMI
+ PM2250_SPMI_OBJS += pm2250_spmi.o
+endif
+
+ifdef CONFIG_SND_SOC_ROULEUR_SLAVE
+ ROULEUR_SLAVE_OBJS += rouleur_slave.o
+endif
+
+LINUX_INC += -Iinclude/linux
+
+INCS += $(COMMON_INC) \
+ $(UAPI_INC)
+
+EXTRA_CFLAGS += $(INCS)
+
+
+CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \
+ -DANI_LITTLE_BIT_ENDIAN \
+ -DDOT11F_LITTLE_ENDIAN_HOST \
+ -DANI_COMPILER_TYPE_GCC \
+ -DANI_OS_TYPE_ANDROID=6 \
+ -DPTT_SOCK_SVC_ENABLE \
+ -Wall\
+ -Werror\
+ -D__linux__
+
+KBUILD_CPPFLAGS += $(CDEFINES)
+
+# Currently, for versions of gcc which support it, the kernel Makefile
+# is disabling the maybe-uninitialized warning. Re-enable it for the
+# AUDIO driver. Note that we must use EXTRA_CFLAGS here so that it
+# will override the kernel settings.
+ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y)
+EXTRA_CFLAGS += -Wmaybe-uninitialized
+endif
+#EXTRA_CFLAGS += -Wmissing-prototypes
+
+ifeq ($(call cc-option-yn, -Wheader-guard),y)
+EXTRA_CFLAGS += -Wheader-guard
+endif
+
+ifeq ($(KERNEL_BUILD), 0)
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers
+endif
+
+# Module information used by KBuild framework
+obj-$(CONFIG_SND_SOC_ROULEUR) += rouleur_dlkm.o
+rouleur_dlkm-y := $(ROULEUR_OBJS)
+
+obj-$(CONFIG_SND_SOC_ROULEUR_SLAVE) += rouleur_slave_dlkm.o
+rouleur_slave_dlkm-y := $(ROULEUR_SLAVE_OBJS)
+
+obj-$(CONFIG_PM2250_SPMI) += pm2250_spmi_dlkm.o
+pm2250_spmi_dlkm-y := $(PM2250_SPMI_OBJS)
+
+# inject some build related information
+DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"
diff --git a/asoc/codecs/rouleur/internal.h b/asoc/codecs/rouleur/internal.h
new file mode 100644
index 0000000..7104685
--- /dev/null
+++ b/asoc/codecs/rouleur/internal.h
@@ -0,0 +1,172 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _ROULEUR_INTERNAL_H
+#define _ROULEUR_INTERNAL_H
+
+#include <asoc/wcd-clsh.h>
+#include <asoc/wcd-mbhc-v2.h>
+#include <asoc/wcd-irq.h>
+#include "rouleur-mbhc.h"
+
+#define ROULEUR_MAX_MICBIAS 3
+
+/* Convert from vout ctl to micbias voltage in mV */
+#define WCD_VOUT_CTL_TO_MICB(v) (1600 + v * 50)
+#define MAX_PORT 8
+#define MAX_CH_PER_PORT 8
+
+extern struct regmap_config rouleur_regmap_config;
+
+struct codec_port_info {
+ u32 slave_port_type;
+ u32 master_port_type;
+ u32 ch_mask;
+ u32 num_ch;
+ u32 ch_rate;
+};
+
+struct rouleur_priv {
+ struct device *dev;
+
+ int variant;
+ struct snd_soc_component *component;
+ struct device_node *spmi_np;
+ struct regmap *regmap;
+
+ struct swr_device *rx_swr_dev;
+ struct swr_device *tx_swr_dev;
+
+ s32 micb_ref[ROULEUR_MAX_MICBIAS];
+ s32 pullup_ref[ROULEUR_MAX_MICBIAS];
+
+ struct fw_info *fw_data;
+
+ struct mutex micb_lock;
+ s32 dmic_0_1_clk_cnt;
+ /* mbhc module */
+ struct rouleur_mbhc *mbhc;
+
+ bool comp1_enable;
+ bool comp2_enable;
+
+ struct irq_domain *virq;
+ struct wcd_irq_info irq_info;
+ u32 rx_clk_cnt;
+ int num_irq_regs;
+ /* to track the status */
+ unsigned long status_mask;
+
+ u8 num_tx_ports;
+ u8 num_rx_ports;
+ struct codec_port_info
+ tx_port_mapping[MAX_PORT][MAX_CH_PER_PORT];
+ struct codec_port_info
+ rx_port_mapping[MAX_PORT][MAX_CH_PER_PORT];
+ struct regulator_bulk_data *supplies;
+ struct notifier_block nblock;
+ /* wcd callback to bolero */
+ void *handle;
+ int (*update_wcd_event)(void *handle, u16 event, u32 data);
+ int (*register_notifier)(void *handle,
+ struct notifier_block *nblock,
+ bool enable);
+ int (*wakeup)(void *handle, bool enable);
+ u32 version;
+ /* Entry for version info */
+ struct snd_info_entry *entry;
+ struct snd_info_entry *version_entry;
+ struct device *spmi_dev;
+ int reset_reg;
+ int mbias_cnt;
+ struct mutex rx_clk_lock;
+ struct mutex main_bias_lock;
+};
+
+struct rouleur_micbias_setting {
+ u32 micb1_mv;
+ u32 micb2_mv;
+ u32 micb3_mv;
+};
+
+struct rouleur_pdata {
+ struct device_node *spmi_np;
+ struct device_node *rx_slave;
+ struct device_node *tx_slave;
+ struct rouleur_micbias_setting micbias;
+
+ struct cdc_regulator *regulator;
+ int num_supplies;
+ int reset_reg;
+};
+
+struct wcd_ctrl_platform_data {
+ void *handle;
+ int (*update_wcd_event)(void *handle, u16 event, u32 data);
+ int (*register_notifier)(void *handle,
+ struct notifier_block *nblock,
+ bool enable);
+};
+
+enum {
+ WCD_RX1,
+ WCD_RX2,
+ WCD_RX3
+};
+
+enum {
+ BOLERO_WCD_EVT_TX_CH_HOLD_CLEAR = 1,
+ BOLERO_WCD_EVT_PA_OFF_PRE_SSR,
+ BOLERO_WCD_EVT_SSR_DOWN,
+ BOLERO_WCD_EVT_SSR_UP,
+};
+
+enum {
+ WCD_BOLERO_EVT_RX_MUTE = 1, /* for RX mute/unmute */
+ WCD_BOLERO_EVT_IMPED_TRUE, /* for imped true */
+ WCD_BOLERO_EVT_IMPED_FALSE, /* for imped false */
+ WCD_BOLERO_EVT_RX_COMPANDER_SOFT_RST,
+ WCD_BOLERO_EVT_BCS_CLK_OFF,
+};
+
+enum {
+ /* INTR_CTRL_INT_MASK_0 */
+ ROULEUR_IRQ_MBHC_BUTTON_PRESS_DET = 0,
+ ROULEUR_IRQ_MBHC_BUTTON_RELEASE_DET,
+ ROULEUR_IRQ_MBHC_ELECT_INS_REM_DET,
+ ROULEUR_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+ ROULEUR_IRQ_MBHC_SW_DET,
+ ROULEUR_IRQ_HPHR_OCP_INT,
+ ROULEUR_IRQ_HPHR_CNP_INT,
+ ROULEUR_IRQ_HPHL_OCP_INT,
+
+ /* INTR_CTRL_INT_MASK_1 */
+ ROULEUR_IRQ_HPHL_CNP_INT,
+ ROULEUR_IRQ_EAR_CNP_INT,
+ ROULEUR_IRQ_EAR_OCP_INT,
+ ROULEUR_IRQ_LO_CNP_INT,
+ ROULEUR_IRQ_LO_OCP_INT,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT,
+ ROULEUR_IRQ_HPHR_PDM_WD_INT,
+ ROULEUR_IRQ_RESERVED_0,
+
+ /* INTR_CTRL_INT_MASK_2 */
+ ROULEUR_IRQ_RESERVED_1,
+ ROULEUR_IRQ_RESERVED_2,
+ ROULEUR_IRQ_HPHL_SURGE_DET_INT,
+ ROULEUR_IRQ_HPHR_SURGE_DET_INT,
+ ROULEUR_NUM_IRQS,
+};
+
+extern void rouleur_disable_bcs_before_slow_insert(
+ struct snd_soc_component *component,
+ bool bcs_disable);
+extern struct rouleur_mbhc *rouleur_soc_get_mbhc(
+ struct snd_soc_component *component);
+extern int rouleur_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
+ int volt, int micb_num);
+extern int rouleur_get_micb_vout_ctl_val(u32 micb_mv);
+extern int rouleur_micbias_control(struct snd_soc_component *component,
+ int micb_num, int req, bool is_dapm);
+#endif
diff --git a/asoc/codecs/rouleur/pm2250-spmi.h b/asoc/codecs/rouleur/pm2250-spmi.h
new file mode 100644
index 0000000..87c913d
--- /dev/null
+++ b/asoc/codecs/rouleur/pm2250-spmi.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _PM2250_SPMI_H
+#define _PM2250_SPMI_H
+
+#ifdef CONFIG_PM2250_SPMI
+int pm2250_spmi_write(struct device *dev, int reg, int value);
+#else
+int pm2250_spmi_write(struct device *dev, int reg, int value)
+{
+ return 0;
+}
+#endif /* CONFIG_PM2250_SPMI */
+
+#endif
diff --git a/asoc/codecs/rouleur/pm2250_spmi.c b/asoc/codecs/rouleur/pm2250_spmi.c
new file mode 100644
index 0000000..1e5f70d
--- /dev/null
+++ b/asoc/codecs/rouleur/pm2250_spmi.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/**
+ * @regmap: regmap used to access PMIC registers
+ */
+struct pm2250_spmi {
+ struct regmap *regmap;
+};
+
+static const struct of_device_id pm2250_id_table[] = {
+ { .compatible = "qcom,pm2250-spmi" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, pm2250_id_table);
+
+int pm2250_spmi_write(struct device *dev, int reg, int value)
+{
+ int rc;
+ struct pm2250_spmi *spmi_dd;
+
+ if (!of_device_is_compatible(dev->of_node, "qcom,pm2250-spmi")) {
+ pr_err("%s: Device node is invalid\n", __func__);
+ return -EINVAL;
+ }
+
+ spmi_dd = dev_get_drvdata(dev);
+ if (!spmi_dd)
+ return -EINVAL;
+
+ rc = regmap_write(spmi_dd->regmap, reg, value);
+ if (rc)
+ dev_err(dev, "%s: Write to PMIC register failed\n", __func__);
+
+ return rc;
+}
+EXPORT_SYMBOL(pm2250_spmi_write);
+
+static int pm2250_spmi_probe(struct platform_device *pdev)
+{
+ struct pm2250_spmi *spmi_dd;
+ const struct of_device_id *match;
+
+ match = of_match_node(pm2250_id_table, pdev->dev.of_node);
+ if (!match)
+ return -ENXIO;
+
+ spmi_dd = devm_kzalloc(&pdev->dev, sizeof(*spmi_dd), GFP_KERNEL);
+ if (spmi_dd == NULL)
+ return -ENOMEM;
+
+ spmi_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!spmi_dd->regmap) {
+ dev_err(&pdev->dev, "Parent regmap unavailable.\n");
+ return -ENXIO;
+ }
+
+ platform_set_drvdata(pdev, spmi_dd);
+
+ dev_dbg(&pdev->dev, "Probe success !!\n");
+
+ return 0;
+}
+
+static int pm2250_spmi_remove(struct platform_device *pdev)
+{
+ of_platform_depopulate(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver pm2250_spmi_driver = {
+ .probe = pm2250_spmi_probe,
+ .remove = pm2250_spmi_remove,
+ .driver = {
+ .name = "pm2250-spmi",
+ .of_match_table = pm2250_id_table,
+ },
+};
+module_platform_driver(pm2250_spmi_driver);
+
+MODULE_ALIAS("platform:pm2250-spmi");
+MODULE_DESCRIPTION("PMIC SPMI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/rouleur/rouleur-mbhc.c b/asoc/codecs/rouleur/rouleur-mbhc.c
new file mode 100644
index 0000000..3e3ef51
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur-mbhc.c
@@ -0,0 +1,1155 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include "rouleur-registers.h"
+#include <asoc/wcdcal-hwdep.h>
+#include <asoc/wcd-mbhc-v2-api.h>
+#include "internal.h"
+
+#define ROULEUR_ZDET_SUPPORTED true
+/* Z value defined in milliohm */
+#define ROULEUR_ZDET_VAL_32 32000
+#define ROULEUR_ZDET_VAL_400 400000
+#define ROULEUR_ZDET_VAL_1200 1200000
+#define ROULEUR_ZDET_VAL_100K 100000000
+/* Z floating defined in ohms */
+#define ROULEUR_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE
+
+#define ROULEUR_ZDET_NUM_MEASUREMENTS 900
+#define ROULEUR_MBHC_GET_C1(c) ((c & 0xC000) >> 14)
+#define ROULEUR_MBHC_GET_X1(x) (x & 0x3FFF)
+/* Z value compared in milliOhm */
+#define ROULEUR_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000))
+#define ROULEUR_MBHC_ZDET_CONST (86 * 16384)
+#define ROULEUR_MBHC_MOISTURE_RREF R_24_KOHM
+
+static struct wcd_mbhc_register
+ wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
+ WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN",
+ ROULEUR_ANA_MBHC_MECH, 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN",
+ ROULEUR_ANA_MBHC_MECH, 0x40, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE",
+ ROULEUR_ANA_MBHC_MECH, 0x20, 5, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL",
+ ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, 0x30, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE",
+ ROULEUR_ANA_MBHC_ELECT, 0x08, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL",
+ ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, 0xC0, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL",
+ ROULEUR_ANA_MBHC_MECH, 0x04, 2, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE",
+ ROULEUR_ANA_MBHC_MECH, 0x10, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE",
+ ROULEUR_ANA_MBHC_MECH, 0x08, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND",
+ ROULEUR_ANA_MBHC_MECH, 0x01, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC",
+ ROULEUR_ANA_MBHC_ELECT, 0x06, 1, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN",
+ ROULEUR_ANA_MBHC_ELECT, 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC",
+ ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, 0x0F, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC",
+ ROULEUR_ANA_MBHC_CTL_1, 0x03, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF",
+ ROULEUR_ANA_MBHC_CTL_2, 0x03, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x08, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_IN2P_CLAMP_STATE",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x10, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x20, 5, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x40, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN",
+ SND_SOC_NOPM, 0x00, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x07, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL",
+ ROULEUR_ANA_MBHC_ELECT, 0x70, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
+ ROULEUR_ANA_MBHC_RESULT_3, 0xFF, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
+ ROULEUR_ANA_MICBIAS_MICB_1_2_EN, 0x04, 2, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
+ SND_SOC_NOPM, 0x00, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
+ ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x40, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN",
+ ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN",
+ ROULEUR_ANA_HPHPA_CNP_CTL_2, 0xC0, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x10, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
+ 0, 0, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN",
+ SND_SOC_NOPM, 0x00, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS",
+ ROULEUR_ANA_MBHC_FSM_STATUS, 0x01, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL",
+ ROULEUR_ANA_MBHC_CTL_2, 0x70, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS",
+ ROULEUR_ANA_MBHC_FSM_STATUS, 0x20, 5, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND",
+ SND_SOC_NOPM, 0x00, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND",
+ SND_SOC_NOPM, 0x00, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN",
+ ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x02, 1, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN",
+ ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x01, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS",
+ ROULEUR_DIG_SWR_INTR_STATUS_0, 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS",
+ ROULEUR_DIG_SWR_INTR_STATUS_0, 0x20, 5, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ADC_EN",
+ ROULEUR_ANA_MBHC_CTL_1, 0x08, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ADC_COMPLETE", ROULEUR_ANA_MBHC_FSM_STATUS,
+ 0x40, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ADC_TIMEOUT", ROULEUR_ANA_MBHC_FSM_STATUS,
+ 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ADC_RESULT", ROULEUR_ANA_MBHC_ADC_RESULT,
+ 0xFF, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MICB2_VOUT",
+ ROULEUR_ANA_MICBIAS_LDO_1_SETTING, 0xF8, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ADC_MODE",
+ ROULEUR_ANA_MBHC_CTL_1, 0x10, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_DETECTION_DONE",
+ ROULEUR_ANA_MBHC_CTL_1, 0x04, 2, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ELECT_ISRC_EN",
+ ROULEUR_ANA_MBHC_ZDET, 0x02, 1, 0),
+};
+
+static const struct wcd_mbhc_intr intr_ids = {
+ .mbhc_sw_intr = ROULEUR_IRQ_MBHC_SW_DET,
+ .mbhc_btn_press_intr = ROULEUR_IRQ_MBHC_BUTTON_PRESS_DET,
+ .mbhc_btn_release_intr = ROULEUR_IRQ_MBHC_BUTTON_RELEASE_DET,
+ .mbhc_hs_ins_intr = ROULEUR_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+ .mbhc_hs_rem_intr = ROULEUR_IRQ_MBHC_ELECT_INS_REM_DET,
+ .hph_left_ocp = ROULEUR_IRQ_HPHL_OCP_INT,
+ .hph_right_ocp = ROULEUR_IRQ_HPHR_OCP_INT,
+};
+
+struct rouleur_mbhc_zdet_param {
+ u16 ldo_ctl;
+ u16 noff;
+ u16 nshift;
+ u16 btn5;
+ u16 btn6;
+ u16 btn7;
+};
+
+static int rouleur_mbhc_request_irq(struct snd_soc_component *component,
+ int irq, irq_handler_t handler,
+ const char *name, void *data)
+{
+ struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
+
+ return wcd_request_irq(&rouleur->irq_info, irq, name, handler, data);
+}
+
+static void rouleur_mbhc_irq_control(struct snd_soc_component *component,
+ int irq, bool enable)
+{
+ struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
+
+ if (enable)
+ wcd_enable_irq(&rouleur->irq_info, irq);
+ else
+ wcd_disable_irq(&rouleur->irq_info, irq);
+}
+
+static int rouleur_mbhc_free_irq(struct snd_soc_component *component,
+ int irq, void *data)
+{
+ struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
+
+ wcd_free_irq(&rouleur->irq_info, irq, data);
+
+ return 0;
+}
+
+static void rouleur_mbhc_clk_setup(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable)
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_1,
+ 0x80, 0x80);
+ else
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_1,
+ 0x80, 0x00);
+}
+
+static int rouleur_mbhc_btn_to_num(struct snd_soc_component *component)
+{
+ return snd_soc_component_read32(component, ROULEUR_ANA_MBHC_RESULT_3) &
+ 0x7;
+}
+
+static void rouleur_mbhc_mbhc_bias_control(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable)
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ELECT,
+ 0x01, 0x01);
+ else
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ELECT,
+ 0x01, 0x00);
+}
+
+static void rouleur_mbhc_program_btn_thr(struct snd_soc_component *component,
+ s16 *btn_low, s16 *btn_high,
+ int num_btn, bool is_micbias)
+{
+ int i;
+ int vth;
+
+ if (num_btn > WCD_MBHC_DEF_BUTTONS) {
+ dev_err(component->dev, "%s: invalid number of buttons: %d\n",
+ __func__, num_btn);
+ return;
+ }
+
+ for (i = 0; i < num_btn; i++) {
+ vth = ((btn_high[i] * 2) / 25) & 0x3F;
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBHC_BTN0_ZDET_VREF1 + i,
+ 0xFC, vth << 2);
+ dev_dbg(component->dev, "%s: btn_high[%d]: %d, vth: %d\n",
+ __func__, i, btn_high[i], vth);
+ }
+}
+
+static bool rouleur_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock)
+{
+ struct snd_soc_component *component = mbhc->component;
+ struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
+
+ rouleur->wakeup((void *)rouleur, lock);
+ return true;
+}
+
+static int rouleur_mbhc_register_notifier(struct wcd_mbhc *mbhc,
+ struct notifier_block *nblock,
+ bool enable)
+{
+ struct rouleur_mbhc *rouleur_mbhc;
+
+ rouleur_mbhc = container_of(mbhc, struct rouleur_mbhc, wcd_mbhc);
+
+ if (enable)
+ return blocking_notifier_chain_register(&rouleur_mbhc->notifier,
+ nblock);
+ else
+ return blocking_notifier_chain_unregister(
+ &rouleur_mbhc->notifier, nblock);
+}
+
+static bool rouleur_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num)
+{
+ u8 val = 0;
+
+ if (micb_num == MIC_BIAS_2) {
+ val = ((snd_soc_component_read32(mbhc->component,
+ ROULEUR_ANA_MICBIAS_MICB_1_2_EN) & 0x04)
+ >> 2);
+ if (val == 0x01)
+ return true;
+ }
+ return false;
+}
+
+static bool rouleur_mbhc_hph_pa_on_status(struct snd_soc_component *component)
+{
+ return (snd_soc_component_read32(component, ROULEUR_ANA_HPHPA_PA_STATUS)
+ & 0xFF) ? true : false;
+}
+
+static void rouleur_mbhc_hph_l_pull_up_control(
+ struct snd_soc_component *component,
+ int pull_up_cur)
+{
+ /* Default pull up current to 2uA */
+ if (pull_up_cur < I_OFF || pull_up_cur > I_3P0_UA ||
+ pull_up_cur == I_DEFAULT)
+ pull_up_cur = I_2P0_UA;
+
+ dev_dbg(component->dev, "%s: HS pull up current:%d\n",
+ __func__, pull_up_cur);
+
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBHC_PLUG_DETECT_CTL,
+ 0xC0, pull_up_cur);
+}
+
+static int rouleur_mbhc_request_micbias(struct snd_soc_component *component,
+ int micb_num, int req)
+{
+ int ret = 0;
+
+ ret = rouleur_micbias_control(component, micb_num, req, false);
+
+ return ret;
+}
+
+static void rouleur_mbhc_micb_ramp_control(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBHC_MICB2_RAMP,
+ 0x1C, 0x0C);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBHC_MICB2_RAMP,
+ 0x80, 0x80);
+ } else {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBHC_MICB2_RAMP,
+ 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBHC_MICB2_RAMP,
+ 0x1C, 0x00);
+ }
+}
+
+static struct firmware_cal *rouleur_get_hwdep_fw_cal(struct wcd_mbhc *mbhc,
+ enum wcd_cal_type type)
+{
+ struct rouleur_mbhc *rouleur_mbhc;
+ struct firmware_cal *hwdep_cal;
+ struct snd_soc_component *component = mbhc->component;
+
+ rouleur_mbhc = container_of(mbhc, struct rouleur_mbhc, wcd_mbhc);
+
+ if (!component) {
+ pr_err("%s: NULL component pointer\n", __func__);
+ return NULL;
+ }
+ hwdep_cal = wcdcal_get_fw_cal(rouleur_mbhc->fw_data, type);
+ if (!hwdep_cal)
+ dev_err(component->dev, "%s: cal not sent by %d\n",
+ __func__, type);
+
+ return hwdep_cal;
+}
+
+static int rouleur_mbhc_micb_ctrl_threshold_mic(
+ struct snd_soc_component *component,
+ int micb_num, bool req_en)
+{
+ struct rouleur_pdata *pdata = dev_get_platdata(component->dev);
+ int rc, micb_mv;
+
+ if (micb_num != MIC_BIAS_2)
+ return -EINVAL;
+ /*
+ * If device tree micbias level is already above the minimum
+ * voltage needed to detect threshold microphone, then do
+ * not change the micbias, just return.
+ */
+ if (pdata->micbias.micb2_mv >= WCD_MBHC_THR_HS_MICB_MV)
+ return 0;
+
+ micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : pdata->micbias.micb2_mv;
+
+ rc = rouleur_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2);
+
+ return rc;
+}
+
+static inline void rouleur_mbhc_get_result_params(struct rouleur_priv *rouleur,
+ s16 *d1_a, u16 noff,
+ int32_t *zdet)
+{
+ int i;
+ int val = 0, val1 = 0;
+ s16 c1 = 0;
+ s32 x1 = 0, d1 = 0;
+ int32_t denom;
+ int minCode_param[] = {
+ 3277, 1639, 820, 410, 205, 103, 52, 26
+ };
+
+ regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x20, 0x20);
+ for (i = 0; i < ROULEUR_ZDET_NUM_MEASUREMENTS; i++) {
+ regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &val);
+ if (val & 0x80)
+ break;
+ }
+ val = val << 0x8;
+ regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_1, &val1);
+ val |= val1;
+ regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x20, 0x00);
+ x1 = ROULEUR_MBHC_GET_X1(val);
+ c1 = ROULEUR_MBHC_GET_C1(val);
+ /* If ramp is not complete, give additional 5ms */
+ if ((c1 < 2) && x1)
+ usleep_range(5000, 5050);
+
+ if (!c1 || !x1) {
+ dev_dbg(rouleur->dev,
+ "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n",
+ __func__, c1, x1);
+ goto ramp_down;
+ }
+ d1 = d1_a[c1];
+ denom = (x1 * d1) - (1 << (14 - noff));
+ if (denom > 0)
+ *zdet = (ROULEUR_MBHC_ZDET_CONST * 1000) / denom;
+ else if (x1 < minCode_param[noff])
+ *zdet = ROULEUR_ZDET_FLOATING_IMPEDANCE;
+
+ dev_dbg(rouleur->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n",
+ __func__, d1, c1, x1, *zdet);
+ramp_down:
+ i = 0;
+ while (x1) {
+ regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_1, &val);
+ regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &val1);
+ val = val << 0x8;
+ val |= val1;
+ x1 = ROULEUR_MBHC_GET_X1(val);
+ i++;
+ if (i == ROULEUR_ZDET_NUM_MEASUREMENTS)
+ break;
+ }
+}
+
+#if 0
+static void rouleur_mbhc_zdet_ramp(struct snd_soc_component *component,
+ struct rouleur_mbhc_zdet_param *zdet_param,
+ int32_t *zl, int32_t *zr, s16 *d1_a)
+{
+ struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
+ int32_t zdet = 0;
+
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ZDET_ANA_CTL,
+ 0x70, zdet_param->ldo_ctl << 4);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_BTN5, 0xFC,
+ zdet_param->btn5);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_BTN6, 0xFC,
+ zdet_param->btn6);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_BTN7, 0xFC,
+ zdet_param->btn7);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ZDET_ANA_CTL,
+ 0x0F, zdet_param->noff);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ZDET_RAMP_CTL,
+ 0x0F, zdet_param->nshift);
+
+ if (!zl)
+ goto z_right;
+ /* Start impedance measurement for HPH_L */
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_ZDET, 0x80, 0x80);
+ dev_dbg(rouleur->dev, "%s: ramp for HPH_L, noff = %d\n",
+ __func__, zdet_param->noff);
+ rouleur_mbhc_get_result_params(rouleur, d1_a, zdet_param->noff, &zdet);
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_ZDET, 0x80, 0x00);
+
+ *zl = zdet;
+
+z_right:
+ if (!zr)
+ return;
+ /* Start impedance measurement for HPH_R */
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_ZDET, 0x40, 0x40);
+ dev_dbg(rouleur->dev, "%s: ramp for HPH_R, noff = %d\n",
+ __func__, zdet_param->noff);
+ rouleur_mbhc_get_result_params(rouleur, d1_a, zdet_param->noff, &zdet);
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_ZDET, 0x40, 0x00);
+
+ *zr = zdet;
+}
+
+static inline void rouleur_wcd_mbhc_qfuse_cal(
+ struct snd_soc_component *component,
+ int32_t *z_val, int flag_l_r)
+{
+ s16 q1;
+ int q1_cal;
+
+ if (*z_val < (ROULEUR_ZDET_VAL_400/1000))
+ q1 = snd_soc_component_read32(component,
+ ROULEUR_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r));
+ else
+ q1 = snd_soc_component_read32(component,
+ ROULEUR_DIGITAL_EFUSE_REG_24 + (2 * flag_l_r));
+ if (q1 & 0x80)
+ q1_cal = (10000 - ((q1 & 0x7F) * 25));
+ else
+ q1_cal = (10000 + (q1 * 25));
+ if (q1_cal > 0)
+ *z_val = ((*z_val) * 10000) / q1_cal;
+}
+
+static void rouleur_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
+ uint32_t *zr)
+{
+ struct snd_soc_component *component = mbhc->component;
+ struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
+ s16 reg0, reg1, reg2, reg3, reg4;
+ int32_t z1L, z1R, z1Ls;
+ int zMono, z_diff1, z_diff2;
+ bool is_fsm_disable = false;
+ struct rouleur_mbhc_zdet_param zdet_param[] = {
+ {4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */
+ {2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */
+ {1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */
+ {1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */
+ };
+ struct rouleur_mbhc_zdet_param *zdet_param_ptr = NULL;
+ s16 d1_a[][4] = {
+ {0, 30, 90, 30},
+ {0, 30, 30, 5},
+ {0, 30, 30, 5},
+ {0, 30, 30, 5},
+ };
+ s16 *d1 = NULL;
+
+ WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+
+ reg0 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_BTN5);
+ reg1 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_BTN6);
+ reg2 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_BTN7);
+ reg3 = snd_soc_component_read32(component, ROULEUR_MBHC_CTL_CLK);
+ reg4 = snd_soc_component_read32(component,
+ ROULEUR_ANA_MBHC_ZDET_ANA_CTL);
+
+ if (snd_soc_component_read32(component, ROULEUR_ANA_MBHC_ELECT) &
+ 0x80) {
+ is_fsm_disable = true;
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_ELECT, 0x80, 0x00);
+ }
+
+ /* For NO-jack, disable L_DET_EN before Z-det measurements */
+ if (mbhc->hphl_swh)
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_MECH, 0x80, 0x00);
+
+ /* Turn off 100k pull down on HPHL */
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_MECH, 0x01, 0x00);
+
+ /* Disable surge protection before impedance detection.
+ * This is done to give correct value for high impedance.
+ */
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0x00);
+ /* 1ms delay needed after disable surge protection */
+ usleep_range(1000, 1010);
+
+ /* First get impedance on Left */
+ d1 = d1_a[1];
+ zdet_param_ptr = &zdet_param[1];
+ rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1);
+
+ if (!ROULEUR_MBHC_IS_SECOND_RAMP_REQUIRED(z1L))
+ goto left_ch_impedance;
+
+ /* Second ramp for left ch */
+ if (z1L < ROULEUR_ZDET_VAL_32) {
+ zdet_param_ptr = &zdet_param[0];
+ d1 = d1_a[0];
+ } else if ((z1L > ROULEUR_ZDET_VAL_400) &&
+ (z1L <= ROULEUR_ZDET_VAL_1200)) {
+ zdet_param_ptr = &zdet_param[2];
+ d1 = d1_a[2];
+ } else if (z1L > ROULEUR_ZDET_VAL_1200) {
+ zdet_param_ptr = &zdet_param[3];
+ d1 = d1_a[3];
+ }
+ rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1);
+
+left_ch_impedance:
+ if ((z1L == ROULEUR_ZDET_FLOATING_IMPEDANCE) ||
+ (z1L > ROULEUR_ZDET_VAL_100K)) {
+ *zl = ROULEUR_ZDET_FLOATING_IMPEDANCE;
+ zdet_param_ptr = &zdet_param[1];
+ d1 = d1_a[1];
+ } else {
+ *zl = z1L/1000;
+ rouleur_wcd_mbhc_qfuse_cal(component, zl, 0);
+ }
+ dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n",
+ __func__, *zl);
+
+ /* Start of right impedance ramp and calculation */
+ rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1);
+ if (ROULEUR_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) {
+ if (((z1R > ROULEUR_ZDET_VAL_1200) &&
+ (zdet_param_ptr->noff == 0x6)) ||
+ ((*zl) != ROULEUR_ZDET_FLOATING_IMPEDANCE))
+ goto right_ch_impedance;
+ /* Second ramp for right ch */
+ if (z1R < ROULEUR_ZDET_VAL_32) {
+ zdet_param_ptr = &zdet_param[0];
+ d1 = d1_a[0];
+ } else if ((z1R > ROULEUR_ZDET_VAL_400) &&
+ (z1R <= ROULEUR_ZDET_VAL_1200)) {
+ zdet_param_ptr = &zdet_param[2];
+ d1 = d1_a[2];
+ } else if (z1R > ROULEUR_ZDET_VAL_1200) {
+ zdet_param_ptr = &zdet_param[3];
+ d1 = d1_a[3];
+ }
+ rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, NULL,
+ &z1R, d1);
+ }
+right_ch_impedance:
+ if ((z1R == ROULEUR_ZDET_FLOATING_IMPEDANCE) ||
+ (z1R > ROULEUR_ZDET_VAL_100K)) {
+ *zr = ROULEUR_ZDET_FLOATING_IMPEDANCE;
+ } else {
+ *zr = z1R/1000;
+ rouleur_wcd_mbhc_qfuse_cal(component, zr, 1);
+ }
+ dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n",
+ __func__, *zr);
+
+ /* Mono/stereo detection */
+ if ((*zl == ROULEUR_ZDET_FLOATING_IMPEDANCE) &&
+ (*zr == ROULEUR_ZDET_FLOATING_IMPEDANCE)) {
+ dev_dbg(component->dev,
+ "%s: plug type is invalid or extension cable\n",
+ __func__);
+ goto zdet_complete;
+ }
+ if ((*zl == ROULEUR_ZDET_FLOATING_IMPEDANCE) ||
+ (*zr == ROULEUR_ZDET_FLOATING_IMPEDANCE) ||
+ ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) ||
+ ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) {
+ dev_dbg(component->dev,
+ "%s: Mono plug type with one ch floating or shorted to GND\n",
+ __func__);
+ mbhc->hph_type = WCD_MBHC_HPH_MONO;
+ goto zdet_complete;
+ }
+ snd_soc_component_update_bits(component, ROULEUR_HPH_R_ATEST,
+ 0x02, 0x02);
+ snd_soc_component_update_bits(component, ROULEUR_HPH_PA_CTL2,
+ 0x40, 0x01);
+ if (*zl < (ROULEUR_ZDET_VAL_32/1000))
+ rouleur_mbhc_zdet_ramp(component, &zdet_param[0], &z1Ls,
+ NULL, d1);
+ else
+ rouleur_mbhc_zdet_ramp(component, &zdet_param[1], &z1Ls,
+ NULL, d1);
+ snd_soc_component_update_bits(component, ROULEUR_HPH_PA_CTL2,
+ 0x40, 0x00);
+ snd_soc_component_update_bits(component, ROULEUR_HPH_R_ATEST,
+ 0x02, 0x00);
+ z1Ls /= 1000;
+ rouleur_wcd_mbhc_qfuse_cal(component, &z1Ls, 0);
+ /* Parallel of left Z and 9 ohm pull down resistor */
+ zMono = ((*zl) * 9) / ((*zl) + 9);
+ z_diff1 = (z1Ls > zMono) ? (z1Ls - zMono) : (zMono - z1Ls);
+ z_diff2 = ((*zl) > z1Ls) ? ((*zl) - z1Ls) : (z1Ls - (*zl));
+ if ((z_diff1 * (*zl + z1Ls)) > (z_diff2 * (z1Ls + zMono))) {
+ dev_dbg(component->dev, "%s: stereo plug type detected\n",
+ __func__);
+ mbhc->hph_type = WCD_MBHC_HPH_STEREO;
+ } else {
+ dev_dbg(component->dev, "%s: MONO plug type detected\n",
+ __func__);
+ mbhc->hph_type = WCD_MBHC_HPH_MONO;
+ }
+
+ /* Enable surge protection again after impedance detection */
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0);
+zdet_complete:
+ snd_soc_component_write(component, ROULEUR_ANA_MBHC_BTN5, reg0);
+ snd_soc_component_write(component, ROULEUR_ANA_MBHC_BTN6, reg1);
+ snd_soc_component_write(component, ROULEUR_ANA_MBHC_BTN7, reg2);
+ /* Turn on 100k pull down on HPHL */
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_MECH, 0x01, 0x01);
+
+ /* For NO-jack, re-enable L_DET_EN after Z-det measurements */
+ if (mbhc->hphl_swh)
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_MECH, 0x80, 0x80);
+
+ snd_soc_component_write(component, ROULEUR_ANA_MBHC_ZDET_ANA_CTL, reg4);
+ snd_soc_component_write(component, ROULEUR_MBHC_CTL_CLK, reg3);
+ if (is_fsm_disable)
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_ELECT, 0x80, 0x80);
+}
+#endif
+
+static void rouleur_mbhc_gnd_det_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH,
+ 0x02, 0x02);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH,
+ 0x40, 0x40);
+ } else {
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH,
+ 0x40, 0x00);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH,
+ 0x02, 0x00);
+ }
+}
+
+static void rouleur_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x30, 0x10);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x0C, 0x04);
+ } else {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x30, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x0C, 0x00);
+ }
+}
+
+static void rouleur_mbhc_moisture_config(struct wcd_mbhc *mbhc)
+{
+ struct snd_soc_component *component = mbhc->component;
+
+ if ((mbhc->moist_rref == R_OFF) ||
+ (mbhc->mbhc_cfg->enable_usbc_analog)) {
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, R_OFF << 2);
+ return;
+ }
+
+ /* Do not enable moisture detection if jack type is NC */
+ if (!mbhc->hphl_swh) {
+ dev_dbg(component->dev, "%s: disable moisture detection for NC\n",
+ __func__);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, R_OFF << 2);
+ return;
+ }
+
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, mbhc->moist_rref << 2);
+}
+
+static void rouleur_mbhc_moisture_detect_en(struct wcd_mbhc *mbhc, bool enable)
+{
+ struct snd_soc_component *component = mbhc->component;
+
+ if (enable)
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, mbhc->moist_rref << 2);
+ else
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, R_OFF << 2);
+}
+
+static bool rouleur_mbhc_get_moisture_status(struct wcd_mbhc *mbhc)
+{
+ struct snd_soc_component *component = mbhc->component;
+ bool ret = false;
+
+ if ((mbhc->moist_rref == R_OFF) ||
+ (mbhc->mbhc_cfg->enable_usbc_analog)) {
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, R_OFF << 2);
+ goto done;
+ }
+
+ /* Do not enable moisture detection if jack type is NC */
+ if (!mbhc->hphl_swh) {
+ dev_dbg(component->dev, "%s: disable moisture detection for NC\n",
+ __func__);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, R_OFF << 2);
+ goto done;
+ }
+
+ /* If moisture_en is already enabled, then skip to plug type
+ * detection.
+ */
+ if ((snd_soc_component_read32(component, ROULEUR_ANA_MBHC_CTL_2) &
+ 0x0C))
+ goto done;
+
+ rouleur_mbhc_moisture_detect_en(mbhc, true);
+ /* Read moisture comparator status */
+ ret = ((snd_soc_component_read32(component, ROULEUR_ANA_MBHC_FSM_STATUS)
+ & 0x20) ? 0 : 1);
+
+done:
+ return ret;
+
+}
+
+static void rouleur_mbhc_bcs_enable(struct wcd_mbhc *mbhc,
+ bool bcs_enable)
+{
+ if (bcs_enable)
+ rouleur_disable_bcs_before_slow_insert(mbhc->component, false);
+ else
+ rouleur_disable_bcs_before_slow_insert(mbhc->component, true);
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+ .request_irq = rouleur_mbhc_request_irq,
+ .irq_control = rouleur_mbhc_irq_control,
+ .free_irq = rouleur_mbhc_free_irq,
+ .clk_setup = rouleur_mbhc_clk_setup,
+ .map_btn_code_to_num = rouleur_mbhc_btn_to_num,
+ .mbhc_bias = rouleur_mbhc_mbhc_bias_control,
+ .set_btn_thr = rouleur_mbhc_program_btn_thr,
+ .lock_sleep = rouleur_mbhc_lock_sleep,
+ .register_notifier = rouleur_mbhc_register_notifier,
+ .micbias_enable_status = rouleur_mbhc_micb_en_status,
+ .hph_pa_on_status = rouleur_mbhc_hph_pa_on_status,
+ .hph_pull_up_control = rouleur_mbhc_hph_l_pull_up_control,
+ .mbhc_micbias_control = rouleur_mbhc_request_micbias,
+ .mbhc_micb_ramp_control = rouleur_mbhc_micb_ramp_control,
+ .get_hwdep_fw_cal = rouleur_get_hwdep_fw_cal,
+ .mbhc_micb_ctrl_thr_mic = rouleur_mbhc_micb_ctrl_threshold_mic,
+ //.compute_impedance = rouleur_wcd_mbhc_calc_impedance,
+ .mbhc_gnd_det_ctrl = rouleur_mbhc_gnd_det_ctrl,
+ .hph_pull_down_ctrl = rouleur_mbhc_hph_pull_down_ctrl,
+ .mbhc_moisture_config = rouleur_mbhc_moisture_config,
+ .mbhc_get_moisture_status = rouleur_mbhc_get_moisture_status,
+ .mbhc_moisture_detect_en = rouleur_mbhc_moisture_detect_en,
+ .bcs_enable = rouleur_mbhc_bcs_enable,
+};
+
+static int rouleur_get_hph_type(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct rouleur_mbhc *rouleur_mbhc = rouleur_soc_get_mbhc(component);
+ struct wcd_mbhc *mbhc;
+
+ if (!rouleur_mbhc) {
+ dev_err(component->dev, "%s: mbhc not initialized!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mbhc = &rouleur_mbhc->wcd_mbhc;
+
+ ucontrol->value.integer.value[0] = (u32) mbhc->hph_type;
+ dev_dbg(component->dev, "%s: hph_type = %u\n", __func__,
+ mbhc->hph_type);
+
+ return 0;
+}
+
+static int rouleur_hph_impedance_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint32_t zl = 0, zr = 0;
+ bool hphr;
+ struct soc_multi_mixer_control *mc;
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct rouleur_mbhc *rouleur_mbhc = rouleur_soc_get_mbhc(component);
+
+ if (!rouleur_mbhc) {
+ dev_err(component->dev, "%s: mbhc not initialized!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+ wcd_mbhc_get_impedance(&rouleur_mbhc->wcd_mbhc, &zl, &zr);
+ dev_dbg(component->dev, "%s: zl=%u(ohms), zr=%u(ohms)\n", __func__,
+ zl, zr);
+ ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new hph_type_detect_controls[] = {
+ SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
+ rouleur_get_hph_type, NULL),
+};
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+ SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
+ rouleur_hph_impedance_get, NULL),
+ SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
+ rouleur_hph_impedance_get, NULL),
+};
+
+/*
+ * rouleur_mbhc_get_impedance: get impedance of headphone
+ * left and right channels
+ * @rouleur_mbhc: handle to struct rouleur_mbhc *
+ * @zl: handle to left-ch impedance
+ * @zr: handle to right-ch impedance
+ * return 0 for success or error code in case of failure
+ */
+int rouleur_mbhc_get_impedance(struct rouleur_mbhc *rouleur_mbhc,
+ uint32_t *zl, uint32_t *zr)
+{
+ if (!rouleur_mbhc) {
+ pr_err("%s: mbhc not initialized!\n", __func__);
+ return -EINVAL;
+ }
+ if (!zl || !zr) {
+ pr_err("%s: zl or zr null!\n", __func__);
+ return -EINVAL;
+ }
+
+ return wcd_mbhc_get_impedance(&rouleur_mbhc->wcd_mbhc, zl, zr);
+}
+EXPORT_SYMBOL(rouleur_mbhc_get_impedance);
+
+/*
+ * rouleur_mbhc_hs_detect: starts mbhc insertion/removal functionality
+ * @component: handle to snd_soc_component *
+ * @mbhc_cfg: handle to mbhc configuration structure
+ * return 0 if mbhc_start is success or error code in case of failure
+ */
+int rouleur_mbhc_hs_detect(struct snd_soc_component *component,
+ struct wcd_mbhc_config *mbhc_cfg)
+{
+ struct rouleur_priv *rouleur = NULL;
+ struct rouleur_mbhc *rouleur_mbhc = NULL;
+
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ rouleur = snd_soc_component_get_drvdata(component);
+ if (!rouleur) {
+ pr_err("%s: rouleur is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ rouleur_mbhc = rouleur->mbhc;
+ if (!rouleur_mbhc) {
+ dev_err(component->dev, "%s: mbhc not initialized!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ return wcd_mbhc_start(&rouleur_mbhc->wcd_mbhc, mbhc_cfg);
+}
+EXPORT_SYMBOL(rouleur_mbhc_hs_detect);
+
+/*
+ * rouleur_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality
+ * @component: handle to snd_soc_component *
+ */
+void rouleur_mbhc_hs_detect_exit(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = NULL;
+ struct rouleur_mbhc *rouleur_mbhc = NULL;
+
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return;
+ }
+
+ rouleur = snd_soc_component_get_drvdata(component);
+ if (!rouleur) {
+ pr_err("%s: rouleur is NULL\n", __func__);
+ return;
+ }
+
+ rouleur_mbhc = rouleur->mbhc;
+ if (!rouleur_mbhc) {
+ dev_err(component->dev, "%s: mbhc not initialized!\n",
+ __func__);
+ return;
+ }
+ wcd_mbhc_stop(&rouleur_mbhc->wcd_mbhc);
+}
+EXPORT_SYMBOL(rouleur_mbhc_hs_detect_exit);
+
+/*
+ * rouleur_mbhc_ssr_down: stop mbhc during
+ * rouleur subsystem restart
+ * @mbhc: pointer to rouleur_mbhc structure
+ * @component: handle to snd_soc_component *
+ */
+void rouleur_mbhc_ssr_down(struct rouleur_mbhc *mbhc,
+ struct snd_soc_component *component)
+{
+ struct wcd_mbhc *wcd_mbhc = NULL;
+
+ if (!mbhc || !component)
+ return;
+
+ wcd_mbhc = &mbhc->wcd_mbhc;
+ if (wcd_mbhc == NULL) {
+ dev_err(component->dev, "%s: wcd_mbhc is NULL\n", __func__);
+ return;
+ }
+
+ rouleur_mbhc_hs_detect_exit(component);
+ wcd_mbhc_deinit(wcd_mbhc);
+}
+EXPORT_SYMBOL(rouleur_mbhc_ssr_down);
+
+/*
+ * rouleur_mbhc_post_ssr_init: initialize mbhc for
+ * rouleur post subsystem restart
+ * @mbhc: poniter to rouleur_mbhc structure
+ * @component: handle to snd_soc_component *
+ *
+ * return 0 if mbhc_init is success or error code in case of failure
+ */
+int rouleur_mbhc_post_ssr_init(struct rouleur_mbhc *mbhc,
+ struct snd_soc_component *component)
+{
+ int ret = 0;
+ struct wcd_mbhc *wcd_mbhc = NULL;
+
+ if (!mbhc || !component)
+ return -EINVAL;
+
+ wcd_mbhc = &mbhc->wcd_mbhc;
+ if (wcd_mbhc == NULL) {
+ pr_err("%s: wcd_mbhc is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH,
+ 0x20, 0x20);
+ ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, &intr_ids,
+ wcd_mbhc_registers, ROULEUR_ZDET_SUPPORTED);
+ if (ret)
+ dev_err(component->dev, "%s: mbhc initialization failed\n",
+ __func__);
+
+ return ret;
+}
+EXPORT_SYMBOL(rouleur_mbhc_post_ssr_init);
+
+/*
+ * rouleur_mbhc_init: initialize mbhc for rouleur
+ * @mbhc: poniter to rouleur_mbhc struct pointer to store the configs
+ * @component: handle to snd_soc_component *
+ * @fw_data: handle to firmware data
+ *
+ * return 0 if mbhc_init is success or error code in case of failure
+ */
+int rouleur_mbhc_init(struct rouleur_mbhc **mbhc,
+ struct snd_soc_component *component,
+ struct fw_info *fw_data)
+{
+ struct rouleur_mbhc *rouleur_mbhc = NULL;
+ struct wcd_mbhc *wcd_mbhc = NULL;
+ struct rouleur_pdata *pdata;
+ int ret = 0;
+
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ rouleur_mbhc = devm_kzalloc(component->dev, sizeof(struct rouleur_mbhc),
+ GFP_KERNEL);
+ if (!rouleur_mbhc)
+ return -ENOMEM;
+
+ rouleur_mbhc->fw_data = fw_data;
+ BLOCKING_INIT_NOTIFIER_HEAD(&rouleur_mbhc->notifier);
+ wcd_mbhc = &rouleur_mbhc->wcd_mbhc;
+ if (wcd_mbhc == NULL) {
+ pr_err("%s: wcd_mbhc is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+
+ /* Setting default mbhc detection logic to ADC */
+ wcd_mbhc->mbhc_detection_logic = WCD_DETECTION_ADC;
+
+ pdata = dev_get_platdata(component->dev);
+ if (!pdata) {
+ dev_err(component->dev, "%s: pdata pointer is NULL\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ wcd_mbhc->micb_mv = pdata->micbias.micb2_mv;
+
+ ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb,
+ &intr_ids, wcd_mbhc_registers,
+ ROULEUR_ZDET_SUPPORTED);
+ if (ret) {
+ dev_err(component->dev, "%s: mbhc initialization failed\n",
+ __func__);
+ goto err;
+ }
+
+ (*mbhc) = rouleur_mbhc;
+ snd_soc_add_component_controls(component, impedance_detect_controls,
+ ARRAY_SIZE(impedance_detect_controls));
+ snd_soc_add_component_controls(component, hph_type_detect_controls,
+ ARRAY_SIZE(hph_type_detect_controls));
+
+ return 0;
+err:
+ devm_kfree(component->dev, rouleur_mbhc);
+ return ret;
+}
+EXPORT_SYMBOL(rouleur_mbhc_init);
+
+/*
+ * rouleur_mbhc_deinit: deinitialize mbhc for rouleur
+ * @component: handle to snd_soc_component *
+ */
+void rouleur_mbhc_deinit(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur;
+ struct rouleur_mbhc *rouleur_mbhc;
+
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return;
+ }
+
+ rouleur = snd_soc_component_get_drvdata(component);
+ if (!rouleur) {
+ pr_err("%s: rouleur is NULL\n", __func__);
+ return;
+ }
+
+ rouleur_mbhc = rouleur->mbhc;
+ if (rouleur_mbhc) {
+ wcd_mbhc_deinit(&rouleur_mbhc->wcd_mbhc);
+ devm_kfree(component->dev, rouleur_mbhc);
+ }
+}
+EXPORT_SYMBOL(rouleur_mbhc_deinit);
diff --git a/asoc/codecs/rouleur/rouleur-mbhc.h b/asoc/codecs/rouleur/rouleur-mbhc.h
new file mode 100644
index 0000000..40bef37
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur-mbhc.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+#ifndef __ROULEUR_MBHC_H__
+#define __ROULEUR_MBHC_H__
+#include <asoc/wcd-mbhc-v2.h>
+
+struct rouleur_mbhc {
+ struct wcd_mbhc wcd_mbhc;
+ struct blocking_notifier_head notifier;
+ struct fw_info *fw_data;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_ROULEUR)
+extern int rouleur_mbhc_init(struct rouleur_mbhc **mbhc,
+ struct snd_soc_component *component,
+ struct fw_info *fw_data);
+extern void rouleur_mbhc_hs_detect_exit(struct snd_soc_component *component);
+extern int rouleur_mbhc_hs_detect(struct snd_soc_component *component,
+ struct wcd_mbhc_config *mbhc_cfg);
+extern void rouleur_mbhc_deinit(struct snd_soc_component *component);
+extern int rouleur_mbhc_post_ssr_init(struct rouleur_mbhc *mbhc,
+ struct snd_soc_component *component);
+extern void rouleur_mbhc_ssr_down(struct rouleur_mbhc *mbhc,
+ struct snd_soc_component *component);
+extern int rouleur_mbhc_get_impedance(struct rouleur_mbhc *rouleur_mbhc,
+ uint32_t *zl, uint32_t *zr);
+#else
+static inline int rouleur_mbhc_init(struct rouleur_mbhc **mbhc,
+ struct snd_soc_component *component,
+ struct fw_info *fw_data)
+{
+ return 0;
+}
+static inline void rouleur_mbhc_hs_detect_exit(
+ struct snd_soc_component *component)
+{
+}
+static inline int rouleur_mbhc_hs_detect(struct snd_soc_component *component,
+ struct wcd_mbhc_config *mbhc_cfg)
+{
+ return 0;
+}
+static inline void rouleur_mbhc_deinit(struct snd_soc_component *component)
+{
+}
+static inline int rouleur_mbhc_post_ssr_init(struct rouleur_mbhc *mbhc,
+ struct snd_soc_component *component)
+{
+ return 0;
+}
+static inline void rouleur_mbhc_ssr_down(struct rouleur_mbhc *mbhc,
+ struct snd_soc_component *component)
+{
+}
+static inline int rouleur_mbhc_get_impedance(struct rouleur_mbhc *rouleur_mbhc,
+ uint32_t *zl, uint32_t *zr)
+{
+ if (zl)
+ *zl = 0;
+ if (zr)
+ *zr = 0;
+ return -EINVAL;
+}
+#endif
+
+#endif /* __ROULEUR_MBHC_H__ */
diff --git a/asoc/codecs/rouleur/rouleur-registers.h b/asoc/codecs/rouleur/rouleur-registers.h
new file mode 100644
index 0000000..ff3934b
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur-registers.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _ROULEUR_REGISTERS_H
+#define _ROULEUR_REGISTERS_H
+
+#define ROULEUR_ANA_BASE_ADDR 0x3000
+#define ROULEUR_DIG_BASE_ADDR 0x3400
+
+#define ROULEUR_REG(reg) ((reg > ROULEUR_DIG_BASE_ADDR) ? \
+ (reg - ROULEUR_DIG_BASE_ADDR) : \
+ (reg - ROULEUR_ANA_BASE_ADDR))
+
+enum {
+ REG_NO_ACCESS,
+ RD_REG,
+ WR_REG,
+ RD_WR_REG
+};
+
+#define ROULEUR_ANA_MICBIAS_MICB_1_2_EN (ROULEUR_ANA_BASE_ADDR+0x040)
+#define ROULEUR_ANA_MICBIAS_MICB_3_EN (ROULEUR_ANA_BASE_ADDR+0x041)
+#define ROULEUR_ANA_MICBIAS_LDO_1_SETTING (ROULEUR_ANA_BASE_ADDR+0x042)
+#define ROULEUR_ANA_MICBIAS_LDO_1_CTRL (ROULEUR_ANA_BASE_ADDR+0x043)
+#define ROULEUR_ANA_TX_AMIC1 (ROULEUR_ANA_BASE_ADDR+0x047)
+#define ROULEUR_ANA_TX_AMIC2 (ROULEUR_ANA_BASE_ADDR+0x048)
+#define ROULEUR_ANA_MBHC_MECH (ROULEUR_ANA_BASE_ADDR+0x05A)
+#define ROULEUR_ANA_MBHC_ELECT (ROULEUR_ANA_BASE_ADDR+0x05B)
+#define ROULEUR_ANA_MBHC_ZDET (ROULEUR_ANA_BASE_ADDR+0x05C)
+#define ROULEUR_ANA_MBHC_RESULT_1 (ROULEUR_ANA_BASE_ADDR+0x05D)
+#define ROULEUR_ANA_MBHC_RESULT_2 (ROULEUR_ANA_BASE_ADDR+0x05E)
+#define ROULEUR_ANA_MBHC_RESULT_3 (ROULEUR_ANA_BASE_ADDR+0x05F)
+#define ROULEUR_ANA_MBHC_BTN0_ZDET_VREF1 (ROULEUR_ANA_BASE_ADDR+0x060)
+#define ROULEUR_ANA_MBHC_BTN1_ZDET_VREF2 (ROULEUR_ANA_BASE_ADDR+0x061)
+#define ROULEUR_ANA_MBHC_BTN2_ZDET_VREF3 (ROULEUR_ANA_BASE_ADDR+0x062)
+#define ROULEUR_ANA_MBHC_BTN3_ZDET_DBG_400 (ROULEUR_ANA_BASE_ADDR+0x063)
+#define ROULEUR_ANA_MBHC_BTN4_ZDET_DBG_1400 (ROULEUR_ANA_BASE_ADDR+0x064)
+#define ROULEUR_ANA_MBHC_MICB2_RAMP (ROULEUR_ANA_BASE_ADDR+0x065)
+#define ROULEUR_ANA_MBHC_CTL_1 (ROULEUR_ANA_BASE_ADDR+0x066)
+#define ROULEUR_ANA_MBHC_CTL_2 (ROULEUR_ANA_BASE_ADDR+0x067)
+#define ROULEUR_ANA_MBHC_PLUG_DETECT_CTL (ROULEUR_ANA_BASE_ADDR+0x068)
+#define ROULEUR_ANA_MBHC_ZDET_ANA_CTL (ROULEUR_ANA_BASE_ADDR+0x069)
+#define ROULEUR_ANA_MBHC_ZDET_RAMP_CTL (ROULEUR_ANA_BASE_ADDR+0x06A)
+#define ROULEUR_ANA_MBHC_FSM_STATUS (ROULEUR_ANA_BASE_ADDR+0x06B)
+#define ROULEUR_ANA_MBHC_ADC_RESULT (ROULEUR_ANA_BASE_ADDR+0x06C)
+#define ROULEUR_ANA_MBHC_MCLK (ROULEUR_ANA_BASE_ADDR+0x06D)
+#define ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT (ROULEUR_ANA_BASE_ADDR+0x072)
+#define ROULEUR_ANA_NCP_EN (ROULEUR_ANA_BASE_ADDR+0x077)
+#define ROULEUR_ANA_HPHPA_CNP_CTL_2 (ROULEUR_ANA_BASE_ADDR+0x084)
+#define ROULEUR_ANA_HPHPA_PA_STATUS (ROULEUR_ANA_BASE_ADDR+0x087)
+#define ROULEUR_ANA_HPHPA_FSM_CLK (ROULEUR_ANA_BASE_ADDR+0x088)
+#define ROULEUR_ANA_HPHPA_L_GAIN (ROULEUR_ANA_BASE_ADDR+0x08B)
+#define ROULEUR_ANA_HPHPA_R_GAIN (ROULEUR_ANA_BASE_ADDR+0x08C)
+#define ROULEUR_ANA_HPHPA_SPARE_CTL (ROULEUR_ANA_BASE_ADDR+0x08E)
+#define ROULEUR_ANA_SURGE_EN (ROULEUR_ANA_BASE_ADDR+0x097)
+#define ROULEUR_ANA_COMBOPA_CTL (ROULEUR_ANA_BASE_ADDR+0x09B)
+#define ROULEUR_ANA_RXLDO_CTL (ROULEUR_ANA_BASE_ADDR+0x0B2)
+#define ROULEUR_ANA_MBIAS_EN (ROULEUR_ANA_BASE_ADDR+0x0B4)
+
+#define ROULEUR_DIG_SWR_CHIP_ID0 (ROULEUR_DIG_BASE_ADDR+0x001)
+#define ROULEUR_DIG_SWR_CHIP_ID1 (ROULEUR_DIG_BASE_ADDR+0x002)
+#define ROULEUR_DIG_SWR_CHIP_ID2 (ROULEUR_DIG_BASE_ADDR+0x003)
+#define ROULEUR_DIG_SWR_CHIP_ID3 (ROULEUR_DIG_BASE_ADDR+0x004)
+#define ROULEUR_DIG_SWR_SWR_TX_CLK_RATE (ROULEUR_DIG_BASE_ADDR+0x040)
+#define ROULEUR_DIG_SWR_CDC_RST_CTL (ROULEUR_DIG_BASE_ADDR+0x041)
+#define ROULEUR_DIG_SWR_TOP_CLK_CFG (ROULEUR_DIG_BASE_ADDR+0x042)
+#define ROULEUR_DIG_SWR_CDC_RX_CLK_CTL (ROULEUR_DIG_BASE_ADDR+0x043)
+#define ROULEUR_DIG_SWR_CDC_TX_CLK_CTL (ROULEUR_DIG_BASE_ADDR+0x044)
+#define ROULEUR_DIG_SWR_SWR_RST_EN (ROULEUR_DIG_BASE_ADDR+0x045)
+#define ROULEUR_DIG_SWR_CDC_RX_RST (ROULEUR_DIG_BASE_ADDR+0x047)
+#define ROULEUR_DIG_SWR_CDC_RX0_CTL (ROULEUR_DIG_BASE_ADDR+0x048)
+#define ROULEUR_DIG_SWR_CDC_RX1_CTL (ROULEUR_DIG_BASE_ADDR+0x049)
+#define ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1 (ROULEUR_DIG_BASE_ADDR+0x04B)
+#define ROULEUR_DIG_SWR_CDC_COMP_CTL_0 (ROULEUR_DIG_BASE_ADDR+0x04F)
+#define ROULEUR_DIG_SWR_CDC_RX_DELAY_CTL (ROULEUR_DIG_BASE_ADDR+0x052)
+#define ROULEUR_DIG_SWR_CDC_RX_GAIN_0 (ROULEUR_DIG_BASE_ADDR+0x053)
+#define ROULEUR_DIG_SWR_CDC_RX_GAIN_1 (ROULEUR_DIG_BASE_ADDR+0x054)
+#define ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL (ROULEUR_DIG_BASE_ADDR+0x057)
+#define ROULEUR_DIG_SWR_CDC_TX0_CTL (ROULEUR_DIG_BASE_ADDR+0x060)
+#define ROULEUR_DIG_SWR_CDC_TX1_CTL (ROULEUR_DIG_BASE_ADDR+0x061)
+#define ROULEUR_DIG_SWR_CDC_TX_RST (ROULEUR_DIG_BASE_ADDR+0x063)
+#define ROULEUR_DIG_SWR_CDC_REQ0_CTL (ROULEUR_DIG_BASE_ADDR+0x064)
+#define ROULEUR_DIG_SWR_CDC_REQ1_CTL (ROULEUR_DIG_BASE_ADDR+0x065)
+#define ROULEUR_DIG_SWR_CDC_RST (ROULEUR_DIG_BASE_ADDR+0x067)
+#define ROULEUR_DIG_SWR_CDC_AMIC_CTL (ROULEUR_DIG_BASE_ADDR+0x06A)
+#define ROULEUR_DIG_SWR_CDC_DMIC_CTL (ROULEUR_DIG_BASE_ADDR+0x06B)
+#define ROULEUR_DIG_SWR_CDC_DMIC1_CTL (ROULEUR_DIG_BASE_ADDR+0x06C)
+#define ROULEUR_DIG_SWR_CDC_DMIC1_RATE (ROULEUR_DIG_BASE_ADDR+0x06D)
+#define ROULEUR_DIG_SWR_PDM_WD_CTL0 (ROULEUR_DIG_BASE_ADDR+0x070)
+#define ROULEUR_DIG_SWR_PDM_WD_CTL1 (ROULEUR_DIG_BASE_ADDR+0x071)
+#define ROULEUR_DIG_SWR_INTR_MODE (ROULEUR_DIG_BASE_ADDR+0x080)
+#define ROULEUR_DIG_SWR_INTR_MASK_0 (ROULEUR_DIG_BASE_ADDR+0x081)
+#define ROULEUR_DIG_SWR_INTR_MASK_1 (ROULEUR_DIG_BASE_ADDR+0x082)
+#define ROULEUR_DIG_SWR_INTR_MASK_2 (ROULEUR_DIG_BASE_ADDR+0x083)
+#define ROULEUR_DIG_SWR_INTR_STATUS_0 (ROULEUR_DIG_BASE_ADDR+0x084)
+#define ROULEUR_DIG_SWR_INTR_STATUS_1 (ROULEUR_DIG_BASE_ADDR+0x085)
+#define ROULEUR_DIG_SWR_INTR_STATUS_2 (ROULEUR_DIG_BASE_ADDR+0x086)
+#define ROULEUR_DIG_SWR_INTR_CLEAR_0 (ROULEUR_DIG_BASE_ADDR+0x087)
+#define ROULEUR_DIG_SWR_INTR_CLEAR_1 (ROULEUR_DIG_BASE_ADDR+0x088)
+#define ROULEUR_DIG_SWR_INTR_CLEAR_2 (ROULEUR_DIG_BASE_ADDR+0x089)
+#define ROULEUR_DIG_SWR_INTR_LEVEL_0 (ROULEUR_DIG_BASE_ADDR+0x08A)
+#define ROULEUR_DIG_SWR_INTR_LEVEL_1 (ROULEUR_DIG_BASE_ADDR+0x08B)
+#define ROULEUR_DIG_SWR_INTR_LEVEL_2 (ROULEUR_DIG_BASE_ADDR+0x08C)
+#define ROULEUR_DIG_SWR_CDC_CONN_RX0_CTL (ROULEUR_DIG_BASE_ADDR+0x093)
+#define ROULEUR_DIG_SWR_CDC_CONN_RX1_CTL (ROULEUR_DIG_BASE_ADDR+0x094)
+#define ROULEUR_DIG_SWR_LOOP_BACK_MODE (ROULEUR_DIG_BASE_ADDR+0x097)
+#define ROULEUR_DIG_SWR_DRIVE_STRENGTH_0 (ROULEUR_DIG_BASE_ADDR+0x0A0)
+#define ROULEUR_DIG_SWR_DIG_DEBUG_CTL (ROULEUR_DIG_BASE_ADDR+0x0AB)
+#define ROULEUR_DIG_SWR_DIG_DEBUG_EN (ROULEUR_DIG_BASE_ADDR+0x0AC)
+#define ROULEUR_DIG_SWR_DEM_BYPASS_DATA0 (ROULEUR_DIG_BASE_ADDR+0x0B0)
+#define ROULEUR_DIG_SWR_DEM_BYPASS_DATA1 (ROULEUR_DIG_BASE_ADDR+0x0B1)
+#define ROULEUR_DIG_SWR_DEM_BYPASS_DATA2 (ROULEUR_DIG_BASE_ADDR+0x0B2)
+#define ROULEUR_DIG_SWR_DEM_BYPASS_DATA3 (ROULEUR_DIG_BASE_ADDR+0x0B3)
+
+#define ROULEUR_ANALOG_REGISTERS_MAX_SIZE (ROULEUR_ANA_BASE_ADDR+0x0B5)
+#define ROULEUR_DIGITAL_REGISTERS_MAX_SIZE (ROULEUR_DIG_BASE_ADDR+0x0B4)
+#define ROULEUR_ANALOG_MAX_REGISTER (ROULEUR_ANALOG_REGISTERS_MAX_SIZE - 1)
+#define ROULEUR_DIGITAL_MAX_REGISTER (ROULEUR_DIGITAL_REGISTERS_MAX_SIZE - 1)
+#endif
diff --git a/asoc/codecs/rouleur/rouleur-regmap.c b/asoc/codecs/rouleur/rouleur-regmap.c
new file mode 100644
index 0000000..6250214
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur-regmap.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "rouleur-registers.h"
+
+extern const u8 rouleur_reg_access_analog[
+ ROULEUR_REG(ROULEUR_ANALOG_REGISTERS_MAX_SIZE)];
+extern const u8 rouleur_reg_access_digital[
+ ROULEUR_REG(ROULEUR_DIGITAL_REGISTERS_MAX_SIZE)];
+
+static const struct reg_default rouleur_defaults[] = {
+ { ROULEUR_ANA_MICBIAS_MICB_1_2_EN, 0x01 },
+ { ROULEUR_ANA_MICBIAS_MICB_3_EN, 0x00 },
+ { ROULEUR_ANA_MICBIAS_LDO_1_SETTING, 0x21 },
+ { ROULEUR_ANA_MICBIAS_LDO_1_CTRL, 0x01 },
+ { ROULEUR_ANA_TX_AMIC1, 0x00 },
+ { ROULEUR_ANA_TX_AMIC2, 0x00 },
+ { ROULEUR_ANA_MBHC_MECH, 0x39 },
+ { ROULEUR_ANA_MBHC_ELECT, 0x08 },
+ { ROULEUR_ANA_MBHC_ZDET, 0x10 },
+ { ROULEUR_ANA_MBHC_RESULT_1, 0x00 },
+ { ROULEUR_ANA_MBHC_RESULT_2, 0x00 },
+ { ROULEUR_ANA_MBHC_RESULT_3, 0x00 },
+ { ROULEUR_ANA_MBHC_BTN0_ZDET_VREF1, 0x00 },
+ { ROULEUR_ANA_MBHC_BTN1_ZDET_VREF2, 0x10 },
+ { ROULEUR_ANA_MBHC_BTN2_ZDET_VREF3, 0x20 },
+ { ROULEUR_ANA_MBHC_BTN3_ZDET_DBG_400, 0x30 },
+ { ROULEUR_ANA_MBHC_BTN4_ZDET_DBG_1400, 0x40 },
+ { ROULEUR_ANA_MBHC_MICB2_RAMP, 0x00 },
+ { ROULEUR_ANA_MBHC_CTL_1, 0x02 },
+ { ROULEUR_ANA_MBHC_CTL_2, 0x05 },
+ { ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, 0xE9 },
+ { ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x0F },
+ { ROULEUR_ANA_MBHC_ZDET_RAMP_CTL, 0x00 },
+ { ROULEUR_ANA_MBHC_FSM_STATUS, 0x00 },
+ { ROULEUR_ANA_MBHC_ADC_RESULT, 0x00 },
+ { ROULEUR_ANA_MBHC_MCLK, 0x30 },
+ { ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT, 0x00 },
+ { ROULEUR_ANA_NCP_EN, 0x00 },
+ { ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x2B },
+ { ROULEUR_ANA_HPHPA_PA_STATUS, 0x00 },
+ { ROULEUR_ANA_HPHPA_FSM_CLK, 0x12 },
+ { ROULEUR_ANA_HPHPA_SPARE_CTL, 0x02 },
+ { ROULEUR_ANA_SURGE_EN, 0x38 },
+ { ROULEUR_ANA_COMBOPA_CTL, 0x35 },
+ { ROULEUR_ANA_RXLDO_CTL, 0x86 },
+ { ROULEUR_ANA_MBIAS_EN, 0x00 },
+ { ROULEUR_DIG_SWR_CHIP_ID0, 0x00 },
+ { ROULEUR_DIG_SWR_CHIP_ID1, 0x00 },
+ { ROULEUR_DIG_SWR_CHIP_ID2, 0x0C },
+ { ROULEUR_DIG_SWR_CHIP_ID3, 0x01 },
+ { ROULEUR_DIG_SWR_SWR_TX_CLK_RATE, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_RST_CTL, 0x03 },
+ { ROULEUR_DIG_SWR_TOP_CLK_CFG, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_TX_CLK_CTL, 0x33 },
+ { ROULEUR_DIG_SWR_SWR_RST_EN, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_RX_RST, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_RX0_CTL, 0xFC },
+ { ROULEUR_DIG_SWR_CDC_RX1_CTL, 0xFC },
+ { ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_COMP_CTL_0, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_RX_DELAY_CTL, 0x66 },
+ { ROULEUR_DIG_SWR_CDC_RX_GAIN_0, 0x55 },
+ { ROULEUR_DIG_SWR_CDC_RX_GAIN_1, 0xA9 },
+ { ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_TX0_CTL, 0x68 },
+ { ROULEUR_DIG_SWR_CDC_TX1_CTL, 0x68 },
+ { ROULEUR_DIG_SWR_CDC_TX_RST, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_REQ0_CTL, 0x01 },
+ { ROULEUR_DIG_SWR_CDC_REQ1_CTL, 0x01 },
+ { ROULEUR_DIG_SWR_CDC_RST, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_AMIC_CTL, 0x02 },
+ { ROULEUR_DIG_SWR_CDC_DMIC_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_DMIC1_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_DMIC1_RATE, 0x01 },
+ { ROULEUR_DIG_SWR_PDM_WD_CTL0, 0x00 },
+ { ROULEUR_DIG_SWR_PDM_WD_CTL1, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_MODE, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_MASK_0, 0xFF },
+ { ROULEUR_DIG_SWR_INTR_MASK_1, 0x7F },
+ { ROULEUR_DIG_SWR_INTR_MASK_2, 0x0C },
+ { ROULEUR_DIG_SWR_INTR_STATUS_0, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_STATUS_1, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_STATUS_2, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_CLEAR_0, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_CLEAR_1, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_CLEAR_2, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_LEVEL_0, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_LEVEL_1, 0x2A },
+ { ROULEUR_DIG_SWR_INTR_LEVEL_2, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_CONN_RX0_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_CONN_RX1_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_LOOP_BACK_MODE, 0x00 },
+ { ROULEUR_DIG_SWR_DRIVE_STRENGTH_0, 0x00 },
+ { ROULEUR_DIG_SWR_DIG_DEBUG_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_DIG_DEBUG_EN, 0x00 },
+ { ROULEUR_DIG_SWR_DEM_BYPASS_DATA0, 0x55 },
+ { ROULEUR_DIG_SWR_DEM_BYPASS_DATA1, 0x55 },
+ { ROULEUR_DIG_SWR_DEM_BYPASS_DATA2, 0x55 },
+ { ROULEUR_DIG_SWR_DEM_BYPASS_DATA3, 0x01 },
+};
+
+static bool rouleur_readable_register(struct device *dev, unsigned int reg)
+{
+ if (reg > ROULEUR_ANA_BASE_ADDR && reg <
+ ROULEUR_ANALOG_REGISTERS_MAX_SIZE)
+ return rouleur_reg_access_analog[ROULEUR_REG(reg)] & RD_REG;
+ if (reg > ROULEUR_DIG_BASE_ADDR && reg <
+ ROULEUR_DIGITAL_REGISTERS_MAX_SIZE)
+ return rouleur_reg_access_digital[ROULEUR_REG(reg)] & RD_REG;
+ return 0;
+}
+
+static bool rouleur_writeable_register(struct device *dev, unsigned int reg)
+{
+ if (reg > ROULEUR_ANA_BASE_ADDR && reg <
+ ROULEUR_ANALOG_REGISTERS_MAX_SIZE)
+ return rouleur_reg_access_analog[ROULEUR_REG(reg)] & WR_REG;
+ if (reg > ROULEUR_DIG_BASE_ADDR && reg <
+ ROULEUR_DIGITAL_REGISTERS_MAX_SIZE)
+ return rouleur_reg_access_digital[ROULEUR_REG(reg)] & WR_REG;
+ return 0;
+}
+
+static bool rouleur_volatile_register(struct device *dev, unsigned int reg)
+{
+ if (reg > ROULEUR_ANA_BASE_ADDR && reg <
+ ROULEUR_ANALOG_REGISTERS_MAX_SIZE)
+ if ((rouleur_reg_access_analog[ROULEUR_REG(reg)] & RD_REG)
+ && !(rouleur_reg_access_analog[ROULEUR_REG(reg)] & WR_REG))
+ return true;
+ return false;
+ if (reg > ROULEUR_DIG_BASE_ADDR && reg <
+ ROULEUR_DIGITAL_REGISTERS_MAX_SIZE)
+ if ((rouleur_reg_access_digital[ROULEUR_REG(reg)] & RD_REG)
+ && !(rouleur_reg_access_digital[ROULEUR_REG(reg)] & WR_REG))
+ return true;
+ return false;
+ return 0;
+}
+
+struct regmap_config rouleur_regmap_config = {
+ .name = "rouleur_csr",
+ .reg_bits = 16,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rouleur_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rouleur_defaults),
+ .max_register = ROULEUR_ANALOG_MAX_REGISTER +
+ ROULEUR_DIGITAL_MAX_REGISTER,
+ .readable_reg = rouleur_readable_register,
+ .writeable_reg = rouleur_writeable_register,
+ .volatile_reg = rouleur_volatile_register,
+ .can_multi_write = true,
+};
diff --git a/asoc/codecs/rouleur/rouleur-tables.c b/asoc/codecs/rouleur/rouleur-tables.c
new file mode 100644
index 0000000..ea710eb
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur-tables.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include "rouleur-registers.h"
+
+const u8 rouleur_reg_access_analog[ROULEUR_REG(
+ ROULEUR_ANALOG_REGISTERS_MAX_SIZE)] = {
+ [ROULEUR_REG(ROULEUR_ANA_MICBIAS_MICB_1_2_EN)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MICBIAS_MICB_3_EN)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MICBIAS_LDO_1_SETTING)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MICBIAS_LDO_1_CTRL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_TX_AMIC1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_TX_AMIC2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_MECH)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_ELECT)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_RESULT_1)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_RESULT_2)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_RESULT_3)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN0_ZDET_VREF1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN1_ZDET_VREF2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN2_ZDET_VREF3)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN3_ZDET_DBG_400)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN4_ZDET_DBG_1400)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_MICB2_RAMP)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_CTL_1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_CTL_2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_PLUG_DETECT_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_ANA_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_RAMP_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_FSM_STATUS)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_ADC_RESULT)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_MCLK)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_NCP_EN)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_HPHPA_CNP_CTL_2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_HPHPA_PA_STATUS)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_HPHPA_FSM_CLK)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_HPHPA_SPARE_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_SURGE_EN)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_COMBOPA_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_RXLDO_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBIAS_EN)] = RD_WR_REG,
+};
+
+const u8 rouleur_reg_access_digital[ROULEUR_REG(
+ ROULEUR_DIGITAL_REGISTERS_MAX_SIZE)] = {
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CHIP_ID0)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CHIP_ID1)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CHIP_ID2)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CHIP_ID3)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_SWR_TX_CLK_RATE)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RST_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_TOP_CLK_CFG)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_CLK_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX_CLK_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_SWR_RST_EN)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_RST)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX0_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX1_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_COMP_CTL_0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_DELAY_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_GAIN_0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_GAIN_1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX0_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX1_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX_RST)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_REQ0_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_REQ1_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RST)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_AMIC_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_DMIC_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_DMIC1_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_DMIC1_RATE)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_PDM_WD_CTL0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_PDM_WD_CTL1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_MODE)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_MASK_0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_MASK_1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_MASK_2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_STATUS_0)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_STATUS_1)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_STATUS_2)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_CLEAR_0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_CLEAR_1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_CLEAR_2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_LEVEL_0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_LEVEL_1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_LEVEL_2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_CONN_RX0_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_CONN_RX1_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_LOOP_BACK_MODE)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DRIVE_STRENGTH_0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DIG_DEBUG_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DIG_DEBUG_EN)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DEM_BYPASS_DATA0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DEM_BYPASS_DATA1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DEM_BYPASS_DATA2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DEM_BYPASS_DATA3)] = RD_WR_REG,
+};
diff --git a/asoc/codecs/rouleur/rouleur.c b/asoc/codecs/rouleur/rouleur.c
new file mode 100644
index 0000000..14dfd52
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur.c
@@ -0,0 +1,2492 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/component.h>
+#include <linux/regmap.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_platform.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <soc/soundwire.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include "internal.h"
+#include "rouleur.h"
+#include <asoc/wcdcal-hwdep.h>
+#include "rouleur-registers.h"
+#include "pm2250-spmi.h"
+#include <asoc/msm-cdc-pinctrl.h>
+#include <dt-bindings/sound/audio-codec-port-types.h>
+#include <asoc/msm-cdc-supply.h>
+
+#define DRV_NAME "rouleur_codec"
+
+#define NUM_SWRS_DT_PARAMS 5
+
+#define ROULEUR_VERSION_1_0 1
+#define ROULEUR_VERSION_ENTRY_SIZE 32
+
+#define NUM_ATTEMPTS 5
+
+enum {
+ CODEC_TX = 0,
+ CODEC_RX,
+};
+
+enum {
+ ALLOW_VPOS_DISABLE,
+ HPH_COMP_DELAY,
+ HPH_PA_DELAY,
+ AMIC2_BCS_ENABLE,
+};
+
+/* TODO: Check on the step values */
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+
+static int rouleur_handle_post_irq(void *data);
+static int rouleur_reset(struct device *dev, int val);
+
+static const struct regmap_irq ROULEUR_IRQs[ROULEUR_NUM_IRQS] = {
+ REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_SW_DET, 0, 0x10),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHR_OCP_INT, 0, 0x20),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHR_CNP_INT, 0, 0x40),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHL_OCP_INT, 0, 0x80),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHL_CNP_INT, 1, 0x01),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_EAR_CNP_INT, 1, 0x02),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_EAR_OCP_INT, 1, 0x04),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_LO_CNP_INT, 1, 0x08),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_LO_OCP_INT, 1, 0x10),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHL_PDM_WD_INT, 1, 0x20),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHR_PDM_WD_INT, 1, 0x40),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHL_SURGE_DET_INT, 2, 0x04),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHR_SURGE_DET_INT, 2, 0x08),
+};
+
+static struct regmap_irq_chip rouleur_regmap_irq_chip = {
+ .name = "rouleur",
+ .irqs = ROULEUR_IRQs,
+ .num_irqs = ARRAY_SIZE(ROULEUR_IRQs),
+ .num_regs = 3,
+ .status_base = ROULEUR_DIG_SWR_INTR_STATUS_0,
+ .mask_base = ROULEUR_DIG_SWR_INTR_MASK_0,
+ .ack_base = ROULEUR_DIG_SWR_INTR_CLEAR_0,
+ .use_ack = 1,
+ .type_base = ROULEUR_DIG_SWR_INTR_LEVEL_0,
+ .runtime_pm = false,
+ .handle_post_irq = rouleur_handle_post_irq,
+ .irq_drv_data = NULL,
+};
+
+static int rouleur_handle_post_irq(void *data)
+{
+ struct rouleur_priv *rouleur = data;
+ u32 status1 = 0, status2 = 0, status3 = 0;
+
+ regmap_read(rouleur->regmap, ROULEUR_DIG_SWR_INTR_STATUS_0, &status1);
+ regmap_read(rouleur->regmap, ROULEUR_DIG_SWR_INTR_STATUS_1, &status2);
+ regmap_read(rouleur->regmap, ROULEUR_DIG_SWR_INTR_STATUS_2, &status3);
+
+ rouleur->tx_swr_dev->slave_irq_pending =
+ ((status1 || status2 || status3) ? true : false);
+
+ return IRQ_HANDLED;
+}
+
+static int rouleur_init_reg(struct snd_soc_component *component)
+{
+ /* Enable surge protection */
+ snd_soc_component_update_bits(component, ROULEUR_ANA_SURGE_EN,
+ 0xC0, 0xC0);
+ return 0;
+}
+
+static int rouleur_set_port_params(struct snd_soc_component *component,
+ u8 slv_prt_type, u8 *port_id, u8 *num_ch,
+ u8 *ch_mask, u32 *ch_rate,
+ u8 *port_type, u8 path)
+{
+ int i, j;
+ u8 num_ports = 0;
+ struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT] = NULL;
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ switch (path) {
+ case CODEC_RX:
+ map = &rouleur->rx_port_mapping;
+ num_ports = rouleur->num_rx_ports;
+ break;
+ case CODEC_TX:
+ map = &rouleur->tx_port_mapping;
+ num_ports = rouleur->num_tx_ports;
+ break;
+ default:
+ dev_err(component->dev, "%s Invalid path: %d\n",
+ __func__, path);
+ return -EINVAL;
+ }
+
+ for (i = 0; i <= num_ports; i++) {
+ for (j = 0; j < MAX_CH_PER_PORT; j++) {
+ if ((*map)[i][j].slave_port_type == slv_prt_type)
+ goto found;
+ }
+ }
+
+ dev_err(component->dev, "%s Failed to find slave port for type %u\n",
+ __func__, slv_prt_type);
+ return -EINVAL;
+found:
+ *port_id = i;
+ *num_ch = (*map)[i][j].num_ch;
+ *ch_mask = (*map)[i][j].ch_mask;
+ *ch_rate = (*map)[i][j].ch_rate;
+ *port_type = (*map)[i][j].master_port_type;
+
+ return 0;
+}
+
+static int rouleur_parse_port_mapping(struct device *dev,
+ char *prop, u8 path)
+{
+ u32 *dt_array, map_size, map_length;
+ u32 port_num = 0, ch_mask, ch_rate, old_port_num = 0;
+ u32 slave_port_type, master_port_type;
+ u32 i, ch_iter = 0;
+ int ret = 0;
+ u8 *num_ports = NULL;
+ struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT] = NULL;
+ struct rouleur_priv *rouleur = dev_get_drvdata(dev);
+
+ switch (path) {
+ case CODEC_RX:
+ map = &rouleur->rx_port_mapping;
+ num_ports = &rouleur->num_rx_ports;
+ break;
+ case CODEC_TX:
+ map = &rouleur->tx_port_mapping;
+ num_ports = &rouleur->num_tx_ports;
+ break;
+ default:
+ dev_err(dev, "%s Invalid path: %d\n",
+ __func__, path);
+ return -EINVAL;
+ }
+
+ if (!of_find_property(dev->of_node, prop,
+ &map_size)) {
+ dev_err(dev, "missing port mapping prop %s\n", prop);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ map_length = map_size / (NUM_SWRS_DT_PARAMS * sizeof(u32));
+
+ dt_array = kzalloc(map_size, GFP_KERNEL);
+
+ if (!dt_array) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ ret = of_property_read_u32_array(dev->of_node, prop, dt_array,
+ NUM_SWRS_DT_PARAMS * map_length);
+ if (ret) {
+ dev_err(dev, "%s: Failed to read port mapping from prop %s\n",
+ __func__, prop);
+ ret = -EINVAL;
+ goto err_pdata_fail;
+ }
+
+ for (i = 0; i < map_length; i++) {
+ port_num = dt_array[NUM_SWRS_DT_PARAMS * i];
+ slave_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 1];
+ ch_mask = dt_array[NUM_SWRS_DT_PARAMS * i + 2];
+ ch_rate = dt_array[NUM_SWRS_DT_PARAMS * i + 3];
+ master_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 4];
+
+ if (port_num != old_port_num)
+ ch_iter = 0;
+
+ (*map)[port_num][ch_iter].slave_port_type = slave_port_type;
+ (*map)[port_num][ch_iter].ch_mask = ch_mask;
+ (*map)[port_num][ch_iter].master_port_type = master_port_type;
+ (*map)[port_num][ch_iter].num_ch = __sw_hweight8(ch_mask);
+ (*map)[port_num][ch_iter++].ch_rate = ch_rate;
+ old_port_num = port_num;
+ }
+ *num_ports = port_num;
+
+err_pdata_fail:
+ kfree(dt_array);
+err:
+ return ret;
+}
+
+static int rouleur_tx_connect_port(struct snd_soc_component *component,
+ u8 slv_port_type, u8 enable)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ u8 port_id;
+ u8 num_ch;
+ u8 ch_mask;
+ u32 ch_rate;
+ u8 port_type;
+ u8 num_port = 1;
+ int ret = 0;
+
+ ret = rouleur_set_port_params(component, slv_port_type, &port_id,
+ &num_ch, &ch_mask, &ch_rate,
+ &port_type, CODEC_TX);
+
+ if (ret) {
+ dev_err(rouleur->dev, "%s:Failed to set port params: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (enable)
+ ret = swr_connect_port(rouleur->tx_swr_dev, &port_id,
+ num_port, &ch_mask, &ch_rate,
+ &num_ch, &port_type);
+ else
+ ret = swr_disconnect_port(rouleur->tx_swr_dev, &port_id,
+ num_port, &ch_mask, &port_type);
+ return ret;
+
+}
+static int rouleur_rx_connect_port(struct snd_soc_component *component,
+ u8 slv_port_type, u8 enable)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ u8 port_id;
+ u8 num_ch;
+ u8 ch_mask;
+ u32 ch_rate;
+ u8 port_type;
+ u8 num_port = 1;
+ int ret = 0;
+
+ ret = rouleur_set_port_params(component, slv_port_type, &port_id,
+ &num_ch, &ch_mask, &ch_rate,
+ &port_type, CODEC_RX);
+
+ if (ret) {
+ dev_err(rouleur->dev, "%s:Failed to set port params: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (enable)
+ ret = swr_connect_port(rouleur->rx_swr_dev, &port_id,
+ num_port, &ch_mask, &ch_rate,
+ &num_ch, &port_type);
+ else
+ ret = swr_disconnect_port(rouleur->rx_swr_dev, &port_id,
+ num_port, &ch_mask, &port_type);
+ return ret;
+}
+
+static int rouleur_global_mbias_enable(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&rouleur->main_bias_lock);
+ if (rouleur->mbias_cnt == 0) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBIAS_EN, 0x20, 0x20);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBIAS_EN, 0x10, 0x10);
+ usleep_range(1000, 1100);
+ }
+ rouleur->mbias_cnt++;
+ mutex_unlock(&rouleur->main_bias_lock);
+
+ return 0;
+}
+
+static int rouleur_global_mbias_disable(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&rouleur->main_bias_lock);
+ if (rouleur->mbias_cnt == 0) {
+ dev_dbg(rouleur->dev, "%s:mbias already disabled\n", __func__);
+ mutex_unlock(&rouleur->main_bias_lock);
+ return 0;
+ }
+ rouleur->mbias_cnt--;
+ if (rouleur->mbias_cnt == 0) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBIAS_EN, 0x10, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBIAS_EN, 0x20, 0x00);
+ }
+ mutex_unlock(&rouleur->main_bias_lock);
+
+ return 0;
+}
+
+static int rouleur_rx_clk_enable(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&rouleur->rx_clk_lock);
+ if (rouleur->rx_clk_cnt == 0) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x10, 0x10);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x20, 0x20);
+ usleep_range(5000, 5100);
+ rouleur_global_mbias_enable(component);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_FSM_CLK, 0x11, 0x11);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_FSM_CLK, 0x80, 0x80);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_NCP_EN, 0x01, 0x01);
+ usleep_range(500, 510);
+ }
+ rouleur->rx_clk_cnt++;
+ mutex_unlock(&rouleur->rx_clk_lock);
+
+ return 0;
+}
+
+static int rouleur_rx_clk_disable(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&rouleur->rx_clk_lock);
+ if (rouleur->rx_clk_cnt == 0) {
+ dev_dbg(rouleur->dev, "%s:clk already disabled\n", __func__);
+ mutex_unlock(&rouleur->rx_clk_lock);
+ return 0;
+ }
+ rouleur->rx_clk_cnt--;
+ if (rouleur->rx_clk_cnt == 0) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_FSM_CLK, 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_FSM_CLK, 0x11, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_NCP_EN, 0x01, 0x00);
+ rouleur_global_mbias_disable(component);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x20, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x10, 0x00);
+
+ }
+ mutex_unlock(&rouleur->rx_clk_lock);
+ return 0;
+}
+
+/*
+ * rouleur_soc_get_mbhc: get rouleur_mbhc handle of corresponding component
+ * @component: handle to snd_soc_component *
+ *
+ * return rouleur_mbhc handle or error code in case of failure
+ */
+struct rouleur_mbhc *rouleur_soc_get_mbhc(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur;
+
+ if (!component) {
+ pr_err("%s: Invalid params, NULL component\n", __func__);
+ return NULL;
+ }
+ rouleur = snd_soc_component_get_drvdata(component);
+
+ if (!rouleur) {
+ pr_err("%s: Invalid params, NULL tavil\n", __func__);
+ return NULL;
+ }
+
+ return rouleur->mbhc;
+}
+EXPORT_SYMBOL(rouleur_soc_get_mbhc);
+
+static int rouleur_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ rouleur_rx_clk_enable(component);
+ set_bit(HPH_COMP_DELAY, &rouleur->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (rouleur->comp1_enable) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+ 0x02, 0x02);
+
+ if (rouleur->comp2_enable)
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+ 0x01, 0x01);
+ /*
+ * 5ms sleep is required after COMP is enabled as per
+ * HW requirement
+ */
+ if (test_bit(HPH_COMP_DELAY, &rouleur->status_mask)) {
+ usleep_range(5000, 5100);
+ clear_bit(HPH_COMP_DELAY,
+ &rouleur->status_mask);
+ }
+ } else {
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+ 0x02, 0x00);
+ }
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX0_CTL,
+ 0x7C, 0x7C);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL,
+ 0x04, 0x04);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x01, 0x01);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_PDM_WD_CTL0,
+ 0x03, 0x03);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_PDM_WD_CTL0,
+ 0x03, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL,
+ 0x01, 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int rouleur_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ rouleur_rx_clk_enable(component);
+ set_bit(HPH_COMP_DELAY, &rouleur->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (rouleur->comp2_enable) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+ 0x01, 0x01);
+
+ if (rouleur->comp1_enable)
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+ 0x02, 0x02);
+ /*
+ * 5ms sleep is required after COMP is enabled as per
+ * HW requirement
+ */
+ if (test_bit(HPH_COMP_DELAY, &rouleur->status_mask)) {
+ usleep_range(5000, 5100);
+ clear_bit(HPH_COMP_DELAY,
+ &rouleur->status_mask);
+ }
+ } else {
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+ 0x01, 0x00);
+ }
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX1_CTL,
+ 0x7C, 0x7C);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL,
+ 0x08, 0x08);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x02, 0x02);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_PDM_WD_CTL1,
+ 0x03, 0x03);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_PDM_WD_CTL1,
+ 0x03, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x02, 0x00);
+ break;
+
+ }
+
+ return 0;
+}
+
+static int rouleur_codec_ear_lo_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ rouleur_rx_clk_enable(component);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX0_CTL,
+ 0x7C, 0x7C);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL,
+ 0x01, 0x01);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_PDM_WD_CTL0,
+ 0x03, 0x03);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL,
+ 0x04, 0x04);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_PDM_WD_CTL0,
+ 0x03, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL,
+ 0x01, 0x00);
+
+ break;
+ };
+ return 0;
+
+}
+
+static int rouleur_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
+ rouleur->rx_swr_dev->dev_num,
+ true);
+
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x40, 0x40);
+ set_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ /* TODO: WHY SECOND TIME */
+ ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
+ rouleur->rx_swr_dev->dev_num,
+ true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /*
+ * 5ms sleep is required after PA is enabled as per
+ * HW requirement.
+ */
+ if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) {
+ usleep_range(5000, 5100);
+ clear_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ }
+
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX2 << 0x10));
+ wcd_enable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHR_PDM_WD_INT);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wcd_disable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHR_PDM_WD_INT);
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX2 << 0x10 | 0x1));
+ blocking_notifier_call_chain(&rouleur->mbhc->notifier,
+ WCD_EVENT_PRE_HPHR_PA_OFF,
+ &rouleur->mbhc->wcd_mbhc);
+ set_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /*
+ * 7ms sleep is required after PA is disabled as per
+ * HW requirement. If compander is disabled, then
+ * 20ms delay is required.
+ */
+ if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) {
+
+ usleep_range(5000, 5100);
+ clear_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ }
+
+ blocking_notifier_call_chain(&rouleur->mbhc->notifier,
+ WCD_EVENT_POST_HPHR_PA_OFF,
+ &rouleur->mbhc->wcd_mbhc);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x40, 0x00);
+ break;
+ };
+ return ret;
+}
+
+static int rouleur_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
+ rouleur->rx_swr_dev->dev_num,
+ true);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x80, 0x80);
+ set_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /*
+ * 5ms sleep is required after PA is enabled as per
+ * HW requirement.
+ */
+ if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) {
+ usleep_range(5000, 5100);
+ clear_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ }
+
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10));
+ wcd_enable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wcd_disable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT);
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10 | 0x1));
+ blocking_notifier_call_chain(&rouleur->mbhc->notifier,
+ WCD_EVENT_PRE_HPHL_PA_OFF,
+ &rouleur->mbhc->wcd_mbhc);
+ set_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /*
+ * 5ms sleep is required after PA is disabled as per
+ * HW requirement.
+ */
+ if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) {
+ usleep_range(5000, 5100);
+ clear_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ }
+
+ blocking_notifier_call_chain(&rouleur->mbhc->notifier,
+ WCD_EVENT_POST_HPHL_PA_OFF,
+ &rouleur->mbhc->wcd_mbhc);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x80, 0x00);
+
+ break;
+ };
+ return ret;
+}
+
+static int rouleur_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
+ rouleur->rx_swr_dev->dev_num,
+ true);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x80, 0x80);
+ usleep_range(5000, 5100);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10));
+ wcd_enable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wcd_disable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT);
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10 | 0x1));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x80, 0x00);
+ usleep_range(5000, 5100);
+ };
+ return ret;
+}
+
+static int rouleur_codec_enable_lo_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
+ rouleur->rx_swr_dev->dev_num,
+ true);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x40, 0x40);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x80, 0x80);
+ usleep_range(5000, 5100);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10));
+ wcd_enable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wcd_disable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT);
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10 | 0x1));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x40, 0x00);
+ usleep_range(5000, 5100);
+ };
+ return ret;
+}
+
+static int rouleur_enable_rx1(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ rouleur_rx_connect_port(component, HPH_L, true);
+ if (rouleur->comp1_enable)
+ rouleur_rx_connect_port(component, COMP_L, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ rouleur_rx_connect_port(component, HPH_L, false);
+ if (rouleur->comp1_enable)
+ rouleur_rx_connect_port(component, COMP_L, false);
+ rouleur_rx_clk_disable(component);
+ break;
+ };
+ return 0;
+}
+
+static int rouleur_enable_rx2(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ rouleur_rx_connect_port(component, HPH_R, true);
+ if (rouleur->comp2_enable)
+ rouleur_rx_connect_port(component, COMP_R, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ rouleur_rx_connect_port(component, HPH_R, false);
+ if (rouleur->comp2_enable)
+ rouleur_rx_connect_port(component, COMP_R, false);
+ rouleur_rx_clk_disable(component);
+ break;
+ };
+
+ return 0;
+}
+
+static int rouleur_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ u16 dmic_clk_reg;
+ s32 *dmic_clk_cnt;
+ unsigned int dmic;
+ char *wname;
+ int ret = 0;
+
+ wname = strpbrk(w->name, "01");
+
+ if (!wname) {
+ dev_err(component->dev, "%s: widget not found\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = kstrtouint(wname, 10, &dmic);
+ if (ret < 0) {
+ dev_err(component->dev, "%s: Invalid DMIC line on the codec\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (dmic) {
+ case 0:
+ case 1:
+ dmic_clk_cnt = &(rouleur->dmic_0_1_clk_cnt);
+ dmic_clk_reg = ROULEUR_DIG_SWR_CDC_DMIC1_CTL;
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid DMIC Selection\n",
+ __func__);
+ return -EINVAL;
+ };
+ dev_dbg(component->dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n",
+ __func__, event, dmic, *dmic_clk_cnt);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_AMIC_CTL, 0x02, 0x00);
+ snd_soc_component_update_bits(component,
+ dmic_clk_reg, 0x08, 0x08);
+ rouleur_tx_connect_port(component, DMIC0 + (w->shift), true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ rouleur_tx_connect_port(component, DMIC0 + (w->shift), false);
+ snd_soc_component_update_bits(component,
+ dmic_clk_reg, 0x08, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_AMIC_CTL, 0x02, 0x02);
+ break;
+
+ };
+ return 0;
+}
+
+static int rouleur_tx_swr_ctrl(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = swr_slvdev_datapath_control(rouleur->tx_swr_dev,
+ rouleur->tx_swr_dev->dev_num,
+ true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ ret = swr_slvdev_datapath_control(rouleur->tx_swr_dev,
+ rouleur->tx_swr_dev->dev_num,
+ false);
+ break;
+ };
+
+ return ret;
+}
+
+static int rouleur_codec_enable_adc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur =
+ snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable BCS for Headset mic */
+ if (w->shift == 1 && !(snd_soc_component_read32(component,
+ ROULEUR_ANA_TX_AMIC2) & 0x10)) {
+ rouleur_tx_connect_port(component, MBHC, true);
+ set_bit(AMIC2_BCS_ENABLE, &rouleur->status_mask);
+ }
+ rouleur_tx_connect_port(component, ADC1 + (w->shift), true);
+ rouleur_global_mbias_enable(component);
+ if (w->shift)
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1,
+ 0x30, 0x30);
+ else
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1,
+ 0x03, 0x03);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ rouleur_tx_connect_port(component, ADC1 + (w->shift), false);
+ if (w->shift == 1 &&
+ test_bit(AMIC2_BCS_ENABLE, &rouleur->status_mask)) {
+ rouleur_tx_connect_port(component, MBHC, false);
+ clear_bit(AMIC2_BCS_ENABLE, &rouleur->status_mask);
+ }
+ if (w->shift)
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1,
+ 0x30, 0x00);
+ else
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1,
+ 0x03, 0x00);
+ rouleur_global_mbias_disable(component);
+ break;
+ };
+
+ return 0;
+}
+
+/*
+ * rouleur_get_micb_vout_ctl_val: converts micbias from volts to register value
+ * @micb_mv: micbias in mv
+ *
+ * return register value converted
+ */
+int rouleur_get_micb_vout_ctl_val(u32 micb_mv)
+{
+ /* min micbias voltage is 1.6V and maximum is 2.85V */
+ if (micb_mv < 1600 || micb_mv > 2850) {
+ pr_err("%s: unsupported micbias voltage\n", __func__);
+ return -EINVAL;
+ }
+
+ return (micb_mv - 1600) / 50;
+}
+EXPORT_SYMBOL(rouleur_get_micb_vout_ctl_val);
+
+/*
+ * rouleur_mbhc_micb_adjust_voltage: adjust specific micbias voltage
+ * @component: handle to snd_soc_component *
+ * @req_volt: micbias voltage to be set
+ * @micb_num: micbias to be set, e.g. micbias1 or micbias2
+ *
+ * return 0 if adjustment is success or error code in case of failure
+ */
+int rouleur_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
+ int req_volt, int micb_num)
+{
+ struct rouleur_priv *rouleur =
+ snd_soc_component_get_drvdata(component);
+ int cur_vout_ctl, req_vout_ctl;
+ int micb_reg, micb_val, micb_en;
+ int ret = 0;
+ int pullup_mask;
+
+ micb_reg = ROULEUR_ANA_MICBIAS_MICB_1_2_EN;
+ switch (micb_num) {
+ case MIC_BIAS_1:
+ micb_val = snd_soc_component_read32(component, micb_reg);
+ micb_en = (micb_val & 0x40) >> 6;
+ pullup_mask = 0x20;
+ break;
+ case MIC_BIAS_2:
+ micb_val = snd_soc_component_read32(component, micb_reg);
+ micb_en = (micb_val & 0x04) >> 2;
+ pullup_mask = 0x02;
+ break;
+ case MIC_BIAS_3:
+ default:
+ dev_err(component->dev, "%s: Invalid micbias number: %d\n",
+ __func__, micb_num);
+ return -EINVAL;
+ }
+ mutex_lock(&rouleur->micb_lock);
+
+ /*
+ * If requested micbias voltage is same as current micbias
+ * voltage, then just return. Otherwise, adjust voltage as
+ * per requested value. If micbias is already enabled, then
+ * to avoid slow micbias ramp-up or down enable pull-up
+ * momentarily, change the micbias value and then re-enable
+ * micbias.
+ */
+ cur_vout_ctl = (snd_soc_component_read32(component,
+ ROULEUR_ANA_MICBIAS_LDO_1_SETTING)) & 0xF8;
+
+ req_vout_ctl = rouleur_get_micb_vout_ctl_val(req_volt);
+ if (req_vout_ctl < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ if (cur_vout_ctl == req_vout_ctl) {
+ ret = 0;
+ goto exit;
+ }
+
+ dev_dbg(component->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n",
+ __func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl),
+ req_volt, micb_en);
+
+ if (micb_en == 0x1)
+ snd_soc_component_update_bits(component, micb_reg, pullup_mask,
+ pullup_mask);
+
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MICBIAS_LDO_1_SETTING, 0xF8, req_vout_ctl);
+
+ if (micb_en == 0x1) {
+ snd_soc_component_update_bits(component, micb_reg,
+ pullup_mask, 0x00);
+ /*
+ * Add 2ms delay as per HW requirement after enabling
+ * micbias
+ */
+ usleep_range(2000, 2100);
+ }
+exit:
+ mutex_unlock(&rouleur->micb_lock);
+ return ret;
+}
+EXPORT_SYMBOL(rouleur_mbhc_micb_adjust_voltage);
+
+int rouleur_micbias_control(struct snd_soc_component *component,
+ int micb_num, int req, bool is_dapm)
+{
+
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int micb_index = micb_num - 1;
+ u16 micb_reg;
+ int pre_off_event = 0, post_off_event = 0;
+ int post_on_event = 0, post_dapm_off = 0;
+ int post_dapm_on = 0;
+ u8 pullup_mask = 0, enable_mask = 0;
+
+ if ((micb_index < 0) || (micb_index > ROULEUR_MAX_MICBIAS - 1)) {
+ dev_err(component->dev, "%s: Invalid micbias index, micb_ind:%d\n",
+ __func__, micb_index);
+ return -EINVAL;
+ }
+ switch (micb_num) {
+ case MIC_BIAS_1:
+ micb_reg = ROULEUR_ANA_MICBIAS_MICB_1_2_EN;
+ pullup_mask = 0x20;
+ enable_mask = 0x40;
+ break;
+ case MIC_BIAS_2:
+ micb_reg = ROULEUR_ANA_MICBIAS_MICB_1_2_EN;
+ pullup_mask = 0x02;
+ enable_mask = 0x04;
+ pre_off_event = WCD_EVENT_PRE_MICBIAS_2_OFF;
+ post_off_event = WCD_EVENT_POST_MICBIAS_2_OFF;
+ post_on_event = WCD_EVENT_POST_MICBIAS_2_ON;
+ post_dapm_on = WCD_EVENT_POST_DAPM_MICBIAS_2_ON;
+ post_dapm_off = WCD_EVENT_POST_DAPM_MICBIAS_2_OFF;
+ break;
+ case MIC_BIAS_3:
+ micb_reg = ROULEUR_ANA_MICBIAS_MICB_3_EN;
+ pullup_mask = 0x02;
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid micbias number: %d\n",
+ __func__, micb_num);
+ return -EINVAL;
+ };
+ mutex_lock(&rouleur->micb_lock);
+
+ switch (req) {
+ case MICB_PULLUP_ENABLE:
+ rouleur->pullup_ref[micb_index]++;
+ if ((rouleur->pullup_ref[micb_index] == 1) &&
+ (rouleur->micb_ref[micb_index] == 0))
+ snd_soc_component_update_bits(component, micb_reg,
+ pullup_mask, pullup_mask);
+ break;
+ case MICB_PULLUP_DISABLE:
+ if (rouleur->pullup_ref[micb_index] > 0)
+ rouleur->pullup_ref[micb_index]--;
+ if ((rouleur->pullup_ref[micb_index] == 0) &&
+ (rouleur->micb_ref[micb_index] == 0))
+ snd_soc_component_update_bits(component, micb_reg,
+ pullup_mask, 0x00);
+ break;
+ case MICB_ENABLE:
+ rouleur->micb_ref[micb_index]++;
+ if (rouleur->micb_ref[micb_index] == 1) {
+ rouleur_global_mbias_enable(component);
+ snd_soc_component_update_bits(component,
+ micb_reg, enable_mask, enable_mask);
+ if (post_on_event)
+ blocking_notifier_call_chain(
+ &rouleur->mbhc->notifier, post_on_event,
+ &rouleur->mbhc->wcd_mbhc);
+ }
+ if (is_dapm && post_dapm_on && rouleur->mbhc)
+ blocking_notifier_call_chain(
+ &rouleur->mbhc->notifier, post_dapm_on,
+ &rouleur->mbhc->wcd_mbhc);
+ break;
+ case MICB_DISABLE:
+ if (rouleur->micb_ref[micb_index] > 0)
+ rouleur->micb_ref[micb_index]--;
+ if ((rouleur->micb_ref[micb_index] == 0) &&
+ (rouleur->pullup_ref[micb_index] == 0)) {
+ if (pre_off_event && rouleur->mbhc)
+ blocking_notifier_call_chain(
+ &rouleur->mbhc->notifier, pre_off_event,
+ &rouleur->mbhc->wcd_mbhc);
+ snd_soc_component_update_bits(component, micb_reg,
+ enable_mask, 0x00);
+ rouleur_global_mbias_disable(component);
+ if (post_off_event && rouleur->mbhc)
+ blocking_notifier_call_chain(
+ &rouleur->mbhc->notifier,
+ post_off_event,
+ &rouleur->mbhc->wcd_mbhc);
+ }
+ if (is_dapm && post_dapm_off && rouleur->mbhc)
+ blocking_notifier_call_chain(
+ &rouleur->mbhc->notifier, post_dapm_off,
+ &rouleur->mbhc->wcd_mbhc);
+ break;
+ };
+
+ dev_dbg(component->dev, "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n",
+ __func__, micb_num, rouleur->micb_ref[micb_index],
+ rouleur->pullup_ref[micb_index]);
+ mutex_unlock(&rouleur->micb_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(rouleur_micbias_control);
+
+void rouleur_disable_bcs_before_slow_insert(struct snd_soc_component *component,
+ bool bcs_disable)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ if (rouleur->update_wcd_event) {
+ if (bcs_disable)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_BCS_CLK_OFF, 0);
+ else
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_BCS_CLK_OFF, 1);
+ }
+}
+
+static int rouleur_get_logical_addr(struct swr_device *swr_dev)
+{
+ int ret = 0;
+ uint8_t devnum = 0;
+ int num_retry = NUM_ATTEMPTS;
+
+ do {
+ ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum);
+ if (ret) {
+ dev_err(&swr_dev->dev,
+ "%s get devnum %d for dev addr %lx failed\n",
+ __func__, devnum, swr_dev->addr);
+ /* retry after 1ms */
+ usleep_range(1000, 1010);
+ }
+ } while (ret && --num_retry);
+ swr_dev->dev_num = devnum;
+ return 0;
+}
+
+static int rouleur_event_notify(struct notifier_block *block,
+ unsigned long val,
+ void *data)
+{
+ u16 event = (val & 0xffff);
+ int ret = 0;
+ struct rouleur_priv *rouleur = dev_get_drvdata((struct device *)data);
+ struct snd_soc_component *component = rouleur->component;
+ struct wcd_mbhc *mbhc;
+
+ switch (event) {
+ case BOLERO_WCD_EVT_PA_OFF_PRE_SSR:
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0xC0, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x40, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x40, 0x40);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x80, 0x00);
+ break;
+ case BOLERO_WCD_EVT_SSR_DOWN:
+ rouleur->mbhc->wcd_mbhc.deinit_in_progress = true;
+ mbhc = &rouleur->mbhc->wcd_mbhc;
+ rouleur_mbhc_ssr_down(rouleur->mbhc, component);
+ rouleur_reset(rouleur->dev, 0x01);
+ break;
+ case BOLERO_WCD_EVT_SSR_UP:
+ rouleur_reset(rouleur->dev, 0x00);
+ /* allow reset to take effect */
+ usleep_range(10000, 10010);
+ rouleur_get_logical_addr(rouleur->tx_swr_dev);
+ rouleur_get_logical_addr(rouleur->rx_swr_dev);
+
+ rouleur_init_reg(component);
+ regcache_mark_dirty(rouleur->regmap);
+ regcache_sync(rouleur->regmap);
+ /* Initialize MBHC module */
+ mbhc = &rouleur->mbhc->wcd_mbhc;
+ ret = rouleur_mbhc_post_ssr_init(rouleur->mbhc, component);
+ if (ret) {
+ dev_err(component->dev, "%s: mbhc initialization failed\n",
+ __func__);
+ } else {
+ rouleur_mbhc_hs_detect(component, mbhc->mbhc_cfg);
+ }
+ rouleur->mbhc->wcd_mbhc.deinit_in_progress = false;
+ break;
+ default:
+ dev_err(component->dev, "%s: invalid event %d\n", __func__,
+ event);
+ break;
+ }
+ return 0;
+}
+
+static int __rouleur_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ int micb_num;
+
+ dev_dbg(component->dev, "%s: wname: %s, event: %d\n",
+ __func__, w->name, event);
+
+ if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1")))
+ micb_num = MIC_BIAS_1;
+ else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2")))
+ micb_num = MIC_BIAS_2;
+ else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3")))
+ micb_num = MIC_BIAS_3;
+ else
+ return -EINVAL;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Micbias LD0 enable not supported for MicBias 3*/
+ if (micb_num == MIC_BIAS_3)
+ rouleur_micbias_control(component, micb_num,
+ MICB_PULLUP_ENABLE, true);
+ else
+ rouleur_micbias_control(component, micb_num,
+ MICB_ENABLE, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(1000, 1100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (micb_num == MIC_BIAS_3)
+ rouleur_micbias_control(component, micb_num,
+ MICB_PULLUP_DISABLE, true);
+ else
+ rouleur_micbias_control(component, micb_num,
+ MICB_DISABLE, true);
+ break;
+ };
+
+ return 0;
+
+}
+
+static int rouleur_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ return __rouleur_codec_enable_micbias(w, event);
+}
+
+static int __rouleur_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ int micb_num;
+
+ dev_dbg(component->dev, "%s: wname: %s, event: %d\n",
+ __func__, w->name, event);
+
+ if (strnstr(w->name, "VA MIC BIAS1", sizeof("VA MIC BIAS1")))
+ micb_num = MIC_BIAS_1;
+ else if (strnstr(w->name, "VA MIC BIAS2", sizeof("VA MIC BIAS2")))
+ micb_num = MIC_BIAS_2;
+ else if (strnstr(w->name, "VA MIC BIAS3", sizeof("VA MIC BIAS3")))
+ micb_num = MIC_BIAS_3;
+ else
+ return -EINVAL;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ rouleur_micbias_control(component, micb_num,
+ MICB_PULLUP_ENABLE, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* 1 msec delay as per HW requirement */
+ usleep_range(1000, 1100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ rouleur_micbias_control(component, micb_num,
+ MICB_PULLUP_DISABLE, true);
+ break;
+ };
+
+ return 0;
+
+}
+
+static int rouleur_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ return __rouleur_codec_enable_micbias_pullup(w, event);
+}
+
+static int rouleur_get_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ bool hphr;
+ struct soc_multi_mixer_control *mc;
+
+ mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+
+ ucontrol->value.integer.value[0] = hphr ? rouleur->comp2_enable :
+ rouleur->comp1_enable;
+ return 0;
+}
+
+static int rouleur_set_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int value = ucontrol->value.integer.value[0];
+ bool hphr;
+ struct soc_multi_mixer_control *mc;
+
+ mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+ if (hphr)
+ rouleur->comp2_enable = value;
+ else
+ rouleur->comp1_enable = value;
+
+ return 0;
+}
+
+static int rouleur_codec_enable_pa_vpos(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ struct rouleur_pdata *pdata = NULL;
+ int ret = 0;
+
+ pdata = dev_get_platdata(rouleur->dev);
+
+ if (!pdata) {
+ dev_err(component->dev, "%s: pdata is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (test_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask)) {
+ dev_dbg(component->dev,
+ "%s: vpos already in enabled state\n",
+ __func__);
+ clear_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask);
+ return 0;
+ }
+ ret = msm_cdc_enable_ondemand_supply(rouleur->dev,
+ rouleur->supplies,
+ pdata->regulator,
+ pdata->num_supplies,
+ "cdc-pa-vpos");
+ if (ret == -EINVAL) {
+ dev_err(component->dev, "%s: pa vpos is not enabled\n",
+ __func__);
+ return ret;
+ }
+ clear_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask);
+ /*
+ * 200us sleep is required after LDO15 is enabled as per
+ * HW requirement
+ */
+ usleep_range(200, 250);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ set_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_kcontrol_new rouleur_snd_controls[] = {
+ SOC_SINGLE_EXT("HPHL_COMP Switch", SND_SOC_NOPM, 0, 1, 0,
+ rouleur_get_compander, rouleur_set_compander),
+ SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0,
+ rouleur_get_compander, rouleur_set_compander),
+
+ SOC_SINGLE_TLV("HPHL Volume", ROULEUR_ANA_HPHPA_L_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", ROULEUR_ANA_HPHPA_R_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("ADC1 Volume", ROULEUR_ANA_TX_AMIC1, 0, 8, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", ROULEUR_ANA_TX_AMIC2, 0, 8, 0,
+ analog_gain),
+};
+
+static const struct snd_kcontrol_new adc1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new ear_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new lo_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphl_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphr_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const char * const adc2_mux_text[] = {
+ "INP2", "INP3"
+};
+
+static const struct soc_enum adc2_enum =
+ SOC_ENUM_SINGLE(ROULEUR_ANA_TX_AMIC2, 4,
+ ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+
+static const struct snd_kcontrol_new tx_adc2_mux =
+ SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
+
+static const struct snd_soc_dapm_widget rouleur_dapm_widgets[] = {
+
+ /*input widgets*/
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_INPUT("AMIC3"),
+ SND_SOC_DAPM_INPUT("IN1_HPHL"),
+ SND_SOC_DAPM_INPUT("IN2_HPHR"),
+
+ /*tx widgets*/
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0,
+ rouleur_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
+ &tx_adc2_mux),
+
+ /*tx mixers*/
+ SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0,
+ adc1_switch, ARRAY_SIZE(adc1_switch),
+ rouleur_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 0, 0,
+ adc2_switch, ARRAY_SIZE(adc2_switch),
+ rouleur_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* micbias widgets*/
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY("PA_VPOS", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_pa_vpos,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /*rx widgets*/
+ SND_SOC_DAPM_PGA_E("EAR PGA", ROULEUR_ANA_COMBOPA_CTL, 7, 0, NULL, 0,
+ rouleur_codec_enable_ear_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LO PGA", ROULEUR_ANA_COMBOPA_CTL, 7, 0, NULL, 0,
+ rouleur_codec_enable_lo_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHL PGA", ROULEUR_ANA_HPHPA_CNP_CTL_2, 7, 0, NULL,
+ 0, rouleur_codec_enable_hphl_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHR PGA", ROULEUR_ANA_HPHPA_CNP_CTL_2, 6, 0, NULL,
+ 0, rouleur_codec_enable_hphr_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0,
+ rouleur_codec_hphl_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0,
+ rouleur_codec_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0,
+ rouleur_codec_ear_lo_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rouleur_enable_rx1, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rouleur_enable_rx2, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* rx mixer widgets*/
+
+ SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0,
+ ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)),
+ SND_SOC_DAPM_MIXER("LO_RDAC", SND_SOC_NOPM, 0, 0,
+ lo_rdac_switch, ARRAY_SIZE(lo_rdac_switch)),
+ SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0,
+ hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)),
+ SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0,
+ hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)),
+
+ /*output widgets tx*/
+
+ SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"),
+
+ /*output widgets rx*/
+ SND_SOC_DAPM_OUTPUT("EAR"),
+ SND_SOC_DAPM_OUTPUT("LO"),
+ SND_SOC_DAPM_OUTPUT("HPHL"),
+ SND_SOC_DAPM_OUTPUT("HPHR"),
+
+ /* micbias pull up widgets*/
+ SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS1", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS2", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS3", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0,
+ rouleur_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /*tx mixer widgets*/
+ SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0,
+ 0, dmic1_switch, ARRAY_SIZE(dmic1_switch),
+ rouleur_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 0,
+ 0, dmic2_switch, ARRAY_SIZE(dmic2_switch),
+ rouleur_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /*output widgets*/
+ SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"),
+};
+
+static const struct snd_soc_dapm_route rouleur_audio_map[] = {
+ {"ADC1_OUTPUT", NULL, "ADC1_MIXER"},
+ {"ADC1_MIXER", "Switch", "ADC1"},
+ {"ADC1", NULL, "AMIC1"},
+
+ {"ADC2_OUTPUT", NULL, "ADC2_MIXER"},
+ {"ADC2_MIXER", "Switch", "ADC2"},
+ {"ADC2", NULL, "ADC2 MUX"},
+ {"ADC2 MUX", "INP3", "AMIC3"},
+ {"ADC2 MUX", "INP2", "AMIC2"},
+
+ {"IN1_HPHL", NULL, "PA_VPOS"},
+ {"RX1", NULL, "IN1_HPHL"},
+ {"RDAC1", NULL, "RX1"},
+ {"HPHL_RDAC", "Switch", "RDAC1"},
+ {"HPHL PGA", NULL, "HPHL_RDAC"},
+ {"HPHL", NULL, "HPHL PGA"},
+
+ {"IN2_HPHR", NULL, "PA_VPOS"},
+ {"RX2", NULL, "IN2_HPHR"},
+ {"RDAC2", NULL, "RX2"},
+ {"HPHR_RDAC", "Switch", "RDAC2"},
+ {"HPHR PGA", NULL, "HPHR_RDAC"},
+ {"HPHR", NULL, "HPHR PGA"},
+
+ {"RDAC3", NULL, "RX1"},
+ {"EAR_RDAC", "Switch", "RDAC3"},
+ {"EAR PGA", NULL, "EAR_RDAC"},
+ {"EAR", NULL, "EAR PGA"},
+
+ {"RDAC3", NULL, "RX1"},
+ {"LO_RDAC", "Switch", "RDAC3"},
+ {"LO PGA", NULL, "LO_RDAC"},
+ {"LO", NULL, "LO PGA"},
+
+ {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"},
+ {"DMIC1_MIXER", "Switch", "DMIC1"},
+
+ {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"},
+ {"DMIC2_MIXER", "Switch", "DMIC2"},
+};
+
+static ssize_t rouleur_version_read(struct snd_info_entry *entry,
+ void *file_private_data,
+ struct file *file,
+ char __user *buf, size_t count,
+ loff_t pos)
+{
+ struct rouleur_priv *priv;
+ char buffer[ROULEUR_VERSION_ENTRY_SIZE];
+ int len = 0;
+
+ priv = (struct rouleur_priv *) entry->private_data;
+ if (!priv) {
+ pr_err("%s: rouleur priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (priv->version) {
+ case ROULEUR_VERSION_1_0:
+ len = snprintf(buffer, sizeof(buffer), "rouleur_1_0\n");
+ break;
+ default:
+ len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+ }
+
+ return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops rouleur_info_ops = {
+ .read = rouleur_version_read,
+};
+
+/*
+ * rouleur_info_create_codec_entry - creates rouleur module
+ * @codec_root: The parent directory
+ * @component: component instance
+ *
+ * Creates rouleur module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int rouleur_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_component *component)
+{
+ struct snd_info_entry *version_entry;
+ struct rouleur_priv *priv;
+ struct snd_soc_card *card;
+
+ if (!codec_root || !component)
+ return -EINVAL;
+
+ priv = snd_soc_component_get_drvdata(component);
+ if (priv->entry) {
+ dev_dbg(priv->dev,
+ "%s:rouleur module already created\n", __func__);
+ return 0;
+ }
+ card = component->card;
+ priv->entry = snd_info_create_subdir(codec_root->module,
+ "rouleur", codec_root);
+ if (!priv->entry) {
+ dev_dbg(component->dev, "%s: failed to create rouleur entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+ version_entry = snd_info_create_card_entry(card->snd_card,
+ "version",
+ priv->entry);
+ if (!version_entry) {
+ dev_dbg(component->dev, "%s: failed to create rouleur version entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ version_entry->private_data = priv;
+ version_entry->size = ROULEUR_VERSION_ENTRY_SIZE;
+ version_entry->content = SNDRV_INFO_CONTENT_DATA;
+ version_entry->c.ops = &rouleur_info_ops;
+
+ if (snd_info_register(version_entry) < 0) {
+ snd_info_free_entry(version_entry);
+ return -ENOMEM;
+ }
+ priv->version_entry = version_entry;
+
+ return 0;
+}
+EXPORT_SYMBOL(rouleur_info_create_codec_entry);
+
+static int rouleur_set_micbias_data(struct rouleur_priv *rouleur,
+ struct rouleur_pdata *pdata)
+{
+ int vout_ctl = 0;
+ int rc = 0;
+
+ if (!pdata) {
+ dev_err(rouleur->dev, "%s: NULL pdata\n", __func__);
+ return -ENODEV;
+ }
+
+ /* set micbias voltage */
+ vout_ctl = rouleur_get_micb_vout_ctl_val(pdata->micbias.micb1_mv);
+ if (vout_ctl < 0) {
+ rc = -EINVAL;
+ goto done;
+ }
+ regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MICBIAS_LDO_1_SETTING,
+ 0xF8, vout_ctl);
+done:
+ return rc;
+}
+
+static int rouleur_soc_codec_probe(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ int ret = -EINVAL;
+
+ dev_info(component->dev, "%s()\n", __func__);
+ rouleur = snd_soc_component_get_drvdata(component);
+
+ if (!rouleur)
+ return -EINVAL;
+
+ rouleur->component = component;
+ snd_soc_component_init_regmap(component, rouleur->regmap);
+
+ rouleur->fw_data = devm_kzalloc(component->dev,
+ sizeof(*(rouleur->fw_data)),
+ GFP_KERNEL);
+ if (!rouleur->fw_data) {
+ dev_err(component->dev, "Failed to allocate fw_data\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ set_bit(WCD9XXX_MBHC_CAL, rouleur->fw_data->cal_bit);
+ ret = wcd_cal_create_hwdep(rouleur->fw_data,
+ WCD9XXX_CODEC_HWDEP_NODE, component);
+
+ if (ret < 0) {
+ dev_err(component->dev, "%s hwdep failed %d\n", __func__, ret);
+ goto done;
+ }
+
+ ret = rouleur_mbhc_init(&rouleur->mbhc, component, rouleur->fw_data);
+ if (ret) {
+ pr_err("%s: mbhc initialization failed\n", __func__);
+ goto done;
+ }
+ 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, "IN1_HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "IN2_HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "ADC1_OUTPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "ADC2_OUTPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "LO");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC1_OUTPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC2_OUTPUT");
+ snd_soc_dapm_sync(dapm);
+
+ rouleur_init_reg(component);
+
+ rouleur->version = ROULEUR_VERSION_1_0;
+ /* Register event notifier */
+ rouleur->nblock.notifier_call = rouleur_event_notify;
+ if (rouleur->register_notifier) {
+ ret = rouleur->register_notifier(rouleur->handle,
+ &rouleur->nblock,
+ true);
+ if (ret) {
+ dev_err(component->dev,
+ "%s: Failed to register notifier %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+done:
+ return ret;
+}
+
+static void rouleur_soc_codec_remove(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ if (!rouleur)
+ return;
+
+ if (rouleur->register_notifier)
+ rouleur->register_notifier(rouleur->handle,
+ &rouleur->nblock,
+ false);
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_rouleur = {
+ .name = DRV_NAME,
+ .probe = rouleur_soc_codec_probe,
+ .remove = rouleur_soc_codec_remove,
+ .controls = rouleur_snd_controls,
+ .num_controls = ARRAY_SIZE(rouleur_snd_controls),
+ .dapm_widgets = rouleur_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rouleur_dapm_widgets),
+ .dapm_routes = rouleur_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rouleur_audio_map),
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int rouleur_suspend(struct device *dev)
+{
+ struct rouleur_priv *rouleur = NULL;
+ int ret = 0;
+ struct rouleur_pdata *pdata = NULL;
+
+ if (!dev)
+ return -ENODEV;
+
+ rouleur = dev_get_drvdata(dev);
+ if (!rouleur)
+ return -EINVAL;
+
+ pdata = dev_get_platdata(rouleur->dev);
+
+ if (!pdata) {
+ dev_err(dev, "%s: pdata is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (test_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask)) {
+ ret = msm_cdc_disable_ondemand_supply(rouleur->dev,
+ rouleur->supplies,
+ pdata->regulator,
+ pdata->num_supplies,
+ "cdc-pa-vpos");
+ if (ret == -EINVAL) {
+ dev_err(dev, "%s: pa vpos is not disabled\n",
+ __func__);
+ return 0;
+ }
+ clear_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask);
+ }
+ return 0;
+}
+
+static int rouleur_resume(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+static int rouleur_reset(struct device *dev, int reset_val)
+{
+ struct rouleur_priv *rouleur = NULL;
+
+ if (!dev)
+ return -ENODEV;
+
+ rouleur = dev_get_drvdata(dev);
+ if (!rouleur)
+ return -EINVAL;
+
+ pm2250_spmi_write(rouleur->spmi_dev, rouleur->reset_reg, reset_val);
+
+ return 0;
+}
+
+static int rouleur_read_of_property_u32(struct device *dev, const char *name,
+ u32 *val)
+{
+ int rc = 0;
+
+ rc = of_property_read_u32(dev->of_node, name, val);
+ if (rc)
+ dev_err(dev, "%s: Looking up %s property in node %s failed\n",
+ __func__, name, dev->of_node->full_name);
+
+ return rc;
+}
+
+static void rouleur_dt_parse_micbias_info(struct device *dev,
+ struct rouleur_micbias_setting *mb)
+{
+ u32 prop_val = 0;
+ int rc = 0;
+
+ /* MB1 */
+ if (of_find_property(dev->of_node, "qcom,cdc-micbias1-mv",
+ NULL)) {
+ rc = rouleur_read_of_property_u32(dev,
+ "qcom,cdc-micbias1-mv",
+ &prop_val);
+ if (!rc)
+ mb->micb1_mv = prop_val;
+ } else {
+ dev_info(dev, "%s: Micbias1 DT property not found\n",
+ __func__);
+ }
+
+ /* MB2 */
+ if (of_find_property(dev->of_node, "qcom,cdc-micbias2-mv",
+ NULL)) {
+ rc = rouleur_read_of_property_u32(dev,
+ "qcom,cdc-micbias2-mv",
+ &prop_val);
+ if (!rc)
+ mb->micb2_mv = prop_val;
+ } else {
+ dev_info(dev, "%s: Micbias2 DT property not found\n",
+ __func__);
+ }
+
+ /* MB3 */
+ if (of_find_property(dev->of_node, "qcom,cdc-micbias3-mv",
+ NULL)) {
+ rc = rouleur_read_of_property_u32(dev,
+ "qcom,cdc-micbias3-mv",
+ &prop_val);
+ if (!rc)
+ mb->micb3_mv = prop_val;
+ } else {
+ dev_info(dev, "%s: Micbias3 DT property not found\n",
+ __func__);
+ }
+}
+
+struct rouleur_pdata *rouleur_populate_dt_data(struct device *dev)
+{
+ struct rouleur_pdata *pdata = NULL;
+ u32 reg;
+ int ret = 0;
+
+ pdata = kzalloc(sizeof(struct rouleur_pdata),
+ GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ pdata->spmi_np = of_parse_phandle(dev->of_node,
+ "qcom,pmic-spmi-node", 0);
+ if (!pdata->spmi_np) {
+ dev_err(dev, "%s: Looking up %s property in node %s failed\n",
+ __func__, "qcom,pmic-spmi-node",
+ dev->of_node->full_name);
+ kfree(pdata);
+ return NULL;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "qcom,wcd-reset-reg", ®);
+ if (ret) {
+ dev_err(dev, "%s: Failed to obtain reset reg value %d\n",
+ __func__, ret);
+ kfree(pdata);
+ return NULL;
+ }
+ pdata->reset_reg = reg;
+
+ /* Parse power supplies */
+ msm_cdc_get_power_supplies(dev, &pdata->regulator,
+ &pdata->num_supplies);
+ if (!pdata->regulator || (pdata->num_supplies <= 0)) {
+ dev_err(dev, "%s: no power supplies defined for codec\n",
+ __func__);
+ kfree(pdata);
+ return NULL;
+ }
+
+ pdata->rx_slave = of_parse_phandle(dev->of_node, "qcom,rx-slave", 0);
+ pdata->tx_slave = of_parse_phandle(dev->of_node, "qcom,tx-slave", 0);
+ rouleur_dt_parse_micbias_info(dev, &pdata->micbias);
+
+ return pdata;
+}
+
+static int rouleur_wakeup(void *handle, bool enable)
+{
+ struct rouleur_priv *priv;
+
+ if (!handle) {
+ pr_err("%s: NULL handle\n", __func__);
+ return -EINVAL;
+ }
+ priv = (struct rouleur_priv *)handle;
+ if (!priv->tx_swr_dev) {
+ pr_err("%s: tx swr dev is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (enable)
+ return swr_device_wakeup_vote(priv->tx_swr_dev);
+ else
+ return swr_device_wakeup_unvote(priv->tx_swr_dev);
+}
+
+static irqreturn_t rouleur_wd_handle_irq(int irq, void *data)
+{
+ pr_err_ratelimited("%s: Watchdog interrupt for irq =%d triggered\n",
+ __func__, irq);
+ return IRQ_HANDLED;
+}
+
+static int rouleur_bind(struct device *dev)
+{
+ int ret = 0, i = 0;
+ struct rouleur_priv *rouleur = NULL;
+ struct rouleur_pdata *pdata = NULL;
+ struct wcd_ctrl_platform_data *plat_data = NULL;
+ struct platform_device *pdev = NULL;
+
+ rouleur = kzalloc(sizeof(struct rouleur_priv), GFP_KERNEL);
+ if (!rouleur)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rouleur);
+
+ pdata = rouleur_populate_dt_data(dev);
+ if (!pdata) {
+ dev_err(dev, "%s: Fail to obtain platform data\n", __func__);
+ kfree(rouleur);
+ return -EINVAL;
+ }
+ rouleur->dev = dev;
+ rouleur->dev->platform_data = pdata;
+ pdev = of_find_device_by_node(pdata->spmi_np);
+ if (!pdev) {
+ dev_err(dev, "%s: platform device from SPMI node is NULL\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_bind_all;
+ }
+
+ rouleur->spmi_dev = &pdev->dev;
+ rouleur->reset_reg = pdata->reset_reg;
+ ret = msm_cdc_init_supplies(dev, &rouleur->supplies,
+ pdata->regulator, pdata->num_supplies);
+ if (!rouleur->supplies) {
+ dev_err(dev, "%s: Cannot init wcd supplies\n",
+ __func__);
+ goto err_bind_all;
+ }
+
+ plat_data = dev_get_platdata(dev->parent);
+ if (!plat_data) {
+ dev_err(dev, "%s: platform data from parent is NULL\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_bind_all;
+ }
+ rouleur->handle = (void *)plat_data->handle;
+ if (!rouleur->handle) {
+ dev_err(dev, "%s: handle is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err_bind_all;
+ }
+ rouleur->update_wcd_event = plat_data->update_wcd_event;
+ if (!rouleur->update_wcd_event) {
+ dev_err(dev, "%s: update_wcd_event api is null!\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_bind_all;
+ }
+ rouleur->register_notifier = plat_data->register_notifier;
+ if (!rouleur->register_notifier) {
+ dev_err(dev, "%s: register_notifier api is null!\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_bind_all;
+ }
+
+ ret = msm_cdc_enable_static_supplies(dev, rouleur->supplies,
+ pdata->regulator,
+ pdata->num_supplies);
+ if (ret) {
+ dev_err(dev, "%s: wcd static supply enable failed!\n",
+ __func__);
+ goto err_bind_all;
+ }
+
+ rouleur_reset(dev, 0x01);
+ usleep_range(20, 30);
+ rouleur_reset(dev, 0x00);
+ /*
+ * Add 5msec delay to provide sufficient time for
+ * soundwire auto enumeration of slave devices as
+ * as per HW requirement.
+ */
+ usleep_range(5000, 5010);
+ rouleur->wakeup = rouleur_wakeup;
+
+ ret = component_bind_all(dev, rouleur);
+ if (ret) {
+ dev_err(dev, "%s: Slave bind failed, ret = %d\n",
+ __func__, ret);
+ goto err_bind_all;
+ }
+
+ ret = rouleur_parse_port_mapping(dev, "qcom,rx_swr_ch_map", CODEC_RX);
+ ret |= rouleur_parse_port_mapping(dev, "qcom,tx_swr_ch_map", CODEC_TX);
+
+ if (ret) {
+ dev_err(dev, "Failed to read port mapping\n");
+ goto err;
+ }
+
+ rouleur->rx_swr_dev = get_matching_swr_slave_device(pdata->rx_slave);
+ if (!rouleur->rx_swr_dev) {
+ dev_err(dev, "%s: Could not find RX swr slave device\n",
+ __func__);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ rouleur->tx_swr_dev = get_matching_swr_slave_device(pdata->tx_slave);
+ if (!rouleur->tx_swr_dev) {
+ dev_err(dev, "%s: Could not find TX swr slave device\n",
+ __func__);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ rouleur->regmap = devm_regmap_init_swr(rouleur->tx_swr_dev,
+ &rouleur_regmap_config);
+ if (!rouleur->regmap) {
+ dev_err(dev, "%s: Regmap init failed\n",
+ __func__);
+ goto err;
+ }
+
+ /* Set all interupts as edge triggered */
+ for (i = 0; i < rouleur_regmap_irq_chip.num_regs; i++)
+ regmap_write(rouleur->regmap,
+ (ROULEUR_DIG_SWR_INTR_LEVEL_0 + i), 0);
+
+ rouleur_regmap_irq_chip.irq_drv_data = rouleur;
+ rouleur->irq_info.wcd_regmap_irq_chip = &rouleur_regmap_irq_chip;
+ rouleur->irq_info.codec_name = "rouleur";
+ rouleur->irq_info.regmap = rouleur->regmap;
+ rouleur->irq_info.dev = dev;
+ ret = wcd_irq_init(&rouleur->irq_info, &rouleur->virq);
+
+ if (ret) {
+ dev_err(dev, "%s: IRQ init failed: %d\n",
+ __func__, ret);
+ goto err;
+ }
+ rouleur->tx_swr_dev->slave_irq = rouleur->virq;
+
+ mutex_init(&rouleur->micb_lock);
+ mutex_init(&rouleur->main_bias_lock);
+ mutex_init(&rouleur->rx_clk_lock);
+
+ ret = rouleur_set_micbias_data(rouleur, pdata);
+ if (ret < 0) {
+ dev_err(dev, "%s: bad micbias pdata\n", __func__);
+ goto err_irq;
+ }
+
+ /* Request for watchdog interrupt */
+ wcd_request_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHR_PDM_WD_INT,
+ "HPHR PDM WD INT", rouleur_wd_handle_irq, NULL);
+ wcd_request_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHL_PDM_WD_INT,
+ "HPHL PDM WD INT", rouleur_wd_handle_irq, NULL);
+ /* Disable watchdog interrupt for HPH */
+ wcd_disable_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHR_PDM_WD_INT);
+ wcd_disable_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHL_PDM_WD_INT);
+
+ ret = snd_soc_register_component(dev, &soc_codec_dev_rouleur,
+ NULL, 0);
+ if (ret) {
+ dev_err(dev, "%s: Codec registration failed\n",
+ __func__);
+ goto err_irq;
+ }
+
+ return ret;
+err_irq:
+ wcd_irq_exit(&rouleur->irq_info, rouleur->virq);
+ mutex_destroy(&rouleur->micb_lock);
+ mutex_destroy(&rouleur->main_bias_lock);
+ mutex_destroy(&rouleur->rx_clk_lock);
+err:
+ component_unbind_all(dev, rouleur);
+err_bind_all:
+ dev_set_drvdata(dev, NULL);
+ kfree(pdata);
+ kfree(rouleur);
+ return ret;
+}
+
+static void rouleur_unbind(struct device *dev)
+{
+ struct rouleur_priv *rouleur = dev_get_drvdata(dev);
+ struct rouleur_pdata *pdata = dev_get_platdata(rouleur->dev);
+
+ wcd_irq_exit(&rouleur->irq_info, rouleur->virq);
+ snd_soc_unregister_component(dev);
+ component_unbind_all(dev, rouleur);
+ mutex_destroy(&rouleur->micb_lock);
+ mutex_destroy(&rouleur->main_bias_lock);
+ mutex_destroy(&rouleur->rx_clk_lock);
+ dev_set_drvdata(dev, NULL);
+ kfree(pdata);
+ kfree(rouleur);
+}
+
+static const struct of_device_id rouleur_dt_match[] = {
+ { .compatible = "qcom,rouleur-codec" },
+ {}
+};
+
+static const struct component_master_ops rouleur_comp_ops = {
+ .bind = rouleur_bind,
+ .unbind = rouleur_unbind,
+};
+
+static int rouleur_compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static void rouleur_release_of(struct device *dev, void *data)
+{
+ of_node_put(data);
+}
+
+static int rouleur_add_slave_components(struct device *dev,
+ struct component_match **matchptr)
+{
+ struct device_node *np, *rx_node, *tx_node;
+
+ np = dev->of_node;
+
+ rx_node = of_parse_phandle(np, "qcom,rx-slave", 0);
+ if (!rx_node) {
+ dev_err(dev, "%s: Rx-slave node not defined\n", __func__);
+ return -ENODEV;
+ }
+ of_node_get(rx_node);
+ component_match_add_release(dev, matchptr,
+ rouleur_release_of,
+ rouleur_compare_of,
+ rx_node);
+
+ tx_node = of_parse_phandle(np, "qcom,tx-slave", 0);
+ if (!tx_node) {
+ dev_err(dev, "%s: Tx-slave node not defined\n", __func__);
+ return -ENODEV;
+ }
+ of_node_get(tx_node);
+ component_match_add_release(dev, matchptr,
+ rouleur_release_of,
+ rouleur_compare_of,
+ tx_node);
+ return 0;
+}
+
+static int rouleur_probe(struct platform_device *pdev)
+{
+ struct component_match *match = NULL;
+ int ret;
+
+ ret = rouleur_add_slave_components(&pdev->dev, &match);
+ if (ret)
+ return ret;
+
+ return component_master_add_with_match(&pdev->dev,
+ &rouleur_comp_ops, match);
+}
+
+static int rouleur_remove(struct platform_device *pdev)
+{
+ component_master_del(&pdev->dev, &rouleur_comp_ops);
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static const struct dev_pm_ops rouleur_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(
+ rouleur_suspend,
+ rouleur_resume
+ )
+};
+#endif
+
+static struct platform_driver rouleur_codec_driver = {
+ .probe = rouleur_probe,
+ .remove = rouleur_remove,
+ .driver = {
+ .name = "rouleur_codec",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rouleur_dt_match),
+#ifdef CONFIG_PM_SLEEP
+ .pm = &rouleur_dev_pm_ops,
+#endif
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(rouleur_codec_driver);
+MODULE_DESCRIPTION("Rouleur Codec driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/asoc/codecs/rouleur/rouleur.h b/asoc/codecs/rouleur/rouleur.h
new file mode 100644
index 0000000..51abff3
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _ROULEUR_H
+#define _ROULEUR_H
+
+#ifdef CONFIG_SND_SOC_ROULEUR
+extern int rouleur_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_component *component);
+#else
+extern int rouleur_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_component *component)
+{
+ return 0;
+}
+#endif /* CONFIG_SND_SOC_ROULEUR */
+
+#endif
diff --git a/asoc/codecs/rouleur/rouleur_slave.c b/asoc/codecs/rouleur/rouleur_slave.c
new file mode 100644
index 0000000..8fac8a6
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur_slave.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/component.h>
+#include <soc/soundwire.h>
+
+struct rouleur_slave_priv {
+ struct swr_device *swr_slave;
+};
+
+static int rouleur_slave_bind(struct device *dev,
+ struct device *master, void *data)
+{
+ int ret = 0;
+ struct rouleur_slave_priv *rouleur_slave = NULL;
+ uint8_t devnum = 0;
+ struct swr_device *pdev = to_swr_device(dev);
+
+ if (pdev == NULL) {
+ dev_err(dev, "%s: pdev is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ rouleur_slave = devm_kzalloc(&pdev->dev,
+ sizeof(struct rouleur_slave_priv), GFP_KERNEL);
+ if (!rouleur_slave)
+ return -ENOMEM;
+
+ swr_set_dev_data(pdev, rouleur_slave);
+
+ rouleur_slave->swr_slave = pdev;
+
+ ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
+ if (ret) {
+ dev_dbg(&pdev->dev,
+ "%s get devnum %d for dev addr %lx failed\n",
+ __func__, devnum, pdev->addr);
+ swr_remove_device(pdev);
+ return ret;
+ }
+ pdev->dev_num = devnum;
+
+ return ret;
+}
+
+static void rouleur_slave_unbind(struct device *dev,
+ struct device *master, void *data)
+{
+ struct rouleur_slave_priv *rouleur_slave = NULL;
+ struct swr_device *pdev = to_swr_device(dev);
+
+ if (pdev == NULL) {
+ dev_err(dev, "%s: pdev is NULL\n", __func__);
+ return;
+ }
+
+ rouleur_slave = swr_get_dev_data(pdev);
+ if (!rouleur_slave) {
+ dev_err(&pdev->dev, "%s: rouleur_slave is NULL\n", __func__);
+ return;
+ }
+
+ swr_set_dev_data(pdev, NULL);
+}
+
+static const struct swr_device_id rouleur_swr_id[] = {
+ {"rouleur-slave", 0},
+ {}
+};
+
+static const struct of_device_id rouleur_swr_dt_match[] = {
+ {
+ .compatible = "qcom,rouleur-slave",
+ },
+ {}
+};
+
+static const struct component_ops rouleur_slave_comp_ops = {
+ .bind = rouleur_slave_bind,
+ .unbind = rouleur_slave_unbind,
+};
+
+static int rouleur_swr_up(struct swr_device *pdev)
+{
+ return 0;
+}
+
+static int rouleur_swr_down(struct swr_device *pdev)
+{
+ return 0;
+}
+
+static int rouleur_swr_reset(struct swr_device *pdev)
+{
+ return 0;
+}
+
+static int rouleur_swr_probe(struct swr_device *pdev)
+{
+ return component_add(&pdev->dev, &rouleur_slave_comp_ops);
+}
+
+static int rouleur_swr_remove(struct swr_device *pdev)
+{
+ component_del(&pdev->dev, &rouleur_slave_comp_ops);
+ return 0;
+}
+
+static struct swr_driver rouleur_slave_driver = {
+ .driver = {
+ .name = "rouleur-slave",
+ .owner = THIS_MODULE,
+ .of_match_table = rouleur_swr_dt_match,
+ },
+ .probe = rouleur_swr_probe,
+ .remove = rouleur_swr_remove,
+ .id_table = rouleur_swr_id,
+ .device_up = rouleur_swr_up,
+ .device_down = rouleur_swr_down,
+ .reset_device = rouleur_swr_reset,
+};
+
+static int __init rouleur_slave_init(void)
+{
+ return swr_driver_register(&rouleur_slave_driver);
+}
+
+static void __exit rouleur_slave_exit(void)
+{
+ swr_driver_unregister(&rouleur_slave_driver);
+}
+
+module_init(rouleur_slave_init);
+module_exit(rouleur_slave_exit);
+
+MODULE_DESCRIPTION("WCD937X Swr Slave driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd-mbhc-adc.c b/asoc/codecs/wcd-mbhc-adc.c
index 9652d11..f961230 100644
--- a/asoc/codecs/wcd-mbhc-adc.c
+++ b/asoc/codecs/wcd-mbhc-adc.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
#include <linux/init.h>
@@ -694,7 +694,8 @@
*/
if (plug_type == MBHC_PLUG_TYPE_HEADSET ||
plug_type == MBHC_PLUG_TYPE_HEADPHONE)
- mbhc->mbhc_cb->bcs_enable(mbhc, false);
+ if (mbhc->mbhc_cb->bcs_enable)
+ mbhc->mbhc_cb->bcs_enable(mbhc, false);
timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
while (!time_after(jiffies, timeout)) {
@@ -842,7 +843,8 @@
}
if ((plug_type == MBHC_PLUG_TYPE_HEADSET ||
plug_type == MBHC_PLUG_TYPE_HEADPHONE))
- mbhc->mbhc_cb->bcs_enable(mbhc, true);
+ if (mbhc->mbhc_cb->bcs_enable)
+ mbhc->mbhc_cb->bcs_enable(mbhc, true);
if (!wrk_complete) {
/*
@@ -1111,6 +1113,7 @@
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_ISRC_EN, 0);
mbhc->is_extn_cable = true;
mbhc->btn_press_intr = false;
+ mbhc->force_linein = false;
wcd_mbhc_adc_detect_plug_type(mbhc);
WCD_MBHC_RSC_UNLOCK(mbhc);
pr_debug("%s: leave\n", __func__);
diff --git a/asoc/codecs/wcd-mbhc-v2.c b/asoc/codecs/wcd-mbhc-v2.c
index fd55715..f3e71af 100644
--- a/asoc/codecs/wcd-mbhc-v2.c
+++ b/asoc/codecs/wcd-mbhc-v2.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
#include <linux/init.h>
@@ -415,7 +415,6 @@
&mbhc->hph_pa_dac_state)) {
pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_PA_EN, 1);
- WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_OCP_DET_EN, 1);
pa_turned_on = true;
}
mutex_unlock(&mbhc->hphr_pa_lock);
@@ -424,7 +423,6 @@
&mbhc->hph_pa_dac_state)) {
pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PA_EN, 1);
- WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_OCP_DET_EN, 1);
pa_turned_on = true;
}
mutex_unlock(&mbhc->hphl_pa_lock);
@@ -634,11 +632,12 @@
}
mbhc->hph_type = WCD_MBHC_HPH_NONE;
mbhc->zl = mbhc->zr = 0;
- pr_debug("%s: Reporting removal (%x)\n",
- __func__, mbhc->hph_status);
- wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
- 0, WCD_MBHC_JACK_MASK);
-
+ if (!mbhc->force_linein) {
+ pr_debug("%s: Reporting removal (%x)\n",
+ __func__, mbhc->hph_status);
+ wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
+ 0, WCD_MBHC_JACK_MASK);
+ }
if (mbhc->hph_status == SND_JACK_LINEOUT) {
pr_debug("%s: Enable micbias\n", __func__);
@@ -732,6 +731,10 @@
mbhc->hph_status |= jack_type;
+ if (jack_type == SND_JACK_HEADPHONE &&
+ mbhc->mbhc_cb->mbhc_micb_ramp_control)
+ mbhc->mbhc_cb->mbhc_micb_ramp_control(component, false);
+
pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
@@ -922,6 +925,10 @@
else
pr_info("%s: hs_detect_plug work not cancelled\n", __func__);
+ /* Enable micbias ramp */
+ if (mbhc->mbhc_cb->mbhc_micb_ramp_control)
+ mbhc->mbhc_cb->mbhc_micb_ramp_control(component, true);
+
if (mbhc->mbhc_cb->micbias_enable_status)
micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
MIC_BIAS_1);
@@ -1417,9 +1424,6 @@
/* Button Debounce set to 16ms */
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_DBNC, 2);
- /* Enable micbias ramp */
- if (mbhc->mbhc_cb->mbhc_micb_ramp_control)
- mbhc->mbhc_cb->mbhc_micb_ramp_control(component, true);
/* enable bias */
mbhc->mbhc_cb->mbhc_bias(component, true);
/* enable MBHC clock */
diff --git a/asoc/codecs/wcd937x/Android.mk b/asoc/codecs/wcd937x/Android.mk
index 4168dd1..643339a 100644
--- a/asoc/codecs/wcd937x/Android.mk
+++ b/asoc/codecs/wcd937x/Android.mk
@@ -13,7 +13,7 @@
AUDIO_CHIPSET := audio
# Build/Package only in case of supported target
-ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) bengal),true)
+ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) bengal lito),true)
LOCAL_PATH := $(call my-dir)
diff --git a/asoc/codecs/wcd937x/Kbuild b/asoc/codecs/wcd937x/Kbuild
index e353e8a..5bbbad7 100644
--- a/asoc/codecs/wcd937x/Kbuild
+++ b/asoc/codecs/wcd937x/Kbuild
@@ -31,6 +31,11 @@
export
INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
endif
+ ifeq ($(CONFIG_ARCH_LITO), y)
+ include $(AUDIO_ROOT)/config/litoauto.conf
+ export
+ INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
+ endif
endif
# As per target team, build is done as follows:
diff --git a/asoc/codecs/wcd937x/internal.h b/asoc/codecs/wcd937x/internal.h
index faf0118..381634c 100644
--- a/asoc/codecs/wcd937x/internal.h
+++ b/asoc/codecs/wcd937x/internal.h
@@ -133,6 +133,7 @@
WCD_BOLERO_EVT_RX_MUTE = 1, /* for RX mute/unmute */
WCD_BOLERO_EVT_IMPED_TRUE, /* for imped true */
WCD_BOLERO_EVT_IMPED_FALSE, /* for imped false */
+ WCD_BOLERO_EVT_RX_COMPANDER_SOFT_RST,
WCD_BOLERO_EVT_BCS_CLK_OFF,
};
diff --git a/asoc/codecs/wcd937x/wcd937x-mbhc.h b/asoc/codecs/wcd937x/wcd937x-mbhc.h
index 43d1661..2e6bbe8 100644
--- a/asoc/codecs/wcd937x/wcd937x-mbhc.h
+++ b/asoc/codecs/wcd937x/wcd937x-mbhc.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#ifndef __WCD937X_MBHC_H__
#define __WCD937X_MBHC_H__
@@ -52,7 +52,6 @@
static inline void wcd937x_mbhc_ssr_down(struct wcd937x_mbhc *mbhc,
struct snd_soc_component *component)
{
- return 0;
}
static inline int wcd937x_mbhc_get_impedance(struct wcd937x_mbhc *wcd937x_mbhc,
uint32_t *zl, uint32_t *zr)
diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c
index 21325ae..0196539 100644
--- a/asoc/codecs/wcd937x/wcd937x.c
+++ b/asoc/codecs/wcd937x/wcd937x.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -623,7 +623,6 @@
break;
case SND_SOC_DAPM_POST_PMD:
- wcd937x_rx_clk_disable(component);
snd_soc_component_update_bits(component,
WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
0x04, 0x00);
@@ -1581,20 +1580,20 @@
0x80, 0x00);
break;
case BOLERO_WCD_EVT_SSR_DOWN:
+ wcd937x->mbhc->wcd_mbhc.deinit_in_progress = true;
mbhc = &wcd937x->mbhc->wcd_mbhc;
wcd937x_mbhc_ssr_down(wcd937x->mbhc, component);
wcd937x_reset_low(wcd937x->dev);
break;
case BOLERO_WCD_EVT_SSR_UP:
wcd937x_reset(wcd937x->dev);
+ /* allow reset to take effect */
+ usleep_range(10000, 10010);
wcd937x_get_logical_addr(wcd937x->tx_swr_dev);
wcd937x_get_logical_addr(wcd937x->rx_swr_dev);
+ wcd937x_init_reg(component);
regcache_mark_dirty(wcd937x->regmap);
regcache_sync(wcd937x->regmap);
- /* Enable surge protection */
- snd_soc_component_update_bits(component,
- WCD937X_HPH_SURGE_HPHLR_SURGE_EN,
- 0xFF, 0xD9);
/* Initialize MBHC module */
mbhc = &wcd937x->mbhc->wcd_mbhc;
ret = wcd937x_mbhc_post_ssr_init(wcd937x->mbhc, component);
@@ -1604,6 +1603,7 @@
} else {
wcd937x_mbhc_hs_detect(component, mbhc->mbhc_cfg);
}
+ wcd937x->mbhc->wcd_mbhc.deinit_in_progress = false;
break;
default:
dev_err(component->dev, "%s: invalid event %d\n", __func__,
@@ -2462,6 +2462,7 @@
return -EINVAL;
wcd937x->component = component;
+ snd_soc_component_init_regmap(component, wcd937x->regmap);
variant = (snd_soc_component_read32(
component, WCD937X_DIGITAL_EFUSE_REG_0) & 0x1E) >> 1;
wcd937x->variant = variant;
diff --git a/asoc/codecs/wcd938x/internal.h b/asoc/codecs/wcd938x/internal.h
index 46d61a0..c59d5b8 100644
--- a/asoc/codecs/wcd938x/internal.h
+++ b/asoc/codecs/wcd938x/internal.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _WCD938X_INTERNAL_H
@@ -70,6 +70,7 @@
bool comp1_enable;
bool comp2_enable;
bool ldoh;
+ bool bcs_dis;
struct irq_domain *virq;
struct wcd_irq_info irq_info;
u32 rx_clk_cnt;
diff --git a/asoc/codecs/wcd938x/wcd938x-slave.c b/asoc/codecs/wcd938x/wcd938x-slave.c
index 75cc783..1f83b4c 100644
--- a/asoc/codecs/wcd938x/wcd938x-slave.c
+++ b/asoc/codecs/wcd938x/wcd938x-slave.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -287,7 +287,7 @@
ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
if (ret) {
dev_dbg(&pdev->dev,
- "%s get devnum %d for dev addr %lx failed\n",
+ "%s get devnum %d for dev addr %llx failed\n",
__func__, devnum, pdev->addr);
return ret;
}
diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c
index ae88d7c..8ade1d9 100644
--- a/asoc/codecs/wcd938x/wcd938x.c
+++ b/asoc/codecs/wcd938x/wcd938x.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -41,6 +41,8 @@
#define ADC_MODE_VAL_ULP1 0x09
#define ADC_MODE_VAL_ULP2 0x0B
+#define NUM_ATTEMPTS 5
+
enum {
CODEC_TX = 0,
CODEC_RX,
@@ -67,6 +69,16 @@
ADC_MODE_ULP2,
};
+static u8 tx_mode_bit[] = {
+ [ADC_MODE_INVALID] = 0x00,
+ [ADC_MODE_HIFI] = 0x01,
+ [ADC_MODE_LO_HIF] = 0x02,
+ [ADC_MODE_NORMAL] = 0x04,
+ [ADC_MODE_LP] = 0x08,
+ [ADC_MODE_ULP1] = 0x10,
+ [ADC_MODE_ULP2] = 0x20,
+};
+
static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
@@ -139,26 +151,56 @@
return ((bank & 0x40) ? 1: 0);
}
-static int wcd938x_swr_slv_set_host_clk_div2(struct swr_device *dev,
- u8 devnum, int bank)
+static int wcd938x_get_clk_rate(int mode)
{
- u8 val = (bank ? 1 : 0);
+ int rate;
- return (swr_write(dev, devnum,
- (SWR_SCP_HOST_CLK_DIV2_CTL_BANK + (0x10 * bank)), &val));
+ switch (mode) {
+ case ADC_MODE_ULP2:
+ rate = SWR_CLK_RATE_0P6MHZ;
+ break;
+ case ADC_MODE_ULP1:
+ rate = SWR_CLK_RATE_1P2MHZ;
+ break;
+ case ADC_MODE_LP:
+ rate = SWR_CLK_RATE_4P8MHZ;
+ break;
+ case ADC_MODE_NORMAL:
+ case ADC_MODE_LO_HIF:
+ case ADC_MODE_HIFI:
+ case ADC_MODE_INVALID:
+ default:
+ rate = SWR_CLK_RATE_9P6MHZ;
+ break;
+ }
+
+ return rate;
}
static int wcd938x_set_swr_clk_rate(struct snd_soc_component *component,
- int mode, int bank)
+ int rate, int bank)
{
u8 mask = (bank ? 0xF0 : 0x0F);
u8 val = 0;
- if ((mode == ADC_MODE_ULP1) || (mode == ADC_MODE_ULP2))
+ switch (rate) {
+ case SWR_CLK_RATE_0P6MHZ:
val = (bank ? 0x60 : 0x06);
- else
+ break;
+ case SWR_CLK_RATE_1P2MHZ:
+ val = (bank ? 0x50 : 0x05);
+ break;
+ case SWR_CLK_RATE_2P4MHZ:
+ val = (bank ? 0x30 : 0x03);
+ break;
+ case SWR_CLK_RATE_4P8MHZ:
+ val = (bank ? 0x10 : 0x01);
+ break;
+ case SWR_CLK_RATE_9P6MHZ:
+ default:
val = 0x00;
-
+ break;
+ }
snd_soc_component_update_bits(component,
WCD938X_DIGITAL_SWR_TX_CLK_RATE,
mask, val);
@@ -223,6 +265,11 @@
WCD938X_MICB4_TEST_CTL_1, 0xE0, 0xE0);
snd_soc_component_update_bits(component,
WCD938X_TX_3_4_TEST_BLK_EN2, 0x01, 0x00);
+ snd_soc_component_update_bits(component, WCD938X_SLEEP_CTL, 0x0E,
+ ((snd_soc_component_read32(component,
+ WCD938X_DIGITAL_EFUSE_REG_30) & 0x07) << 1));
+ snd_soc_component_update_bits(component,
+ WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0);
return 0;
}
@@ -352,7 +399,8 @@
}
static int wcd938x_tx_connect_port(struct snd_soc_component *component,
- u8 slv_port_type, u8 enable)
+ u8 slv_port_type, int clk_rate,
+ u8 enable)
{
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
u8 port_id, num_ch, ch_mask, port_type;
@@ -363,6 +411,8 @@
ret = wcd938x_set_port_params(component, slv_port_type, &port_id,
&num_ch, &ch_mask, &ch_rate,
&port_type, CODEC_TX);
+ if (clk_rate)
+ ch_rate = clk_rate;
if (ret)
return ret;
@@ -626,6 +676,15 @@
if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) {
snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x01, 0x00);
+ snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x04, 0x00);
+ } else {
+ snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x04, 0x00);
+ snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x00);
+ snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x02, 0x00);
}
snd_soc_component_update_bits(component,
WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x00);
@@ -706,6 +765,11 @@
WCD_CLSH_STATE_HPHR,
hph_mode);
wcd_clsh_set_hph_mode(component, CLS_H_HIFI);
+ if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI ||
+ hph_mode == CLS_H_ULP) {
+ snd_soc_component_update_bits(component,
+ WCD938X_HPH_REFBUFF_LP_CTL, 0x01, 0x01);
+ }
snd_soc_component_update_bits(component, WCD938X_ANA_HPH,
0x10, 0x10);
wcd_clsh_set_hph_mode(component, hph_mode);
@@ -726,6 +790,12 @@
usleep_range(20000, 20100);
else
usleep_range(7000, 7100);
+ if (hph_mode == CLS_H_LP ||
+ hph_mode == CLS_H_LOHIFI ||
+ hph_mode == CLS_H_ULP)
+ snd_soc_component_update_bits(component,
+ WCD938X_HPH_REFBUFF_LP_CTL, 0x01,
+ 0x00);
clear_bit(HPH_PA_DELAY, &wcd938x->status_mask);
}
snd_soc_component_update_bits(component,
@@ -831,6 +901,11 @@
WCD_CLSH_STATE_HPHL,
hph_mode);
wcd_clsh_set_hph_mode(component, CLS_H_HIFI);
+ if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI ||
+ hph_mode == CLS_H_ULP) {
+ snd_soc_component_update_bits(component,
+ WCD938X_HPH_REFBUFF_LP_CTL, 0x01, 0x01);
+ }
snd_soc_component_update_bits(component, WCD938X_ANA_HPH,
0x20, 0x20);
wcd_clsh_set_hph_mode(component, hph_mode);
@@ -851,6 +926,12 @@
usleep_range(20000, 20100);
else
usleep_range(7000, 7100);
+ if (hph_mode == CLS_H_LP ||
+ hph_mode == CLS_H_LOHIFI ||
+ hph_mode == CLS_H_ULP)
+ snd_soc_component_update_bits(component,
+ WCD938X_HPH_REFBUFF_LP_CTL,
+ 0x01, 0x00);
clear_bit(HPH_PA_DELAY, &wcd938x->status_mask);
}
snd_soc_component_update_bits(component,
@@ -1292,10 +1373,12 @@
/* enable clock scaling */
snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_DMIC_CTL, 0x06, 0x06);
- wcd938x_tx_connect_port(component, DMIC0 + (w->shift), true);
+ wcd938x_tx_connect_port(component, DMIC0 + (w->shift),
+ SWR_CLK_RATE_2P4MHZ, true);
break;
case SND_SOC_DAPM_POST_PMD:
- wcd938x_tx_connect_port(component, DMIC0 + (w->shift), false);
+ wcd938x_tx_connect_port(component, DMIC0 + (w->shift), 0,
+ false);
snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_AMIC_CTL,
(0x01 << dmic_ctl_shift),
@@ -1416,32 +1499,54 @@
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
int ret = 0;
int bank = 0;
- int mode = 0;
+ u8 mode = 0;
+ int i = 0;
+ int rate = 0;
- bank = wcd938x_swr_slv_get_current_bank(wcd938x->tx_swr_dev,
- wcd938x->tx_swr_dev->dev_num);
- wcd938x_swr_slv_set_host_clk_div2(wcd938x->tx_swr_dev,
- wcd938x->tx_swr_dev->dev_num, bank);
+ bank = (wcd938x_swr_slv_get_current_bank(wcd938x->tx_swr_dev,
+ wcd938x->tx_swr_dev->dev_num) ? 0 : 1);
+
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ if (strnstr(w->name, "ADC", sizeof("ADC"))) {
+ if (test_bit(WCD_ADC1, &wcd938x->status_mask))
+ mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC1]];
+ if (test_bit(WCD_ADC2, &wcd938x->status_mask))
+ mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC2]];
+ if (test_bit(WCD_ADC3, &wcd938x->status_mask))
+ mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC3]];
+ if (test_bit(WCD_ADC4, &wcd938x->status_mask))
+ mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC4]];
+
+ if (mode != 0) {
+ for (i = 0; i < ADC_MODE_ULP2; i++) {
+ if (mode & (1 << i)) {
+ i++;
+ break;
+ }
+ }
+ }
+ rate = wcd938x_get_clk_rate(i);
+ wcd938x_set_swr_clk_rate(component, rate, bank);
+ }
ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
wcd938x->tx_swr_dev->dev_num,
true);
- if (test_bit(WCD_ADC1, &wcd938x->status_mask))
- mode |= wcd938x->tx_mode[WCD_ADC1];
- if (test_bit(WCD_ADC2, &wcd938x->status_mask))
- mode |= wcd938x->tx_mode[WCD_ADC2];
- if (test_bit(WCD_ADC3, &wcd938x->status_mask))
- mode |= wcd938x->tx_mode[WCD_ADC3];
- if (test_bit(WCD_ADC4, &wcd938x->status_mask))
- mode |= wcd938x->tx_mode[WCD_ADC4];
- wcd938x_set_swr_clk_rate(component, mode, bank);
+ if (strnstr(w->name, "ADC", sizeof("ADC"))) {
+ /* Copy clk settings to active bank */
+ wcd938x_set_swr_clk_rate(component, rate, !bank);
+ }
break;
case SND_SOC_DAPM_POST_PMD:
+ if (strnstr(w->name, "ADC", sizeof("ADC"))) {
+ rate = wcd938x_get_clk_rate(ADC_MODE_INVALID);
+ wcd938x_set_swr_clk_rate(component, rate, !bank);
+ }
ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev,
wcd938x->tx_swr_dev->dev_num,
false);
- wcd938x_set_swr_clk_rate(component, ADC_MODE_INVALID, bank);
+ if (strnstr(w->name, "ADC", sizeof("ADC")))
+ wcd938x_set_swr_clk_rate(component, rate, bank);
break;
};
@@ -1488,6 +1593,7 @@
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+ int clk_rate = 0;
dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
w->name, event);
@@ -1499,19 +1605,25 @@
snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
set_bit(w->shift, &wcd938x->status_mask);
+ clk_rate = wcd938x_get_clk_rate(wcd938x->tx_mode[w->shift]);
/* Enable BCS for Headset mic */
if (w->shift == 1 && !(snd_soc_component_read32(component,
WCD938X_TX_NEW_AMIC_MUX_CFG) & 0x80)) {
- wcd938x_tx_connect_port(component, MBHC, true);
+ if (!wcd938x->bcs_dis)
+ wcd938x_tx_connect_port(component, MBHC,
+ SWR_CLK_RATE_4P8MHZ, true);
set_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask);
}
- wcd938x_tx_connect_port(component, ADC1 + (w->shift), true);
+ wcd938x_tx_connect_port(component, ADC1 + (w->shift), clk_rate,
+ true);
break;
case SND_SOC_DAPM_POST_PMD:
- wcd938x_tx_connect_port(component, ADC1 + (w->shift), false);
+ wcd938x_tx_connect_port(component, ADC1 + (w->shift), 0, false);
if (w->shift == 1 &&
test_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask)) {
- wcd938x_tx_connect_port(component, MBHC, false);
+ if (!wcd938x->bcs_dis)
+ wcd938x_tx_connect_port(component, MBHC, 0,
+ false);
clear_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask);
}
snd_soc_component_update_bits(component,
@@ -1842,15 +1954,18 @@
{
int ret = 0;
uint8_t devnum = 0;
+ int num_retry = NUM_ATTEMPTS;
- ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum);
- if (ret) {
- dev_err(&swr_dev->dev,
- "%s get devnum %d for dev addr %lx failed\n",
- __func__, devnum, swr_dev->addr);
- swr_remove_device(swr_dev);
- return ret;
- }
+ do {
+ ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum);
+ if (ret) {
+ dev_err(&swr_dev->dev,
+ "%s get devnum %d for dev addr %llx failed\n",
+ __func__, devnum, swr_dev->addr);
+ /* retry after 1ms */
+ usleep_range(1000, 1010);
+ }
+ } while (ret && --num_retry);
swr_dev->dev_num = devnum;
return 0;
}
@@ -1898,14 +2013,19 @@
break;
case BOLERO_WCD_EVT_SSR_DOWN:
wcd938x->dev_up = false;
+ wcd938x->mbhc->wcd_mbhc.deinit_in_progress = true;
mbhc = &wcd938x->mbhc->wcd_mbhc;
wcd938x_mbhc_ssr_down(wcd938x->mbhc, component);
wcd938x_reset_low(wcd938x->dev);
break;
case BOLERO_WCD_EVT_SSR_UP:
wcd938x_reset(wcd938x->dev);
+ /* allow reset to take effect */
+ usleep_range(10000, 10010);
+
wcd938x_get_logical_addr(wcd938x->tx_swr_dev);
wcd938x_get_logical_addr(wcd938x->rx_swr_dev);
+
wcd938x_init_reg(component);
regcache_mark_dirty(wcd938x->regmap);
regcache_sync(wcd938x->regmap);
@@ -1918,6 +2038,7 @@
} else {
wcd938x_mbhc_hs_detect(component, mbhc->mbhc_cfg);
}
+ wcd938x->mbhc->wcd_mbhc.deinit_in_progress = false;
wcd938x->dev_up = true;
break;
case BOLERO_WCD_EVT_CLK_NOTIFY:
@@ -2263,6 +2384,30 @@
return 0;
}
+static int wcd938x_bcs_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wcd938x->bcs_dis;
+
+ return 0;
+}
+
+static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+ wcd938x->bcs_dis = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
static const char * const tx_mode_mux_text_wcd9380[] = {
"ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP",
};
@@ -2346,10 +2491,12 @@
wcd938x_get_compander, wcd938x_set_compander),
SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0,
wcd938x_get_compander, wcd938x_set_compander),
-
SOC_SINGLE_EXT("LDOH Enable", SND_SOC_NOPM, 0, 1, 0,
wcd938x_ldoh_get, wcd938x_ldoh_put),
+ SOC_SINGLE_EXT("ADC2_BCS Disable", SND_SOC_NOPM, 0, 1, 0,
+ wcd938x_bcs_get, wcd938x_bcs_put),
+
SOC_SINGLE_TLV("HPHL Volume", WCD938X_HPH_L_EN, 0, 20, 1, line_gain),
SOC_SINGLE_TLV("HPHR Volume", WCD938X_HPH_R_EN, 0, 20, 1, line_gain),
SOC_SINGLE_TLV("ADC1 Volume", WCD938X_ANA_TX_CH1, 0, 20, 0,
diff --git a/asoc/codecs/wsa881x-analog.c b/asoc/codecs/wsa881x-analog.c
index c6b4066..038e338 100644
--- a/asoc/codecs/wsa881x-analog.c
+++ b/asoc/codecs/wsa881x-analog.c
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2015-2016, 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, 2018-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -1027,7 +1028,8 @@
return ret;
}
- clk_disable_unprepare(pdata->wsa_mclk);
+ if (__clk_is_enabled(pdata->wsa_mclk))
+ clk_disable_unprepare(pdata->wsa_mclk);
ret = msm_cdc_pinctrl_select_sleep_state(pdata->wsa_clk_gpio_p);
if (ret) {
diff --git a/asoc/codecs/wsa881x.c b/asoc/codecs/wsa881x.c
index fc4f123..fe88d80 100644
--- a/asoc/codecs/wsa881x.c
+++ b/asoc/codecs/wsa881x.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -985,6 +985,9 @@
dwork = to_delayed_work(work);
wsa881x = container_of(dwork, struct wsa881x_priv, ocp_ctl_work);
+ if (wsa881x->state == WSA881X_DEV_DOWN)
+ return;
+
component = wsa881x->component;
wsa881x_get_temp(wsa881x->tz_pdata.tz_dev, &temp_val);
dev_dbg(component->dev, " temp = %d\n", temp_val);
@@ -1232,7 +1235,7 @@
}
if (retry == 0) {
dev_err(component->dev,
- "%s get devnum %d for dev addr %lx failed\n",
+ "%s get devnum %d for dev addr %llx failed\n",
__func__, devnum, dev->addr);
return -EINVAL;
}
@@ -1479,7 +1482,7 @@
ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
if (ret) {
dev_dbg(&pdev->dev,
- "%s get devnum %d for dev addr %lx failed\n",
+ "%s get devnum %d for dev addr %llx failed\n",
__func__, devnum, pdev->addr);
goto dev_err;
}
@@ -1598,14 +1601,14 @@
dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
return -EINVAL;
}
- if (delayed_work_pending(&wsa881x->ocp_ctl_work))
- cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
ret = wsa881x_gpio_ctrl(wsa881x, false);
if (ret)
dev_err(&pdev->dev, "%s: Failed to disable gpio\n", __func__);
else
wsa881x->state = WSA881X_DEV_DOWN;
+ if (delayed_work_pending(&wsa881x->ocp_ctl_work))
+ cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
return ret;
}
diff --git a/asoc/codecs/wsa883x/internal.h b/asoc/codecs/wsa883x/internal.h
index 3f24712..2384043 100644
--- a/asoc/codecs/wsa883x/internal.h
+++ b/asoc/codecs/wsa883x/internal.h
@@ -55,6 +55,20 @@
SWR_VISENSE_PORT,
};
+enum {
+ BOLERO_WSA_EVT_TX_CH_HOLD_CLEAR = 1,
+ BOLERO_WSA_EVT_PA_OFF_PRE_SSR,
+ BOLERO_WSA_EVT_SSR_DOWN,
+ BOLERO_WSA_EVT_SSR_UP,
+};
+
+struct wsa_ctrl_platform_data {
+ void *handle,
+ int (*update_wsa_event)(void *handle, u16 event, u32 data);
+ int (*register_notifier)(void *handle, struct notifer_block *nblock,
+ bool enable);
+};
+
struct swr_port {
u8 port_id;
u8 ch_mask;
@@ -78,7 +92,6 @@
bool visense_enable;
bool ext_vdd_spk;
struct swr_port port[WSA883X_MAX_SWR_PORTS];
- int pd_gpio;
int global_pa_cnt;
int dev_mode;
struct mutex res_lock;
@@ -87,6 +100,9 @@
struct device_node *wsa_rst_np;
int pa_mute;
int curr_temp;
+ int variant;
+ struct irq_domain *virq;
+ struct wcd_irq_info irq_info;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_dent;
struct dentry *debugfs_peek;
@@ -94,6 +110,12 @@
struct dentry *debugfs_reg_dump;
unsigned int read_data;
#endif
+ struct device_node *parent_np;
+ struct platform_device *parent_dev;
+ struct notifier_block parent_nblock;
+ void *handle;
+ int (*register_notifier)(void *handle,
+ struct notifier_block *nblock, bool enable);
};
static int32_t wsa883x_resource_acquire(struct snd_soc_component *component,
diff --git a/asoc/codecs/wsa883x/wsa883x.c b/asoc/codecs/wsa883x/wsa883x.c
index cbf9559..08f6858 100644
--- a/asoc/codecs/wsa883x/wsa883x.c
+++ b/asoc/codecs/wsa883x/wsa883x.c
@@ -53,6 +53,51 @@
static int wsa883x_get_temperature(struct snd_soc_component *component,
int *temp);
+enum {
+ WSA8830 = 0,
+ WSA8835,
+};
+
+enum {
+ WSA883X_IRQ_INT_SAF2WAR = 0,
+ WSA883X_IRQ_INT_WAR2SAF,
+ WSA883X_IRQ_INT_DISABLE,
+ WSA883X_IRQ_INT_OCP,
+ WSA883X_IRQ_INT_CLIP,
+ WSA883X_IRQ_INT_PDM_WD,
+ WSA883X_IRQ_INT_CLK_WD,
+ WSA883X_IRQ_INT_INTR_PIN,
+ WSA883X_IRQ_INT_UVLO,
+ WSA883X_IRQ_INT_PA_ON_ERR,
+};
+
+static const struct regmap_irq wsa883x_irqs[WSA883X_NUM_IRQS] = {
+ REGMAP_IRQ_REG(WSA883X_IRQ_INT_SAF2WAR, 0, 0x01),
+ REGMAP_IRQ_REG(WSA883X_IRQ_INT_WAR2SAF, 0, 0x02),
+ REGMAP_IRQ_REG(WSA883X_IRQ_INT_DISABLE, 0, 0x04),
+ REGMAP_IRQ_REG(WSA883X_IRQ_INT_OCP, 0, 0x08),
+ REGMAP_IRQ_REG(WSA883X_IRQ_INT_CLIP, 0, 0x10),
+ REGMAP_IRQ_REG(WSA883X_IRQ_INT_PDM_WD, 0, 0x20),
+ REGMAP_IRQ_REG(WSA883X_IRQ_INT_CLK_WD, 0, 0x40),
+ REGMAP_IRQ_REG(WSA883X_IRQ_INT_INTR_PIN, 0, 0x80),
+ REGMAP_IRQ_REG(WSA883X_IRQ_INT_UVLO, 1, 0x01),
+ REGMAP_IRQ_REG(WSA883X_IRQ_INT_PA_ON_ERR, 1, 0x02),
+};
+
+static struct regmap_irq_chip wsa883x_regmap_irq_chip = {
+ .name = "wsa883x",
+ .irqs = wsa883x_irqs,
+ .num_irqs = ARRAY_SIZE(wsa883x_irqs),
+ .num_regs = 2,
+ .status_base = WSA883X_INTR_STATUS0,
+ .mask_base = WSA883X_INTR_MASK0,
+ .type_base = WSA883X_INTR_LEVEL0,
+ .ack_base = WSA883X_INTR_CLEAR0,
+ .use_ack = 1,
+ .runtime_pm = false,
+ .irq_drv_data = NULL,
+};
+
#ifdef CONFIG_DEBUG_FS
static int codec_debug_open(struct inode *inode, struct file *file)
{
@@ -289,6 +334,76 @@
};
#endif
+static irqreturn_t wsa883x_saf2war_handle_irq(int irq, void *data)
+{
+ pr_err_ratelimited("%s: interrupt for irq =%d triggered\n",
+ __func__, irq);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wsa883x_war2saf_handle_irq(int irq, void *data)
+{
+ pr_err_ratelimited("%s: interrupt for irq =%d triggered\n",
+ __func__, irq);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wsa883x_otp_handle_irq(int irq, void *data)
+{
+ pr_err_ratelimited("%s: interrupt for irq =%d triggered\n",
+ __func__, irq);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wsa883x_ocp_handle_irq(int irq, void *data)
+{
+ pr_err_ratelimited("%s: interrupt for irq =%d triggered\n",
+ __func__, irq);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wsa883x_clip_handle_irq(int irq, void *data)
+{
+ pr_err_ratelimited("%s: interrupt for irq =%d triggered\n",
+ __func__, irq);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wsa883x_pdm_wd_handle_irq(int irq, void *data)
+{
+ pr_err_ratelimited("%s: interrupt for irq =%d triggered\n",
+ __func__, irq);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wsa883x_clk_wd_handle_irq(int irq, void *data)
+{
+ pr_err_ratelimited("%s: interrupt for irq =%d triggered\n",
+ __func__, irq);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wsa883x_ext_int_handle_irq(int irq, void *data)
+{
+ pr_err_ratelimited("%s: interrupt for irq =%d triggered\n",
+ __func__, irq);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wsa883x_uvlo_handle_irq(int irq, void *data)
+{
+ pr_err_ratelimited("%s: interrupt for irq =%d triggered\n",
+ __func__, irq);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wsa883x_pa_on_err_handle_irq(int irq, void *data)
+{
+ pr_err_ratelimited("%s: interrupt for irq =%d triggered\n",
+ __func__, irq);
+ return IRQ_HANDLED;
+}
+
static const char * const wsa_dev_mode_text[] = {
"speaker", "receiver", "ultrasound"
};
@@ -940,12 +1055,39 @@
return ret;
}
+static int wsa883x_event_notify(struct notifier_block *nb,
+ unsigned long val, void *ptr)
+{
+ u16 event = (val & 0xffff);
+ struct wsa883x_priv *wsa883x = container_of(nb, struct wsa883x_priv,
+ parent_nblock);
+
+ if (!wsa883x)
+ return -EINVAL;
+
+ switch (event) {
+ case BOLERO_WSA_EVT_PA_OFF_PRE_SSR:
+ snd_soc_component_update_bits(wsa883x->component,
+ WSA883X_SPKR_DRV_GAIN,
+ 0xF0, 0xC0);
+ snd_soc_component_update_bits(wsa883x->component,
+ WSA883X_SPKR_DRV_EN,
+ 0x80, 0x00);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int wsa883x_swr_probe(struct swr_device *pdev)
{
int ret = 0;
struct wsa883x_priv *wsa883x;
u8 devnum = 0;
bool pin_state_current = false;
+ struct wsa_ctrl_platform_data *plat_data = NULL;
wsa883x = devm_kzalloc(&pdev->dev, sizeof(struct wsa883x_priv),
GFP_KERNEL);
@@ -986,39 +1128,118 @@
goto dev_err;
}
+ /* Set all interrupts as edge triggered */
+ for (i = 0; i < wsa883x_regmap_irq_chip.num_regs; i++)
+ regmap_write(wsa883x->regmap, (WSA883X_INTR_LEVEL0 + i), 0);
+
+ wsa883x_regmap_irq_chip.irq_drv_data = wsa883x;
+ wsa883x->irq_info.wcd_regmap_irq_chip = &wsa883x_regmap_irq_chip;
+ wsa883x->irq_info.codec_name = "WSA883X";
+ wsa883x->irq_info.regmap = wsa883x->regmap;
+ wsa883x->irq_info.dev = dev;
+ ret = wcd_irq_init(&wsa883x->irq_info, &wsa883x->virq);
+
+ if (ret) {
+ dev_err(wsa883x->dev, "%s: IRQ init failed: %d\n",
+ __func__, ret);
+ goto dev_err;
+ }
+
+ wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_SAF2WAR,
+ "WSA SAF2WAR", wsa883x_saf2war_handle_irq, NULL);
+
+ wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_WAR2SAF,
+ "WSA WAR2SAF", wsa883x_war2saf_handle_irq, NULL);
+
+ wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_DISABLE,
+ "WSA OTP", wsa883x_otp_handle_irq, NULL);
+
+ wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_OCP,
+ "WSA OCP", wsa883x_ocp_handle_irq, NULL);
+
+ wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_CLIP,
+ "WSA CLIP", wsa883x_clip_handle_irq, NULL);
+
+ wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PDM_WD,
+ "WSA PDM WD", wsa883x_pdm_wd_handle_irq, NULL);
+
+ wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_CLK_WD,
+ "WSA CLK WD", wsa883x_clk_wd_handle_irq, NULL);
+
+ wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_INTR_PIN,
+ "WSA EXT INT", wsa883x_ext_int_handle_irq, NULL);
+
+ /* Under Voltage Lock out (UVLO) interrupt handle */
+ wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO,
+ "WSA UVLO", wsa883x_uvlo_handle_irq, NULL);
+
+ wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PA_ON_ERR,
+ "WSA PA ERR", wsa883x_pa_on_err_handle_irq, NULL);
+
ret = snd_soc_register_component(&pdev->dev, &soc_codec_dev_wsa883x,
NULL, 0);
if (ret) {
dev_err(&pdev->dev, "%s: Codec registration failed\n",
__func__);
- goto dev_err;
+ goto err_irq;
}
+
+ wsa883x->parent_np = of_parse_phandle(pdev->dev.of_node,
+ "qcom,bolero-handle", 0);
+ if (wsa883x->parent_np) {
+ wsa883x->parent_dev =
+ of_find_device_by_node(wsa883x->parent_np);
+ if (wsa883x->parent_dev) {
+ plat_data = dev_get_platdata(&wsa883x->parent_dev->dev);
+ if (plat_data) {
+ wsa883x->parent_nblock.notifier_call =
+ wsa883x_event_notify;
+ if (plat_data->register_notifier)
+ plat_data->register_notifier(
+ plat_data->handle,
+ &wsa883x->parent_nblock,
+ true);
+ wsa883x->register_notifier =
+ plat_data->register_notifier;
+ wsa883x->handle = plat_data->handle;
+ } else {
+ dev_err(&pdev->dev, "%s: plat data not found\n",
+ __func__);
+ }
+ } else {
+ dev_err(&pdev->dev, "%s: parent dev not found\n",
+ __func__);
+ }
+ } else {
+ dev_info(&pdev->dev, "%s: parent node not found\n", __func__);
+ }
+
mutex_init(&wsa883x->res_lock);
#ifdef CONFIG_DEBUG_FS
- if (!wcd938x->debugfs_dent) {
- wcd938x->debugfs_dent = debugfs_create_dir(
+ if (!wsa883x->debugfs_dent) {
+ wsa883x->debugfs_dent = debugfs_create_dir(
dev_name(&pdev->dev), 0);
- if (!IS_ERR(wcd938x->debugfs_dent)) {
- wcd938x->debugfs_peek =
+ if (!IS_ERR(wsa883x->debugfs_dent)) {
+ wsa883x->debugfs_peek =
debugfs_create_file("swrslave_peek",
S_IFREG | 0444,
- wcd938x->debugfs_dent,
+ wsa883x->debugfs_dent,
(void *) pdev,
&codec_debug_read_ops);
- wcd938x->debugfs_poke =
+ wsa883x->debugfs_poke =
debugfs_create_file("swrslave_poke",
S_IFREG | 0444,
- wcd938x->debugfs_dent,
+ wsa883x->debugfs_dent,
(void *) pdev,
&codec_debug_write_ops);
- wcd938x->debugfs_reg_dump =
+ wsa883x->debugfs_reg_dump =
debugfs_create_file(
"swrslave_reg_dump",
S_IFREG | 0444,
- wcd938x->debugfs_dent,
+ wsa883x->debugfs_dent,
(void *) pdev,
&codec_debug_dump_ops);
}
@@ -1027,6 +1248,18 @@
return 0;
+err_irq:
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_SAF2WAR, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_WAR2SAF, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_DISABLE, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_OCP, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_CLIP, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PDM_WD, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_CLK_WD, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_INTR_PIN, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PA_ON_ERR, NULL);
+ wcd_irq_exit(&wsa883x->irq_info, wsa883x->virq);
dev_err:
if (pin_state_current == false)
wsa883x_gpio_ctrl(wsa883x, false);
@@ -1044,6 +1277,21 @@
dev_err(&pdev->dev, "%s: wsa883x is NULL\n", __func__);
return -EINVAL;
}
+
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_SAF2WAR, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_WAR2SAF, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_DISABLE, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_OCP, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_CLIP, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PDM_WD, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_CLK_WD, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_INTR_PIN, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO, NULL);
+ wcd_free_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PA_ON_ERR, NULL);
+
+ if (wsa883x->register_notifier)
+ wsa883x->register_notifier(wsa883x->handle,
+ &wsa883x->parent_nblock, false);
#ifdef CONFIG_DEBUG_FS
debugfs_remove_recursive(wsa883x->debugfs_dent);
wsa883x->debugfs_dent = NULL;
diff --git a/asoc/kona.c b/asoc/kona.c
index 1df6d34..a97590f 100644
--- a/asoc/kona.c
+++ b/asoc/kona.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
@@ -4435,6 +4435,8 @@
break;
case MSM_BACKEND_DAI_SLIMBUS_7_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_tx_cfg[SLIM_TX_7].bit_format);
rate->min = rate->max = slim_tx_cfg[SLIM_TX_7].sample_rate;
channels->min = channels->max =
slim_tx_cfg[SLIM_TX_7].channels;
@@ -6187,6 +6189,33 @@
.ignore_suspend = 1,
.ignore_pmdown_time = 1,
},
+ /* Proxy Tx BACK END DAI Link */
+ {
+ .name = LPASS_BE_PROXY_TX,
+ .stream_name = "Proxy Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.8195",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_PROXY_TX,
+ .ignore_suspend = 1,
+ },
+ /* Proxy Rx BACK END DAI Link */
+ {
+ .name = LPASS_BE_PROXY_RX,
+ .stream_name = "Proxy Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.8194",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_PROXY_RX,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
{
.name = LPASS_BE_USB_AUDIO_RX,
.stream_name = "USB Audio Playback",
@@ -7594,8 +7623,8 @@
u32 codec_max_aux_devs = 0;
u32 codec_aux_dev_cnt = 0;
int i;
- struct msm_wsa881x_dev_info *wsa881x_dev_info;
- struct aux_codec_dev_info *aux_cdc_dev_info;
+ struct msm_wsa881x_dev_info *wsa881x_dev_info = NULL;
+ struct aux_codec_dev_info *aux_cdc_dev_info = NULL;
const char *auxdev_name_prefix[1];
char *dev_name_str = NULL;
int found = 0;
@@ -8155,8 +8184,11 @@
"qcom,quin-mi2s-gpios", 0);
pdata->mi2s_gpio_p[SEN_MI2S] = of_parse_phandle(pdev->dev.of_node,
"qcom,sen-mi2s-gpios", 0);
- for (index = PRIM_MI2S; index < MI2S_MAX; index++)
+ for (index = PRIM_MI2S; index < MI2S_MAX; index++) {
+ if (pdata->mi2s_gpio_p[index])
+ msm_cdc_pinctrl_set_wakeup_capable(pdata->mi2s_gpio_p[index], false);
atomic_set(&(pdata->mi2s_gpio_ref_count[index]), 0);
+ }
/* Register LPASS audio hw vote */
lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote");
diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c
index 4890749..6221a2f 100644
--- a/asoc/msm-compress-q6-v2.c
+++ b/asoc/msm-compress-q6-v2.c
@@ -827,15 +827,23 @@
* RESUME
*/
if ((prtd->copied_total == prtd->bytes_sent) &&
- atomic_read(&prtd->drain)) {
- pr_debug("RUN ack, wake up & continue pending drain\n");
+ atomic_read(&prtd->drain)) {
+ bytes_available = prtd->bytes_received - prtd->copied_total;
+ if (bytes_available < cstream->runtime->fragment_size) {
+ pr_debug("%s: RUN ack, wake up & continue pending drain\n",
+ __func__);
- if (prtd->last_buffer)
- prtd->last_buffer = 0;
+ if (prtd->last_buffer)
+ prtd->last_buffer = 0;
- prtd->drain_ready = 1;
- wake_up(&prtd->drain_wait);
- atomic_set(&prtd->drain, 0);
+ prtd->drain_ready = 1;
+ wake_up(&prtd->drain_wait);
+ atomic_set(&prtd->drain, 0);
+ } else if (atomic_read(&prtd->xrun)) {
+ pr_debug("%s: RUN ack, continue write cycle\n", __func__);
+ atomic_set(&prtd->xrun, 0);
+ msm_compr_send_buffer(prtd);
+ }
}
spin_unlock_irqrestore(&prtd->lock, flags);
@@ -1510,6 +1518,7 @@
struct audio_client *ac = prtd->audio_client;
uint32_t stream_index;
uint32_t enc_cfg_id = ENC_CFG_ID_NONE;
+ bool compress_ts = false;
switch (prtd->codec_param.codec.format) {
case SNDRV_PCM_FORMAT_S24_LE:
@@ -1559,22 +1568,19 @@
return ret;
}
} else {
- if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) {
+ if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG)
+ compress_ts = true;
+
+ if (q6core_get_avcs_api_version_per_service(
+ APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
+ ADSP_ASM_API_VERSION_V2)
+ ret = q6asm_open_read_v5(prtd->audio_client,
+ prtd->codec, bits_per_sample,
+ compress_ts, enc_cfg_id);
+ else
ret = q6asm_open_read_v4(prtd->audio_client,
- prtd->codec,
- bits_per_sample, true, enc_cfg_id);
- } else {
- if (q6core_get_avcs_api_version_per_service(
- APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
- ADSP_ASM_API_VERSION_V2)
- ret = q6asm_open_read_v5(prtd->audio_client,
- prtd->codec, bits_per_sample,
- false, enc_cfg_id);
- else
- ret = q6asm_open_read_v4(prtd->audio_client,
- prtd->codec, bits_per_sample,
- false, enc_cfg_id);
- }
+ prtd->codec, bits_per_sample,
+ compress_ts, enc_cfg_id);
if (ret < 0) {
pr_err("%s: q6asm_open_read failed:%d\n",
__func__, ret);
@@ -3709,8 +3715,7 @@
if (fe_id >= MSM_FRONTEND_DAI_MAX) {
pr_err("%s Received out of bounds fe_id %lu\n",
__func__, fe_id);
- rc = -EINVAL;
- goto end;
+ return -EINVAL;
}
cstream = pdata->cstream[fe_id];
@@ -3718,14 +3723,12 @@
if (!cstream || !dec_params) {
pr_err("%s: stream or dec_params inactive\n", __func__);
- rc = -EINVAL;
- goto end;
+ return -EINVAL;
}
prtd = cstream->runtime->private_data;
if (!prtd) {
pr_err("%s: cannot set dec_params\n", __func__);
- rc = -EINVAL;
- goto end;
+ return -EINVAL;
}
mutex_lock(&pdata->lock);
@@ -3982,22 +3985,19 @@
if (fe_id >= MSM_FRONTEND_DAI_MAX) {
pr_err("%s Received invalid fe_id %lu\n",
__func__, fe_id);
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
cstream = pdata->cstream[fe_id];
if (cstream == NULL) {
pr_err("%s cstream is null\n", __func__);
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
prtd = cstream->runtime->private_data;
if (!prtd) {
pr_err("%s: prtd is null\n", __func__);
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
mutex_lock(&pdata->lock);
@@ -4048,22 +4048,19 @@
if (fe_id >= MSM_FRONTEND_DAI_MAX) {
pr_err("%s Received out of bounds invalid fe_id %lu\n",
__func__, fe_id);
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
cstream = pdata->cstream[fe_id];
if (cstream == NULL) {
pr_err("%s cstream is null\n", __func__);
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
prtd = cstream->runtime->private_data;
if (!prtd) {
pr_err("%s: prtd is null\n", __func__);
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
mutex_lock(&pdata->lock);
@@ -4097,8 +4094,7 @@
if (fe_id >= MSM_FRONTEND_DAI_MAX) {
pr_err("%s Received invalid fe_id %lu\n",
__func__, fe_id);
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
mutex_lock(&pdata->lock);
diff --git a/asoc/msm-dai-fe.c b/asoc/msm-dai-fe.c
index ba77a07..29e15dd 100644
--- a/asoc/msm-dai-fe.c
+++ b/asoc/msm-dai-fe.c
@@ -2726,6 +2726,105 @@
},
{
.playback = {
+ .stream_name = "MultiMedia23 Playback",
+ .aif_name = "MM_DL23",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "MultiMedia23 Capture",
+ .aif_name = "MM_UL23",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia23",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia24 Playback",
+ .aif_name = "MM_DL24",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "MultiMedia24 Capture",
+ .aif_name = "MM_UL24",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia24",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia25 Playback",
+ .aif_name = "MM_DL25",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "MultiMedia25 Capture",
+ .aif_name = "MM_UL25",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia25",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
.stream_name = "MultiMedia26 Playback",
.aif_name = "MM_DL26",
.rates = (SNDRV_PCM_RATE_8000_384000|
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index a4a561e..a0d9895 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -1286,6 +1286,7 @@
u16 port_id = (u16)kcontrol->private_value;
pr_debug("%s: island mode = %d\n", __func__, value);
+ trace_printk("%s: island mode = %d\n", __func__, value);
afe_set_island_mode_cfg(port_id, value);
return 0;
@@ -2621,6 +2622,8 @@
case RT_PROXY_DAI_001_RX:
case RT_PROXY_DAI_002_TX:
case RT_PROXY_DAI_002_RX:
+ case RT_PROXY_PORT_002_TX:
+ case RT_PROXY_PORT_002_RX:
rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
break;
case VOICE_PLAYBACK_TX:
@@ -4247,6 +4250,42 @@
},
};
+static struct snd_soc_dai_driver msm_dai_q6_proxy_tx_dai = {
+ .capture = {
+ .stream_name = "Proxy Capture",
+ .aif_name = "PROXY_TX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = RT_PROXY_PORT_002_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_proxy_rx_dai = {
+ .playback = {
+ .stream_name = "Proxy Playback",
+ .aif_name = "PROXY_RX",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .id = RT_PROXY_PORT_002_RX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
static struct snd_soc_dai_driver msm_dai_q6_usb_rx_dai = {
.playback = {
.stream_name = "USB Audio Playback",
@@ -7288,7 +7327,14 @@
pr_err("%s: Device not found stream name %s\n",
__func__, stream_name);
break;
-
+ case RT_PROXY_PORT_002_RX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component, &msm_dai_q6_proxy_rx_dai, 1);
+ break;
+ case RT_PROXY_PORT_002_TX:
+ rc = snd_soc_register_component(&pdev->dev,
+ &msm_dai_q6_component, &msm_dai_q6_proxy_tx_dai, 1);
+ break;
default:
rc = -ENODEV;
break;
diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c
index 5bc897d..b6624f0 100644
--- a/asoc/msm-lsm-client.c
+++ b/asoc/msm-lsm-client.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/init.h>
#include <linux/err.h>
@@ -33,6 +33,8 @@
#define CAPTURE_MIN_PERIOD_SIZE 320
#define LISTEN_MAX_STATUS_PAYLOAD_SIZE 256
+#define WAKELOCK_TIMEOUT 2000
+
#define LAB_BUFFER_ALLOC 1
#define LAB_BUFFER_DEALLOC 0
@@ -90,6 +92,7 @@
int xrun_count;
int xrun_index;
spinlock_t xrun_lock;
+ struct wakeup_source ws;
};
enum { /* lsm session states */
@@ -217,6 +220,8 @@
}
rtd = substream->private_data;
+ pm_wakeup_ws_event(&prtd->ws, WAKELOCK_TIMEOUT, true);
+ dev_dbg(rtd->dev, "%s: opcode %x\n", __func__, opcode);
switch (opcode) {
case LSM_DATA_EVENT_READ_DONE: {
int rc;
@@ -230,11 +235,13 @@
"%s: EVENT_READ_DONE invalid callback, session %d callback %d payload %pK",
__func__, prtd->lsm_client->session,
token, read_done);
+ __pm_relax(&prtd->ws);
return;
}
if (atomic_read(&prtd->read_abort)) {
dev_dbg(rtd->dev,
"%s: read abort set skip data\n", __func__);
+ __pm_relax(&prtd->ws);
return;
}
if (!lsm_lab_buffer_sanity(prtd, read_done, &buf_index)) {
@@ -247,6 +254,7 @@
"%s: Invalid index %d buf_index max cnt %d\n",
__func__, buf_index,
prtd->lsm_client->out_hw_params.period_count);
+ __pm_relax(&prtd->ws);
return;
}
spin_lock_irqsave(&prtd->xrun_lock, flags);
@@ -284,6 +292,7 @@
dev_err(rtd->dev,
"%s: client_size has invalid size[%d]\n",
__func__, client_size);
+ __pm_relax(&prtd->ws);
return;
}
status = (uint16_t)((uint8_t *)payload)[0];
@@ -299,13 +308,14 @@
dev_err(rtd->dev,
"%s: client_size has invalid size[%d]\n",
__func__, client_size);
+ __pm_relax(&prtd->ws);
return;
}
status = (uint16_t)((uint8_t *)payload)[0];
payload_size = (uint16_t)((uint8_t *)payload)[1];
index = 2;
dev_dbg(rtd->dev,
- "%s: event detect status = %d payload size = %d\n",
+ "%s: event detect status_v2 = %d payload size = %d\n",
__func__, status, payload_size);
break;
@@ -314,6 +324,7 @@
dev_err(rtd->dev,
"%s: client_size has invalid size[%d]\n",
__func__, client_size);
+ __pm_relax(&prtd->ws);
return;
}
event_ts_lsw = ((uint32_t *)payload)[0];
@@ -333,6 +344,7 @@
dev_err(rtd->dev,
"%s: client_size has invalid size[%d]\n",
__func__, client_size);
+ __pm_relax(&prtd->ws);
return;
}
@@ -352,6 +364,7 @@
"LSM_SESSION_DETECTION_ENGINE_GENERIC_EVENT",
sizeof(struct snd_lsm_event_status) +
payload_size);
+ __pm_relax(&prtd->ws);
return;
}
@@ -366,6 +379,7 @@
dev_err(rtd->dev,
"%s: Failed to copy memory with invalid size = %d\n",
__func__, payload_size);
+ __pm_relax(&prtd->ws);
return;
}
prtd->event_avail = 1;
@@ -390,12 +404,14 @@
opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V2 ||
opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V3) {
spin_lock_irqsave(&prtd->event_lock, flags);
+ dev_dbg(rtd->dev, "%s: detection status\n", __func__);
temp = krealloc(prtd->event_status,
sizeof(struct snd_lsm_event_status_v3) +
payload_size, GFP_ATOMIC);
if (!temp) {
dev_err(rtd->dev, "%s: no memory for event status\n",
__func__);
+ __pm_relax(&prtd->ws);
return;
}
/*
@@ -415,12 +431,14 @@
payload_size);
prtd->event_avail = 1;
spin_unlock_irqrestore(&prtd->event_lock, flags);
+ dev_dbg(rtd->dev, "%s: wakeup event_wait\n", __func__);
wake_up(&prtd->event_wait);
} else {
spin_unlock_irqrestore(&prtd->event_lock, flags);
dev_err(rtd->dev,
"%s: Failed to copy memory with invalid size = %d\n",
__func__, payload_size);
+ __pm_relax(&prtd->ws);
return;
}
} else {
@@ -432,6 +450,7 @@
if (substream->timer_running)
snd_timer_interrupt(substream->timer, 1);
}
+ dev_dbg(rtd->dev, "%s: leave\n", __func__);
}
static int msm_lsm_lab_buffer_alloc(struct lsm_priv *lsm, int alloc)
@@ -659,6 +678,10 @@
"%s: Failed to set min_conf_levels, err = %d\n",
__func__, rc);
+ if (prtd->lsm_client->confidence_levels) {
+ kfree(prtd->lsm_client->confidence_levels);
+ prtd->lsm_client->confidence_levels = NULL;
+ }
return rc;
}
@@ -1055,7 +1078,6 @@
struct snd_pcm_runtime *runtime;
struct lsm_priv *prtd;
struct snd_lsm_detection_params det_params;
- uint8_t *confidence_level = NULL;
uint32_t max_detection_stages_supported = LSM_MAX_STAGES_PER_SESSION;
if (!substream || !substream->private_data) {
@@ -1068,6 +1090,7 @@
prtd = runtime->private_data;
rtd = substream->private_data;
+ dev_dbg(rtd->dev, "%s: enter, cmd %x\n", __func__, cmd);
switch (cmd) {
case SNDRV_LSM_SET_SESSION_DATA:
case SNDRV_LSM_SET_SESSION_DATA_V2:
@@ -1133,6 +1156,7 @@
dev_err(rtd->dev,
"%s: lsm open failed, %d\n",
__func__, ret);
+ __pm_relax(&prtd->ws);
return ret;
}
prtd->lsm_client->opened = true;
@@ -1210,12 +1234,12 @@
dev_err(rtd->dev,
"%s: Register snd Model v2 failed =%d\n",
__func__, rc);
- kfree(confidence_level);
q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info);
}
-
- kfree(prtd->lsm_client->confidence_levels);
- prtd->lsm_client->confidence_levels = NULL;
+ if (prtd->lsm_client->confidence_levels) {
+ kfree(prtd->lsm_client->confidence_levels);
+ prtd->lsm_client->confidence_levels = NULL;
+ }
break;
}
case SNDRV_LSM_SET_PARAMS:
@@ -1247,10 +1271,10 @@
dev_err(rtd->dev,
"%s: Failed to set params, err = %d\n",
__func__, rc);
-
- kfree(prtd->lsm_client->confidence_levels);
- prtd->lsm_client->confidence_levels = NULL;
-
+ if (prtd->lsm_client->confidence_levels) {
+ kfree(prtd->lsm_client->confidence_levels);
+ prtd->lsm_client->confidence_levels = NULL;
+ }
break;
case SNDRV_LSM_DEREG_SND_MODEL:
@@ -1268,7 +1292,7 @@
uint32_t ts_lsw, ts_msw;
uint16_t status = 0, payload_size = 0;
- dev_dbg(rtd->dev, "%s: Get event status\n", __func__);
+ dev_dbg(rtd->dev, "%s: Get event status cmd %xx\n", __func__, cmd);
atomic_set(&prtd->event_wait_stop, 0);
/*
@@ -1281,6 +1305,7 @@
(cmpxchg(&prtd->event_avail, 1, 0) ||
(xchg = atomic_cmpxchg(&prtd->event_wait_stop,
1, 0))));
+ dev_dbg(rtd->dev, "%s: wait event is done\n", __func__);
mutex_lock(&prtd->lsm_api_lock);
dev_dbg(rtd->dev, "%s: wait_event_freezable %d event_wait_stop %d\n",
__func__, rc, xchg);
@@ -1457,6 +1482,12 @@
prtd->lsm_client->lab_started = false;
}
}
+
+ if (!atomic_read(&prtd->read_abort)) {
+ dev_dbg(rtd->dev,
+ "%s: set read_abort to stop buffering\n", __func__);
+ atomic_set(&prtd->read_abort, 1);
+ }
rc = q6lsm_stop(prtd->lsm_client, true);
if (!rc)
dev_dbg(rtd->dev,
@@ -1473,12 +1504,14 @@
if (prtd->lsm_client->num_stages > 1) {
dev_err(rtd->dev, "%s: %s: not supported for multi stage session\n",
__func__, "LSM_LAB_CONTROL");
+ __pm_relax(&prtd->ws);
return -EINVAL;
}
if (copy_from_user(&enable, arg, sizeof(enable))) {
dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n",
__func__, "LSM_LAB_CONTROL");
+ __pm_relax(&prtd->ws);
return -EFAULT;
}
@@ -1533,6 +1566,7 @@
if (copy_from_user(&mode, arg, sizeof(mode))) {
dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n",
__func__, "LSM_SET_FWK_MODE_CONFIG");
+ __pm_relax(&prtd->ws);
return -EFAULT;
}
@@ -1563,6 +1597,7 @@
if (copy_from_user(¶ms, arg, sizeof(params))) {
dev_err(rtd->dev, "%s: %s: copy_from_user failed\n",
__func__, "LSM_SET_INPUT_HW_PARAMS");
+ __pm_relax(&prtd->ws);
return -EFAULT;
}
@@ -1589,6 +1624,7 @@
dev_err(rtd->dev, "%s: cmd 0x%x failed %d\n",
__func__, cmd, rc);
+ __pm_relax(&prtd->ws);
return rc;
}
@@ -2493,6 +2529,7 @@
prtd->lsm_client->fe_id = rtd->dai_link->id;
prtd->lsm_client->unprocessed_data = 0;
+ wakeup_source_init(&prtd->ws, "lsm-client");
return 0;
}
@@ -2660,6 +2697,12 @@
__func__, ret);
}
}
+
+ if (!atomic_read(&prtd->read_abort)) {
+ dev_dbg(rtd->dev,
+ "%s: set read_abort to stop buffering\n", __func__);
+ atomic_set(&prtd->read_abort, 1);
+ }
ret = q6lsm_stop(prtd->lsm_client, true);
if (ret)
dev_err(rtd->dev,
@@ -2690,6 +2733,11 @@
SNDRV_PCM_STREAM_CAPTURE);
if (prtd->lsm_client->opened) {
+ if (!atomic_read(&prtd->read_abort)) {
+ dev_dbg(rtd->dev,
+ "%s: set read_abort to stop buffering\n", __func__);
+ atomic_set(&prtd->read_abort, 1);
+ }
q6lsm_close(prtd->lsm_client);
prtd->lsm_client->opened = false;
}
@@ -2726,6 +2774,7 @@
q6lsm_client_free(prtd->lsm_client);
+ wakeup_source_trash(&prtd->ws);
spin_lock_irqsave(&prtd->event_lock, flags);
kfree(prtd->event_status);
prtd->event_status = NULL;
diff --git a/asoc/msm-pcm-dtmf-v2.c b/asoc/msm-pcm-dtmf-v2.c
index 3dc7a26..a136102 100644
--- a/asoc/msm-pcm-dtmf-v2.c
+++ b/asoc/msm-pcm-dtmf-v2.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2013-2014, 2017-2019 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2017-2020 The Linux Foundation. All rights reserved.
*/
#include <linux/init.h>
@@ -97,7 +97,7 @@
uint16_t gain = ucontrol->value.integer.value[3];
pr_debug("%s: low_freq=%d high_freq=%d duration=%lld gain=%d\n",
- __func__, low_freq, high_freq, (int)duration, gain);
+ __func__, low_freq, high_freq, duration, gain);
if (duration == DTMF_MAX_DURATION)
duration = -1;
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index 262182f..f9d6856 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -68,7 +68,7 @@
static int sen_mi2s_switch_enable;
static int fm_pcmrx_switch_enable;
static int usb_switch_enable;
-static int lsm_port_index;
+static int lsm_port_index[MAX_LSM_SESSIONS];
static int slim0_rx_aanc_fb_port;
static int msm_route_ec_ref_rx;
static int msm_ec_ref_ch = 4;
@@ -79,6 +79,7 @@
static int msm_route_ext_ec_ref;
static bool is_custom_stereo_on;
static bool is_ds2_on;
+static bool ffecns_freeze_event;
static bool swap_ch;
static bool hifi_filter_enabled;
static int aanc_level;
@@ -696,6 +697,8 @@
LPASS_BE_PRI_META_MI2S_RX},
{ AFE_PORT_ID_SECONDARY_META_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0,
LPASS_BE_SEC_META_MI2S_RX},
+ { RT_PROXY_PORT_002_RX, 0, {0}, {0}, 0, 0, 0, 0, LPASS_BE_PROXY_RX},
+ { RT_PROXY_PORT_002_TX, 0, {0}, {0}, 0, 0, 0, 0, LPASS_BE_PROXY_TX},
};
/* Track ASM playback & capture sessions of DAI
@@ -769,6 +772,15 @@
/* MULTIMEDIA22 */
{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM},
{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM} },
+ /* MULTIMEDIA23 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM},
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM} },
+ /* MULTIMEDIA24 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM},
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM} },
+ /* MULTIMEDIA25 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM},
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM} },
/* MULTIMEDIA26 */
{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM},
{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM} },
@@ -1374,9 +1386,11 @@
if ((fe_id >= MSM_FRONTEND_DAI_LSM1) &&
(fe_id <= MSM_FRONTEND_DAI_LSM8)) {
/* fe id is listen while port is set to afe */
- if (lsm_port_index != ADM_LSM_PORT_INDEX) {
+ if (lsm_port_index[fe_id - MSM_FRONTEND_DAI_LSM1] !=
+ ADM_LSM_PORT_INDEX) {
pr_debug("%s: fe_id %d, lsm mux slim port %d\n",
- __func__, fe_id, lsm_port_index);
+ __func__, fe_id,
+ lsm_port_index[fe_id - MSM_FRONTEND_DAI_LSM1]);
rc = false;
}
}
@@ -2967,10 +2981,44 @@
return 1;
}
+static void msm_routing_get_lsm_fe_idx(struct snd_kcontrol *kcontrol,
+ u8 *fe_idx)
+{
+ int fe_id = MSM_FRONTEND_DAI_LSM1;
+
+ if (strnstr(kcontrol->id.name, "LSM1", sizeof("LSM1"))) {
+ fe_id = MSM_FRONTEND_DAI_LSM1;
+ } else if (strnstr(kcontrol->id.name, "LSM2", sizeof("LSM2"))) {
+ fe_id = MSM_FRONTEND_DAI_LSM2;
+ } else if (strnstr(kcontrol->id.name, "LSM3", sizeof("LSM3"))) {
+ fe_id = MSM_FRONTEND_DAI_LSM3;
+ } else if (strnstr(kcontrol->id.name, "LSM4", sizeof("LSM4"))) {
+ fe_id = MSM_FRONTEND_DAI_LSM4;
+ } else if (strnstr(kcontrol->id.name, "LSM5", sizeof("LSM5"))) {
+ fe_id = MSM_FRONTEND_DAI_LSM5;
+ } else if (strnstr(kcontrol->id.name, "LSM6", sizeof("LSM6"))) {
+ fe_id = MSM_FRONTEND_DAI_LSM6;
+ } else if (strnstr(kcontrol->id.name, "LSM7", sizeof("LSM7"))) {
+ fe_id = MSM_FRONTEND_DAI_LSM7;
+ } else if (strnstr(kcontrol->id.name, "LSM8", sizeof("LSM8"))) {
+ fe_id = MSM_FRONTEND_DAI_LSM8;
+ } else {
+ pr_err("%s: Invalid kcontrol name:%s\n", __func__,
+ kcontrol->id.name);
+ return;
+ }
+
+ *fe_idx = fe_id - MSM_FRONTEND_DAI_LSM1;
+ pr_debug("%s: fe_id: %d, fe_idx:%d\n", __func__, fe_id, *fe_idx);
+}
+
static int msm_routing_lsm_port_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = lsm_port_index;
+ u8 fe_idx = 0;
+
+ msm_routing_get_lsm_fe_idx(kcontrol, &fe_idx);
+ ucontrol->value.integer.value[0] = lsm_port_index[fe_idx];
return 0;
}
@@ -2980,6 +3028,7 @@
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int mux = ucontrol->value.enumerated.item[0];
int lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
+ u8 fe_idx = 0;
if (mux >= e->items) {
pr_err("%s: Invalid mux value %d\n", __func__, mux);
@@ -3042,7 +3091,8 @@
break;
}
set_lsm_port(lsm_port);
- lsm_port_index = ucontrol->value.integer.value[0];
+ msm_routing_get_lsm_fe_idx(kcontrol, &fe_idx);
+ lsm_port_index[fe_idx] = ucontrol->value.integer.value[0];
return 0;
}
@@ -3484,7 +3534,7 @@
"RX_CDC_DMA_RX_6", "RX_CDC_DMA_RX_7",
"PRI_SPDIF_TX", "SEC_SPDIF_RX", "SEC_SPDIF_TX",
"SLIM_9_RX", "SLIM_9_TX", "AFE_LOOPBACK_TX", "PRI_META_MI2S_RX",
-"SEC_META_MI2S_RX"
+"SEC_META_MI2S_RX", "PROXY_RX", "PROXY_TX"
};
static SOC_ENUM_SINGLE_DECL(mm1_channel_mux,
@@ -5467,6 +5517,14 @@
*index = 38;
port_id = AFE_PORT_ID_SENARY_MI2S_RX;
break;
+ case 39:
+ *index = 39;
+ port_id = AFE_PORT_ID_SENARY_MI2S_TX;
+ break;
+ case 40:
+ *index = 40;
+ port_id = AFE_PORT_ID_QUINARY_TDM_TX;
+ break;
default:
*index = 0; /* NONE */
pr_err("%s: Invalid value %d\n", __func__, value);
@@ -5524,7 +5582,7 @@
"WSA_CDC_DMA_TX_0", "WSA_CDC_DMA_TX_1", "WSA_CDC_DMA_TX_2",
"SLIM_7_RX", "RX_CDC_DMA_RX_0", "RX_CDC_DMA_RX_1", "RX_CDC_DMA_RX_2",
"RX_CDC_DMA_RX_3", "TX_CDC_DMA_TX_0", "TERT_TDM_RX_2", "SEC_TDM_TX_0",
- "DISPLAY_PORT1", "SEN_MI2S_RX",
+ "DISPLAY_PORT1", "SEN_MI2S_RX", "SENARY_MI2S_TX", "QUIN_TDM_TX_0",
};
static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
@@ -5559,6 +5617,12 @@
SOC_SINGLE_MULTI_EXT("EC Reference ChMixer Weights Ch6", SND_SOC_NOPM,
5, 16384, 0, PCM_FORMAT_MAX_NUM_CHANNEL_V8, NULL,
msm_ec_ref_chmixer_weights_put),
+ SOC_SINGLE_MULTI_EXT("EC Reference ChMixer Weights Ch7", SND_SOC_NOPM,
+ 6, 16384, 0, PCM_FORMAT_MAX_NUM_CHANNEL_V8, NULL,
+ msm_ec_ref_chmixer_weights_put),
+ SOC_SINGLE_MULTI_EXT("EC Reference ChMixer Weights Ch8", SND_SOC_NOPM,
+ 7, 16384, 0, PCM_FORMAT_MAX_NUM_CHANNEL_V8, NULL,
+ msm_ec_ref_chmixer_weights_put),
SOC_ENUM_EXT("AFE_LOOPBACK_TX Port", msm_route_ec_ref_rx_enum[0],
msm_routing_afe_lb_tx_port_get, msm_routing_afe_lb_tx_port_put),
};
@@ -5751,7 +5815,7 @@
"SEC_MI2S_TX", "TERT_MI2S_TX",
"QUAT_MI2S_TX", "QUIN_MI2S_TX",
"SLIM_1_TX", "PRI_TDM_TX",
- "SEC_TDM_TX"};
+ "SEC_TDM_TX", "SENARY_MI2S_TX"};
static const struct soc_enum msm_route_ext_ec_ref_rx_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ext_ec_ref_rx), ext_ec_ref_rx),
@@ -6575,6 +6639,10 @@
MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM,
MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer,
@@ -9589,6 +9657,18 @@
MSM_BACKEND_DAI_PRI_TDM_RX_0,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = {
@@ -9664,6 +9744,18 @@
MSM_BACKEND_DAI_PRI_TDM_RX_1,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_tdm_rx_2_mixer_controls[] = {
@@ -9739,6 +9831,18 @@
MSM_BACKEND_DAI_PRI_TDM_RX_2,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_tdm_rx_3_mixer_controls[] = {
@@ -9814,6 +9918,18 @@
MSM_BACKEND_DAI_PRI_TDM_RX_3,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_tdm_tx_0_mixer_controls[] = {
@@ -9881,6 +9997,18 @@
MSM_BACKEND_DAI_PRI_TDM_TX_0,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_tdm_rx_0_mixer_controls[] = {
@@ -9956,6 +10084,18 @@
MSM_BACKEND_DAI_SEC_TDM_RX_0,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = {
@@ -10031,6 +10171,18 @@
MSM_BACKEND_DAI_SEC_TDM_RX_1,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_tdm_rx_2_mixer_controls[] = {
@@ -10106,6 +10258,18 @@
MSM_BACKEND_DAI_SEC_TDM_RX_2,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_tdm_rx_3_mixer_controls[] = {
@@ -10181,6 +10345,18 @@
MSM_BACKEND_DAI_SEC_TDM_RX_3,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_tdm_tx_0_mixer_controls[] = {
@@ -10248,6 +10424,18 @@
MSM_BACKEND_DAI_SEC_TDM_TX_0,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_tdm_rx_0_mixer_controls[] = {
@@ -10323,6 +10511,18 @@
MSM_BACKEND_DAI_TERT_TDM_RX_0,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_tdm_tx_0_mixer_controls[] = {
@@ -10390,6 +10590,18 @@
MSM_BACKEND_DAI_TERT_TDM_TX_0,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_tdm_rx_1_mixer_controls[] = {
@@ -10465,6 +10677,18 @@
MSM_BACKEND_DAI_TERT_TDM_RX_1,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_tdm_rx_2_mixer_controls[] = {
@@ -10540,6 +10764,18 @@
MSM_BACKEND_DAI_TERT_TDM_RX_2,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = {
@@ -10615,6 +10851,18 @@
MSM_BACKEND_DAI_TERT_TDM_RX_3,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = {
@@ -10690,6 +10938,18 @@
MSM_BACKEND_DAI_TERT_TDM_RX_4,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = {
@@ -10769,6 +11029,18 @@
MSM_BACKEND_DAI_QUAT_TDM_RX_0,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quat_tdm_tx_0_mixer_controls[] = {
@@ -10836,6 +11108,18 @@
MSM_BACKEND_DAI_QUAT_TDM_TX_0,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quat_tdm_rx_1_mixer_controls[] = {
@@ -10915,6 +11199,18 @@
MSM_BACKEND_DAI_QUAT_TDM_RX_1,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = {
@@ -10994,6 +11290,18 @@
MSM_BACKEND_DAI_QUAT_TDM_RX_2,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = {
@@ -11073,6 +11381,18 @@
MSM_BACKEND_DAI_QUAT_TDM_RX_3,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quin_tdm_rx_0_mixer_controls[] = {
@@ -11152,6 +11472,18 @@
MSM_BACKEND_DAI_QUIN_TDM_RX_0,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quin_tdm_tx_0_mixer_controls[] = {
@@ -11219,6 +11551,18 @@
MSM_BACKEND_DAI_QUIN_TDM_TX_0,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quin_tdm_tx_1_mixer_controls[] = {
@@ -11432,6 +11776,18 @@
MSM_BACKEND_DAI_QUIN_TDM_TX_2,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quin_tdm_rx_2_mixer_controls[] = {
@@ -11511,6 +11867,18 @@
MSM_BACKEND_DAI_QUIN_TDM_RX_2,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quin_tdm_tx_3_mixer_controls[] = {
@@ -11657,6 +12025,18 @@
MSM_BACKEND_DAI_QUIN_TDM_RX_3,
MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sen_tdm_rx_0_mixer_controls[] = {
@@ -13135,6 +13515,14 @@
MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_MI2S_TX", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUINARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SENARY_MI2S_TX", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SENARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM,
MSM_BACKEND_DAI_SLIMBUS_7_TX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
@@ -14334,6 +14722,14 @@
MSM_BACKEND_DAI_AFE_LOOPBACK_TX,
MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("USB_AUDIO_TX", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_USB_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mmul18_mixer_controls[] = {
@@ -15003,6 +15399,255 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul23_mixer_controls[] = {
+ SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul24_mixer_controls[] = {
+ SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul25_mixer_controls[] = {
+ SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new mmul27_mixer_controls[] = {
SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM,
MSM_BACKEND_DAI_SLIMBUS_0_TX,
@@ -16484,6 +17129,17 @@
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new proxy_rx_voice_mixer_controls[] = {
+ SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PROXY_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PROXY_RX,
+ MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
static const struct snd_kcontrol_new tx_voicemmode1_mixer_controls[] = {
SOC_DOUBLE_EXT("PRI_TX_MMode1", SND_SOC_NOPM,
MSM_BACKEND_DAI_PRI_I2S_TX,
@@ -16581,6 +17237,9 @@
SOC_DOUBLE_EXT("PRI_TDM_TX_3_MMode1", SND_SOC_NOPM,
MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_VOICEMMODE1,
1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_DOUBLE_EXT("PROXY_TX_MMode1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PROXY_TX, MSM_FRONTEND_DAI_VOICEMMODE1,
+ 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voicemmode2_mixer_controls[] = {
@@ -16676,6 +17335,9 @@
SOC_DOUBLE_EXT("PRI_TDM_TX_3_MMode2", SND_SOC_NOPM,
MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_VOICEMMODE2,
1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_DOUBLE_EXT("PROXY_TX_MMode2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PROXY_TX, MSM_FRONTEND_DAI_VOICEMMODE2,
+ 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
@@ -21493,6 +22155,11 @@
0, 1, 0, msm_routing_get_switch_mixer,
msm_routing_put_switch_mixer);
+static const struct snd_kcontrol_new cdc_dma_rx_1_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_switch_mixer,
+ msm_routing_put_switch_mixer);
+
static const struct snd_kcontrol_new slim6_fm_switch_mixer_controls =
SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
0, 1, 0, msm_routing_get_switch_mixer,
@@ -21985,6 +22652,7 @@
kcontrol->private_value)->shift;
int i = 0, j = 0;
+ mutex_lock(&routing_lock);
ucontrol->value.integer.value[i] = num_app_cfg_types;
for (j = 0; j < num_app_cfg_types; ++j) {
@@ -21998,6 +22666,7 @@
ucontrol->value.integer.value[++i] =
lsm_app_type_cfg[j].num_out_channels;
}
+ mutex_unlock(&routing_lock);
return 0;
}
@@ -22009,9 +22678,11 @@
kcontrol->private_value)->shift;
int i = 0, j;
+ mutex_lock(&routing_lock);
if (ucontrol->value.integer.value[0] > MAX_APP_TYPES) {
pr_err("%s: number of app types exceed the max supported\n",
__func__);
+ mutex_unlock(&routing_lock);
return -EINVAL;
}
@@ -22031,7 +22702,7 @@
lsm_app_type_cfg[j].num_out_channels =
ucontrol->value.integer.value[i++];
}
-
+ mutex_unlock(&routing_lock);
return 0;
}
@@ -22088,6 +22759,36 @@
msm_routing_put_hifi_filter_control),
};
+static int msm_routing_get_ffecns_freeze_event_control(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = ffecns_freeze_event;
+ return 0;
+}
+
+static int msm_routing_put_ffecns_freeze_event_control(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = -EINVAL;
+
+ ffecns_freeze_event = ucontrol->value.integer.value[0];
+
+ ret = adm_set_ffecns_freeze_event(ffecns_freeze_event);
+ if (ret)
+ pr_err("%s: failed to set ffecns imc event to%d\n",
+ __func__, ffecns_freeze_event);
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new use_ffecns_freeze_event_controls[] = {
+ SOC_SINGLE_EXT("FFECNS Freeze Event", SND_SOC_NOPM, 0,
+ 1, 0, msm_routing_get_ffecns_freeze_event_control,
+ msm_routing_put_ffecns_freeze_event_control),
+};
+
int msm_routing_get_rms_value_control(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
int rc = 0;
@@ -22718,6 +23419,9 @@
.info = msm_source_tracking_info,
.get = msm_audio_source_tracking_get,
},
+};
+
+static const struct snd_kcontrol_new msm_source_doa_tracking_controls[] = {
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -22971,6 +23675,9 @@
SND_SOC_DAPM_AIF_IN("MM_DL20", "MultiMedia20 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL21", "MultiMedia21 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL22", "MultiMedia22 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL23", "MultiMedia23 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL24", "MultiMedia24 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL25", "MultiMedia25 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL26", "MultiMedia26 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
@@ -22989,6 +23696,9 @@
SND_SOC_DAPM_AIF_OUT("MM_UL20", "MultiMedia20 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL21", "MultiMedia21 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL22", "MultiMedia22 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL23", "MultiMedia23 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL24", "MultiMedia24 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL25", "MultiMedia25 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL27", "MultiMedia27 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL28", "MultiMedia28 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL29", "MultiMedia29 Capture", 0, 0, 0, 0),
@@ -23817,6 +24527,8 @@
SND_SOC_DAPM_AIF_IN("SLIMBUS_9_TX", "Slimbus9 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("USB_AUDIO_RX", "USB Audio Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("USB_AUDIO_TX", "USB Audio Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PROXY_RX", "Proxy Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PROXY_TX", "Proxy Capture", 0, 0, 0, 0),
/* Switch Definitions */
SND_SOC_DAPM_SWITCH("SLIMBUS_DL_HL", SND_SOC_NOPM, 0, 0,
@@ -23865,6 +24577,8 @@
&cdc_dma_wsa_switch_mixer_controls),
SND_SOC_DAPM_SWITCH("RX_CDC_DMA_RX_0_DL_HL", SND_SOC_NOPM, 0, 0,
&cdc_dma_rx_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("RX_CDC_DMA_RX_1_DL_HL", SND_SOC_NOPM, 0, 0,
+ &cdc_dma_rx_1_switch_mixer_controls),
/* Mixer definitions */
SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -24090,6 +24804,12 @@
mmul21_mixer_controls, ARRAY_SIZE(mmul21_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia22 Mixer", SND_SOC_NOPM, 0, 0,
mmul22_mixer_controls, ARRAY_SIZE(mmul22_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia23 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul23_mixer_controls, ARRAY_SIZE(mmul23_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia24 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul24_mixer_controls, ARRAY_SIZE(mmul24_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia25 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul25_mixer_controls, ARRAY_SIZE(mmul25_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia27 Mixer", SND_SOC_NOPM, 0, 0,
mmul27_mixer_controls, ARRAY_SIZE(mmul27_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia28 Mixer", SND_SOC_NOPM, 0, 0,
@@ -24242,6 +24962,10 @@
SND_SOC_NOPM, 0, 0,
wsa_cdc_dma_rx_0_voice_mixer_controls,
ARRAY_SIZE(wsa_cdc_dma_rx_0_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PROXY_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ proxy_rx_voice_mixer_controls,
+ ARRAY_SIZE(proxy_rx_voice_mixer_controls)),
SND_SOC_DAPM_MIXER("RX_CDC_DMA_RX_0_Voice Mixer",
SND_SOC_NOPM, 0, 0,
rx_cdc_dma_rx_0_voice_mixer_controls,
@@ -25036,6 +25760,8 @@
{"MultiMedia4 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"MultiMedia17 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia17 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"MultiMedia17 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
+ {"MultiMedia17 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
{"MultiMedia18 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia18 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"MultiMedia19 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
@@ -25133,6 +25859,7 @@
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia14", "MM_DL14"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia15", "MM_DL15"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"},
{"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"},
@@ -25322,6 +26049,9 @@
{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"},
{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25342,6 +26072,9 @@
{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"PRI_TDM_RX_1", NULL, "PRI_TDM_RX_1 Audio Mixer"},
{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25362,6 +26095,9 @@
{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"PRI_TDM_RX_2", NULL, "PRI_TDM_RX_2 Audio Mixer"},
{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25382,6 +26118,9 @@
{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"PRI_TDM_RX_3", NULL, "PRI_TDM_RX_3 Audio Mixer"},
{"PRI_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25400,6 +26139,9 @@
{"PRI_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
{"PRI_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
{"PRI_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"PRI_TDM_TX_0", NULL, "PRI_TDM_TX_0 Audio Mixer"},
{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25420,6 +26162,9 @@
{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"},
{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25440,6 +26185,9 @@
{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"SEC_TDM_RX_1", NULL, "SEC_TDM_RX_1 Audio Mixer"},
{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25460,6 +26208,9 @@
{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"SEC_TDM_RX_2", NULL, "SEC_TDM_RX_2 Audio Mixer"},
{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25480,6 +26231,9 @@
{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"SEC_TDM_RX_3", NULL, "SEC_TDM_RX_3 Audio Mixer"},
{"SEC_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25498,6 +26252,9 @@
{"SEC_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
{"SEC_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
{"SEC_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"SEC_TDM_TX_0", NULL, "SEC_TDM_TX_0 Audio Mixer"},
{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25518,6 +26275,9 @@
{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"TERT_TDM_RX_0", NULL, "TERT_TDM_RX_0 Audio Mixer"},
{"TERT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25536,6 +26296,9 @@
{"TERT_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
{"TERT_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
{"TERT_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"TERT_TDM_TX_0", NULL, "TERT_TDM_TX_0 Audio Mixer"},
{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25556,6 +26319,9 @@
{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"TERT_TDM_RX_1", NULL, "TERT_TDM_RX_1 Audio Mixer"},
{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25576,6 +26342,9 @@
{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"TERT_TDM_RX_2", NULL, "TERT_TDM_RX_2 Audio Mixer"},
{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25596,6 +26365,9 @@
{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_3 Audio Mixer"},
{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25616,6 +26388,9 @@
{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"TERT_TDM_RX_4", NULL, "TERT_TDM_RX_4 Audio Mixer"},
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25637,6 +26412,9 @@
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia20", "MM_DL20"},
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0 Audio Mixer"},
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25655,6 +26433,9 @@
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUAT_TDM_TX_0", NULL, "QUAT_TDM_TX_0 Audio Mixer"},
{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25676,6 +26457,9 @@
{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia20", "MM_DL20"},
{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUAT_TDM_RX_1", NULL, "QUAT_TDM_RX_1 Audio Mixer"},
{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25697,6 +26481,9 @@
{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia20", "MM_DL20"},
{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2 Audio Mixer"},
{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25718,6 +26505,9 @@
{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia20", "MM_DL20"},
{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3 Audio Mixer"},
{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25739,6 +26529,9 @@
{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia20", "MM_DL20"},
{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUIN_TDM_RX_0", NULL, "QUIN_TDM_RX_0 Audio Mixer"},
{"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25757,6 +26550,9 @@
{"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
{"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
{"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUIN_TDM_TX_0", NULL, "QUIN_TDM_TX_0 Audio Mixer"},
{"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25778,6 +26574,9 @@
{"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia20", "MM_DL20"},
{"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUIN_TDM_RX_1", NULL, "QUIN_TDM_RX_1 Audio Mixer"},
{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25799,6 +26598,9 @@
{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia20", "MM_DL20"},
{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUIN_TDM_RX_2", NULL, "QUIN_TDM_RX_2 Audio Mixer"},
{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25820,6 +26622,9 @@
{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia20", "MM_DL20"},
{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia22", "MM_DL22"},
+ {"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUIN_TDM_RX_3", NULL, "QUIN_TDM_RX_3 Audio Mixer"},
{"SEN_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25997,12 +26802,15 @@
{"MultiMedia28 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia29 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia30 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"MultiMedia5 Mixer", "QUAT_MI2S_TX", "QUAT_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"},
{"MultiMedia6 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
{"MultiMedia6 Mixer", "QUIN_MI2S_TX", "QUIN_MI2S_TX"},
+ {"MultiMedia5 Mixer", "QUIN_MI2S_TX", "QUIN_MI2S_TX"},
{"MultiMedia6 Mixer", "SENARY_MI2S_TX", "SENARY_MI2S_TX"},
+ {"MultiMedia5 Mixer", "SENARY_MI2S_TX", "SENARY_MI2S_TX"},
{"MultiMedia1 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
{"MultiMedia1 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
@@ -26442,6 +27250,69 @@
{"MultiMedia22 Mixer", "QUIN_TDM_TX_2", "QUIN_TDM_TX_2"},
{"MultiMedia22 Mixer", "QUIN_TDM_TX_3", "QUIN_TDM_TX_3"},
+ {"MultiMedia23 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia23 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia23 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia23 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia23 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia23 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia23 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia23 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+ {"MultiMedia23 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia23 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia23 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia23 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia23 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia23 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia23 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia23 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia23 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"MultiMedia23 Mixer", "QUIN_TDM_TX_1", "QUIN_TDM_TX_1"},
+ {"MultiMedia23 Mixer", "QUIN_TDM_TX_2", "QUIN_TDM_TX_2"},
+ {"MultiMedia23 Mixer", "QUIN_TDM_TX_3", "QUIN_TDM_TX_3"},
+
+ {"MultiMedia24 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia24 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia24 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia24 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia24 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia24 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia24 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia24 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+ {"MultiMedia24 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia24 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia24 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia24 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia24 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia24 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia24 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia24 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia24 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"MultiMedia24 Mixer", "QUIN_TDM_TX_1", "QUIN_TDM_TX_1"},
+ {"MultiMedia24 Mixer", "QUIN_TDM_TX_2", "QUIN_TDM_TX_2"},
+ {"MultiMedia24 Mixer", "QUIN_TDM_TX_3", "QUIN_TDM_TX_3"},
+
+ {"MultiMedia25 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia25 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia25 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia25 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia25 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia25 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia25 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia25 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+ {"MultiMedia25 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia25 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia25 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia25 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia25 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia25 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia25 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia25 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia25 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"MultiMedia25 Mixer", "QUIN_TDM_TX_1", "QUIN_TDM_TX_1"},
+ {"MultiMedia25 Mixer", "QUIN_TDM_TX_2", "QUIN_TDM_TX_2"},
+ {"MultiMedia25 Mixer", "QUIN_TDM_TX_3", "QUIN_TDM_TX_3"},
+
{"MultiMedia27 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia27 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"MultiMedia27 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"},
@@ -26686,6 +27557,9 @@
{"MM_UL20", NULL, "MultiMedia20 Mixer"},
{"MM_UL21", NULL, "MultiMedia21 Mixer"},
{"MM_UL22", NULL, "MultiMedia22 Mixer"},
+ {"MM_UL23", NULL, "MultiMedia23 Mixer"},
+ {"MM_UL24", NULL, "MultiMedia24 Mixer"},
+ {"MM_UL25", NULL, "MultiMedia25 Mixer"},
{"MM_UL27", NULL, "MultiMedia27 Mixer"},
{"MM_UL28", NULL, "MultiMedia28 Mixer"},
{"MM_UL29", NULL, "MultiMedia29 Mixer"},
@@ -27035,6 +27909,12 @@
{"WSA_CDC_DMA_RX_0_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
{"WSA_CDC_DMA_RX_0", NULL, "WSA_CDC_DMA_RX_0_Voice Mixer"},
+ {"PROXY_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"PROXY_RX", NULL, "PROXY_RX_Voice Mixer"},
+
+ {"PROXY_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"PROXY_RX", NULL, "PROXY_RX_Voice Mixer"},
+
{"RX_CDC_DMA_RX_0_Voice Mixer", "Voip", "VOIP_DL"},
{"RX_CDC_DMA_RX_0_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
{"RX_CDC_DMA_RX_0_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
@@ -27069,6 +27949,7 @@
{"AUDIO_REF_EC_UL1 MUX", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
{"AUDIO_REF_EC_UL1 MUX", "TERT_TDM_RX_2", "TERT_TDM_RX_2"},
{"AUDIO_REF_EC_UL1 MUX", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"AUDIO_REF_EC_UL1 MUX", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
{"AUDIO_REF_EC_UL2 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"AUDIO_REF_EC_UL2 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
@@ -27202,6 +28083,7 @@
{"VoiceMMode1_Tx Mixer", "QUAT_MI2S_TX_MMode1", "QUAT_MI2S_TX"},
{"VoiceMMode1_Tx Mixer", "QUIN_MI2S_TX_MMode1", "QUIN_MI2S_TX"},
{"VoiceMMode1_Tx Mixer", "PRI_TDM_TX_3_MMode1", "PRI_TDM_TX_3"},
+ {"VoiceMMode1_Tx Mixer", "PROXY_TX_MMode1", "PROXY_TX"},
{"VOICEMMODE1_UL", NULL, "VoiceMMode1_Tx Mixer"},
{"VoiceMMode2_Tx Mixer", "PRI_TX_MMode2", "PRI_I2S_TX"},
@@ -27231,6 +28113,7 @@
{"VoiceMMode2_Tx Mixer", "QUAT_MI2S_TX_MMode2", "QUAT_MI2S_TX"},
{"VoiceMMode2_Tx Mixer", "QUIN_MI2S_TX_MMode2", "QUIN_MI2S_TX"},
{"VoiceMMode2_Tx Mixer", "PRI_TDM_TX_3_MMode2", "PRI_TDM_TX_3"},
+ {"VoiceMMode2_Tx Mixer", "PROXY_TX_MMode2", "PROXY_TX"},
{"VOICEMMODE2_UL", NULL, "VoiceMMode2_Tx Mixer"},
{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
@@ -27282,7 +28165,8 @@
{"CDC_DMA_UL_HL", NULL, "VA_CDC_DMA_TX_0"},
{"RX_CDC_DMA_RX_0_DL_HL", "Switch", "CDC_DMA_DL_HL"},
{"RX_CDC_DMA_RX_0", NULL, "RX_CDC_DMA_RX_0_DL_HL"},
- {"RX_CDC_DMA_RX_1", NULL, "RX_CDC_DMA_RX_0_DL_HL"},
+ {"RX_CDC_DMA_RX_1_DL_HL", "Switch", "CDC_DMA_DL_HL"},
+ {"RX_CDC_DMA_RX_1", NULL, "RX_CDC_DMA_RX_1_DL_HL"},
{"TX3_CDC_DMA_UL_HL", NULL, "TX_CDC_DMA_TX_3"},
{"LSM1 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
{"LSM1 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
@@ -28535,6 +29419,7 @@
{"BE_OUT", NULL, "RX_CDC_DMA_RX_5"},
{"BE_OUT", NULL, "RX_CDC_DMA_RX_6"},
{"BE_OUT", NULL, "RX_CDC_DMA_RX_7"},
+ {"BE_OUT", NULL, "PROXY_RX"},
{"PRI_I2S_TX", NULL, "BE_IN"},
{"MI2S_TX", NULL, "BE_IN"},
@@ -28631,6 +29516,7 @@
{"TX_CDC_DMA_TX_5", NULL, "BE_IN"},
{"PRI_SPDIF_TX", NULL, "BE_IN"},
{"SEC_SPDIF_TX", NULL, "BE_IN"},
+ {"PROXY_TX", NULL, "BE_IN"},
};
static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
@@ -28950,8 +29836,8 @@
pr_debug("%s: port_id %d, copp_idx %d\n", __func__, port_id, copp_idx);
if (port_id != HDMI_RX && port_id != DISPLAY_PORT_RX) {
- pr_err("%s: Device pp params on invalid port %d\n",
- __func__, port_id);
+ pr_err("%s: Device pp params on invalid port %d, copp_idx %d, fe_id %d\n",
+ __func__, port_id, copp_idx, fe_id);
return -EINVAL;
}
@@ -29399,6 +30285,20 @@
.prepare = msm_pcm_routing_prepare,
};
+#ifdef CONFIG_DOA_PARAMS_ENABLED
+void msm_routing_add_doa_control(struct snd_soc_component *component)
+{
+ snd_soc_add_component_controls(component,
+ msm_source_doa_tracking_controls,
+ ARRAY_SIZE(msm_source_doa_tracking_controls));
+}
+#else
+void msm_routing_add_doa_control(struct snd_soc_component *component)
+{
+ return;
+}
+#endif
+
/* Not used but frame seems to require it */
static int msm_routing_probe(struct snd_soc_component *component)
{
@@ -29457,6 +30357,10 @@
ARRAY_SIZE(hifi_filter_controls));
snd_soc_add_component_controls(component,
+ use_ffecns_freeze_event_controls,
+ ARRAY_SIZE(use_ffecns_freeze_event_controls));
+
+ snd_soc_add_component_controls(component,
device_pp_params_mixer_controls,
ARRAY_SIZE(device_pp_params_mixer_controls));
@@ -29464,6 +30368,8 @@
msm_routing_be_dai_name_table_mixer_controls,
ARRAY_SIZE(msm_routing_be_dai_name_table_mixer_controls));
+ /* Add doa control based on config */
+ msm_routing_add_doa_control(component);
snd_soc_add_component_controls(component, msm_source_tracking_controls,
ARRAY_SIZE(msm_source_tracking_controls));
snd_soc_add_component_controls(component, adm_channel_config_controls,
diff --git a/asoc/msm-pcm-routing-v2.h b/asoc/msm-pcm-routing-v2.h
index 8003d91..6b96bde 100644
--- a/asoc/msm-pcm-routing-v2.h
+++ b/asoc/msm-pcm-routing-v2.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_PCM_ROUTING_H
#define _MSM_PCM_ROUTING_H
@@ -42,6 +42,8 @@
#define LPASS_BE_VOICE2_PLAYBACK_TX "VOICE2_PLAYBACK_TX"
#define LPASS_BE_INCALL_RECORD_RX "INCALL_RECORD_RX"
#define LPASS_BE_INCALL_RECORD_TX "INCALL_RECORD_TX"
+#define LPASS_BE_PROXY_RX "PROXY_RX"
+#define LPASS_BE_PROXY_TX "PROXY_TX"
#define LPASS_BE_SEC_I2S_RX "SECONDARY_I2S_RX"
#define LPASS_BE_PRI_SPDIF_RX "PRI_SPDIF_RX"
#define LPASS_BE_PRI_SPDIF_TX "PRI_SPDIF_TX"
@@ -260,6 +262,9 @@
MSM_FRONTEND_DAI_MULTIMEDIA20,
MSM_FRONTEND_DAI_MULTIMEDIA21,
MSM_FRONTEND_DAI_MULTIMEDIA22,
+ MSM_FRONTEND_DAI_MULTIMEDIA23,
+ MSM_FRONTEND_DAI_MULTIMEDIA24,
+ MSM_FRONTEND_DAI_MULTIMEDIA25,
MSM_FRONTEND_DAI_MULTIMEDIA26,
MSM_FRONTEND_DAI_MULTIMEDIA27,
MSM_FRONTEND_DAI_MULTIMEDIA28,
@@ -499,6 +504,8 @@
MSM_BACKEND_DAI_AFE_LOOPBACK_TX,
MSM_BACKEND_DAI_PRI_META_MI2S_RX,
MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+ MSM_BACKEND_DAI_PROXY_RX,
+ MSM_BACKEND_DAI_PROXY_TX,
MSM_BACKEND_DAI_MAX,
};
diff --git a/asoc/sa6155.c b/asoc/sa6155.c
index 73b95b2..d242738 100644
--- a/asoc/sa6155.c
+++ b/asoc/sa6155.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2020, 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
@@ -213,7 +213,7 @@
},
{ /* QUAT TDM */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* RX_0 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* RX_1 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
@@ -222,10 +222,10 @@
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
},
{ /* QUIN TDM */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_0 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_1 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_2 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 6}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
@@ -266,7 +266,7 @@
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
},
{ /* QUAT TDM */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 16}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* TX_0 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
@@ -276,9 +276,9 @@
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
},
{ /* QUIN TDM */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 6}, /* TX_0 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 4}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_2 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
@@ -415,20 +415,20 @@
{0xFFFF}, /* not used */
},
{/* QUAT TDM */
- {0, 4, 8, 12, 16, 20, 24, 28, 0xFFFF},/*AMP OUT*/
+ {0, 8, 16, 24, 32, 40, 48, 56, 0xFFFF}, /*8 CH SPKR*/
+ {4, 12, 20, 28, 36, 44, 52, 60, 0xFFFF}, /*8 CH SPKR*/
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
- {0xFFFF}, /* not used */
- {28,0xFFFF},
+ {60,0xFFFF},
},
{/* QUIN TDM */
- {0, 4, 0xFFFF},/*STEREO SPKR1*/
- {8, 12, 0xFFFF},/*STEREO SPKR2*/
- {16, 20, 0xFFFF},/*STEREO SPKR3*/
- {24, 28, 0xFFFF},/*STEREO SPKR4*/
+ {0, 4, 8, 12, 16, 20, 0xFFFF},
+ {24, 0xFFFF},
+ {28, 0xFFFF},
+ {0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
@@ -469,8 +469,7 @@
{28, 0xFFFF},
},
{/* QUAT TDM */
- {0, 4, 8, 12, 16, 20, 24, 28,
- 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},/*MIC ARR*/
+ {0, 8, 16, 24, 4, 12, 20, 28, 0xFFFF}, /*8 CH MIC ARR*/
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
@@ -480,14 +479,14 @@
{60,0xFFFF},
},
{/* QUIN TDM */
- {0, 4, 8, 12, 16, 20, 0xFFFF},/*EC/ANC REF*/
+ {0, 4, 8, 12, 0xFFFF},
+ {16, 20, 0xFFFF},
+ {24, 28, 0xFFFF},
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
- {0xFFFF}, /* not used */
- {0xFFFF}, /* not used */
- {20, 0xFFFF},
+ {28, 0xFFFF},
}
};
@@ -4801,11 +4800,13 @@
if (index == TDM_TERT || index == TDM_QUAT ||
index == TDM_QUIN) {
pinctrl_info = &pdata->pinctrl_info[index];
- ret_pinctrl = msm_set_pinctrl(pinctrl_info,
- STATE_ACTIVE);
- if (ret_pinctrl)
- pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
- __func__, ret_pinctrl);
+ if (pinctrl_info->pinctrl) {
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info,
+ STATE_ACTIVE);
+ if (ret_pinctrl)
+ pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
+ __func__, ret_pinctrl);
+ }
}
}
mutex_unlock(&intf_conf->lock);
@@ -4841,11 +4842,13 @@
if (index == TDM_TERT || index == TDM_QUAT ||
index == TDM_QUIN) {
pinctrl_info = &pdata->pinctrl_info[index];
- ret_pinctrl = msm_set_pinctrl(pinctrl_info,
- STATE_SLEEP);
- if (ret_pinctrl)
- pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
- __func__, ret_pinctrl);
+ if (pinctrl_info->pinctrl) {
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info,
+ STATE_SLEEP);
+ if (ret_pinctrl)
+ pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
+ __func__, ret_pinctrl);
+ }
}
}
mutex_unlock(&intf_conf->lock);
@@ -4935,11 +4938,13 @@
}
pinctrl_info = &pdata->pinctrl_info[index];
- ret_pinctrl = msm_set_pinctrl(pinctrl_info,
- STATE_ACTIVE);
- if (ret_pinctrl)
- pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
- __func__, ret_pinctrl);
+ if (pinctrl_info->pinctrl) {
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info,
+ STATE_ACTIVE);
+ if (ret_pinctrl)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret_pinctrl);
+ }
}
clk_off:
if (ret < 0)
@@ -4979,11 +4984,13 @@
__func__, index, ret);
pinctrl_info = &pdata->pinctrl_info[index];
- ret_pinctrl = msm_set_pinctrl(pinctrl_info,
- STATE_SLEEP);
- if (ret_pinctrl)
- pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
- __func__, ret_pinctrl);
+ if (pinctrl_info->pinctrl) {
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info,
+ STATE_SLEEP);
+ if (ret_pinctrl)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret_pinctrl);
+ }
}
mutex_unlock(&intf_conf->lock);
}
@@ -5885,6 +5892,23 @@
.ignore_pmdown_time = 1,
.id = MSM_FRONTEND_DAI_MULTIMEDIA22
},
+ {
+ .name = MSM_DAILINK_NAME(Media23),
+ .stream_name = "MultiMedia23",
+ .cpu_dai_name = "MultiMedia23",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
+ .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,
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA23
+ },
};
static struct snd_soc_dai_link msm_custom_fe_dai_links[] = {
diff --git a/asoc/sa8155.c b/asoc/sa8155.c
index 228f430..4730060 100644
--- a/asoc/sa8155.c
+++ b/asoc/sa8155.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
*/
/*
* Copyright 2011, The Android Open Source Project
@@ -174,14 +174,14 @@
/* TDM default config */
static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
{ /* PRI TDM */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_0 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_1 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_2 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_3 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_2 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_3 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
},
{ /* SEC TDM */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_0 */
@@ -205,7 +205,7 @@
},
{ /* QUAT TDM */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* RX_0 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* RX_1 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
@@ -214,10 +214,10 @@
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
},
{ /* QUIN TDM */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_0 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_1 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_2 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_3 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 16}, /* RX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
@@ -228,14 +228,14 @@
/* TDM default config */
static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
{ /* PRI TDM */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_0 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_1 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_2 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_3 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_2 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_3 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
},
{ /* SEC TDM */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 6}, /* TX_0 */
@@ -258,7 +258,7 @@
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
},
{ /* QUAT TDM */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 16}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* TX_0 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
@@ -268,7 +268,7 @@
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
},
{ /* QUIN TDM */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 6}, /* TX_0 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8}, /* TX_0 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */
@@ -343,7 +343,7 @@
static struct tdm_slot_cfg tdm_slot[TDM_INTERFACE_MAX] = {
/* PRI TDM */
- {32, 8},
+ {16, 16},
/* SEC TDM */
{32, 8},
/* TERT TDM */
@@ -377,11 +377,11 @@
static unsigned int tdm_rx_slot_offset
[TDM_INTERFACE_MAX][TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = {
{/* PRI TDM */
- {0, 4, 0xFFFF},
- {8, 12, 0xFFFF},
- {16, 20, 0xFFFF},
- {24, 28, 0xFFFF},
- {0xFFFF}, /* not used */
+ {0, 0xFFFF},
+ {2, 0xFFFF},
+ {4, 6, 0xFFFF},
+ {8, 10, 0xFFFF},
+ {12, 14, 0xFFFF},
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
@@ -407,35 +407,36 @@
{0xFFFF}, /* not used */
},
{/* QUAT TDM */
- {0, 4, 8, 12, 16, 20, 24, 28, 0xFFFF},/*AMP OUT*/
+ {0, 8, 16, 24, 32, 40, 48, 56, 0xFFFF}, /*8 CH SPKR*/
+ {4, 12, 20, 28, 36, 44, 52, 60, 0xFFFF}, /*8 CH SPKR*/
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
- {0xFFFF}, /* not used */
- {28,0xFFFF},
+ {60,0xFFFF},
},
{/* QUIN TDM */
- {0, 4, 0xFFFF},/*STEREO SPKR1*/
- {8, 12, 0xFFFF},/*STEREO SPKR2*/
- {16, 20, 0xFFFF},/*STEREO SPKR3*/
- {24, 28, 0xFFFF},/*STEREO SPKR4*/
+ {0, 4, 8, 12, 16, 20, 24, 28,
+ 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF}, /*16 CH SPKR*/
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
- {28, 0xFFFF},
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {0xFFFF}, /* not used */
+ {60, 0xFFFF},
}
};
static unsigned int tdm_tx_slot_offset
[TDM_INTERFACE_MAX][TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = {
{/* PRI TDM */
- {0, 4, 0xFFFF},
- {8, 12, 0xFFFF},
- {16, 20, 0xFFFF},
- {24, 28, 0xFFFF},
- {0xFFFF}, /* not used */
+ {0, 0xFFFF},
+ {2, 0xFFFF},
+ {4, 6, 0xFFFF},
+ {8, 10, 0xFFFF},
+ {12, 14, 0xFFFF},
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
@@ -461,8 +462,7 @@
{28, 0xFFFF},
},
{/* QUAT TDM */
- {0, 4, 8, 12, 16, 20, 24, 28,
- 32, 36, 40, 44, 48, 52, 56, 60, 0xFFFF},/*MIC ARR*/
+ {0, 8, 16, 24, 4, 12, 20, 28, 0xFFFF}, /*8 CH MIC ARR1*/
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
@@ -472,14 +472,14 @@
{60,0xFFFF},
},
{/* QUIN TDM */
- {0, 4, 8, 12, 16, 20, 0xFFFF},/*EC/ANC REF*/
+ {0, 4, 8, 12, 16, 20, 24, 28, 0xFFFF}, /*8 CH MIC ARR2*/
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
- {20, 0xFFFF},
+ {60, 0xFFFF},
}
};
@@ -4791,11 +4791,13 @@
mutex_lock(&intf_conf->lock);
if (++intf_conf->ref_cnt == 1) {
pinctrl_info = &pdata->pinctrl_info[index];
- ret_pinctrl = msm_set_pinctrl(pinctrl_info,
- STATE_ACTIVE);
- if (ret_pinctrl)
- pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
- __func__, ret_pinctrl);
+ if (pinctrl_info->pinctrl) {
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info,
+ STATE_ACTIVE);
+ if (ret_pinctrl)
+ pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
+ __func__, ret_pinctrl);
+ }
}
mutex_unlock(&intf_conf->lock);
@@ -4828,11 +4830,13 @@
mutex_lock(&intf_conf->lock);
if (--intf_conf->ref_cnt == 0) {
pinctrl_info = &pdata->pinctrl_info[index];
- ret_pinctrl = msm_set_pinctrl(pinctrl_info,
- STATE_SLEEP);
- if (ret_pinctrl)
- pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
- __func__, ret_pinctrl);
+ if (pinctrl_info->pinctrl) {
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info,
+ STATE_SLEEP);
+ if (ret_pinctrl)
+ pr_err("%s: TDM TLMM pinctrl set failed with %d\n",
+ __func__, ret_pinctrl);
+ }
}
mutex_unlock(&intf_conf->lock);
}
@@ -4921,11 +4925,13 @@
}
pinctrl_info = &pdata->pinctrl_info[index];
- ret_pinctrl = msm_set_pinctrl(pinctrl_info,
- STATE_ACTIVE);
- if (ret_pinctrl)
- pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
- __func__, ret_pinctrl);
+ if (pinctrl_info->pinctrl) {
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info,
+ STATE_ACTIVE);
+ if (ret_pinctrl)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret_pinctrl);
+ }
}
clk_off:
if (ret < 0)
@@ -4965,11 +4971,13 @@
__func__, index, ret);
pinctrl_info = &pdata->pinctrl_info[index];
- ret_pinctrl = msm_set_pinctrl(pinctrl_info,
- STATE_SLEEP);
- if (ret_pinctrl)
- pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
- __func__, ret_pinctrl);
+ if (pinctrl_info->pinctrl) {
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info,
+ STATE_SLEEP);
+ if (ret_pinctrl)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret_pinctrl);
+ }
}
mutex_unlock(&intf_conf->lock);
}
@@ -5871,6 +5879,57 @@
.ignore_pmdown_time = 1,
.id = MSM_FRONTEND_DAI_MULTIMEDIA22
},
+ {
+ .name = MSM_DAILINK_NAME(Media23),
+ .stream_name = "MultiMedia23",
+ .cpu_dai_name = "MultiMedia23",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
+ .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,
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA23
+ },
+ {
+ .name = MSM_DAILINK_NAME(Media24),
+ .stream_name = "MultiMedia24",
+ .cpu_dai_name = "MultiMedia24",
+ .platform_name = "msm-pcm-loopback",
+ .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,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA24
+ },
+ {
+ .name = MSM_DAILINK_NAME(Media25),
+ .stream_name = "MultiMedia25",
+ .cpu_dai_name = "MultiMedia25",
+ .platform_name = "msm-pcm-loopback",
+ .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,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA25
+ },
};
static struct snd_soc_dai_link msm_custom_fe_dai_links[] = {
diff --git a/config/litoauto.conf b/config/litoauto.conf
index 0bbe4f7..12bb1df 100644
--- a/config/litoauto.conf
+++ b/config/litoauto.conf
@@ -32,5 +32,7 @@
CONFIG_SND_SOC_WCD_IRQ=m
CONFIG_SND_SOC_WCD938X=m
CONFIG_SND_SOC_WCD938X_SLAVE=m
+CONFIG_SND_SOC_WCD937X=m
+CONFIG_SND_SOC_WCD937X_SLAVE=m
CONFIG_SND_SOC_LITO=m
CONFIG_SND_EVENT=m
diff --git a/config/litoautoconf.h b/config/litoautoconf.h
index 2d19f2d..0cfdab2 100644
--- a/config/litoautoconf.h
+++ b/config/litoautoconf.h
@@ -36,5 +36,7 @@
#define CONFIG_SND_SOC_WCD_IRQ 1
#define CONFIG_SND_SOC_WCD938X 1
#define CONFIG_SND_SOC_WCD938X_SLAVE 1
+#define CONFIG_SND_SOC_WCD937X 1
+#define CONFIG_SND_SOC_WCD937X_SLAVE 1
#define CONFIG_SND_SOC_LITO 1
#define CONFIG_SND_EVENT 1
diff --git a/config/qcs405auto.conf b/config/qcs405auto.conf
index 61620eb..ebd6f70 100644
--- a/config/qcs405auto.conf
+++ b/config/qcs405auto.conf
@@ -36,3 +36,4 @@
CONFIG_MSM_AVTIMER=m
CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=m
CONFIG_SND_SOC_EP92=m
+CONFIG_DOA_PARAMS_ENABLED=m
diff --git a/config/qcs405autoconf.h b/config/qcs405autoconf.h
index 04f1e10..286dd31 100644
--- a/config/qcs405autoconf.h
+++ b/config/qcs405autoconf.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/
#define CONFIG_PINCTRL_LPI 1
@@ -40,3 +40,4 @@
#define CONFIG_MSM_AVTIMER 1
#define CONFIG_SND_SOC_MSM_HDMI_CODEC_RX 1
#define CONFIG_SND_SOC_EP92 1
+#define CONFIG_DOA_PARAMS_ENABLED 1
diff --git a/dsp/adsp-loader.c b/dsp/adsp-loader.c
index aec90f5..8316f00 100644
--- a/dsp/adsp-loader.c
+++ b/dsp/adsp-loader.c
@@ -324,14 +324,14 @@
{
struct adsp_loader_private *priv = NULL;
struct nvmem_cell *cell;
- ssize_t len;
+ size_t len;
u32 *buf;
const char **adsp_fw_name_array = NULL;
int adsp_fw_cnt;
u32* adsp_fw_bit_values = NULL;
int i;
int fw_name_size;
- u32 adsp_var_idx;
+ u32 adsp_var_idx = 0;
int ret = 0;
ret = adsp_loader_init_sysfs(pdev);
@@ -349,11 +349,11 @@
}
buf = nvmem_cell_read(cell, &len);
nvmem_cell_put(cell);
- if (IS_ERR_OR_NULL(buf)) {
+ if (IS_ERR_OR_NULL(buf) || len <= 0 || len > sizeof(u32)) {
dev_dbg(&pdev->dev, "%s: FAILED to read nvmem cell \n", __func__);
goto wqueue;
}
- adsp_var_idx = (*buf);
+ memcpy(&adsp_var_idx, buf, len);
kfree(buf);
/* Get count of fw images */
diff --git a/dsp/codecs/audio_native.c b/dsp/codecs/audio_native.c
index 9337029..6e24914 100644
--- a/dsp/codecs/audio_native.c
+++ b/dsp/codecs/audio_native.c
@@ -1,12 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, 2020, The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "audio_utils.h"
+spinlock_t enc_dec_lock;
+
static int __init audio_native_init(void)
{
aac_in_init();
@@ -31,6 +33,7 @@
g711alaw_in_init();
g711mlaw_in_init();
qcelp_in_init();
+ spin_lock_init(&enc_dec_lock);
return 0;
}
diff --git a/dsp/codecs/audio_utils.c b/dsp/codecs/audio_utils.c
index 26e9b0b..ac93413 100644
--- a/dsp/codecs/audio_utils.c
+++ b/dsp/codecs/audio_utils.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2010-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -943,8 +943,11 @@
audio_in_disable(audio);
q6asm_audio_client_free(audio->ac);
mutex_unlock(&audio->lock);
+ spin_lock(&enc_dec_lock);
kfree(audio->enc_cfg);
kfree(audio->codec_cfg);
kfree(audio);
+ file->private_data = NULL;
+ spin_unlock(&enc_dec_lock);
return 0;
}
diff --git a/dsp/codecs/audio_utils_aio.c b/dsp/codecs/audio_utils_aio.c
index 62b9455..93095e3 100644
--- a/dsp/codecs/audio_utils_aio.c
+++ b/dsp/codecs/audio_utils_aio.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2020, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -631,9 +631,11 @@
#ifdef CONFIG_DEBUG_FS
debugfs_remove(audio->dentry);
#endif
+ spin_lock(&enc_dec_lock);
kfree(audio->codec_cfg);
kfree(audio);
file->private_data = NULL;
+ spin_unlock(&enc_dec_lock);
mutex_unlock(&lock);
return 0;
}
diff --git a/dsp/codecs/q6audio_common.h b/dsp/codecs/q6audio_common.h
index c37813e..67003fe 100644
--- a/dsp/codecs/q6audio_common.h
+++ b/dsp/codecs/q6audio_common.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 2017, 2020 The Linux Foundation. All rights reserved.
*/
@@ -9,7 +9,7 @@
#include <dsp/apr_audio-v2.h>
#include <dsp/q6asm-v2.h>
-
+extern spinlock_t enc_dec_lock;
void q6_audio_cb(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv);
diff --git a/dsp/codecs/q6audio_v2.c b/dsp/codecs/q6audio_v2.c
index c98ef1c..6a402f5 100644
--- a/dsp/codecs/q6audio_v2.c
+++ b/dsp/codecs/q6audio_v2.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2012-2013, 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 2015-2017, 2020 The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -21,6 +21,11 @@
struct q6audio_in *audio = (struct q6audio_in *)priv;
unsigned long flags;
+ spin_lock(&enc_dec_lock);
+ if (audio == NULL) {
+ pr_err("%s: failed to get q6audio value\n", __func__);
+ goto error;
+ }
pr_debug("%s:session id %d: opcode[0x%x]\n", __func__,
audio->ac->session, opcode);
@@ -58,6 +63,8 @@
break;
}
spin_unlock_irqrestore(&audio->dsp_lock, flags);
+error:
+ spin_unlock(&enc_dec_lock);
}
void audio_in_get_dsp_frames(void *priv,
diff --git a/dsp/codecs/q6audio_v2_aio.c b/dsp/codecs/q6audio_v2_aio.c
index 4cb4636..ecd14da 100644
--- a/dsp/codecs/q6audio_v2_aio.c
+++ b/dsp/codecs/q6audio_v2_aio.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -43,6 +43,11 @@
struct q6audio_aio *audio = (struct q6audio_aio *)priv;
union msm_audio_event_payload e_payload;
+ spin_lock(&enc_dec_lock);
+ if (audio == NULL) {
+ pr_err("%s: failed to get q6audio value\n", __func__);
+ goto error;
+ }
switch (opcode) {
case ASM_DATA_EVENT_WRITE_DONE_V2:
pr_debug("%s[%pK]:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
@@ -107,6 +112,8 @@
default:
break;
}
+error:
+ spin_unlock(&enc_dec_lock);
}
int extract_meta_out_info(struct q6audio_aio *audio,
diff --git a/dsp/msm_audio_ion_vm.c b/dsp/msm_audio_ion_vm.c
index f9635b3..37b17b6 100644
--- a/dsp/msm_audio_ion_vm.c
+++ b/dsp/msm_audio_ion_vm.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/init.h>
@@ -306,7 +306,6 @@
struct msm_audio_smmu_vm_map_cmd_rsp cmd_rsp;
struct msm_audio_alloc_data *alloc_data = NULL;
unsigned long delay = jiffies + (HZ / 2);
- void *vaddr;
*len = ((struct dma_buf*)handle)->size;
@@ -315,14 +314,13 @@
list) {
if (alloc_data->handle == handle) {
found = true;
- vaddr = alloc_data->vaddr;
/* Export the buffer to physical VM */
- rc = habmm_export(msm_audio_ion_hab_handle, vaddr, *len,
- &export_id, 0);
+ rc = habmm_export(msm_audio_ion_hab_handle, handle, *len,
+ &export_id, HABMM_EXPIMP_FLAGS_DMABUF);
if (rc) {
- pr_err("%s: habmm_export failed vaddr = %pK, len = %zd, rc = %d\n",
- __func__, vaddr, *len, rc);
+ pr_err("%s: habmm_export failed handle = %pK, len = %zd, rc = %d\n",
+ __func__, handle, *len, rc);
goto err;
}
@@ -564,6 +562,7 @@
if (rc) {
pr_err("%s: failed to do smmu map, err = %d\n",
__func__, rc);
+ msm_audio_dma_buf_unmap((struct dma_buf *) handle);
goto err;
}
}
diff --git a/dsp/q6adm.c b/dsp/q6adm.c
index 69c0d69..a2f644f 100644
--- a/dsp/q6adm.c
+++ b/dsp/q6adm.c
@@ -513,6 +513,17 @@
pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
return -EINVAL;
}
+
+ /*
+ * check if PSPD is already configured
+ * if it is configured already, return 0 without applying PSPD.
+ */
+ if (atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]) > 1) {
+ pr_debug("%s: copp.cnt:%#x\n", __func__,
+ atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]));
+ return 0;
+ }
+
/*
* First 8 bytes are 4 bytes as rule number, 2 bytes as output
* channel and 2 bytes as input channel.
@@ -3374,7 +3385,7 @@
ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
atomic_read(&this_adm.copp.stat
[port_idx][copp_idx]) >= 0,
- msecs_to_jiffies(TIMEOUT_MS));
+ msecs_to_jiffies(2 * TIMEOUT_MS));
if (!ret) {
pr_err("%s: ADM open timedout for port_id: 0x%x for [0x%x]\n",
__func__, tmp_port, port_id);
@@ -4571,6 +4582,49 @@
EXPORT_SYMBOL(adm_set_ffecns_effect);
/**
+ * adm_set_ffecns_freeze_event -
+ * command to set event for ffecns module
+ *
+ * @event: send ffecns freeze event true or false
+ *
+ * Returns 0 on success or error on failure
+ */
+int adm_set_ffecns_freeze_event(bool ffecns_freeze_event)
+{
+ struct ffv_spf_freeze_param_t ffv_param;
+ struct param_hdr_v3 param_hdr;
+ int rc = 0;
+ int copp_idx = 0;
+
+ memset(¶m_hdr, 0, sizeof(param_hdr));
+ memset(&ffv_param, 0, sizeof(ffv_param));
+
+ ffv_param.freeze = ffecns_freeze_event ? 1 : 0;
+ ffv_param.source_id = 0; /*default value*/
+
+ copp_idx = adm_get_default_copp_idx(this_adm.ffecns_port_id);
+ if ((copp_idx < 0) || (copp_idx >= MAX_COPPS_PER_PORT)) {
+ pr_err("%s, no active copp to query rms copp_idx:%d\n",
+ __func__, copp_idx);
+ return -EINVAL;
+ }
+
+ param_hdr.module_id = FFECNS_MODULE_ID;
+ param_hdr.instance_id = INSTANCE_ID_0;
+ param_hdr.param_id = PARAM_ID_FFV_SPF_FREEZE;
+ param_hdr.param_size = sizeof(ffv_param);
+
+ rc = adm_pack_and_set_one_pp_param(this_adm.ffecns_port_id, copp_idx,
+ param_hdr, (uint8_t *) &ffv_param);
+ if (rc)
+ pr_err("%s: Failed to set ffecns imc event, err %d\n",
+ __func__, rc);
+
+ return rc;
+}
+EXPORT_SYMBOL(adm_set_ffecns_freeze_event);
+
+/**
* adm_param_enable -
* command to send params to ADM for given module
*
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index 7297a1e..017ae06 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/slab.h>
#include <linux/debugfs.h>
@@ -23,6 +23,7 @@
#include "q6afecal-hwdep.h"
#define WAKELOCK_TIMEOUT 5000
+#define AFE_CLK_TOKEN 1024
enum {
AFE_COMMON_RX_CAL = 0,
AFE_COMMON_TX_CAL,
@@ -106,8 +107,11 @@
void *apr;
atomic_t state;
atomic_t status;
+ atomic_t clk_state;
+ atomic_t clk_status;
wait_queue_head_t wait[AFE_MAX_PORTS];
wait_queue_head_t wait_wakeup;
+ wait_queue_head_t clk_wait;
struct task_struct *task;
wait_queue_head_t lpass_core_hw_wait;
uint32_t lpass_hw_core_client_hdl[AFE_LPASS_CORE_HW_VOTE_MAX];
@@ -153,6 +157,8 @@
uint32_t afe_sample_rates[AFE_MAX_PORTS];
struct aanc_data aanc_info;
struct mutex afe_cmd_lock;
+ struct mutex afe_apr_lock;
+ struct mutex afe_clk_lock;
int set_custom_topology;
int dev_acdb_id[AFE_MAX_PORTS];
routing_cb rt_cb;
@@ -679,8 +685,8 @@
if (data->token < AFE_LPASS_CORE_HW_VOTE_MAX)
this_afe.lpass_hw_core_client_hdl[data->token] =
payload[0];
- atomic_set(&this_afe.state, 0);
- atomic_set(&this_afe.status, 0);
+ atomic_set(&this_afe.clk_state, 0);
+ atomic_set(&this_afe.clk_status, 0);
wake_up(&this_afe.lpass_core_hw_wait);
} else if (data->payload_size) {
uint32_t *payload;
@@ -698,7 +704,10 @@
payload[0], payload[1], data->token);
/* payload[1] contains the error status for response */
if (payload[1] != 0) {
- atomic_set(&this_afe.status, payload[1]);
+ if(data->token == AFE_CLK_TOKEN)
+ atomic_set(&this_afe.clk_status, payload[1]);
+ else
+ atomic_set(&this_afe.status, payload[1]);
pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
__func__, payload[0], payload[1]);
}
@@ -719,11 +728,16 @@
case AFE_SVC_CMD_SET_PARAM:
case AFE_SVC_CMD_SET_PARAM_V2:
case AFE_PORT_CMD_MOD_EVENT_CFG:
- atomic_set(&this_afe.state, 0);
- if (afe_token_is_valid(data->token))
- wake_up(&this_afe.wait[data->token]);
- else
- return -EINVAL;
+ if(data->token == AFE_CLK_TOKEN) {
+ atomic_set(&this_afe.clk_state, 0);
+ wake_up(&this_afe.clk_wait);
+ } else {
+ atomic_set(&this_afe.state, 0);
+ if (afe_token_is_valid(data->token))
+ wake_up(&this_afe.wait[data->token]);
+ else
+ return -EINVAL;
+ }
break;
case AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER:
break;
@@ -769,7 +783,10 @@
break;
case AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST:
case AFE_CMD_REMOTE_LPASS_CORE_HW_DEVOTE_REQUEST:
- atomic_set(&this_afe.state, 0);
+ atomic_set(&this_afe.clk_state, 0);
+ if (payload[1] != 0)
+ atomic_set(&this_afe.clk_status,
+ payload[1]);
wake_up(&this_afe.lpass_core_hw_wait);
break;
case AFE_SVC_CMD_EVENT_CFG:
@@ -971,6 +988,8 @@
break;
case RT_PROXY_PORT_001_RX:
case RT_PROXY_PORT_001_TX:
+ case RT_PROXY_PORT_002_RX:
+ case RT_PROXY_PORT_002_TX:
ret_size = SIZEOF_CFG_CMD(afe_param_id_rt_proxy_port_cfg);
break;
case AFE_PORT_ID_USB_RX:
@@ -1053,6 +1072,7 @@
{
int ret;
+ mutex_lock(&this_afe.afe_apr_lock);
if (wait)
atomic_set(&this_afe.state, 1);
atomic_set(&this_afe.status, 0);
@@ -1063,7 +1083,11 @@
(atomic_read(&this_afe.state) == 0),
msecs_to_jiffies(2 * TIMEOUT_MS));
if (!ret) {
+ pr_err_ratelimited("%s: request timedout\n",
+ __func__);
ret = -ETIMEDOUT;
+ trace_printk("%s: wait for ADSP response timed out\n",
+ __func__);
} else if (atomic_read(&this_afe.status) > 0) {
pr_err("%s: DSP returned error[%s]\n", __func__,
adsp_err_get_err_str(atomic_read(
@@ -1083,6 +1107,47 @@
}
pr_debug("%s: leave %d\n", __func__, ret);
+ mutex_unlock(&this_afe.afe_apr_lock);
+ return ret;
+}
+/*
+ * afe_apr_send_clk_pkt : returns 0 on success, negative otherwise.
+ */
+static int afe_apr_send_clk_pkt(void *data, wait_queue_head_t *wait)
+{
+ int ret;
+
+ if (wait)
+ atomic_set(&this_afe.clk_state, 1);
+ atomic_set(&this_afe.clk_status, 0);
+ ret = apr_send_pkt(this_afe.apr, data);
+ if (ret > 0) {
+ if (wait) {
+ ret = wait_event_timeout(*wait,
+ (atomic_read(&this_afe.clk_state) == 0),
+ msecs_to_jiffies(2 * TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: timeout\n", __func__);
+ ret = -ETIMEDOUT;
+ } else if (atomic_read(&this_afe.clk_status) > 0) {
+ pr_err("%s: DSP returned error[%s]\n", __func__,
+ adsp_err_get_err_str(atomic_read(
+ &this_afe.clk_status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.clk_status));
+ } else {
+ ret = 0;
+ }
+ } else {
+ ret = 0;
+ }
+ } else if (ret == 0) {
+ pr_err("%s: packet not transmitted\n", __func__);
+ /* apr_send_pkt can return 0 when nothing is transmitted */
+ ret = -EINVAL;
+ }
+
+ pr_debug("%s: leave %d\n", __func__, ret);
return ret;
}
@@ -1481,6 +1546,122 @@
return rc;
}
+/*
+ * This function shouldn't be called directly. Instead call
+ * q6afe_clk_set_params.
+ */
+static int q6afe_clk_set_params_v1(int index, struct mem_mapping_hdr *mem_hdr,
+ u8 *packed_param_data, u32 packed_data_size)
+{
+ struct afe_svc_cmd_set_param_v1 *svc_set_param = NULL;
+ uint32_t size = sizeof(struct afe_svc_cmd_set_param_v1);
+ int rc = 0;
+
+ if (packed_param_data != NULL)
+ size += packed_data_size;
+ svc_set_param = kzalloc(size, GFP_KERNEL);
+ if (svc_set_param == NULL)
+ return -ENOMEM;
+
+ svc_set_param->apr_hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ svc_set_param->apr_hdr.pkt_size = size;
+ svc_set_param->apr_hdr.src_port = 0;
+ svc_set_param->apr_hdr.dest_port = 0;
+ svc_set_param->apr_hdr.token = AFE_CLK_TOKEN;
+ svc_set_param->apr_hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+ svc_set_param->payload_size = packed_data_size;
+
+ if (mem_hdr != NULL) {
+ /* Out of band case. */
+ svc_set_param->mem_hdr = *mem_hdr;
+ } else if (packed_param_data != NULL) {
+ /* In band case. */
+ memcpy(&svc_set_param->param_data, packed_param_data,
+ packed_data_size);
+ } else {
+ pr_err("%s: Both memory header and param data are NULL\n",
+ __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ rc = afe_apr_send_clk_pkt(svc_set_param, &this_afe.clk_wait);
+done:
+ kfree(svc_set_param);
+ return rc;
+}
+
+/*
+ * This function shouldn't be called directly. Instead call
+ * q6afe_clk_set_params.
+ */
+static int q6afe_clk_set_params_v2(int index, struct mem_mapping_hdr *mem_hdr,
+ u8 *packed_param_data, u32 packed_data_size)
+{
+ struct afe_svc_cmd_set_param_v2 *svc_set_param = NULL;
+ uint16_t size = sizeof(struct afe_svc_cmd_set_param_v2);
+ int rc = 0;
+
+ if (packed_param_data != NULL)
+ size += packed_data_size;
+ svc_set_param = kzalloc(size, GFP_KERNEL);
+ if (svc_set_param == NULL)
+ return -ENOMEM;
+
+ svc_set_param->apr_hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ svc_set_param->apr_hdr.pkt_size = size;
+ svc_set_param->apr_hdr.src_port = 0;
+ svc_set_param->apr_hdr.dest_port = 0;
+ svc_set_param->apr_hdr.token = AFE_CLK_TOKEN;
+ svc_set_param->apr_hdr.opcode = AFE_SVC_CMD_SET_PARAM_V2;
+ svc_set_param->payload_size = packed_data_size;
+
+ if (mem_hdr != NULL) {
+ /* Out of band case. */
+ svc_set_param->mem_hdr = *mem_hdr;
+ } else if (packed_param_data != NULL) {
+ /* In band case. */
+ memcpy(&svc_set_param->param_data, packed_param_data,
+ packed_data_size);
+ } else {
+ pr_err("%s: Both memory header and param data are NULL\n",
+ __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ rc = afe_apr_send_clk_pkt(svc_set_param, &this_afe.clk_wait);
+done:
+ kfree(svc_set_param);
+ return rc;
+}
+
+static int q6afe_clk_set_params(int index, struct mem_mapping_hdr *mem_hdr,
+ u8 *packed_param_data, u32 packed_data_size,
+ bool is_iid_supported)
+{
+ int ret;
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ if (is_iid_supported)
+ return q6afe_clk_set_params_v2(index, mem_hdr,
+ packed_param_data,
+ packed_data_size);
+ else
+ return q6afe_clk_set_params_v1(index, mem_hdr,
+ packed_param_data,
+ packed_data_size);
+}
+
static int q6afe_svc_set_params(int index, struct mem_mapping_hdr *mem_hdr,
u8 *packed_param_data, u32 packed_data_size,
bool is_iid_supported)
@@ -1525,9 +1706,12 @@
__func__, ret);
goto done;
}
-
- ret = q6afe_svc_set_params(index, NULL, packed_param_data,
- packed_data_size, is_iid_supported);
+ if (param_hdr.module_id == AFE_MODULE_CLOCK_SET)
+ ret = q6afe_clk_set_params(index, NULL, packed_param_data,
+ packed_data_size, is_iid_supported);
+ else
+ ret = q6afe_svc_set_params(index, NULL, packed_param_data,
+ packed_data_size, is_iid_supported);
done:
kfree(packed_param_data);
@@ -1807,34 +1991,7 @@
config->num_events = num_events;
config->version = 1;
memcpy(config->payload, &pl, sizeof(pl));
- atomic_set(&this_afe.state, 1);
- atomic_set(&this_afe.status, 0);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) config);
- if (ret < 0) {
- pr_err("%s: port = 0x%x failed %d\n",
- __func__, port_id, ret);
- goto fail_cmd;
- }
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- if (atomic_read(&this_afe.status) > 0) {
- pr_err("%s: config cmd failed [%s]\n",
- __func__, adsp_err_get_err_str(
- atomic_read(&this_afe.status)));
- ret = adsp_err_get_lnx_err_code(
- atomic_read(&this_afe.status));
- goto fail_idx;
- }
- ret = 0;
-fail_cmd:
- pr_debug("%s: config.opcode 0x%x status %d\n",
- __func__, config->hdr.opcode, ret);
+ ret = afe_apr_send_pkt((uint32_t *) config, &this_afe.wait[index]);
fail_idx:
kfree(config);
@@ -2082,7 +2239,7 @@
__func__, port_id, ret);
fail_cmd:
- pr_debug("%s: port_id 0x%x rate %u delay_usec %d status %d\n",
+ pr_info("%s: port_id 0x%x rate %u delay_usec %d status %d\n",
__func__, port_id, rate, delay_entry.delay_usec, ret);
return ret;
}
@@ -2106,6 +2263,8 @@
/* Skip cal_block if it is already marked stale */
if (cal_utils_is_cal_stale(cal_block))
continue;
+ pr_info("%s: port id: 0x%x, dev_acdb_id: %d\n", __func__,
+ port_id, this_afe.dev_acdb_id[afe_port_index]);
path = ((afe_get_port_type(port_id) ==
MSM_AFE_PORT_TYPE_TX)?(TX_DEVICE):(RX_DEVICE));
afe_top =
@@ -2114,14 +2273,14 @@
if (this_afe.dev_acdb_id[afe_port_index] > 0) {
if (afe_top->acdb_id ==
this_afe.dev_acdb_id[afe_port_index]) {
- pr_debug("%s: top_id:%x acdb_id:%d afe_port_id:%d\n",
+ pr_info("%s: top_id:%x acdb_id:%d afe_port_id:0x%x\n",
__func__, afe_top->topology,
afe_top->acdb_id,
q6audio_get_port_id(port_id));
return cal_block;
}
} else {
- pr_debug("%s: top_id:%x acdb_id:%d afe_port:%d\n",
+ pr_info("%s: top_id:%x acdb_id:%d afe_port:0x%x\n",
__func__, afe_top->topology, afe_top->acdb_id,
q6audio_get_port_id(port_id));
return cal_block;
@@ -2178,9 +2337,9 @@
*topology_id = (u32)afe_top_info->topology;
cal_utils_mark_cal_used(cal_block);
- pr_debug("%s: port_id = %u acdb_id = %d topology_id = %u ret=%d\n",
+ pr_info("%s: port_id = 0x%x acdb_id = %d topology_id = 0x%x cal_type_index=%d ret=%d\n",
__func__, port_id, afe_top_info->acdb_id,
- afe_top_info->topology, ret);
+ afe_top_info->topology, cal_type_index, ret);
unlock:
mutex_unlock(&this_afe.cal_data[cal_type_index]->lock);
return ret;
@@ -2235,7 +2394,7 @@
this_afe.topology[index] = topology_id;
rtac_update_afe_topology(port_id);
done:
- pr_debug("%s: AFE set topology id 0x%x enable for port 0x%x ret %d\n",
+ pr_info("%s: AFE set topology id 0x%x enable for port 0x%x ret %d\n",
__func__, topology_id, port_id, ret);
return ret;
@@ -2308,6 +2467,8 @@
}
pr_debug("%s: AFE set island mode 0x%x enable for port 0x%x ret %d\n",
__func__, island_mode, port_id, ret);
+ trace_printk("%s: AFE set island mode 0x%x enable for port 0x%x ret %d\n",
+ __func__, island_mode, port_id, ret);
return ret;
}
EXPORT_SYMBOL(afe_send_port_island_mode);
@@ -2470,7 +2631,7 @@
struct audio_cal_info_afe *afe_cal_info = NULL;
int afe_port_index = q6audio_get_port_index(port_id);
- pr_debug("%s: cal_index %d port_id %d port_index %d\n", __func__,
+ pr_info("%s: cal_index %d port_id 0x%x port_index %d\n", __func__,
cal_index, port_id, afe_port_index);
if (afe_port_index < 0) {
pr_err("%s: Error getting AFE port index %d\n",
@@ -2482,16 +2643,21 @@
&this_afe.cal_data[cal_index]->cal_blocks) {
cal_block = list_entry(ptr, struct cal_block_data, list);
afe_cal_info = cal_block->cal_info;
+ pr_info("%s: acdb_id %d dev_acdb_id %d sample_rate %d afe_sample_rates %d\n",
+ __func__, afe_cal_info->acdb_id,
+ this_afe.dev_acdb_id[afe_port_index],
+ afe_cal_info->sample_rate,
+ this_afe.afe_sample_rates[afe_port_index]);
if ((afe_cal_info->acdb_id ==
this_afe.dev_acdb_id[afe_port_index]) &&
(afe_cal_info->sample_rate ==
this_afe.afe_sample_rates[afe_port_index])) {
- pr_debug("%s: cal block is a match, size is %zd\n",
+ pr_info("%s: cal block is a match, size is %zd\n",
__func__, cal_block->cal_data.size);
goto exit;
}
}
- pr_debug("%s: no matching cal_block found\n", __func__);
+ pr_info("%s: no matching cal_block found\n", __func__);
cal_block = NULL;
exit:
@@ -2504,7 +2670,7 @@
int ret;
int afe_port_index = q6audio_get_port_index(port_id);
- pr_debug("%s:\n", __func__);
+ pr_info("%s: cal_index is %d\n", __func__, cal_index);
if (this_afe.cal_data[cal_index] == NULL) {
pr_warn("%s: cal_index %d not allocated!\n",
@@ -2521,7 +2687,9 @@
}
mutex_lock(&this_afe.cal_data[cal_index]->lock);
-
+ pr_info("%s: dev_acdb_id[%d] is %d\n",
+ __func__, afe_port_index,
+ this_afe.dev_acdb_id[afe_port_index]);
if (((cal_index == AFE_COMMON_RX_CAL) ||
(cal_index == AFE_COMMON_TX_CAL) ||
(cal_index == AFE_LSM_TX_CAL)) &&
@@ -2537,7 +2705,7 @@
goto unlock;
}
- pr_debug("%s: Sending cal_index cal %d\n", __func__, cal_index);
+ pr_info("%s: Sending cal_index cal %d\n", __func__, cal_index);
ret = remap_cal_data(cal_block, cal_index);
if (ret) {
@@ -2548,7 +2716,7 @@
}
ret = afe_send_cal_block(port_id, cal_block);
if (ret < 0)
- pr_debug("%s: No cal sent for cal_index %d, port_id = 0x%x! ret %d\n",
+ pr_err("%s: No cal sent for cal_index %d, port_id = 0x%x! ret %d\n",
__func__, cal_index, port_id, ret);
cal_utils_mark_cal_used(cal_block);
@@ -3315,34 +3483,7 @@
config->num_events = num_events;
config->version = 1;
memcpy(config->payload, &pl, sizeof(pl));
- atomic_set(&this_afe.state, 1);
- atomic_set(&this_afe.status, 0);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) config);
- if (ret < 0) {
- pr_err("%s: port = 0x%x failed %d\n",
- __func__, port_id, ret);
- goto fail_cmd;
- }
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- if (atomic_read(&this_afe.status) > 0) {
- pr_err("%s: config cmd failed [%s]\n",
- __func__, adsp_err_get_err_str(
- atomic_read(&this_afe.status)));
- ret = adsp_err_get_lnx_err_code(
- atomic_read(&this_afe.status));
- goto fail_idx;
- }
- ret = 0;
-fail_cmd:
- pr_debug("%s: config.opcode 0x%x status %d\n",
- __func__, config->hdr.opcode, ret);
+ ret = afe_apr_send_pkt((uint32_t *) config, &this_afe.wait[index]);
fail_idx:
kfree(config);
@@ -3650,6 +3791,8 @@
port_index = afe_get_port_index(port_id);
this_afe.island_mode[port_index] = enable_flag;
+ trace_printk("%s: set island mode cfg 0x%x for port 0x%x\n",
+ __func__, this_afe.island_mode[port_index], port_id);
}
EXPORT_SYMBOL(afe_set_island_mode_cfg);
@@ -4029,6 +4172,7 @@
struct asm_aptx_ad_speech_mode_cfg_t speech_codec_init_param;
struct param_hdr_v3 param_hdr;
int ret;
+ uint32_t frame_size_ctl_value_v2;
pr_debug("%s:update DSP for enc format = %d\n", __func__, format);
@@ -4116,8 +4260,9 @@
frame_ctl_param.ctl_type = enc_blk_param.
enc_blk_config.aac_config.frame_ctl.ctl_type;
frame_ctl_param.ctl_value = frame_size_ctl_value;
+
pr_debug("%s: send AFE_PARAM_ID_AAC_FRM_SIZE_CONTROL\n",
- __func__);
+ __func__);
ret = q6afe_pack_and_set_param_in_band(port_id,
q6audio_get_port_index(port_id),
param_hdr,
@@ -4128,6 +4273,29 @@
goto exit;
}
}
+ frame_size_ctl_value_v2 = enc_blk_param.enc_blk_config.
+ aac_config.frame_ctl_v2.ctl_value;
+ if (frame_size_ctl_value_v2 > 0) {
+ param_hdr.param_id =
+ AFE_PARAM_ID_AAC_FRM_SIZE_CONTROL;
+ param_hdr.param_size = sizeof(frame_ctl_param);
+ frame_ctl_param.ctl_type = enc_blk_param.
+ enc_blk_config.aac_config.frame_ctl_v2.ctl_type;
+ frame_ctl_param.ctl_value = enc_blk_param.
+ enc_blk_config.aac_config.frame_ctl_v2.ctl_value;
+
+ pr_debug("%s: send AFE_PARAM_ID_AAC_FRM_SIZE_CONTROL V2\n",
+ __func__);
+ ret = q6afe_pack_and_set_param_in_band(port_id,
+ q6audio_get_port_index(port_id),
+ param_hdr,
+ (u8 *) &frame_ctl_param);
+ if (ret) {
+ pr_err("%s: AAC_FRM_SIZE_CONTROL with VBR support failed %d\n",
+ __func__, ret);
+ goto exit;
+ }
+ }
}
if (format == ASM_MEDIA_FMT_APTX) {
@@ -4433,7 +4601,7 @@
port_id = VIRTUAL_ID_TO_PORTID(port_id);
}
- pr_debug("%s: port id: 0x%x\n", __func__, port_id);
+ pr_info("%s: port id: 0x%x\n", __func__, port_id);
index = q6audio_get_port_index(port_id);
if (index < 0 || index >= AFE_MAX_PORTS) {
@@ -4614,6 +4782,8 @@
break;
case RT_PROXY_PORT_001_RX:
case RT_PROXY_PORT_001_TX:
+ case RT_PROXY_PORT_002_RX:
+ case RT_PROXY_PORT_002_TX:
cfg_type = AFE_PARAM_ID_RT_PROXY_CONFIG;
break;
case INT_BT_SCO_RX:
@@ -5161,6 +5331,10 @@
return IDX_AFE_PORT_ID_RX_CODEC_DMA_RX_7;
case AFE_LOOPBACK_TX:
return IDX_AFE_LOOPBACK_TX;
+ case RT_PROXY_PORT_002_RX:
+ return IDX_RT_PROXY_PORT_002_RX;
+ case RT_PROXY_PORT_002_TX:
+ return IDX_RT_PROXY_PORT_002_TX;
default:
pr_err("%s: port 0x%x\n", __func__, port_id);
return -EINVAL;
@@ -6061,39 +6235,10 @@
pr_debug("%s: dma_addr_p 0x%pK , size %d\n", __func__,
&dma_addr_p, dma_buf_sz);
- atomic_set(&this_afe.state, 1);
- atomic_set(&this_afe.status, 0);
this_afe.mmap_handle = 0;
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
- if (ret < 0) {
- pr_err("%s: AFE memory map cmd failed %d\n",
- __func__, ret);
- ret = -EINVAL;
- goto fail_cmd;
- }
-
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- if (atomic_read(&this_afe.status) > 0) {
- pr_err("%s: config cmd failed [%s]\n",
- __func__, adsp_err_get_err_str(
- atomic_read(&this_afe.status)));
- ret = adsp_err_get_lnx_err_code(
- atomic_read(&this_afe.status));
- goto fail_cmd;
- }
-
+ ret = afe_apr_send_pkt((uint32_t *) mmap_region_cmd,
+ &this_afe.wait[index]);
kfree(mmap_region_cmd);
- return 0;
-fail_cmd:
- kfree(mmap_region_cmd);
- pr_err("%s: fail_cmd\n", __func__);
return ret;
}
@@ -6508,10 +6653,19 @@
afecmd_wr.available_bytes = bytes;
afecmd_wr.reserved = 0;
- ret = afe_apr_send_pkt(&afecmd_wr, NULL);
- if (ret)
+ /*
+ * Do not call afe_apr_send_pkt() here as it acquires
+ * a mutex lock inside and this function gets called in
+ * interrupt context leading to scheduler crash
+ */
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_wr);
+ if (ret < 0) {
pr_err("%s: AFE rtproxy write to port 0x%x failed %d\n",
- __func__, afecmd_wr.port_id, ret);
+ __func__, afecmd_wr.port_id, ret);
+ ret = -EINVAL;
+ }
+
return ret;
}
@@ -6555,10 +6709,19 @@
afecmd_rd.available_bytes = bytes;
afecmd_rd.mem_map_handle = mem_map_handle;
- ret = afe_apr_send_pkt(&afecmd_rd, NULL);
- if (ret)
+ /*
+ * Do not call afe_apr_send_pkt() here as it acquires
+ * a mutex lock inside and this function gets called in
+ * interrupt context leading to scheduler crash
+ */
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_rd);
+ if (ret < 0) {
pr_err("%s: AFE rtproxy read cmd to port 0x%x failed %d\n",
- __func__, afecmd_rd.port_id, ret);
+ __func__, afecmd_rd.port_id, ret);
+ ret = -EINVAL;
+ }
+
return ret;
}
EXPORT_SYMBOL(afe_rt_proxy_port_read);
@@ -6802,15 +6965,6 @@
cmd_dtmf.num_ports = 1;
cmd_dtmf.port_ids = q6audio_get_port_id(this_afe.dtmf_gen_rx_portid);
- atomic_set(&this_afe.state, 1);
- atomic_set(&this_afe.status, 0);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_dtmf);
- if (ret < 0) {
- pr_err("%s: AFE DTMF failed for num_ports:%d ids:0x%x\n",
- __func__, cmd_dtmf.num_ports, cmd_dtmf.port_ids);
- ret = -EINVAL;
- goto fail_cmd;
- }
index = q6audio_get_port_index(this_afe.dtmf_gen_rx_portid);
if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: AFE port index[%d] invalid!\n",
@@ -6818,24 +6972,9 @@
ret = -EINVAL;
goto fail_cmd;
}
- ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- if (atomic_read(&this_afe.status) > 0) {
- pr_err("%s: config cmd failed [%s]\n",
- __func__, adsp_err_get_err_str(
- atomic_read(&this_afe.status)));
- ret = adsp_err_get_lnx_err_code(
- atomic_read(&this_afe.status));
- goto fail_cmd;
- }
- return 0;
-
+ ret = afe_apr_send_pkt((uint32_t *) &cmd_dtmf,
+ &this_afe.wait[index]);
+ return ret;
fail_cmd:
pr_err("%s: failed %d\n", __func__, ret);
return ret;
@@ -6914,7 +7053,7 @@
* Set IIR enable params
*/
param_hdr.module_id = mid;
- param_hdr.param_id = INSTANCE_ID_0;
+ param_hdr.instance_id = INSTANCE_ID_0;
param_hdr.param_id = AFE_PARAM_ID_ENABLE;
param_hdr.param_size = sizeof(enable);
enable.enable = iir_enable;
@@ -7393,6 +7532,8 @@
case AFE_PORT_ID_TX_CODEC_DMA_TX_5:
case AFE_PORT_ID_RX_CODEC_DMA_RX_6:
case AFE_PORT_ID_RX_CODEC_DMA_RX_7:
+ case RT_PROXY_PORT_002_RX:
+ case RT_PROXY_PORT_002_TX:
{
ret = 0;
break;
@@ -7489,7 +7630,7 @@
ret = -EINVAL;
goto fail_cmd;
}
- pr_debug("%s: port_id = 0x%x\n", __func__, port_id);
+ pr_info("%s: port_id = 0x%x\n", __func__, port_id);
if ((port_id == RT_PROXY_DAI_001_RX) ||
(port_id == RT_PROXY_DAI_002_TX)) {
pr_debug("%s: before decrementing pcm_afe_instance %d\n",
@@ -7547,6 +7688,7 @@
pr_debug("%s: Not a MAD port\n", __func__);
}
+ mutex_lock(&this_afe.afe_cmd_lock);
port_index = afe_get_port_index(port_id);
if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
this_afe.afe_sample_rates[port_index] = 0;
@@ -7589,6 +7731,7 @@
pr_err("%s: AFE close failed %d\n", __func__, ret);
fail_cmd:
+ mutex_unlock(&this_afe.afe_cmd_lock);
return ret;
}
EXPORT_SYMBOL(afe_close);
@@ -7674,6 +7817,15 @@
cfg->clk_root, cfg->clk_set_mode,
cfg->reserved, q6audio_get_port_id(port_id));
+ trace_printk("%s: Minor version =0x%x clk val1 = %d\n"
+ "clk val2 = %d, clk src = 0x%x\n"
+ "clk root = 0x%x clk mode = 0x%x resrv = 0x%x\n"
+ "port id = 0x%x\n",
+ __func__, cfg->i2s_cfg_minor_version,
+ cfg->clk_val1, cfg->clk_val2, cfg->clk_src,
+ cfg->clk_root, cfg->clk_set_mode,
+ cfg->reserved, q6audio_get_port_id(port_id));
+
ret = q6afe_pack_and_set_param_in_band(port_id,
q6audio_get_port_index(port_id),
param_hdr, (u8 *) &clk_cfg);
@@ -7712,13 +7864,7 @@
memset(¶m_hdr, 0, sizeof(param_hdr));
- ret = afe_q6_interface_prepare();
- if (ret != 0) {
- pr_err_ratelimited("%s: Q6 interface prepare failed %d\n", __func__, ret);
- return ret;
- }
-
- mutex_lock(&this_afe.afe_cmd_lock);
+ mutex_lock(&this_afe.afe_clk_lock);
param_hdr.module_id = AFE_MODULE_CLOCK_SET;
param_hdr.instance_id = INSTANCE_ID_0;
param_hdr.param_id = AFE_PARAM_ID_CLOCK_SET;
@@ -7732,13 +7878,22 @@
cfg->clk_id, cfg->clk_freq_in_hz, cfg->clk_attri,
cfg->clk_root, cfg->enable);
+ trace_printk("%s: Minor version =0x%x clk id = %d\n"
+ "clk freq (Hz) = %d, clk attri = 0x%x\n"
+ "clk root = 0x%x clk enable = 0x%x\n",
+ __func__, cfg->clk_set_minor_version,
+ cfg->clk_id, cfg->clk_freq_in_hz, cfg->clk_attri,
+ cfg->clk_root, cfg->enable);
+
ret = q6afe_svc_pack_and_set_param_in_band(index, param_hdr,
(u8 *) cfg);
- if (ret < 0)
+ if (ret < 0) {
pr_err_ratelimited("%s: AFE clk cfg failed with ret %d\n",
+ __func__, ret);
+ trace_printk("%s: AFE clk cfg failed with ret %d\n",
__func__, ret);
-
- mutex_unlock(&this_afe.afe_cmd_lock);
+ }
+ mutex_unlock(&this_afe.afe_clk_lock);
return ret;
}
EXPORT_SYMBOL(afe_set_lpass_clk_cfg);
@@ -9085,6 +9240,8 @@
atomic_set(&this_afe.state, 0);
atomic_set(&this_afe.status, 0);
+ atomic_set(&this_afe.clk_state, 0);
+ atomic_set(&this_afe.clk_status, 0);
atomic_set(&this_afe.mem_map_cal_index, -1);
this_afe.apr = NULL;
this_afe.dtmf_gen_rx_portid = -1;
@@ -9097,6 +9254,8 @@
this_afe.th_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
this_afe.ex_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
mutex_init(&this_afe.afe_cmd_lock);
+ mutex_init(&this_afe.afe_apr_lock);
+ mutex_init(&this_afe.afe_clk_lock);
for (i = 0; i < AFE_MAX_PORTS; i++) {
this_afe.afe_cal_mode[i] = AFE_CAL_MODE_DEFAULT;
this_afe.afe_sample_rates[i] = 0;
@@ -9108,6 +9267,7 @@
}
init_waitqueue_head(&this_afe.wait_wakeup);
init_waitqueue_head(&this_afe.lpass_core_hw_wait);
+ init_waitqueue_head(&this_afe.clk_wait);
wakeup_source_init(&wl.ws, "spkr-prot");
ret = afe_init_cal_data();
if (ret)
@@ -9151,6 +9311,8 @@
config_debug_fs_exit();
mutex_destroy(&this_afe.afe_cmd_lock);
+ mutex_destroy(&this_afe.afe_apr_lock);
+ mutex_destroy(&this_afe.afe_clk_lock);
wakeup_source_trash(&wl.ws);
}
@@ -9214,7 +9376,7 @@
return ret;
}
- mutex_lock(&this_afe.afe_cmd_lock);
+ mutex_lock(&this_afe.afe_clk_lock);
memset(cmd_ptr, 0, sizeof(hw_vote_cfg));
@@ -9233,43 +9395,18 @@
pr_debug("%s: lpass core hw vote opcode[0x%x] hw id[0x%x]\n",
__func__, cmd_ptr->hdr.opcode, cmd_ptr->hw_block_id);
+ trace_printk("%s: lpass core hw vote opcode[0x%x] hw id[0x%x]\n",
+ __func__, cmd_ptr->hdr.opcode, cmd_ptr->hw_block_id);
*client_handle = 0;
- atomic_set(&this_afe.status, 0);
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) cmd_ptr);
- if (ret < 0) {
- pr_err("%s: lpass core hw vote failed %d\n",
- __func__, ret);
- goto done;
- }
- ret = wait_event_timeout(this_afe.lpass_core_hw_wait,
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: timeout. waited for lpass core hw vote\n",
- __func__);
- ret = -ETIMEDOUT;
- goto done;
- } else {
- /* set ret to 0 as no timeout happened */
- ret = 0;
+ ret = afe_apr_send_clk_pkt((uint32_t *)cmd_ptr,
+ &this_afe.lpass_core_hw_wait);
+ if (ret == 0) {
+ *client_handle = this_afe.lpass_hw_core_client_hdl[hw_block_id];
+ pr_debug("%s: lpass_hw_core_client_hdl %d\n", __func__,
+ this_afe.lpass_hw_core_client_hdl[hw_block_id]);
}
-
- if (atomic_read(&this_afe.status) > 0) {
- pr_err("%s: lpass core hw vote cmd failed [%s]\n",
- __func__, adsp_err_get_err_str(
- atomic_read(&this_afe.status)));
- ret = adsp_err_get_lnx_err_code(
- atomic_read(&this_afe.status));
- goto done;
- }
-
- *client_handle = this_afe.lpass_hw_core_client_hdl[hw_block_id];
- pr_debug("%s: lpass_hw_core_client_hdl %d\n", __func__,
- this_afe.lpass_hw_core_client_hdl[hw_block_id]);
-done:
- mutex_unlock(&this_afe.afe_cmd_lock);
+ mutex_unlock(&this_afe.afe_clk_lock);
return ret;
}
EXPORT_SYMBOL(afe_vote_lpass_core_hw);
@@ -9295,10 +9432,11 @@
return ret;
}
- mutex_lock(&this_afe.afe_cmd_lock);
+ mutex_lock(&this_afe.afe_clk_lock);
if (!this_afe.lpass_hw_core_client_hdl[hw_block_id]) {
pr_debug("%s: SSR in progress, return\n", __func__);
+ trace_printk("%s: SSR in progress, return\n", __func__);
goto done;
}
@@ -9318,44 +9456,19 @@
pr_debug("%s: lpass core hw unvote opcode[0x%x] hw id[0x%x]\n",
__func__, cmd_ptr->hdr.opcode, cmd_ptr->hw_block_id);
+ trace_printk("%s: lpass core hw unvote opcode[0x%x] hw id[0x%x]\n",
+ __func__, cmd_ptr->hdr.opcode, cmd_ptr->hw_block_id);
+
if (cmd_ptr->client_handle <= 0) {
pr_err("%s: invalid client handle\n", __func__);
ret = -EINVAL;
goto done;
}
- atomic_set(&this_afe.status, 0);
- atomic_set(&this_afe.state, 1);
- ret = apr_send_pkt(this_afe.apr, (uint32_t *) cmd_ptr);
- if (ret < 0) {
- pr_err("%s: lpass core hw devote failed %d\n",
- __func__, ret);
- goto done;
- }
-
- ret = wait_event_timeout(this_afe.lpass_core_hw_wait,
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: timeout. waited for lpass core hw devote\n",
- __func__);
- ret = -ETIMEDOUT;
- goto done;
- } else {
- /* set ret to 0 as no timeout happened */
- ret = 0;
- }
-
- if (atomic_read(&this_afe.status) > 0) {
- pr_err("%s: lpass core hw devote cmd failed [%s]\n",
- __func__, adsp_err_get_err_str(
- atomic_read(&this_afe.status)));
- ret = adsp_err_get_lnx_err_code(
- atomic_read(&this_afe.status));
- }
-
+ ret = afe_apr_send_clk_pkt((uint32_t *)cmd_ptr,
+ &this_afe.lpass_core_hw_wait);
done:
- mutex_unlock(&this_afe.afe_cmd_lock);
+ mutex_unlock(&this_afe.afe_clk_lock);
return ret;
}
EXPORT_SYMBOL(afe_unvote_lpass_core_hw);
diff --git a/dsp/q6asm.c b/dsp/q6asm.c
index 19e23e3..6b0a377 100644
--- a/dsp/q6asm.c
+++ b/dsp/q6asm.c
@@ -2552,7 +2552,7 @@
/* To make it more robust, we could loop and get the
* next avail buf, its risky though
*/
- pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n",
+ pr_debug("%s: Next buf idx[0x%x] not available, dir[%d]\n",
__func__, idx, dir);
mutex_unlock(&port->lock);
return NULL;
diff --git a/dsp/q6audio-v2.c b/dsp/q6audio-v2.c
index 68b3736..e3a2dc7 100644
--- a/dsp/q6audio-v2.c
+++ b/dsp/q6audio-v2.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/slab.h>
@@ -385,6 +385,10 @@
return IDX_AFE_PORT_ID_RX_CODEC_DMA_RX_6;
case AFE_PORT_ID_RX_CODEC_DMA_RX_7:
return IDX_AFE_PORT_ID_RX_CODEC_DMA_RX_7;
+ case RT_PROXY_PORT_002_RX:
+ return IDX_RT_PROXY_PORT_002_RX;
+ case RT_PROXY_PORT_002_TX:
+ return IDX_RT_PROXY_PORT_002_TX;
default: return -EINVAL;
}
}
@@ -767,6 +771,10 @@
return AFE_PORT_ID_RX_CODEC_DMA_RX_6;
case AFE_PORT_ID_RX_CODEC_DMA_RX_7:
return AFE_PORT_ID_RX_CODEC_DMA_RX_7;
+ case RT_PROXY_PORT_002_RX:
+ return RT_PROXY_PORT_002_RX;
+ case RT_PROXY_PORT_002_TX:
+ return RT_PROXY_PORT_002_TX;
default:
pr_warn("%s: Invalid port_id %d\n", __func__, port_id);
return -EINVAL;
@@ -1196,6 +1204,8 @@
case AFE_PORT_ID_TX_CODEC_DMA_TX_5:
case AFE_PORT_ID_RX_CODEC_DMA_RX_6:
case AFE_PORT_ID_RX_CODEC_DMA_RX_7:
+ case RT_PROXY_PORT_002_RX:
+ case RT_PROXY_PORT_002_TX:
{
ret = 0;
break;
diff --git a/dsp/q6core.c b/dsp/q6core.c
index 68fe9e5..15c00bd 100644
--- a/dsp/q6core.c
+++ b/dsp/q6core.c
@@ -502,6 +502,7 @@
struct apr_hdr avcs_ver_cmd;
int ret;
+ mutex_lock(&q6core_lcl.cmd_lock);
avcs_ver_cmd.hdr_field =
APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
APR_PKT_VER);
@@ -548,6 +549,7 @@
ret = 0;
done:
+ mutex_unlock(&q6core_lcl.cmd_lock);
return ret;
}
@@ -1428,14 +1430,16 @@
int i = 0;
int cmd_size = 0;
+ mutex_lock(&q6core_lcl.cmd_lock);
cmd_size = sizeof(struct avs_cmd_map_mdf_shared_memory)
+ sizeof(struct avs_shared_map_region_payload)
* bufcnt;
mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
- if (mmap_region_cmd == NULL)
+ if (mmap_region_cmd == NULL) {
+ mutex_unlock(&q6core_lcl.cmd_lock);
return -ENOMEM;
-
+ }
mmap_regions = (struct avs_cmd_map_mdf_shared_memory *)mmap_region_cmd;
mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -1502,6 +1506,7 @@
done:
kfree(mmap_region_cmd);
+ mutex_unlock(&q6core_lcl.cmd_lock);
return ret;
}
diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c
index d5c8e7e..66883ba 100644
--- a/dsp/q6lsm.c
+++ b/dsp/q6lsm.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2013-2019, Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, Linux Foundation. All rights reserved.
*/
#include <linux/fs.h>
#include <linux/mutex.h>
@@ -28,7 +28,6 @@
#include "adsp_err.h"
#define APR_TIMEOUT (HZ)
-#define LSM_ALIGN_BOUNDARY 512
#define LSM_SAMPLE_RATE 16000
#define QLSM_PARAM_ID_MINOR_VERSION 1
#define QLSM_PARAM_ID_MINOR_VERSION_2 2
@@ -1099,7 +1098,7 @@
lsm_client_afe_data[n].fe_id = fe_id;
lsm_client_afe_data[n].unprocessed_data =
afe_data_format;
- pr_debug("%s: session ID is %d, fe_id is %d\n",
+ pr_debug("%s: session ID is %d, fe_id is %llu\n",
__func__, n, fe_id);
return 0;
}
@@ -1132,7 +1131,7 @@
if (fe_id == lsm_client_afe_data[n].fe_id) {
*afe_data_format =
lsm_client_afe_data[n].unprocessed_data;
- pr_debug("%s: session: %d, fe_id: %d, afe data: %s\n",
+ pr_debug("%s: session: %d, fe_id: %llu, afe data: %s\n",
__func__, n, fe_id,
*afe_data_format ? "unprocessed" : "processed");
return;
@@ -1973,7 +1972,7 @@
size_t total_mem = 0;
struct lsm_sound_model *sm = NULL;
- if (!client || len <= LSM_ALIGN_BOUNDARY)
+ if (!client)
return rc;
pr_debug("%s:Snd Model len = %zd, stage idx %d\n",
diff --git a/dsp/q6voice.c b/dsp/q6voice.c
index e0491f1..110d844 100644
--- a/dsp/q6voice.c
+++ b/dsp/q6voice.c
@@ -1273,7 +1273,6 @@
goto unlock;
}
- mutex_lock(&common.common_lock);
result = voice_send_mvm_unmap_memory_physical_cmd(
v, cal_block->map_data.q6map_handle);
if (result)
@@ -1281,7 +1280,6 @@
__func__, v->session_id, result);
cal_block->map_data.q6map_handle = 0;
- mutex_unlock(&common.common_lock);
unlock:
mutex_unlock(&common.cal_data[cal_index]->lock);
done:
diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h
index 40b44ba..46cf6d3 100644
--- a/include/dsp/apr_audio-v2.h
+++ b/include/dsp/apr_audio-v2.h
@@ -849,6 +849,7 @@
*/
#define AUDPROC_MODULE_ID_MFC_EC_REF 0x0001092C
+#define PARAM_ID_FFV_SPF_FREEZE 0x00010960
struct adm_cmd_set_pp_params_v5 {
struct apr_hdr hdr;
@@ -1384,7 +1385,7 @@
#define AFE_PORT_ID_SLIMBUS_RANGE_SIZE 0xA
/* Size of the range of port IDs for real-time proxy ports. */
-#define AFE_PORT_ID_RT_PROXY_PORT_RANGE_SIZE 0x2
+#define AFE_PORT_ID_RT_PROXY_PORT_RANGE_SIZE 0x4
/* Size of the range of port IDs for pseudoports. */
#define AFE_PORT_ID_PSEUDOPORT_RANGE_SIZE 0x5
@@ -1663,6 +1664,16 @@
#define AFE_PORT_ID_VOICE2_PLAYBACK_TX 0x8002
#define AFE_PORT_ID_VOICE_PLAYBACK_TX 0x8005
+/*
+ * Proxyport used for voice call data processing.
+ * In cases like call-screening feature, where user can communicate
+ * with caller with the help of "call screen" mode, and without
+ * connecting the call with any HW input/output devices in the phon,
+ * voice call can use Pseudo port to start voice data processing.
+ */
+#define RT_PROXY_PORT_002_TX 0x2003
+#define RT_PROXY_PORT_002_RX 0x2002
+
#define AFE_PORT_ID_PRIMARY_TDM_RX \
(AFE_PORT_ID_TDM_PORT_RANGE_START + 0x00)
#define AFE_PORT_ID_PRIMARY_TDM_RX_1 \
@@ -4339,6 +4350,7 @@
struct asm_aac_enc_cfg_t {
struct asm_aac_enc_cfg_v2_t aac_cfg;
struct asm_aac_frame_size_control_t frame_ctl;
+ struct asm_aac_frame_size_control_t frame_ctl_v2;
} __packed;
/* FMT ID for apt-X Classic */
diff --git a/include/dsp/q6adm-v2.h b/include/dsp/q6adm-v2.h
index d694506..53514c3 100644
--- a/include/dsp/q6adm-v2.h
+++ b/include/dsp/q6adm-v2.h
@@ -85,6 +85,11 @@
bool override_out_ch_map;
};
+struct ffv_spf_freeze_param_t {
+ uint16_t freeze;
+ uint16_t source_id;
+};
+
int srs_trumedia_open(int port_id, int copp_idx, __s32 srs_tech_id,
void *srs_params);
@@ -222,4 +227,5 @@
void msm_dts_srs_acquire_lock(void);
void msm_dts_srs_release_lock(void);
void adm_set_native_mode(int mode);
+int adm_set_ffecns_freeze_event(bool ffecns_freeze_event);
#endif /* __Q6_ADM_V2_H__ */
diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h
index 9e1a0b2..73a7cf8 100644
--- a/include/dsp/q6afe-v2.h
+++ b/include/dsp/q6afe-v2.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
*/
#ifndef __Q6AFE_V2_H__
#define __Q6AFE_V2_H__
@@ -284,6 +284,9 @@
/* IDX 208-> 209 */
IDX_AFE_PORT_ID_PRIMARY_META_MI2S_RX,
IDX_AFE_PORT_ID_SECONDARY_META_MI2S_RX,
+ /* IDX 210-> 211 */
+ IDX_RT_PROXY_PORT_002_RX,
+ IDX_RT_PROXY_PORT_002_TX,
AFE_MAX_PORTS
};
diff --git a/include/dsp/q6lsm.h b/include/dsp/q6lsm.h
index af43cdd..02897d9 100644
--- a/include/dsp/q6lsm.h
+++ b/include/dsp/q6lsm.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
*/
#ifndef __Q6LSM_H__
#define __Q6LSM_H__
@@ -20,6 +20,8 @@
#define LSM_API_VERSION_V3 3
+#define MAX_LSM_SESSIONS 8
+
typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token,
uint32_t *payload, uint16_t client_size, void *priv);
diff --git a/include/soc/soundwire.h b/include/soc/soundwire.h
index 655b53e..3e61da1 100644
--- a/include/soc/soundwire.h
+++ b/include/soc/soundwire.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _LINUX_SOUNDWIRE_H
@@ -10,6 +10,13 @@
#include <linux/mod_devicetable.h>
#include <linux/irqdomain.h>
+#define SWR_CLK_RATE_0P6MHZ 600000
+#define SWR_CLK_RATE_1P2MHZ 1200000
+#define SWR_CLK_RATE_2P4MHZ 2400000
+#define SWR_CLK_RATE_4P8MHZ 4800000
+#define SWR_CLK_RATE_9P6MHZ 9600000
+#define SWR_CLK_RATE_11P2896MHZ 1128960
+
extern struct bus_type soundwire_type;
/* Soundwire supports max. of 8 channels per port */
@@ -200,7 +207,7 @@
struct list_head dev_list;
u8 dev_num;
struct device dev;
- unsigned long addr;
+ u64 addr;
u8 group_id;
struct irq_domain *slave_irq;
bool slave_irq_pending;
diff --git a/include/soc/swr-wcd.h b/include/soc/swr-wcd.h
index 4ec5094..8ed9f0a 100644
--- a/include/soc/swr-wcd.h
+++ b/include/soc/swr-wcd.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2015, 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 2017-2020 The Linux Foundation. All rights reserved.
*/
#ifndef _LINUX_SWR_WCD_H
@@ -32,6 +32,7 @@
};
#define MCLK_FREQ 9600000
+#define MCLK_FREQ_LP 600000
#define MCLK_FREQ_NATIVE 11289600
#if (IS_ENABLED(CONFIG_SOUNDWIRE_WCD_CTRL) || \
diff --git a/soc/pinctrl-lpi.c b/soc/pinctrl-lpi.c
index 2b9e52e..c3d2326 100644
--- a/soc/pinctrl-lpi.c
+++ b/soc/pinctrl-lpi.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/gpio.h>
@@ -497,6 +497,7 @@
{
int ret = 0;
+ trace_printk("%s: system suspend\n", __func__);
dev_dbg(dev, "%s: system suspend\n", __func__);
if ((!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev))) {
@@ -533,6 +534,7 @@
static void lpi_pinctrl_ssr_disable(struct device *dev, void *data)
{
+ trace_printk("%s: enter\n", __func__);
lpi_dev_up = false;
lpi_pinctrl_suspend(dev);
}
@@ -689,7 +691,7 @@
}
} else {
slew_base = NULL;
- dev_dbg(dev, "error in reading lpi slew register: %d\n",
+ dev_dbg(dev, "%s: error in reading lpi slew register: %d\n",
__func__, ret);
}
@@ -857,6 +859,7 @@
int ret = 0;
struct clk *hw_vote = state->lpass_core_hw_vote;
+ trace_printk("%s: enter\n", __func__);
if (state->lpass_core_hw_vote == NULL) {
dev_dbg(dev, "%s: Invalid core hw node\n", __func__);
if (state->lpass_audio_hw_vote == NULL) {
@@ -882,6 +885,7 @@
exit:
mutex_unlock(&state->core_hw_vote_lock);
+ trace_printk("%s: exit\n", __func__);
return 0;
}
@@ -890,6 +894,7 @@
struct lpi_gpio_state *state = dev_get_drvdata(dev);
struct clk *hw_vote = state->lpass_core_hw_vote;
+ trace_printk("%s: enter\n", __func__);
if (state->lpass_core_hw_vote == NULL) {
dev_dbg(dev, "%s: Invalid core hw node\n", __func__);
if (state->lpass_audio_hw_vote == NULL) {
@@ -905,6 +910,7 @@
state->core_hw_vote_status = false;
}
mutex_unlock(&state->core_hw_vote_lock);
+ trace_printk("%s: exit\n", __func__);
return 0;
}
diff --git a/soc/soundwire.c b/soc/soundwire.c
index 72a94ac..2aa3ba4 100644
--- a/soc/soundwire.c
+++ b/soc/soundwire.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
@@ -126,7 +126,7 @@
list_add_tail(&swr->dev_list, &master->devices);
mutex_unlock(&master->mlock);
- dev_set_name(&swr->dev, "%s.%lx", swr->name, swr->addr);
+ dev_set_name(&swr->dev, "%s.%llx", swr->name, swr->addr);
result = device_register(&swr->dev);
if (result) {
dev_err(&master->dev, "device [%s] register failed err %d\n",
@@ -138,7 +138,7 @@
return swr;
err_out:
- dev_dbg(&master->dev, "Failed to register swr device %s at 0x%lx %d\n",
+ dev_dbg(&master->dev, "Failed to register swr device %s at 0x%llx %d\n",
swr->name, swr->addr, result);
swr_master_put(master);
kfree(swr);
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index c90e6b4..4aa5c0c 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/irq.h>
@@ -25,7 +25,10 @@
#include "swrm_registers.h"
#include "swr-mstr-ctrl.h"
+#define SWR_NUM_PORTS 4 /* TODO - Get this info from DT */
+
#define SWRM_FRAME_SYNC_SEL 4000 /* 4KHz */
+#define SWRM_FRAME_SYNC_SEL_NATIVE 3675 /* 3.675KHz */
#define SWRM_SYSTEM_RESUME_TIMEOUT_MS 700
#define SWRM_SYS_SUSPEND_WAIT 1
@@ -44,7 +47,7 @@
#define ERR_AUTO_SUSPEND_TIMER_VAL 0x1
#define SWRM_INTERRUPT_STATUS_MASK 0x1FDFD
-#define SWRM_LINK_STATUS_RETRY_CNT 0x5
+#define SWRM_LINK_STATUS_RETRY_CNT 100
#define SWRM_ROW_48 48
#define SWRM_ROW_50 50
@@ -93,6 +96,42 @@
static u32 swr_master_read(struct swr_mstr_ctrl *swrm, unsigned int reg_addr);
static void swr_master_write(struct swr_mstr_ctrl *swrm, u16 reg_addr, u32 val);
+
+static u8 swrm_get_clk_div(int mclk_freq, int bus_clk_freq)
+{
+ int clk_div = 0;
+ u8 div_val = 0;
+
+ if (!mclk_freq || !bus_clk_freq)
+ return 0;
+
+ clk_div = (mclk_freq / bus_clk_freq);
+
+ switch (clk_div) {
+ case 32:
+ div_val = 5;
+ break;
+ case 16:
+ div_val = 4;
+ break;
+ case 8:
+ div_val = 3;
+ break;
+ case 4:
+ div_val = 2;
+ break;
+ case 2:
+ div_val = 1;
+ break;
+ case 1:
+ default:
+ div_val = 0;
+ break;
+ }
+
+ return div_val;
+}
+
static bool swrm_is_msm_variant(int val)
{
return (val == SWRM_VERSION_1_3);
@@ -315,38 +354,87 @@
func, reg[i], val[i]);
}
+static bool is_swr_clk_needed(struct swr_mstr_ctrl *swrm)
+{
+ return ((swrm->version <= SWRM_VERSION_1_5_1) ? true : false);
+}
+
static int swrm_request_hw_vote(struct swr_mstr_ctrl *swrm,
int core_type, bool enable)
{
int ret = 0;
+ mutex_lock(&swrm->devlock);
if (core_type == LPASS_HW_CORE) {
if (swrm->lpass_core_hw_vote) {
if (enable) {
- ret =
- clk_prepare_enable(swrm->lpass_core_hw_vote);
- if (ret < 0)
- dev_err(swrm->dev,
- "%s:lpass core hw enable failed\n",
- __func__);
- } else
- clk_disable_unprepare(swrm->lpass_core_hw_vote);
+ if (!swrm->dev_up) {
+ dev_dbg(swrm->dev, "%s: device is down or SSR state\n",
+ __func__);
+ trace_printk("%s: device is down or SSR state\n",
+ __func__);
+ mutex_unlock(&swrm->devlock);
+ return -ENODEV;
+ }
+ if (++swrm->hw_core_clk_en == 1) {
+ ret =
+ clk_prepare_enable(
+ swrm->lpass_core_hw_vote);
+ if (ret < 0) {
+ dev_err(swrm->dev,
+ "%s:lpass core hw enable failed\n",
+ __func__);
+ --swrm->hw_core_clk_en;
+ }
+ }
+ } else {
+ --swrm->hw_core_clk_en;
+ if (swrm->hw_core_clk_en < 0)
+ swrm->hw_core_clk_en = 0;
+ else if (swrm->hw_core_clk_en == 0)
+ clk_disable_unprepare(
+ swrm->lpass_core_hw_vote);
+ }
}
}
if (core_type == LPASS_AUDIO_CORE) {
if (swrm->lpass_core_audio) {
if (enable) {
- ret =
- clk_prepare_enable(swrm->lpass_core_audio);
- if (ret < 0)
- dev_err(swrm->dev,
- "%s:lpass audio hw enable failed\n",
- __func__);
- } else
- clk_disable_unprepare(swrm->lpass_core_audio);
+ if (!swrm->dev_up) {
+ dev_dbg(swrm->dev, "%s: device is down or SSR state\n",
+ __func__);
+ trace_printk("%s: device is down or SSR state\n",
+ __func__);
+ mutex_unlock(&swrm->devlock);
+ return -ENODEV;
+ }
+ if (++swrm->aud_core_clk_en == 1) {
+ ret =
+ clk_prepare_enable(
+ swrm->lpass_core_audio);
+ if (ret < 0) {
+ dev_err(swrm->dev,
+ "%s:lpass audio hw enable failed\n",
+ __func__);
+ --swrm->aud_core_clk_en;
+ }
+ }
+ } else {
+ --swrm->aud_core_clk_en;
+ if (swrm->aud_core_clk_en < 0)
+ swrm->aud_core_clk_en = 0;
+ else if (swrm->aud_core_clk_en == 0)
+ clk_disable_unprepare(
+ swrm->lpass_core_audio);
+ }
}
}
+ mutex_unlock(&swrm->devlock);
+ dev_dbg(swrm->dev, "%s: hw_clk_en: %d audio_core_clk_en: %d\n",
+ __func__, swrm->hw_core_clk_en, swrm->aud_core_clk_en);
+ trace_printk("%s: hw_clk_en: %d audio_core_clk_en: %d\n",
+ __func__, swrm->hw_core_clk_en, swrm->aud_core_clk_en);
return ret;
}
@@ -360,6 +448,30 @@
return ((swrm->bus_clk * 2) / ((row * col) * frame_sync));
}
+static int swrm_core_vote_request(struct swr_mstr_ctrl *swrm)
+{
+ int ret = 0;
+
+ if (!swrm->handle)
+ return -EINVAL;
+
+ mutex_lock(&swrm->clklock);
+ if (!swrm->dev_up) {
+ ret = -ENODEV;
+ goto exit;
+ }
+ if (swrm->core_vote) {
+ ret = swrm->core_vote(swrm->handle, true);
+ if (ret)
+ dev_err_ratelimited(swrm->dev,
+ "%s: core vote request failed\n", __func__);
+ }
+exit:
+ mutex_unlock(&swrm->clklock);
+
+ return ret;
+}
+
static int swrm_clk_request(struct swr_mstr_ctrl *swrm, bool enable)
{
int ret = 0;
@@ -373,17 +485,21 @@
ret = -ENODEV;
goto exit;
}
- if (swrm->core_vote) {
- ret = swrm->core_vote(swrm->handle, true);
- if (ret) {
- dev_err_ratelimited(swrm->dev,
- "%s: clock enable req failed",
- __func__);
- goto exit;
+ if (is_swr_clk_needed(swrm)) {
+ if (swrm->core_vote) {
+ ret = swrm->core_vote(swrm->handle, true);
+ if (ret) {
+ dev_err_ratelimited(swrm->dev,
+ "%s: core vote request failed\n",
+ __func__);
+ goto exit;
+ }
}
}
swrm->clk_ref_count++;
if (swrm->clk_ref_count == 1) {
+ trace_printk("%s: clock enable count %d",
+ __func__, swrm->clk_ref_count);
ret = swrm->clk(swrm->handle, true);
if (ret) {
dev_err_ratelimited(swrm->dev,
@@ -393,6 +509,8 @@
}
}
} else if (--swrm->clk_ref_count == 0) {
+ trace_printk("%s: clock disable count %d",
+ __func__, swrm->clk_ref_count);
swrm->clk(swrm->handle, false);
complete(&swrm->clk_off_complete);
}
@@ -416,14 +534,21 @@
if (!swrm->dev_up)
goto err;
- ret = swrm_clk_request(swrm, TRUE);
- if (ret) {
- dev_err_ratelimited(swrm->dev, "%s: clock request failed\n",
- __func__);
+ if (is_swr_clk_needed(swrm)) {
+ ret = swrm_clk_request(swrm, TRUE);
+ if (ret) {
+ dev_err_ratelimited(swrm->dev,
+ "%s: clock request failed\n",
+ __func__);
+ goto err;
+ }
+ } else if (swrm_core_vote_request(swrm)) {
goto err;
}
+
iowrite32(temp, swrm->swrm_dig_base + reg);
- swrm_clk_request(swrm, FALSE);
+ if (is_swr_clk_needed(swrm))
+ swrm_clk_request(swrm, FALSE);
err:
mutex_unlock(&swrm->devlock);
return ret;
@@ -439,15 +564,21 @@
if (!swrm->dev_up)
goto err;
- ret = swrm_clk_request(swrm, TRUE);
- if (ret) {
- dev_err_ratelimited(swrm->dev, "%s: clock request failed\n",
- __func__);
+ if (is_swr_clk_needed(swrm)) {
+ ret = swrm_clk_request(swrm, TRUE);
+ if (ret) {
+ dev_err_ratelimited(swrm->dev, "%s: clock request failed\n",
+ __func__);
+ goto err;
+ }
+ } else if (swrm_core_vote_request(swrm)) {
goto err;
}
+
temp = ioread32(swrm->swrm_dig_base + reg);
*value = temp;
- swrm_clk_request(swrm, FALSE);
+ if (is_swr_clk_needed(swrm))
+ swrm_clk_request(swrm, FALSE);
err:
mutex_unlock(&swrm->devlock);
return ret;
@@ -500,12 +631,15 @@
int retry = SWRM_LINK_STATUS_RETRY_CNT;
int ret = false;
int status = active ? 0x1 : 0x0;
+ int comp_sts = 0x0;
if ((swrm->version <= SWRM_VERSION_1_5_1))
return true;
do {
- if (swr_master_read(swrm, SWRM_COMP_STATUS) & status) {
+ comp_sts = swr_master_read(swrm, SWRM_COMP_STATUS) & 0x01;
+ /* check comp status and status requested met */
+ if ((comp_sts && status) || (!comp_sts && !status)) {
ret = true;
break;
}
@@ -835,6 +969,39 @@
SWRS_SCP_FRAME_CTRL_BANK(bank));
}
+static void swrm_switch_frame_shape(struct swr_mstr_ctrl *swrm, int mclk_freq)
+{
+ u8 bank;
+ u32 n_row, n_col;
+ u32 value = 0;
+ u32 row = 0, col = 0;
+ u8 ssp_period = 0;
+ int frame_sync = SWRM_FRAME_SYNC_SEL;
+
+ if (mclk_freq == MCLK_FREQ_NATIVE) {
+ n_col = SWR_MAX_COL;
+ col = SWRM_COL_16;
+ n_row = SWR_ROW_64;
+ row = SWRM_ROW_64;
+ frame_sync = SWRM_FRAME_SYNC_SEL_NATIVE;
+ } else {
+ n_col = SWR_MIN_COL;
+ col = SWRM_COL_02;
+ n_row = SWR_ROW_50;
+ row = SWRM_ROW_50;
+ frame_sync = SWRM_FRAME_SYNC_SEL;
+ }
+
+ bank = get_inactive_bank_num(swrm);
+ ssp_period = swrm_get_ssp_period(swrm, row, col, frame_sync);
+ dev_dbg(swrm->dev, "%s: ssp_period: %d\n", __func__, ssp_period);
+ value = ((n_row << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT) |
+ (n_col << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT) |
+ ((ssp_period - 1) << SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_SHFT));
+ swr_master_write(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank), value);
+ enable_bank_switch(swrm, bank, n_row, n_col);
+}
+
static struct swr_port_info *swrm_get_port_req(struct swrm_mports *mport,
u8 slv_port, u8 dev_num)
{
@@ -874,6 +1041,49 @@
return is_removed;
}
+int swrm_get_clk_div_rate(int mclk_freq, int bus_clk_freq)
+{
+ if (!bus_clk_freq)
+ return mclk_freq;
+
+ if (mclk_freq == SWR_CLK_RATE_9P6MHZ) {
+ if (bus_clk_freq <= SWR_CLK_RATE_0P6MHZ)
+ bus_clk_freq = SWR_CLK_RATE_0P6MHZ;
+ else if (bus_clk_freq <= SWR_CLK_RATE_1P2MHZ)
+ bus_clk_freq = SWR_CLK_RATE_1P2MHZ;
+ else if (bus_clk_freq <= SWR_CLK_RATE_2P4MHZ)
+ bus_clk_freq = SWR_CLK_RATE_2P4MHZ;
+ else if(bus_clk_freq <= SWR_CLK_RATE_4P8MHZ)
+ bus_clk_freq = SWR_CLK_RATE_4P8MHZ;
+ else if(bus_clk_freq <= SWR_CLK_RATE_9P6MHZ)
+ bus_clk_freq = SWR_CLK_RATE_9P6MHZ;
+ } else if (mclk_freq == SWR_CLK_RATE_11P2896MHZ)
+ bus_clk_freq = SWR_CLK_RATE_11P2896MHZ;
+
+ return bus_clk_freq;
+}
+
+static int swrm_update_bus_clk(struct swr_mstr_ctrl *swrm)
+{
+ int ret = 0;
+ int agg_clk = 0;
+ int i;
+
+ for (i = 0; i < SWR_MSTR_PORT_LEN; i++)
+ agg_clk += swrm->mport_cfg[i].ch_rate;
+
+ if (agg_clk)
+ swrm->bus_clk = swrm_get_clk_div_rate(swrm->mclk_freq,
+ agg_clk);
+ else
+ swrm->bus_clk = swrm->mclk_freq;
+
+ dev_dbg(swrm->dev, "%s: all_port_clk: %d, bus_clk: %d\n",
+ __func__, agg_clk, swrm->bus_clk);
+
+ return ret;
+}
+
static void swrm_disable_ports(struct swr_master *master,
u8 bank)
{
@@ -1140,15 +1350,18 @@
static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable)
{
u8 bank;
- u32 value, n_row, n_col;
+ u32 value = 0, n_row = 0, n_col = 0;
u32 row = 0, col = 0;
+ int bus_clk_div_factor;
int ret;
u8 ssp_period = 0;
struct swr_mstr_ctrl *swrm = swr_get_ctrl_data(master);
int mask = (SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK |
SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK |
+ SWRM_MCP_FRAME_CTRL_BANK_CLK_DIV_VALUE_BMSK |
SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_BMSK);
u8 inactive_bank;
+ int frame_sync = SWRM_FRAME_SYNC_SEL;
if (!swrm) {
pr_err("%s: swrm is null\n", __func__);
@@ -1206,13 +1419,17 @@
clear_bit(DISABLE_PENDING, &swrm->port_req_pending);
swrm_disable_ports(master, bank);
}
- dev_dbg(swrm->dev, "%s: enable: %d, cfg_devs: %d\n",
- __func__, enable, swrm->num_cfg_devs);
+ dev_dbg(swrm->dev, "%s: enable: %d, cfg_devs: %d freq %d\n",
+ __func__, enable, swrm->num_cfg_devs, swrm->mclk_freq);
if (enable) {
/* set col = 16 */
n_col = SWR_MAX_COL;
col = SWRM_COL_16;
+ if (swrm->bus_clk == MCLK_FREQ_LP) {
+ n_col = SWR_MIN_COL;
+ col = SWRM_COL_02;
+ }
} else {
/*
* Do not change to col = 2 if there are still active ports
@@ -1227,23 +1444,26 @@
}
/* Use default 50 * x, frame shape. Change based on mclk */
if (swrm->mclk_freq == MCLK_FREQ_NATIVE) {
- dev_dbg(swrm->dev, "setting 64 x %d frameshape\n",
- n_col ? 16 : 2);
+ dev_dbg(swrm->dev, "setting 64 x %d frameshape\n", col);
n_row = SWR_ROW_64;
row = SWRM_ROW_64;
+ frame_sync = SWRM_FRAME_SYNC_SEL_NATIVE;
} else {
- dev_dbg(swrm->dev, "setting 50 x %d frameshape\n",
- n_col ? 16 : 2);
+ dev_dbg(swrm->dev, "setting 50 x %d frameshape\n", col);
n_row = SWR_ROW_50;
row = SWRM_ROW_50;
+ frame_sync = SWRM_FRAME_SYNC_SEL;
}
- ssp_period = swrm_get_ssp_period(swrm, row, col, SWRM_FRAME_SYNC_SEL);
- dev_dbg(swrm->dev, "%s: ssp_period: %d\n", __func__, ssp_period);
-
+ ssp_period = swrm_get_ssp_period(swrm, row, col, frame_sync);
+ bus_clk_div_factor = swrm_get_clk_div(swrm->mclk_freq, swrm->bus_clk);
+ dev_dbg(swrm->dev, "%s: ssp_period: %d, bus_clk_div:%d \n", __func__,
+ ssp_period, bus_clk_div_factor);
value = swr_master_read(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank));
value &= (~mask);
value |= ((n_row << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT) |
(n_col << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT) |
+ (bus_clk_div_factor <<
+ SWRM_MCP_FRAME_CTRL_BANK_CLK_DIV_VALUE_SHFT) |
((ssp_period - 1) << SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_SHFT));
swr_master_write(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank), value);
@@ -1347,6 +1567,11 @@
mport->port_en = true;
mport->req_ch |= mstr_ch_msk;
master->port_en_mask |= (1 << mstr_port_id);
+ if (swrm->clk_stop_mode0_supp &&
+ (mport->ch_rate < portinfo->ch_rate[i])) {
+ mport->ch_rate = portinfo->ch_rate[i];
+ swrm_update_bus_clk(swrm);
+ }
}
master->num_port += portinfo->num_port;
set_bit(ENABLE_PENDING, &swrm->port_req_pending);
@@ -1409,6 +1634,10 @@
}
port_req->req_ch &= ~portinfo->ch_en[i];
mport->req_ch &= ~mstr_ch_mask;
+ if (swrm->clk_stop_mode0_supp && !mport->req_ch) {
+ mport->ch_rate = 0;
+ swrm_update_bus_clk(swrm);
+ }
}
master->num_port -= portinfo->num_port;
set_bit(DISABLE_PENDING, &swrm->port_req_pending);
@@ -1451,9 +1680,12 @@
}
dev_dbg(swrm->dev, "%s: slave status: 0x%x\n", __func__, status);
for (i = 0; i < (swrm->master.num_dev + 1); i++) {
- if (status & SWRM_MCP_SLV_STATUS_MASK)
+ if (status & SWRM_MCP_SLV_STATUS_MASK) {
+ swrm_cmd_fifo_wr_cmd(swrm, 0xFF, i, 0x0,
+ SWRS_SCP_INT_STATUS_CLEAR_1);
swrm_cmd_fifo_wr_cmd(swrm, 0x4, i, 0x0,
- SWRS_SCP_INT_STATUS_MASK_1);
+ SWRS_SCP_INT_STATUS_MASK_1);
+ }
status >>= 2;
}
}
@@ -1492,6 +1724,7 @@
struct swr_device *swr_dev;
struct swr_master *mstr = &swrm->master;
+ trace_printk("%s enter\n", __func__);
if (unlikely(swrm_lock_sleep(swrm) == false)) {
dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
return IRQ_NONE;
@@ -1508,6 +1741,8 @@
intr_sts = swr_master_read(swrm, SWRM_INTERRUPT_STATUS);
intr_sts_masked = intr_sts & swrm->intr_mask;
+
+ trace_printk("%s: status: 0x%x \n", __func__, intr_sts_masked);
handle_irq:
for (i = 0; i < SWRM_INTERRUPT_MAX; i++) {
value = intr_sts_masked & (1 << i);
@@ -1652,6 +1887,7 @@
mutex_unlock(&swrm->reslock);
exit:
swrm_unlock_sleep(swrm);
+ trace_printk("%s exit\n", __func__);
return ret;
}
@@ -1666,11 +1902,13 @@
struct swr_device *swr_dev;
struct swr_master *mstr = &swrm->master;
+ trace_printk("%s enter\n", __func__);
if (unlikely(swrm_lock_sleep(swrm) == false)) {
dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
return IRQ_NONE;
}
+ mutex_lock(&swrm->ssr_lock);
mutex_lock(&swrm->reslock);
if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) {
ret = IRQ_NONE;
@@ -1692,6 +1930,7 @@
intr_sts_masked = intr_sts & swrm->intr_mask;
dev_dbg(swrm->dev, "%s: status: 0x%x \n", __func__, intr_sts_masked);
+ trace_printk("%s: status: 0x%x \n", __func__, intr_sts_masked);
handle_irq:
for (i = 0; i < SWRM_INTERRUPT_MAX; i++) {
value = intr_sts_masked & (1 << i);
@@ -1723,6 +1962,7 @@
continue;
if (swr_dev->slave_irq) {
do {
+ swr_dev->slave_irq_pending = 0;
handle_nested_irq(
irq_find_mapping(
swr_dev->slave_irq, 0));
@@ -1737,6 +1977,7 @@
break;
case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS:
status = swr_master_read(swrm, SWRM_MCP_SLV_STATUS);
+ swrm_enable_slave_irq(swrm);
if (status == swrm->slave_status) {
dev_dbg(swrm->dev,
"%s: No change in slave status: %d\n",
@@ -1750,6 +1991,17 @@
dev_dbg(swrm->dev,
"%s: device %d got detached\n",
__func__, devnum);
+ if (devnum == 0) {
+ /*
+ * enable host irq if device 0 detached
+ * as hw will mask host_irq at slave
+ * but will not unmask it afterwards.
+ */
+ swrm_cmd_fifo_wr_cmd(swrm, 0xFF, devnum, 0x0,
+ SWRS_SCP_INT_STATUS_CLEAR_1);
+ swrm_cmd_fifo_wr_cmd(swrm, 0x4, devnum, 0x0,
+ SWRS_SCP_INT_STATUS_MASK_1);
+ }
break;
case SWR_ATTACHED_OK:
dev_dbg(swrm->dev,
@@ -1870,7 +2122,9 @@
swrm_request_hw_vote(swrm, LPASS_HW_CORE, false);
exit:
mutex_unlock(&swrm->reslock);
+ mutex_unlock(&swrm->ssr_lock);
swrm_unlock_sleep(swrm);
+ trace_printk("%s exit\n", __func__);
return ret;
}
@@ -1883,10 +2137,22 @@
pr_err("%s: swrm or dev is null\n", __func__);
return IRQ_NONE;
}
+
+ trace_printk("%s enter\n", __func__);
mutex_lock(&swrm->devlock);
if (!swrm->dev_up) {
- if (swrm->wake_irq > 0)
- disable_irq_nosync(swrm->wake_irq);
+ if (swrm->wake_irq > 0) {
+ if (unlikely(!irq_get_irq_data(swrm->wake_irq))) {
+ pr_err("%s: irq data is NULL\n", __func__);
+ mutex_unlock(&swrm->devlock);
+ return IRQ_NONE;
+ }
+ mutex_lock(&swrm->irq_lock);
+ if (!irqd_irq_disabled(
+ irq_get_irq_data(swrm->wake_irq)))
+ disable_irq_nosync(swrm->wake_irq);
+ mutex_unlock(&swrm->irq_lock);
+ }
mutex_unlock(&swrm->devlock);
return ret;
}
@@ -1895,13 +2161,23 @@
dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
goto exit;
}
- if (swrm->wake_irq > 0)
- disable_irq_nosync(swrm->wake_irq);
+ if (swrm->wake_irq > 0) {
+ if (unlikely(!irq_get_irq_data(swrm->wake_irq))) {
+ pr_err("%s: irq data is NULL\n", __func__);
+ return IRQ_NONE;
+ }
+ mutex_lock(&swrm->irq_lock);
+ if (!irqd_irq_disabled(
+ irq_get_irq_data(swrm->wake_irq)))
+ disable_irq_nosync(swrm->wake_irq);
+ mutex_unlock(&swrm->irq_lock);
+ }
pm_runtime_get_sync(swrm->dev);
pm_runtime_mark_last_busy(swrm->dev);
pm_runtime_put_autosuspend(swrm->dev);
swrm_unlock_sleep(swrm);
exit:
+ trace_printk("%s exit\n", __func__);
return ret;
}
@@ -1916,6 +2192,7 @@
return;
}
+ trace_printk("%s enter\n", __func__);
mutex_lock(&swrm->devlock);
if (!swrm->dev_up) {
mutex_unlock(&swrm->devlock);
@@ -1931,6 +2208,7 @@
pm_runtime_put_autosuspend(swrm->dev);
swrm_unlock_sleep(swrm);
exit:
+ trace_printk("%s exit\n", __func__);
pm_relax(swrm->dev);
}
@@ -1993,7 +2271,7 @@
ret = 0;
}
dev_dbg(swrm->dev,
- "%s: devnum %d is assigned for dev addr %lx\n",
+ "%s: devnum %d is assigned for dev addr %llx\n",
__func__, i, swr_dev->addr);
}
}
@@ -2021,20 +2299,15 @@
dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
return;
}
- if (++swrm->hw_core_clk_en == 1)
- if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) {
- dev_err(swrm->dev, "%s:lpass core hw enable failed\n",
- __func__);
- --swrm->hw_core_clk_en;
- }
- if ( ++swrm->aud_core_clk_en == 1)
- if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) {
- dev_err(swrm->dev, "%s:lpass audio hw enable failed\n",
- __func__);
- --swrm->aud_core_clk_en;
- }
- dev_dbg(swrm->dev, "%s: hw_clk_en: %d audio_core_clk_en: %d\n",
- __func__, swrm->hw_core_clk_en, swrm->aud_core_clk_en);
+ mutex_lock(&swrm->reslock);
+ if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true))
+ dev_err(swrm->dev, "%s:lpass core hw enable failed\n",
+ __func__);
+ if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true))
+ dev_err(swrm->dev, "%s:lpass audio hw enable failed\n",
+ __func__);
+ mutex_unlock(&swrm->reslock);
+
pm_runtime_get_sync(swrm->dev);
}
@@ -2049,20 +2322,11 @@
}
pm_runtime_mark_last_busy(swrm->dev);
pm_runtime_put_autosuspend(swrm->dev);
- dev_dbg(swrm->dev, "%s: hw_clk_en: %d audio_core_clk_en: %d\n",
- __func__, swrm->hw_core_clk_en, swrm->aud_core_clk_en);
- --swrm->aud_core_clk_en;
- if (swrm->aud_core_clk_en < 0)
- swrm->aud_core_clk_en = 0;
- else if (swrm->aud_core_clk_en == 0)
- swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
-
- --swrm->hw_core_clk_en;
- if (swrm->hw_core_clk_en < 0)
- swrm->hw_core_clk_en = 0;
- else if (swrm->hw_core_clk_en == 0)
- swrm_request_hw_vote(swrm, LPASS_HW_CORE, false);
+ mutex_lock(&swrm->reslock);
+ swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
+ swrm_request_hw_vote(swrm, LPASS_HW_CORE, false);
+ mutex_unlock(&swrm->reslock);
swrm_unlock_sleep(swrm);
}
@@ -2131,6 +2395,12 @@
swr_master_bulk_write(swrm, reg, value, len);
+ if (!swrm_check_link_status(swrm, 0x1)) {
+ dev_err(swrm->dev,
+ "%s: swr link failed to connect\n",
+ __func__);
+ return -EINVAL;
+ }
/*
* For SWR master version 1.5.1, continue
* execute on command ignore.
@@ -2290,9 +2560,10 @@
dev_dbg(&pdev->dev, "%s: Looking up %s property failed\n",
__func__, "qcom,swr-num-dev");
} else {
- if (swrm->num_dev > SWR_MAX_SLAVE_DEVICES) {
+ if (swrm->num_dev > SWRM_NUM_AUTO_ENUM_SLAVES) {
dev_err(&pdev->dev, "%s: num_dev %d > max limit %d\n",
- __func__, swrm->num_dev, SWR_MAX_SLAVE_DEVICES);
+ __func__, swrm->num_dev,
+ SWRM_NUM_AUTO_ENUM_SLAVES);
ret = -EINVAL;
goto err_pdata_fail;
}
@@ -2376,6 +2647,7 @@
init_completion(&swrm->reset);
init_completion(&swrm->broadcast);
init_completion(&swrm->clk_off_complete);
+ mutex_init(&swrm->irq_lock);
mutex_init(&swrm->mlock);
mutex_init(&swrm->reslock);
mutex_init(&swrm->force_down_lock);
@@ -2383,6 +2655,7 @@
mutex_init(&swrm->clklock);
mutex_init(&swrm->devlock);
mutex_init(&swrm->pm_lock);
+ mutex_init(&swrm->ssr_lock);
swrm->wlock_holders = 0;
swrm->pm_state = SWRM_PM_SLEEPABLE;
init_waitqueue_head(&swrm->pm_wq);
@@ -2463,15 +2736,15 @@
swr_master_add_boarddevices(&swrm->master);
mutex_lock(&swrm->mlock);
swrm_clk_request(swrm, true);
+ swrm->version = swr_master_read(swrm, SWRM_COMP_HW_VERSION);
ret = swrm_master_init(swrm);
if (ret < 0) {
dev_err(&pdev->dev,
"%s: Error in master Initialization , err %d\n",
__func__, ret);
mutex_unlock(&swrm->mlock);
- goto err_mstr_fail;
+ goto err_mstr_init_fail;
}
- swrm->version = swr_master_read(swrm, SWRM_COMP_HW_VERSION);
mutex_unlock(&swrm->mlock);
INIT_WORK(&swrm->wakeup_work, swrm_wakeup_work);
@@ -2515,6 +2788,8 @@
return 0;
err_irq_wakeup_fail:
device_init_wakeup(swrm->dev, false);
+err_mstr_init_fail:
+ swr_unregister_master(&swrm->master);
err_mstr_fail:
if (swrm->reg_irq)
swrm->reg_irq(swrm->handle, swr_mstr_interrupt,
@@ -2522,12 +2797,14 @@
else if (swrm->irq)
free_irq(swrm->irq, swrm);
err_irq_fail:
+ mutex_destroy(&swrm->irq_lock);
mutex_destroy(&swrm->mlock);
mutex_destroy(&swrm->reslock);
mutex_destroy(&swrm->force_down_lock);
mutex_destroy(&swrm->iolock);
mutex_destroy(&swrm->clklock);
mutex_destroy(&swrm->pm_lock);
+ mutex_destroy(&swrm->ssr_lock);
pm_qos_remove_request(&swrm->pm_qos_req);
err_pdata_fail:
@@ -2554,12 +2831,14 @@
swr_unregister_master(&swrm->master);
msm_aud_evt_unregister_client(&swrm->event_notifier);
device_init_wakeup(swrm->dev, false);
+ mutex_destroy(&swrm->irq_lock);
mutex_destroy(&swrm->mlock);
mutex_destroy(&swrm->reslock);
mutex_destroy(&swrm->iolock);
mutex_destroy(&swrm->clklock);
mutex_destroy(&swrm->force_down_lock);
mutex_destroy(&swrm->pm_lock);
+ mutex_destroy(&swrm->ssr_lock);
pm_qos_remove_request(&swrm->pm_qos_req);
devm_kfree(&pdev->dev, swrm);
return 0;
@@ -2592,6 +2871,8 @@
dev_dbg(dev, "%s: pm_runtime: resume, state:%d\n",
__func__, swrm->state);
+ trace_printk("%s: pm_runtime: resume, state:%d\n",
+ __func__, swrm->state);
mutex_lock(&swrm->reslock);
if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) {
@@ -2608,6 +2889,20 @@
if ((swrm->state == SWR_MSTR_DOWN) ||
(swrm->state == SWR_MSTR_SSR && swrm->dev_up)) {
if (swrm->clk_stop_mode0_supp) {
+ if (swrm->wake_irq > 0) {
+ if (unlikely(!irq_get_irq_data
+ (swrm->wake_irq))) {
+ pr_err("%s: irq data is NULL\n",
+ __func__);
+ mutex_unlock(&swrm->reslock);
+ return IRQ_NONE;
+ }
+ mutex_lock(&swrm->irq_lock);
+ if (!irqd_irq_disabled(
+ irq_get_irq_data(swrm->wake_irq)))
+ disable_irq_nosync(swrm->wake_irq);
+ mutex_unlock(&swrm->irq_lock);
+ }
if (swrm->ipc_wakeup)
msm_aud_evt_blocking_notifier_call_chain(
SWR_WAKE_IRQ_DEREGISTER, (void *)swrm);
@@ -2628,6 +2923,9 @@
dev_dbg(dev,
"%s slave device up not implemented\n",
__func__);
+ trace_printk(
+ "%s slave device up not implemented\n",
+ __func__);
ret = 0;
} else if (ret) {
dev_err(dev,
@@ -2643,7 +2941,8 @@
/* wait for hw enumeration to complete */
usleep_range(100, 105);
if (!swrm_check_link_status(swrm, 0x1))
- goto exit;
+ dev_dbg(dev, "%s:failed in connecting, ssr?\n",
+ __func__);
swrm_cmd_fifo_wr_cmd(swrm, 0x4, 0xF, 0x0,
SWRS_SCP_INT_STATUS_MASK_1);
if (swrm->state == SWR_MSTR_SSR) {
@@ -2654,9 +2953,18 @@
} else {
/*wake up from clock stop*/
swr_master_write(swrm, SWRM_MCP_BUS_CTRL_ADDR, 0x2);
+ /* clear and enable bus clash interrupt */
+ swr_master_write(swrm, SWRM_INTERRUPT_CLEAR, 0x08);
+ swrm->intr_mask |= 0x08;
+ swr_master_write(swrm, SWRM_INTERRUPT_MASK_ADDR,
+ swrm->intr_mask);
+ swr_master_write(swrm,
+ SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN,
+ swrm->intr_mask);
usleep_range(100, 105);
if (!swrm_check_link_status(swrm, 0x1))
- goto exit;
+ dev_dbg(dev, "%s:failed in connecting, ssr?\n",
+ __func__);
}
swrm->state = SWR_MSTR_UP;
}
@@ -2673,6 +2981,8 @@
auto_suspend_timer);
mutex_unlock(&swrm->reslock);
+ trace_printk("%s: pm_runtime: resume done, state:%d\n",
+ __func__, swrm->state);
return ret;
}
@@ -2687,6 +2997,8 @@
struct swr_device *swr_dev;
int current_state = 0;
+ trace_printk("%s: pm_runtime: suspend state: %d\n",
+ __func__, swrm->state);
dev_dbg(dev, "%s: pm_runtime: suspend state: %d\n",
__func__, swrm->state);
mutex_lock(&swrm->reslock);
@@ -2711,30 +3023,64 @@
if ((current_state != SWR_MSTR_SSR) &&
swrm_is_port_en(&swrm->master)) {
dev_dbg(dev, "%s ports are enabled\n", __func__);
+ trace_printk("%s ports are enabled\n", __func__);
ret = -EBUSY;
goto exit;
}
if (!swrm->clk_stop_mode0_supp || swrm->state == SWR_MSTR_SSR) {
+ dev_err(dev, "%s: clk stop mode not supported or SSR entry\n",
+ __func__);
mutex_unlock(&swrm->reslock);
enable_bank_switch(swrm, 0, SWR_ROW_50, SWR_MIN_COL);
mutex_lock(&swrm->reslock);
- swrm_clk_pause(swrm);
+ if (!swrm->clk_stop_mode0_supp) {
+ swrm_clk_pause(swrm);
+ } else {
+ /* Mask bus clash interrupt */
+ swrm->intr_mask &= ~((u32)0x08);
+ swr_master_write(swrm,
+ SWRM_INTERRUPT_MASK_ADDR,
+ swrm->intr_mask);
+ swr_master_write(swrm,
+ SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN,
+ swrm->intr_mask);
+ mutex_unlock(&swrm->reslock);
+ /* clock stop sequence */
+ swrm_cmd_fifo_wr_cmd(swrm, 0x2, 0xF, 0xF,
+ SWRS_SCP_CONTROL);
+ mutex_lock(&swrm->reslock);
+ }
swr_master_write(swrm, SWRM_COMP_CFG_ADDR, 0x00);
list_for_each_entry(swr_dev, &mstr->devices, dev_list) {
ret = swr_device_down(swr_dev);
if (ret == -ENODEV) {
dev_dbg_ratelimited(dev,
"%s slave device down not implemented\n",
- __func__);
+ __func__);
+ trace_printk(
+ "%s slave device down not implemented\n",
+ __func__);
ret = 0;
} else if (ret) {
dev_err(dev,
"%s: failed to shutdown swr dev %d\n",
__func__, swr_dev->dev_num);
+ trace_printk(
+ "%s: failed to shutdown swr dev %d\n",
+ __func__, swr_dev->dev_num);
goto exit;
}
}
+ trace_printk("%s: clk stop mode not supported or SSR exit\n",
+ __func__);
} else {
+ /* Mask bus clash interrupt */
+ swrm->intr_mask &= ~((u32)0x08);
+ swr_master_write(swrm, SWRM_INTERRUPT_MASK_ADDR,
+ swrm->intr_mask);
+ swr_master_write(swrm,
+ SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN,
+ swrm->intr_mask);
mutex_unlock(&swrm->reslock);
/* clock stop sequence */
swrm_cmd_fifo_wr_cmd(swrm, 0x2, 0xF, 0xF,
@@ -2742,6 +3088,9 @@
mutex_lock(&swrm->reslock);
usleep_range(100, 105);
}
+ if (!swrm_check_link_status(swrm, 0x0))
+ dev_dbg(dev, "%s:failed in disconnecting, ssr?\n",
+ __func__);
ret = swrm_clk_request(swrm, false);
if (ret) {
dev_err(dev, "%s: swrmn clk failed\n", __func__);
@@ -2757,8 +3106,6 @@
SWR_WAKE_IRQ_REGISTER, (void *)swrm);
swrm->ipc_wakeup_triggered = false;
}
- if (!swrm_check_link_status(swrm, 0x0))
- goto exit;
}
}
@@ -2771,6 +3118,8 @@
if (!hw_core_err)
swrm_request_hw_vote(swrm, LPASS_HW_CORE, false);
mutex_unlock(&swrm->reslock);
+ trace_printk("%s: pm_runtime: suspend done state: %d\n",
+ __func__, swrm->state);
return ret;
}
#endif /* CONFIG_PM */
@@ -2782,6 +3131,7 @@
int ret = 0;
dev_dbg(dev, "%s: swrm state: %d\n", __func__, swrm->state);
+ trace_printk("%s: swrm state: %d\n", __func__, swrm->state);
if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
ret = swrm_runtime_suspend(dev);
if (!ret) {
@@ -2800,6 +3150,7 @@
struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev);
dev_dbg(dev, "%s: swrm state: %d\n", __func__, swrm->state);
+ trace_printk("%s: swrm state: %d\n", __func__, swrm->state);
mutex_lock(&swrm->force_down_lock);
swrm->state = SWR_MSTR_SSR;
@@ -2928,9 +3279,18 @@
* next activity on soundwire will request clock from new clock
* source.
*/
+ if (!data) {
+ dev_err(swrm->dev, "%s: data is NULL for id:%d\n",
+ __func__, id);
+ ret = -EINVAL;
+ break;
+ }
mutex_lock(&swrm->mlock);
- if (swrm->state == SWR_MSTR_UP)
- swrm_device_suspend(&pdev->dev);
+ if (swrm->clk_src != *(int *)data) {
+ if (swrm->state == SWR_MSTR_UP)
+ swrm_device_suspend(&pdev->dev);
+ swrm->clk_src = *(int *)data;
+ }
mutex_unlock(&swrm->mlock);
break;
case SWR_CLK_FREQ:
@@ -2944,8 +3304,13 @@
if (swrm->state == SWR_MSTR_DOWN)
dev_dbg(swrm->dev, "%s:SWR master is already Down:%d\n",
__func__, swrm->state);
- else
+ else {
+ swrm->mclk_freq = *(int *)data;
+ swrm->bus_clk = swrm->mclk_freq;
+ swrm_switch_frame_shape(swrm,
+ swrm->bus_clk);
swrm_device_suspend(&pdev->dev);
+ }
/*
* add delay to ensure clk release happen
* if interrupt triggered for clk stop,
@@ -2959,15 +3324,26 @@
}
break;
case SWR_DEVICE_SSR_DOWN:
+ trace_printk("%s: swr device down called\n", __func__);
+ mutex_lock(&swrm->ssr_lock);
+ mutex_lock(&swrm->mlock);
+ if (swrm->state == SWR_MSTR_DOWN)
+ dev_dbg(swrm->dev, "%s:SWR master is already Down:%d\n",
+ __func__, swrm->state);
+ else
+ swrm_device_down(&pdev->dev);
mutex_lock(&swrm->devlock);
swrm->dev_up = false;
mutex_unlock(&swrm->devlock);
mutex_lock(&swrm->reslock);
swrm->state = SWR_MSTR_SSR;
mutex_unlock(&swrm->reslock);
+ mutex_unlock(&swrm->mlock);
+ mutex_unlock(&swrm->ssr_lock);
break;
case SWR_DEVICE_SSR_UP:
/* wait for clk voting to be zero */
+ trace_printk("%s: swr device up called\n", __func__);
reinit_completion(&swrm->clk_off_complete);
if (swrm->clk_ref_count &&
!wait_for_completion_timeout(&swrm->clk_off_complete,
@@ -2981,6 +3357,7 @@
break;
case SWR_DEVICE_DOWN:
dev_dbg(swrm->dev, "%s: swr master down called\n", __func__);
+ trace_printk("%s: swr master down called\n", __func__);
mutex_lock(&swrm->mlock);
if (swrm->state == SWR_MSTR_DOWN)
dev_dbg(swrm->dev, "%s:SWR master is already Down:%d\n",
@@ -2991,6 +3368,7 @@
break;
case SWR_DEVICE_UP:
dev_dbg(swrm->dev, "%s: swr master up called\n", __func__);
+ trace_printk("%s: swr master up called\n", __func__);
mutex_lock(&swrm->devlock);
if (!swrm->dev_up) {
dev_dbg(swrm->dev, "SSR not complete yet\n");
diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h
index b07a80d..0fac80e 100644
--- a/soc/swr-mstr-ctrl.h
+++ b/soc/swr-mstr-ctrl.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _SWR_WCD_CTRL_H
@@ -25,7 +25,8 @@
#define SWR_ROW_48 0
#define SWR_ROW_50 1
-#define SWR_ROW_64 2
+#define SWR_ROW_64 3
+#define SWR_COL_04 1 /* Cols = 4 */
#define SWR_MAX_COL 7 /* Cols = 16 */
#define SWR_MIN_COL 0 /* Cols = 2 */
@@ -42,7 +43,7 @@
#define SWR_MAX_CH_PER_PORT 8
-#define SWR_MAX_SLAVE_DEVICES 11
+#define SWRM_NUM_AUTO_ENUM_SLAVES 6
enum {
SWR_MSTR_PAUSE,
@@ -81,7 +82,6 @@
bool port_en;
u8 ch_en;
u8 req_ch;
- u8 ch_rate;
u8 offset1;
u8 offset2;
u8 sinterval;
@@ -91,6 +91,7 @@
u8 blk_pack_mode;
u8 word_length;
u8 lane_ctrl;
+ u32 ch_rate;
};
struct swrm_port_type {
@@ -124,6 +125,8 @@
struct mutex mlock;
struct mutex reslock;
struct mutex pm_lock;
+ struct mutex irq_lock;
+ struct mutex ssr_lock;
u32 swrm_base_reg;
char __iomem *swrm_dig_base;
char __iomem *swrm_hctl_reg;
@@ -177,6 +180,7 @@
u32 swr_irq_wakeup_capable;
int hw_core_clk_en;
int aud_core_clk_en;
+ int clk_src;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_swrm_dent;
struct dentry *debugfs_peek;