Merge "ASoC: rx-macro: Update rx droop based on sampling rate" into audio-drivers.lnx.4.0
diff --git a/Android.mk b/Android.mk
index feead01..cac7388 100644
--- a/Android.mk
+++ b/Android.mk
@@ -38,7 +38,7 @@
endif
endif
-ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET)),true)
+ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) bengal),true)
ifneq ($(TARGET_BOARD_AUTO),true)
$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/bolero/Module.symvers)
include $(MY_LOCAL_PATH)/asoc/codecs/bolero/Android.mk
@@ -47,7 +47,7 @@
endif
endif
-ifeq ($(call is-board-platform-in-list, kona lito bengal),true)
+ifeq ($(call is-board-platform-in-list, kona lito),true)
$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/bolero/Module.symvers)
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)
diff --git a/asoc/Android.mk b/asoc/Android.mk
index 4431f88..4ce1fa7 100644
--- a/asoc/Android.mk
+++ b/asoc/Android.mk
@@ -36,6 +36,11 @@
AUDIO_SELECT := CONFIG_SND_SOC_LITO=m
endif
+ifeq ($(call is-board-platform,bengal),true)
+TARGET := bengal
+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,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike),true)
diff --git a/asoc/Kbuild b/asoc/Kbuild
index 9e455a9..137fd60 100644
--- a/asoc/Kbuild
+++ b/asoc/Kbuild
@@ -51,9 +51,9 @@
INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
endif
ifeq ($(CONFIG_ARCH_BENGAL), y)
- include $(AUDIO_ROOT)/config/litoauto.conf
+ include $(AUDIO_ROOT)/config/bengalauto.conf
export
- INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
+ INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
endif
ifeq ($(CONFIG_ARCH_SDMSHRIKE), y)
ifdef CONFIG_SND_SOC_SA8155
@@ -135,6 +135,11 @@
MACHINE_OBJS += kona.o
endif
+# for BENGAL sound card driver
+ifdef CONFIG_SND_SOC_BENGAL
+ MACHINE_OBJS += bengal.o
+endif
+
# for sa8155 sound card driver
ifdef CONFIG_SND_SOC_SA8155
MACHINE_OBJS += sa8155.o
@@ -244,6 +249,9 @@
obj-$(CONFIG_SND_SOC_LITO) += machine_dlkm.o
machine_dlkm-y := $(MACHINE_OBJS)
+obj-$(CONFIG_SND_SOC_BENGAL) += machine_dlkm.o
+machine_dlkm-y := $(MACHINE_OBJS)
+
obj-$(CONFIG_SND_SOC_SA8155) += machine_dlkm.o
machine_dlkm-y := $(MACHINE_OBJS)
diff --git a/asoc/bengal-port-config.h b/asoc/bengal-port-config.h
new file mode 100644
index 0000000..4ac7e10
--- /dev/null
+++ b/asoc/bengal-port-config.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _BENGAL_PORT_CONFIG
+#define _BENGAL_PORT_CONFIG
+
+#include <soc/swr-common.h>
+
+/*
+ * Add port configuration in the format
+ *{ si, off1, off2, hstart, hstop, wd_len, bp_mode, bgp_ctrl, lane_ctrl}
+ */
+
+static struct port_params rx_frame_params_default[SWR_MSTR_PORT_LEN] = {
+ {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1},
+ {31, 0, 0, 3, 6, 7, 0, 0xFF, 0},
+ {31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0},
+ {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0},
+ {0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0},
+};
+
+static struct port_params rx_frame_params_dsd[SWR_MSTR_PORT_LEN] = {
+ {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1},
+ {31, 0, 0, 3, 6, 7, 0, 0xFF, 0},
+ {31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0},
+ {7, 9, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0},
+ {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 3, 0},
+};
+
+/* 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 */
+};
+
+static struct swr_mstr_port_map sm_port_map[] = {
+ {VA_MACRO, SWR_UC0, tx_frame_params_default},
+ {RX_MACRO, SWR_UC0, rx_frame_params_default},
+ {RX_MACRO, SWR_UC1, rx_frame_params_dsd},
+};
+
+#endif /* _BENGAL_PORT_CONFIG */
diff --git a/asoc/bengal.c b/asoc/bengal.c
new file mode 100644
index 0000000..c500a17
--- /dev/null
+++ b/asoc/bengal.c
@@ -0,0 +1,6629 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/of_device.h>
+#include <linux/soc/qcom/fsa4480-i2c.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <soc/snd_event.h>
+#include <dsp/audio_notifier.h>
+#include <soc/swr-common.h>
+#include <dsp/q6afe-v2.h>
+#include <dsp/q6core.h>
+#include "device_event.h"
+#include "msm-pcm-routing-v2.h"
+#include "asoc/msm-cdc-pinctrl.h"
+#include "asoc/wcd-mbhc-v2.h"
+#include "codecs/wcd937x/wcd937x-mbhc.h"
+#include "codecs/wsa881x-analog.h"
+#include "codecs/wcd937x/wcd937x.h"
+#include "codecs/bolero/bolero-cdc.h"
+#include <dt-bindings/sound/audio-codec-port-types.h>
+#include "bengal-port-config.h"
+
+#define DRV_NAME "bengal-asoc-snd"
+#define __CHIPSET__ "BENGAL "
+#define MSM_DAILINK_NAME(name) (__CHIPSET__#name)
+
+#define SAMPLING_RATE_8KHZ 8000
+#define SAMPLING_RATE_11P025KHZ 11025
+#define SAMPLING_RATE_16KHZ 16000
+#define SAMPLING_RATE_22P05KHZ 22050
+#define SAMPLING_RATE_32KHZ 32000
+#define SAMPLING_RATE_44P1KHZ 44100
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_88P2KHZ 88200
+#define SAMPLING_RATE_96KHZ 96000
+#define SAMPLING_RATE_176P4KHZ 176400
+#define SAMPLING_RATE_192KHZ 192000
+#define SAMPLING_RATE_352P8KHZ 352800
+#define SAMPLING_RATE_384KHZ 384000
+
+#define WCD9XXX_MBHC_DEF_RLOADS 5
+#define WCD9XXX_MBHC_DEF_BUTTONS 8
+#define CODEC_EXT_CLK_RATE 9600000
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+#define DEV_NAME_STR_LEN 32
+#define WCD_MBHC_HS_V_MAX 1600
+
+#define TDM_CHANNEL_MAX 8
+#define DEV_NAME_STR_LEN 32
+
+/* time in us to ensure LPM doesn't go in C3/C4 */
+#define MSM_LL_QOS_VALUE 300
+
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+
+#define WCN_CDC_SLIM_RX_CH_MAX 2
+#define WCN_CDC_SLIM_TX_CH_MAX 3
+
+enum {
+ TDM_0 = 0,
+ TDM_1,
+ TDM_2,
+ TDM_3,
+ TDM_4,
+ TDM_5,
+ TDM_6,
+ TDM_7,
+ TDM_PORT_MAX,
+};
+
+enum {
+ TDM_PRI = 0,
+ TDM_SEC,
+ TDM_TERT,
+ TDM_QUAT,
+ TDM_INTERFACE_MAX,
+};
+
+enum {
+ PRIM_AUX_PCM = 0,
+ SEC_AUX_PCM,
+ TERT_AUX_PCM,
+ QUAT_AUX_PCM,
+ AUX_PCM_MAX,
+};
+
+enum {
+ PRIM_MI2S = 0,
+ SEC_MI2S,
+ TERT_MI2S,
+ QUAT_MI2S,
+ MI2S_MAX,
+};
+
+enum {
+ RX_CDC_DMA_RX_0 = 0,
+ RX_CDC_DMA_RX_1,
+ RX_CDC_DMA_RX_2,
+ RX_CDC_DMA_RX_3,
+ RX_CDC_DMA_RX_5,
+ CDC_DMA_RX_MAX,
+};
+
+enum {
+ TX_CDC_DMA_TX_0 = 0,
+ TX_CDC_DMA_TX_3,
+ TX_CDC_DMA_TX_4,
+ VA_CDC_DMA_TX_0,
+ VA_CDC_DMA_TX_1,
+ VA_CDC_DMA_TX_2,
+ CDC_DMA_TX_MAX,
+};
+
+enum {
+ SLIM_RX_7 = 0,
+ SLIM_RX_MAX,
+};
+
+enum {
+ SLIM_TX_7 = 0,
+ SLIM_TX_8,
+ SLIM_TX_MAX,
+};
+
+enum {
+ AFE_LOOPBACK_TX_IDX = 0,
+ AFE_LOOPBACK_TX_IDX_MAX,
+};
+struct msm_asoc_mach_data {
+ struct snd_info_entry *codec_root;
+ int usbc_en2_gpio; /* used by gpio driver API */
+ struct device_node *dmic01_gpio_p; /* used by pinctrl API */
+ struct device_node *dmic23_gpio_p; /* used by pinctrl API */
+ struct device_node *mi2s_gpio_p[MI2S_MAX]; /* used by pinctrl API */
+ atomic_t mi2s_gpio_ref_count[MI2S_MAX]; /* used by pinctrl API */
+ struct device_node *us_euro_gpio_p; /* used by pinctrl API */
+ struct pinctrl *usbc_en2_gpio_p; /* used by pinctrl API */
+ struct device_node *hph_en1_gpio_p; /* used by pinctrl API */
+ struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
+ bool is_afe_config_done;
+ struct device_node *fsa_handle;
+};
+
+struct tdm_port {
+ u32 mode;
+ u32 channel;
+};
+
+enum {
+ EXT_DISP_RX_IDX_DP = 0,
+ EXT_DISP_RX_IDX_DP1,
+ EXT_DISP_RX_IDX_MAX,
+};
+
+struct msm_wsa881x_dev_info {
+ struct device_node *of_node;
+ u32 index;
+};
+
+struct aux_codec_dev_info {
+ struct device_node *of_node;
+ u32 index;
+};
+
+struct dev_config {
+ u32 sample_rate;
+ u32 bit_format;
+ u32 channels;
+};
+
+/* Default configuration of slimbus channels */
+static struct dev_config slim_rx_cfg[] = {
+ [SLIM_RX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static struct dev_config slim_tx_cfg[] = {
+ [SLIM_TX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+static struct dev_config usb_rx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 2,
+};
+
+static struct dev_config usb_tx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 1,
+};
+
+static struct dev_config proxy_rx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 2,
+};
+
+static struct afe_clk_set mi2s_clk[MI2S_MAX] = {
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+ {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+ },
+};
+
+struct mi2s_conf {
+ struct mutex lock;
+ u32 ref_cnt;
+ u32 msm_is_mi2s_master;
+};
+
+static u32 mi2s_ebit_clk[MI2S_MAX] = {
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT,
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT,
+};
+
+static struct mi2s_conf mi2s_intf_conf[MI2S_MAX];
+
+/* Default configuration of TDM channels */
+static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
+ { /* PRI TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* 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 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+ { /* SEC TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* 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 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+ { /* TERT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* 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 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+ { /* QUAT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* 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 */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ },
+};
+
+static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
+ { /* PRI TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* 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 */
+ {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 */
+ },
+ { /* SEC TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* 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 */
+ {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 */
+ },
+ { /* TERT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* 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 */
+ {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 */
+ },
+ { /* QUAT TDM */
+ {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* 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 */
+ {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 */
+ },
+};
+
+/* Default configuration of AUX PCM channels */
+static struct dev_config aux_pcm_rx_cfg[] = {
+ [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static struct dev_config aux_pcm_tx_cfg[] = {
+ [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+/* Default configuration of MI2S channels */
+static struct dev_config mi2s_rx_cfg[] = {
+ [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+static struct dev_config mi2s_tx_cfg[] = {
+ [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+/* Default configuration of Codec DMA Interface RX */
+static struct dev_config cdc_dma_rx_cfg[] = {
+ [RX_CDC_DMA_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [RX_CDC_DMA_RX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [RX_CDC_DMA_RX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [RX_CDC_DMA_RX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [RX_CDC_DMA_RX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
+/* Default configuration of Codec DMA Interface TX */
+static struct dev_config cdc_dma_tx_cfg[] = {
+ [TX_CDC_DMA_TX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [TX_CDC_DMA_TX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [TX_CDC_DMA_TX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [VA_CDC_DMA_TX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8},
+ [VA_CDC_DMA_TX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8},
+ [VA_CDC_DMA_TX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 8},
+};
+
+static struct dev_config afe_loopback_tx_cfg[] = {
+ [AFE_LOOPBACK_TX_IDX] = {
+ SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+};
+
+static int msm_vi_feed_tx_ch = 2;
+static const char *const vi_feed_ch_text[] = {"One", "Two"};
+static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
+ "S32_LE"};
+static char const *ch_text[] = {"Two", "Three", "Four", "Five",
+ "Six", "Seven", "Eight"};
+static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025",
+ "KHZ_16", "KHZ_22P05",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_88P2", "KHZ_96", "KHZ_176P4",
+ "KHZ_192", "KHZ_352P8", "KHZ_384"};
+static const char *const usb_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven",
+ "Eight"};
+static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32",
+ "KHZ_48", "KHZ_176P4",
+ "KHZ_352P8"};
+static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
+static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven", "Eight"};
+static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"};
+static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_16",
+ "KHZ_22P05", "KHZ_32", "KHZ_44P1",
+ "KHZ_48", "KHZ_96", "KHZ_192"};
+static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven",
+ "Eight"};
+
+static const char *const cdc_dma_rx_ch_text[] = {"One", "Two"};
+static const char *const cdc_dma_tx_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven",
+ "Eight"};
+static char const *cdc_dma_sample_rate_text[] = {"KHZ_8", "KHZ_11P025",
+ "KHZ_16", "KHZ_22P05",
+ "KHZ_32", "KHZ_44P1", "KHZ_48",
+ "KHZ_88P2", "KHZ_96",
+ "KHZ_176P4", "KHZ_192",
+ "KHZ_352P8", "KHZ_384"};
+static char const *bt_sample_rate_text[] = {"KHZ_8", "KHZ_16",
+ "KHZ_44P1", "KHZ_48",
+ "KHZ_88P2", "KHZ_96"};
+static char const *bt_sample_rate_rx_text[] = {"KHZ_8", "KHZ_16",
+ "KHZ_44P1", "KHZ_48",
+ "KHZ_88P2", "KHZ_96"};
+static char const *bt_sample_rate_tx_text[] = {"KHZ_8", "KHZ_16",
+ "KHZ_44P1", "KHZ_48",
+ "KHZ_88P2", "KHZ_96"};
+static const char *const afe_loopback_tx_ch_text[] = {"One", "Two"};
+
+static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_format, tdm_bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_format, tdm_bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_chs, tdm_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_rx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_tx_sample_rate, auxpcm_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(mi2s_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(mi2s_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_0_chs, cdc_dma_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_1_chs, cdc_dma_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_2_chs, cdc_dma_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_3_chs, cdc_dma_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_5_chs, cdc_dma_rx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_0_chs, cdc_dma_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_3_chs, cdc_dma_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_4_chs, cdc_dma_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_0_chs, cdc_dma_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_1_chs, cdc_dma_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_2_chs, cdc_dma_tx_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_0_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_1_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_2_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_3_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_5_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_0_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_3_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_4_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_0_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_1_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_2_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_0_sample_rate,
+ cdc_dma_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_1_sample_rate,
+ cdc_dma_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_2_sample_rate,
+ cdc_dma_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_3_sample_rate,
+ cdc_dma_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(rx_cdc_dma_rx_5_sample_rate,
+ cdc_dma_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_0_sample_rate,
+ cdc_dma_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_3_sample_rate,
+ cdc_dma_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_4_sample_rate,
+ cdc_dma_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_0_sample_rate,
+ cdc_dma_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_1_sample_rate,
+ cdc_dma_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_2_sample_rate,
+ cdc_dma_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_rx, bt_sample_rate_rx_text);
+static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_tx, bt_sample_rate_tx_text);
+static SOC_ENUM_SINGLE_EXT_DECL(afe_loopback_tx_chs, afe_loopback_tx_ch_text);
+
+static bool is_initial_boot;
+static bool codec_reg_done;
+static struct snd_soc_aux_dev *msm_aux_dev;
+static struct snd_soc_codec_conf *msm_codec_conf;
+static struct snd_soc_card snd_soc_card_bengal_msm;
+static int dmic_0_1_gpio_cnt;
+static int dmic_2_3_gpio_cnt;
+
+static void *def_wcd_mbhc_cal(void);
+
+/*
+ * Need to report LINEIN
+ * if R/L channel impedance is larger than 5K ohm
+ */
+static struct wcd_mbhc_config wcd_mbhc_cfg = {
+ .read_fw_bin = false,
+ .calibration = NULL,
+ .detect_extn_cable = true,
+ .mono_stero_detection = false,
+ .swap_gnd_mic = NULL,
+ .hs_ext_micbias = true,
+ .key_code[0] = KEY_MEDIA,
+ .key_code[1] = KEY_VOICECOMMAND,
+ .key_code[2] = KEY_VOLUMEUP,
+ .key_code[3] = KEY_VOLUMEDOWN,
+ .key_code[4] = 0,
+ .key_code[5] = 0,
+ .key_code[6] = 0,
+ .key_code[7] = 0,
+ .linein_th = 5000,
+ .moisture_en = false,
+ .mbhc_micbias = MIC_BIAS_2,
+ .anc_micbias = MIC_BIAS_2,
+ .enable_anc_mic_detect = false,
+ .moisture_duty_cycle_en = true,
+};
+
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p,
+ int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n,
+ unsigned int bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+static int usb_audio_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (usb_rx_cfg.sample_rate) {
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 12;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 11;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 10;
+ break;
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_88P2KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_22P05KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_11P025KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: usb_audio_rx_sample_rate = %d\n", __func__,
+ usb_rx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 12:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ case 11:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 10:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 9:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 8:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 7:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 6:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ;
+ break;
+ case 2:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 1:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ;
+ break;
+ case 0:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ default:
+ usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: control value = %ld, usb_audio_rx_sample_rate = %d\n",
+ __func__, ucontrol->value.integer.value[0],
+ usb_rx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (usb_tx_cfg.sample_rate) {
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 12;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 11;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 10;
+ break;
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_88P2KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_22P05KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_11P025KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ default:
+ sample_rate_val = 6;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: usb_audio_tx_sample_rate = %d\n", __func__,
+ usb_tx_cfg.sample_rate);
+ return 0;
+}
+
+static int usb_audio_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 12:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ case 11:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 10:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 9:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 8:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 7:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 6:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ;
+ break;
+ case 2:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 1:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ;
+ break;
+ case 0:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ default:
+ usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: control value = %ld, usb_audio_tx_sample_rate = %d\n",
+ __func__, ucontrol->value.integer.value[0],
+ usb_tx_cfg.sample_rate);
+ return 0;
+}
+static int afe_loopback_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: afe_loopback_tx_ch = %d\n", __func__,
+ afe_loopback_tx_cfg[0].channels);
+ ucontrol->value.enumerated.item[0] =
+ afe_loopback_tx_cfg[0].channels - 1;
+
+ return 0;
+}
+
+static int afe_loopback_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ afe_loopback_tx_cfg[0].channels =
+ ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: afe_loopback_tx_ch = %d\n", __func__,
+ afe_loopback_tx_cfg[0].channels);
+
+ return 1;
+}
+
+static int usb_audio_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (usb_rx_cfg.bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_rx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int usb_audio_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ case 2:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_rx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return rc;
+}
+
+static int usb_audio_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (usb_tx_cfg.bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_tx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ case 2:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n",
+ __func__, usb_tx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return rc;
+}
+
+static int usb_audio_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: usb_audio_rx_ch = %d\n", __func__,
+ usb_rx_cfg.channels);
+ ucontrol->value.integer.value[0] = usb_rx_cfg.channels - 1;
+ return 0;
+}
+
+static int usb_audio_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ usb_rx_cfg.channels = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: usb_audio_rx_ch = %d\n", __func__, usb_rx_cfg.channels);
+ return 1;
+}
+
+static int usb_audio_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: usb_audio_tx_ch = %d\n", __func__,
+ usb_tx_cfg.channels);
+ ucontrol->value.integer.value[0] = usb_tx_cfg.channels - 1;
+ return 0;
+}
+
+static int usb_audio_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ usb_tx_cfg.channels = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: usb_audio_tx_ch = %d\n", __func__, usb_tx_cfg.channels);
+ return 1;
+}
+
+static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_vi_feed_tx_ch - 1;
+ pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_vi_feed_tx_ch = ucontrol->value.integer.value[0] + 1;
+ pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch);
+ return 1;
+}
+
+static int proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: proxy_rx channels = %d\n",
+ __func__, proxy_rx_cfg.channels);
+ ucontrol->value.integer.value[0] = proxy_rx_cfg.channels - 2;
+
+ return 0;
+}
+
+static int proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ proxy_rx_cfg.channels = ucontrol->value.integer.value[0] + 2;
+ pr_debug("%s: proxy_rx channels = %d\n",
+ __func__, proxy_rx_cfg.channels);
+
+ return 1;
+}
+
+static int tdm_get_port_idx(struct snd_kcontrol *kcontrol,
+ struct tdm_port *port)
+{
+ if (port) {
+ if (strnstr(kcontrol->id.name, "PRI",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_PRI;
+ } else if (strnstr(kcontrol->id.name, "SEC",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_SEC;
+ } else if (strnstr(kcontrol->id.name, "TERT",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_TERT;
+ } else if (strnstr(kcontrol->id.name, "QUAT",
+ sizeof(kcontrol->id.name))) {
+ port->mode = TDM_QUAT;
+ } else {
+ pr_err("%s: unsupported mode in: %s\n",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ if (strnstr(kcontrol->id.name, "RX_0",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_0",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_0;
+ } else if (strnstr(kcontrol->id.name, "RX_1",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_1",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_1;
+ } else if (strnstr(kcontrol->id.name, "RX_2",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_2",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_2;
+ } else if (strnstr(kcontrol->id.name, "RX_3",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_3",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_3;
+ } else if (strnstr(kcontrol->id.name, "RX_4",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_4",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_4;
+ } else if (strnstr(kcontrol->id.name, "RX_5",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_5",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_5;
+ } else if (strnstr(kcontrol->id.name, "RX_6",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_6",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_6;
+ } else if (strnstr(kcontrol->id.name, "RX_7",
+ sizeof(kcontrol->id.name)) ||
+ strnstr(kcontrol->id.name, "TX_7",
+ sizeof(kcontrol->id.name))) {
+ port->channel = TDM_7;
+ } else {
+ pr_err("%s: unsupported channel in: %s\n",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+ } else {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int tdm_get_sample_rate(int value)
+{
+ int sample_rate = 0;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int tdm_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val = 0;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 5;
+ break;
+ default:
+ sample_rate_val = 3;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int tdm_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s\n",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val(
+ tdm_rx_cfg[port.mode][port.channel].sample_rate);
+
+ pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s\n",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_rx_cfg[port.mode][port.channel].sample_rate =
+ tdm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s\n",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val(
+ tdm_tx_cfg[port.mode][port.channel].sample_rate);
+
+ pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s\n",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_tx_cfg[port.mode][port.channel].sample_rate =
+ tdm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_get_format(int value)
+{
+ int format = 0;
+
+ switch (value) {
+ case 0:
+ format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 1:
+ format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 2:
+ format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ default:
+ format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return format;
+}
+
+static int tdm_get_format_val(int format)
+{
+ int value = 0;
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ value = 0;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ value = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ value = 2;
+ break;
+ default:
+ value = 0;
+ break;
+ }
+ return value;
+}
+
+static int tdm_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s\n",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_format_val(
+ tdm_rx_cfg[port.mode][port.channel].bit_format);
+
+ pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s\n",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_rx_cfg[port.mode][port.channel].bit_format =
+ tdm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s\n",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] = tdm_get_format_val(
+ tdm_tx_cfg[port.mode][port.channel].bit_format);
+
+ pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s\n",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_tx_cfg[port.mode][port.channel].bit_format =
+ tdm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].bit_format,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s\n",
+ __func__, kcontrol->id.name);
+ } else {
+
+ ucontrol->value.enumerated.item[0] =
+ tdm_rx_cfg[port.mode][port.channel].channels - 1;
+
+ pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].channels - 1,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s\n",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_rx_cfg[port.mode][port.channel].channels =
+ ucontrol->value.enumerated.item[0] + 1;
+
+ pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__,
+ tdm_rx_cfg[port.mode][port.channel].channels,
+ ucontrol->value.enumerated.item[0] + 1);
+ }
+ return ret;
+}
+
+static int tdm_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s\n",
+ __func__, kcontrol->id.name);
+ } else {
+ ucontrol->value.enumerated.item[0] =
+ tdm_tx_cfg[port.mode][port.channel].channels - 1;
+
+ pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].channels - 1,
+ ucontrol->value.enumerated.item[0]);
+ }
+ return ret;
+}
+
+static int tdm_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tdm_port port;
+ int ret = tdm_get_port_idx(kcontrol, &port);
+
+ if (ret) {
+ pr_err("%s: unsupported control: %s\n",
+ __func__, kcontrol->id.name);
+ } else {
+ tdm_tx_cfg[port.mode][port.channel].channels =
+ ucontrol->value.enumerated.item[0] + 1;
+
+ pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__,
+ tdm_tx_cfg[port.mode][port.channel].channels,
+ ucontrol->value.enumerated.item[0] + 1);
+ }
+ return ret;
+}
+
+static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int idx = 0;
+
+ if (strnstr(kcontrol->id.name, "PRIM_AUX_PCM",
+ sizeof("PRIM_AUX_PCM"))) {
+ idx = PRIM_AUX_PCM;
+ } else if (strnstr(kcontrol->id.name, "SEC_AUX_PCM",
+ sizeof("SEC_AUX_PCM"))) {
+ idx = SEC_AUX_PCM;
+ } else if (strnstr(kcontrol->id.name, "TERT_AUX_PCM",
+ sizeof("TERT_AUX_PCM"))) {
+ idx = TERT_AUX_PCM;
+ } else if (strnstr(kcontrol->id.name, "QUAT_AUX_PCM",
+ sizeof("QUAT_AUX_PCM"))) {
+ idx = QUAT_AUX_PCM;
+ } else {
+ pr_err("%s: unsupported port: %s\n",
+ __func__, kcontrol->id.name);
+ idx = -EINVAL;
+ }
+
+ return idx;
+}
+
+static int aux_pcm_get_sample_rate(int value)
+{
+ int sample_rate = 0;
+
+ switch (value) {
+ case 1:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 0:
+ default:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int aux_pcm_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val = 0;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int mi2s_auxpcm_get_format(int value)
+{
+ int format = 0;
+
+ switch (value) {
+ case 0:
+ format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 1:
+ format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 2:
+ format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 3:
+ format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ default:
+ format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return format;
+}
+
+static int mi2s_auxpcm_get_format_value(int format)
+{
+ int value = 0;
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ value = 0;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ value = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ value = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ value = 3;
+ break;
+ default:
+ value = 0;
+ break;
+ }
+ return value;
+}
+
+static int aux_pcm_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ aux_pcm_get_sample_rate_val(aux_pcm_rx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ aux_pcm_rx_cfg[idx].sample_rate =
+ aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ aux_pcm_get_sample_rate_val(aux_pcm_tx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int aux_pcm_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ aux_pcm_tx_cfg[idx].sample_rate =
+ aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, aux_pcm_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_aux_pcm_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_auxpcm_get_format_value(aux_pcm_rx_cfg[idx].bit_format);
+
+ pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+ idx, aux_pcm_rx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_aux_pcm_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ aux_pcm_rx_cfg[idx].bit_format =
+ mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+ idx, aux_pcm_rx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_aux_pcm_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_auxpcm_get_format_value(aux_pcm_tx_cfg[idx].bit_format);
+
+ pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
+ idx, aux_pcm_tx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_aux_pcm_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = aux_pcm_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ aux_pcm_tx_cfg[idx].bit_format =
+ mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
+ idx, aux_pcm_tx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int idx = 0;
+
+ if (strnstr(kcontrol->id.name, "PRIM_MI2S_RX",
+ sizeof("PRIM_MI2S_RX"))) {
+ idx = PRIM_MI2S;
+ } else if (strnstr(kcontrol->id.name, "SEC_MI2S_RX",
+ sizeof("SEC_MI2S_RX"))) {
+ idx = SEC_MI2S;
+ } else if (strnstr(kcontrol->id.name, "TERT_MI2S_RX",
+ sizeof("TERT_MI2S_RX"))) {
+ idx = TERT_MI2S;
+ } else if (strnstr(kcontrol->id.name, "QUAT_MI2S_RX",
+ sizeof("QUAT_MI2S_RX"))) {
+ idx = QUAT_MI2S;
+ } else if (strnstr(kcontrol->id.name, "PRIM_MI2S_TX",
+ sizeof("PRIM_MI2S_TX"))) {
+ idx = PRIM_MI2S;
+ } else if (strnstr(kcontrol->id.name, "SEC_MI2S_TX",
+ sizeof("SEC_MI2S_TX"))) {
+ idx = SEC_MI2S;
+ } else if (strnstr(kcontrol->id.name, "TERT_MI2S_TX",
+ sizeof("TERT_MI2S_TX"))) {
+ idx = TERT_MI2S;
+ } else if (strnstr(kcontrol->id.name, "QUAT_MI2S_TX",
+ sizeof("QUAT_MI2S_TX"))) {
+ idx = QUAT_MI2S;
+ } else {
+ pr_err("%s: unsupported channel: %s\n",
+ __func__, kcontrol->id.name);
+ idx = -EINVAL;
+ }
+
+ return idx;
+}
+
+static int mi2s_get_sample_rate(int value)
+{
+ int sample_rate = 0;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_11P025KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_22P05KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 7:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 8:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int mi2s_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val = 0;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_11P025KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_22P05KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 8;
+ break;
+ default:
+ sample_rate_val = 6;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int mi2s_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_get_sample_rate_val(mi2s_rx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_rx_cfg[idx].sample_rate =
+ mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_get_sample_rate_val(mi2s_tx_cfg[idx].sample_rate);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_tx_cfg[idx].sample_rate =
+ mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_mi2s_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_auxpcm_get_format_value(mi2s_rx_cfg[idx].bit_format);
+
+ pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_mi2s_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_rx_cfg[idx].bit_format =
+ mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_mi2s_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_auxpcm_get_format_value(mi2s_tx_cfg[idx].bit_format);
+
+ pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_mi2s_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_tx_cfg[idx].bit_format =
+ mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+static int msm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].channels);
+ ucontrol->value.enumerated.item[0] = mi2s_rx_cfg[idx].channels - 1;
+
+ return 0;
+}
+
+static int msm_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_rx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].channels);
+
+ return 1;
+}
+
+static int msm_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].channels);
+ ucontrol->value.enumerated.item[0] = mi2s_tx_cfg[idx].channels - 1;
+
+ return 0;
+}
+
+static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_tx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+ pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].channels);
+
+ return 1;
+}
+
+static int msm_get_port_id(int be_id)
+{
+ int afe_port_id = 0;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_PRI_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_PRI_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX:
+ afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ break;
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX:
+ afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ break;
+ case MSM_BACKEND_DAI_VA_CDC_DMA_TX_0:
+ afe_port_id = AFE_PORT_ID_VA_CODEC_DMA_TX_0;
+ break;
+ case MSM_BACKEND_DAI_VA_CDC_DMA_TX_1:
+ afe_port_id = AFE_PORT_ID_VA_CODEC_DMA_TX_1;
+ break;
+ case MSM_BACKEND_DAI_VA_CDC_DMA_TX_2:
+ afe_port_id = AFE_PORT_ID_VA_CODEC_DMA_TX_2;
+ break;
+ default:
+ pr_err("%s: Invalid BE id: %d\n", __func__, be_id);
+ afe_port_id = -EINVAL;
+ }
+
+ return afe_port_id;
+}
+
+static u32 get_mi2s_bits_per_sample(u32 bit_format)
+{
+ u32 bit_per_sample = 0;
+
+ switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bit_per_sample = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bit_per_sample = 16;
+ break;
+ }
+
+ return bit_per_sample;
+}
+
+static void update_mi2s_clk_val(int dai_id, int stream)
+{
+ u32 bit_per_sample = 0;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ bit_per_sample =
+ get_mi2s_bits_per_sample(mi2s_rx_cfg[dai_id].bit_format);
+ mi2s_clk[dai_id].clk_freq_in_hz =
+ mi2s_rx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
+ } else {
+ bit_per_sample =
+ get_mi2s_bits_per_sample(mi2s_tx_cfg[dai_id].bit_format);
+ mi2s_clk[dai_id].clk_freq_in_hz =
+ mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
+ }
+}
+
+static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int port_id = 0;
+ int index = cpu_dai->id;
+
+ port_id = msm_get_port_id(rtd->dai_link->id);
+ if (port_id < 0) {
+ dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__);
+ ret = port_id;
+ goto err;
+ }
+
+ if (enable) {
+ update_mi2s_clk_val(index, substream->stream);
+ dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__,
+ mi2s_clk[index].clk_freq_in_hz);
+ }
+
+ mi2s_clk[index].enable = enable;
+ ret = afe_set_lpass_clock_v2(port_id,
+ &mi2s_clk[index]);
+ if (ret < 0) {
+ dev_err(rtd->card->dev,
+ "%s: afe lpass clock failed for port 0x%x , err:%d\n",
+ __func__, port_id, ret);
+ goto err;
+ }
+
+err:
+ return ret;
+}
+
+static int cdc_dma_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int idx = 0;
+
+ if (strnstr(kcontrol->id.name, "RX_CDC_DMA_RX_0",
+ sizeof("RX_CDC_DMA_RX_0")))
+ idx = RX_CDC_DMA_RX_0;
+ else if (strnstr(kcontrol->id.name, "RX_CDC_DMA_RX_1",
+ sizeof("RX_CDC_DMA_RX_1")))
+ idx = RX_CDC_DMA_RX_1;
+ else if (strnstr(kcontrol->id.name, "RX_CDC_DMA_RX_2",
+ sizeof("RX_CDC_DMA_RX_2")))
+ idx = RX_CDC_DMA_RX_2;
+ else if (strnstr(kcontrol->id.name, "RX_CDC_DMA_RX_3",
+ sizeof("RX_CDC_DMA_RX_3")))
+ idx = RX_CDC_DMA_RX_3;
+ else if (strnstr(kcontrol->id.name, "RX_CDC_DMA_RX_5",
+ sizeof("RX_CDC_DMA_RX_5")))
+ idx = RX_CDC_DMA_RX_5;
+ else if (strnstr(kcontrol->id.name, "TX_CDC_DMA_TX_0",
+ sizeof("TX_CDC_DMA_TX_0")))
+ idx = TX_CDC_DMA_TX_0;
+ else if (strnstr(kcontrol->id.name, "TX_CDC_DMA_TX_3",
+ sizeof("TX_CDC_DMA_TX_3")))
+ idx = TX_CDC_DMA_TX_3;
+ else if (strnstr(kcontrol->id.name, "TX_CDC_DMA_TX_4",
+ sizeof("TX_CDC_DMA_TX_4")))
+ idx = TX_CDC_DMA_TX_4;
+ else if (strnstr(kcontrol->id.name, "VA_CDC_DMA_TX_0",
+ sizeof("VA_CDC_DMA_TX_0")))
+ idx = VA_CDC_DMA_TX_0;
+ else if (strnstr(kcontrol->id.name, "VA_CDC_DMA_TX_1",
+ sizeof("VA_CDC_DMA_TX_1")))
+ idx = VA_CDC_DMA_TX_1;
+ else if (strnstr(kcontrol->id.name, "VA_CDC_DMA_TX_2",
+ sizeof("VA_CDC_DMA_TX_2")))
+ idx = VA_CDC_DMA_TX_2;
+ else {
+ pr_err("%s: unsupported channel: %s\n",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ return idx;
+}
+
+static int cdc_dma_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = cdc_dma_get_port_idx(kcontrol);
+
+ if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) {
+ pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
+ return ch_num;
+ }
+
+ pr_debug("%s: cdc_dma_rx_ch = %d\n", __func__,
+ cdc_dma_rx_cfg[ch_num].channels - 1);
+ ucontrol->value.integer.value[0] = cdc_dma_rx_cfg[ch_num].channels - 1;
+ return 0;
+}
+
+static int cdc_dma_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = cdc_dma_get_port_idx(kcontrol);
+
+ if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) {
+ pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
+ return ch_num;
+ }
+
+ cdc_dma_rx_cfg[ch_num].channels = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: cdc_dma_rx_ch = %d\n", __func__,
+ cdc_dma_rx_cfg[ch_num].channels);
+ return 1;
+}
+
+static int cdc_dma_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = cdc_dma_get_port_idx(kcontrol);
+
+ if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) {
+ pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
+ return ch_num;
+ }
+
+ switch (cdc_dma_rx_cfg[ch_num].bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: cdc_dma_rx_format = %d, ucontrol value = %ld\n",
+ __func__, cdc_dma_rx_cfg[ch_num].bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int cdc_dma_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ int ch_num = cdc_dma_get_port_idx(kcontrol);
+
+ if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) {
+ pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
+ return ch_num;
+ }
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ cdc_dma_rx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ case 2:
+ cdc_dma_rx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ cdc_dma_rx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ cdc_dma_rx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: cdc_dma_rx_format = %d, ucontrol value = %ld\n",
+ __func__, cdc_dma_rx_cfg[ch_num].bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return rc;
+}
+
+
+static int cdc_dma_get_sample_rate_val(int sample_rate)
+{
+ int sample_rate_val = 0;
+
+ switch (sample_rate) {
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ case SAMPLING_RATE_11P025KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_22P05KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_88P2KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 10;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 11;
+ break;
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 12;
+ break;
+ default:
+ sample_rate_val = 6;
+ break;
+ }
+ return sample_rate_val;
+}
+
+static int cdc_dma_get_sample_rate(int value)
+{
+ int sample_rate = 0;
+
+ switch (value) {
+ case 0:
+ sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ case 1:
+ sample_rate = SAMPLING_RATE_11P025KHZ;
+ break;
+ case 2:
+ sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 3:
+ sample_rate = SAMPLING_RATE_22P05KHZ;
+ break;
+ case 4:
+ sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 5:
+ sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 6:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 7:
+ sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 8:
+ sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 9:
+ sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 10:
+ sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 11:
+ sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 12:
+ sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ default:
+ sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+ return sample_rate;
+}
+
+static int cdc_dma_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = cdc_dma_get_port_idx(kcontrol);
+
+ if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) {
+ pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
+ return ch_num;
+ }
+
+ ucontrol->value.enumerated.item[0] =
+ cdc_dma_get_sample_rate_val(cdc_dma_rx_cfg[ch_num].sample_rate);
+
+ pr_debug("%s: cdc_dma_rx_sample_rate = %d\n", __func__,
+ cdc_dma_rx_cfg[ch_num].sample_rate);
+ return 0;
+}
+
+static int cdc_dma_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = cdc_dma_get_port_idx(kcontrol);
+
+ if (ch_num < 0 || ch_num >= CDC_DMA_RX_MAX) {
+ pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
+ return ch_num;
+ }
+
+ cdc_dma_rx_cfg[ch_num].sample_rate =
+ cdc_dma_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+
+ pr_debug("%s: control value = %d, cdc_dma_rx_sample_rate = %d\n",
+ __func__, ucontrol->value.enumerated.item[0],
+ cdc_dma_rx_cfg[ch_num].sample_rate);
+ return 0;
+}
+
+static int cdc_dma_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = cdc_dma_get_port_idx(kcontrol);
+
+ if (ch_num < 0) {
+ pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
+ return ch_num;
+ }
+
+ pr_debug("%s: cdc_dma_tx_ch = %d\n", __func__,
+ cdc_dma_tx_cfg[ch_num].channels);
+ ucontrol->value.integer.value[0] = cdc_dma_tx_cfg[ch_num].channels - 1;
+ return 0;
+}
+
+static int cdc_dma_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = cdc_dma_get_port_idx(kcontrol);
+
+ if (ch_num < 0) {
+ pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
+ return ch_num;
+ }
+
+ cdc_dma_tx_cfg[ch_num].channels = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: cdc_dma_tx_ch = %d\n", __func__,
+ cdc_dma_tx_cfg[ch_num].channels);
+ return 1;
+}
+
+static int cdc_dma_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val;
+ int ch_num = cdc_dma_get_port_idx(kcontrol);
+
+ if (ch_num < 0) {
+ pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
+ return ch_num;
+ }
+
+ switch (cdc_dma_tx_cfg[ch_num].sample_rate) {
+ case SAMPLING_RATE_384KHZ:
+ sample_rate_val = 12;
+ break;
+ case SAMPLING_RATE_352P8KHZ:
+ sample_rate_val = 11;
+ break;
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 10;
+ break;
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 9;
+ break;
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 8;
+ break;
+ case SAMPLING_RATE_88P2KHZ:
+ sample_rate_val = 7;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ sample_rate_val = 6;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 5;
+ break;
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 4;
+ break;
+ case SAMPLING_RATE_22P05KHZ:
+ sample_rate_val = 3;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ sample_rate_val = 2;
+ break;
+ case SAMPLING_RATE_11P025KHZ:
+ sample_rate_val = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ sample_rate_val = 0;
+ break;
+ default:
+ sample_rate_val = 6;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: cdc_dma_tx_sample_rate = %d\n", __func__,
+ cdc_dma_tx_cfg[ch_num].sample_rate);
+ return 0;
+}
+
+static int cdc_dma_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = cdc_dma_get_port_idx(kcontrol);
+
+ if (ch_num < 0) {
+ pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
+ return ch_num;
+ }
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 12:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_384KHZ;
+ break;
+ case 11:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_352P8KHZ;
+ break;
+ case 10:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 9:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 8:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 7:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 6:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 5:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 4:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_32KHZ;
+ break;
+ case 3:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_22P05KHZ;
+ break;
+ case 2:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 1:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_11P025KHZ;
+ break;
+ case 0:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ default:
+ cdc_dma_tx_cfg[ch_num].sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: control value = %ld, cdc_dma_tx_sample_rate = %d\n",
+ __func__, ucontrol->value.integer.value[0],
+ cdc_dma_tx_cfg[ch_num].sample_rate);
+ return 0;
+}
+
+static int cdc_dma_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ch_num = cdc_dma_get_port_idx(kcontrol);
+
+ if (ch_num < 0) {
+ pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
+ return ch_num;
+ }
+
+ switch (cdc_dma_tx_cfg[ch_num].bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: cdc_dma_tx_format = %d, ucontrol value = %ld\n",
+ __func__, cdc_dma_tx_cfg[ch_num].bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int cdc_dma_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ int ch_num = cdc_dma_get_port_idx(kcontrol);
+
+ if (ch_num < 0) {
+ pr_err("%s: ch_num: %d is invalid\n", __func__, ch_num);
+ return ch_num;
+ }
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 3:
+ cdc_dma_tx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ case 2:
+ cdc_dma_tx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ cdc_dma_tx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ cdc_dma_tx_cfg[ch_num].bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: cdc_dma_tx_format = %d, ucontrol value = %ld\n",
+ __func__, cdc_dma_tx_cfg[ch_num].bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return rc;
+}
+
+static int msm_cdc_dma_get_idx_from_beid(int32_t be_id)
+{
+ int idx = 0;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_0:
+ idx = RX_CDC_DMA_RX_0;
+ break;
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_1:
+ idx = RX_CDC_DMA_RX_1;
+ break;
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_2:
+ idx = RX_CDC_DMA_RX_2;
+ break;
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_3:
+ idx = RX_CDC_DMA_RX_3;
+ break;
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_5:
+ idx = RX_CDC_DMA_RX_5;
+ break;
+ case MSM_BACKEND_DAI_TX_CDC_DMA_TX_0:
+ idx = TX_CDC_DMA_TX_0;
+ break;
+ case MSM_BACKEND_DAI_TX_CDC_DMA_TX_3:
+ idx = TX_CDC_DMA_TX_3;
+ break;
+ case MSM_BACKEND_DAI_TX_CDC_DMA_TX_4:
+ idx = TX_CDC_DMA_TX_4;
+ break;
+ case MSM_BACKEND_DAI_VA_CDC_DMA_TX_0:
+ idx = VA_CDC_DMA_TX_0;
+ break;
+ case MSM_BACKEND_DAI_VA_CDC_DMA_TX_1:
+ idx = VA_CDC_DMA_TX_1;
+ break;
+ case MSM_BACKEND_DAI_VA_CDC_DMA_TX_2:
+ idx = VA_CDC_DMA_TX_2;
+ break;
+ default:
+ idx = RX_CDC_DMA_RX_0;
+ break;
+ }
+
+ return idx;
+}
+
+static int msm_bt_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /*
+ * Slimbus_7_Rx/Tx sample rate values should always be in sync (same)
+ * when used for BT_SCO use case. Return either Rx or Tx sample rate
+ * value.
+ */
+ switch (slim_rx_cfg[SLIM_RX_7].sample_rate) {
+ case SAMPLING_RATE_96KHZ:
+ ucontrol->value.integer.value[0] = 5;
+ break;
+ case SAMPLING_RATE_88P2KHZ:
+ ucontrol->value.integer.value[0] = 4;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+ pr_debug("%s: sample rate = %d\n", __func__,
+ slim_rx_cfg[SLIM_RX_7].sample_rate);
+
+ return 0;
+}
+
+static int msm_bt_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_44P1KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 3:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_48KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 4:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_88P2KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 5:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_96KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: sample rates: slim7_rx = %d, slim7_tx = %d, value = %d\n",
+ __func__,
+ slim_rx_cfg[SLIM_RX_7].sample_rate,
+ slim_tx_cfg[SLIM_TX_7].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_bt_sample_rate_rx_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (slim_rx_cfg[SLIM_RX_7].sample_rate) {
+ case SAMPLING_RATE_96KHZ:
+ ucontrol->value.integer.value[0] = 5;
+ break;
+ case SAMPLING_RATE_88P2KHZ:
+ ucontrol->value.integer.value[0] = 4;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+ pr_debug("%s: sample rate rx = %d\n", __func__,
+ slim_rx_cfg[SLIM_RX_7].sample_rate);
+
+ return 0;
+}
+
+static int msm_bt_sample_rate_rx_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 3:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 4:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 5:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: sample rate: slim7_rx = %d, value = %d\n",
+ __func__,
+ slim_rx_cfg[SLIM_RX_7].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int msm_bt_sample_rate_tx_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (slim_tx_cfg[SLIM_TX_7].sample_rate) {
+ case SAMPLING_RATE_96KHZ:
+ ucontrol->value.integer.value[0] = 5;
+ break;
+ case SAMPLING_RATE_88P2KHZ:
+ ucontrol->value.integer.value[0] = 4;
+ break;
+ case SAMPLING_RATE_48KHZ:
+ ucontrol->value.integer.value[0] = 3;
+ break;
+ case SAMPLING_RATE_44P1KHZ:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ case SAMPLING_RATE_16KHZ:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SAMPLING_RATE_8KHZ:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+ pr_debug("%s: sample rate tx = %d\n", __func__,
+ slim_tx_cfg[SLIM_TX_7].sample_rate);
+
+ return 0;
+}
+
+static int msm_bt_sample_rate_tx_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 2:
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 3:
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ case 4:
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 5:
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: sample rate: slim7_tx = %d, value = %d\n",
+ __func__,
+ slim_tx_cfg[SLIM_TX_7].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new msm_int_snd_controls[] = {
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_0 Channels", rx_cdc_dma_rx_0_chs,
+ cdc_dma_rx_ch_get, cdc_dma_rx_ch_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_1 Channels", rx_cdc_dma_rx_1_chs,
+ cdc_dma_rx_ch_get, cdc_dma_rx_ch_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_2 Channels", rx_cdc_dma_rx_2_chs,
+ cdc_dma_rx_ch_get, cdc_dma_rx_ch_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_3 Channels", rx_cdc_dma_rx_3_chs,
+ cdc_dma_rx_ch_get, cdc_dma_rx_ch_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_5 Channels", rx_cdc_dma_rx_5_chs,
+ cdc_dma_rx_ch_get, cdc_dma_rx_ch_put),
+ SOC_ENUM_EXT("TX_CDC_DMA_TX_0 Channels", tx_cdc_dma_tx_0_chs,
+ cdc_dma_tx_ch_get, cdc_dma_tx_ch_put),
+ SOC_ENUM_EXT("TX_CDC_DMA_TX_3 Channels", tx_cdc_dma_tx_3_chs,
+ cdc_dma_tx_ch_get, cdc_dma_tx_ch_put),
+ SOC_ENUM_EXT("TX_CDC_DMA_TX_4 Channels", tx_cdc_dma_tx_4_chs,
+ cdc_dma_tx_ch_get, cdc_dma_tx_ch_put),
+ SOC_ENUM_EXT("VA_CDC_DMA_TX_0 Channels", va_cdc_dma_tx_0_chs,
+ cdc_dma_tx_ch_get, cdc_dma_tx_ch_put),
+ SOC_ENUM_EXT("VA_CDC_DMA_TX_1 Channels", va_cdc_dma_tx_1_chs,
+ cdc_dma_tx_ch_get, cdc_dma_tx_ch_put),
+ SOC_ENUM_EXT("VA_CDC_DMA_TX_2 Channels", va_cdc_dma_tx_2_chs,
+ cdc_dma_tx_ch_get, cdc_dma_tx_ch_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_0 Format", rx_cdc_dma_rx_0_format,
+ cdc_dma_rx_format_get, cdc_dma_rx_format_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_1 Format", rx_cdc_dma_rx_1_format,
+ cdc_dma_rx_format_get, cdc_dma_rx_format_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_2 Format", rx_cdc_dma_rx_2_format,
+ cdc_dma_rx_format_get, cdc_dma_rx_format_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_3 Format", rx_cdc_dma_rx_3_format,
+ cdc_dma_rx_format_get, cdc_dma_rx_format_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_5 Format", rx_cdc_dma_rx_5_format,
+ cdc_dma_rx_format_get, cdc_dma_rx_format_put),
+ SOC_ENUM_EXT("TX_CDC_DMA_TX_0 Format", tx_cdc_dma_tx_0_format,
+ cdc_dma_tx_format_get, cdc_dma_tx_format_put),
+ SOC_ENUM_EXT("TX_CDC_DMA_TX_3 Format", tx_cdc_dma_tx_3_format,
+ cdc_dma_tx_format_get, cdc_dma_tx_format_put),
+ SOC_ENUM_EXT("TX_CDC_DMA_TX_4 Format", tx_cdc_dma_tx_4_format,
+ cdc_dma_tx_format_get, cdc_dma_tx_format_put),
+ SOC_ENUM_EXT("VA_CDC_DMA_TX_0 Format", va_cdc_dma_tx_0_format,
+ cdc_dma_tx_format_get, cdc_dma_tx_format_put),
+ SOC_ENUM_EXT("VA_CDC_DMA_TX_1 Format", va_cdc_dma_tx_1_format,
+ cdc_dma_tx_format_get, cdc_dma_tx_format_put),
+ SOC_ENUM_EXT("VA_CDC_DMA_TX_2 Format", va_cdc_dma_tx_2_format,
+ cdc_dma_tx_format_get, cdc_dma_tx_format_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_0 SampleRate",
+ rx_cdc_dma_rx_0_sample_rate,
+ cdc_dma_rx_sample_rate_get,
+ cdc_dma_rx_sample_rate_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_1 SampleRate",
+ rx_cdc_dma_rx_1_sample_rate,
+ cdc_dma_rx_sample_rate_get,
+ cdc_dma_rx_sample_rate_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_2 SampleRate",
+ rx_cdc_dma_rx_2_sample_rate,
+ cdc_dma_rx_sample_rate_get,
+ cdc_dma_rx_sample_rate_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_3 SampleRate",
+ rx_cdc_dma_rx_3_sample_rate,
+ cdc_dma_rx_sample_rate_get,
+ cdc_dma_rx_sample_rate_put),
+ SOC_ENUM_EXT("RX_CDC_DMA_RX_5 SampleRate",
+ rx_cdc_dma_rx_5_sample_rate,
+ cdc_dma_rx_sample_rate_get,
+ cdc_dma_rx_sample_rate_put),
+ SOC_ENUM_EXT("TX_CDC_DMA_TX_0 SampleRate",
+ tx_cdc_dma_tx_0_sample_rate,
+ cdc_dma_tx_sample_rate_get,
+ cdc_dma_tx_sample_rate_put),
+ SOC_ENUM_EXT("TX_CDC_DMA_TX_3 SampleRate",
+ tx_cdc_dma_tx_3_sample_rate,
+ cdc_dma_tx_sample_rate_get,
+ cdc_dma_tx_sample_rate_put),
+ SOC_ENUM_EXT("TX_CDC_DMA_TX_4 SampleRate",
+ tx_cdc_dma_tx_4_sample_rate,
+ cdc_dma_tx_sample_rate_get,
+ cdc_dma_tx_sample_rate_put),
+ SOC_ENUM_EXT("VA_CDC_DMA_TX_0 SampleRate",
+ va_cdc_dma_tx_0_sample_rate,
+ cdc_dma_tx_sample_rate_get,
+ cdc_dma_tx_sample_rate_put),
+ SOC_ENUM_EXT("VA_CDC_DMA_TX_1 SampleRate",
+ va_cdc_dma_tx_1_sample_rate,
+ cdc_dma_tx_sample_rate_get,
+ cdc_dma_tx_sample_rate_put),
+ SOC_ENUM_EXT("VA_CDC_DMA_TX_2 SampleRate",
+ va_cdc_dma_tx_2_sample_rate,
+ cdc_dma_tx_sample_rate_get,
+ cdc_dma_tx_sample_rate_put),
+};
+
+static const struct snd_kcontrol_new msm_common_snd_controls[] = {
+ SOC_ENUM_EXT("USB_AUDIO_RX SampleRate", usb_rx_sample_rate,
+ usb_audio_rx_sample_rate_get,
+ usb_audio_rx_sample_rate_put),
+ SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate,
+ usb_audio_tx_sample_rate_get,
+ usb_audio_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
+ tdm_rx_sample_rate_get,
+ tdm_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 SampleRate", tdm_tx_sample_rate,
+ tdm_tx_sample_rate_get,
+ tdm_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_AUX_PCM_RX SampleRate", sec_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_AUX_PCM_RX SampleRate", tert_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_AUX_PCM_RX SampleRate", quat_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_TX SampleRate", prim_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_AUX_PCM_TX SampleRate", sec_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_AUX_PCM_TX SampleRate", tert_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_AUX_PCM_TX SampleRate", quat_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_MI2S_RX SampleRate", prim_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_MI2S_RX SampleRate", sec_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_MI2S_RX SampleRate", tert_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_MI2S_RX SampleRate", quat_mi2s_rx_sample_rate,
+ mi2s_rx_sample_rate_get,
+ mi2s_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_MI2S_TX SampleRate", prim_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("SEC_MI2S_TX SampleRate", sec_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("TERT_MI2S_TX SampleRate", tert_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("QUAT_MI2S_TX SampleRate", quat_mi2s_tx_sample_rate,
+ mi2s_tx_sample_rate_get,
+ mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("USB_AUDIO_RX Format", usb_rx_format,
+ usb_audio_rx_format_get, usb_audio_rx_format_put),
+ SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format,
+ usb_audio_tx_format_get, usb_audio_tx_format_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 Format", tdm_rx_format,
+ tdm_rx_format_get,
+ tdm_rx_format_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 Format", tdm_tx_format,
+ tdm_tx_format_get,
+ tdm_tx_format_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_RX Format", aux_pcm_rx_format,
+ msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
+ SOC_ENUM_EXT("SEC_AUX_PCM_RX Format", aux_pcm_rx_format,
+ msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
+ SOC_ENUM_EXT("TERT_AUX_PCM_RX Format", aux_pcm_rx_format,
+ msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
+ SOC_ENUM_EXT("QUAT_AUX_PCM_RX Format", aux_pcm_rx_format,
+ msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_TX Format", aux_pcm_tx_format,
+ msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
+ SOC_ENUM_EXT("SEC_AUX_PCM_TX Format", aux_pcm_tx_format,
+ msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
+ SOC_ENUM_EXT("TERT_AUX_PCM_TX Format", aux_pcm_tx_format,
+ msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
+ SOC_ENUM_EXT("QUAT_AUX_PCM_TX Format", aux_pcm_tx_format,
+ msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
+ SOC_ENUM_EXT("PRIM_MI2S_RX Format", mi2s_rx_format,
+ msm_mi2s_rx_format_get, msm_mi2s_rx_format_put),
+ SOC_ENUM_EXT("SEC_MI2S_RX Format", mi2s_rx_format,
+ msm_mi2s_rx_format_get, msm_mi2s_rx_format_put),
+ SOC_ENUM_EXT("TERT_MI2S_RX Format", mi2s_rx_format,
+ msm_mi2s_rx_format_get, msm_mi2s_rx_format_put),
+ SOC_ENUM_EXT("QUAT_MI2S_RX Format", mi2s_rx_format,
+ msm_mi2s_rx_format_get, msm_mi2s_rx_format_put),
+ SOC_ENUM_EXT("PRIM_MI2S_TX Format", mi2s_tx_format,
+ msm_mi2s_tx_format_get, msm_mi2s_tx_format_put),
+ SOC_ENUM_EXT("SEC_MI2S_TX Format", mi2s_tx_format,
+ msm_mi2s_tx_format_get, msm_mi2s_tx_format_put),
+ SOC_ENUM_EXT("TERT_MI2S_TX Format", mi2s_tx_format,
+ msm_mi2s_tx_format_get, msm_mi2s_tx_format_put),
+ SOC_ENUM_EXT("QUAT_MI2S_TX Format", mi2s_tx_format,
+ msm_mi2s_tx_format_get, msm_mi2s_tx_format_put),
+ SOC_ENUM_EXT("USB_AUDIO_RX Channels", usb_rx_chs,
+ usb_audio_rx_ch_get, usb_audio_rx_ch_put),
+ SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs,
+ usb_audio_tx_ch_get, usb_audio_tx_ch_put),
+ SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs,
+ proxy_rx_ch_get, proxy_rx_ch_put),
+ SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("SEC_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("QUAT_TDM_RX_0 Channels", tdm_rx_chs,
+ tdm_rx_ch_get,
+ tdm_rx_ch_put),
+ SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("SEC_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("TERT_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("QUAT_TDM_TX_0 Channels", tdm_tx_chs,
+ tdm_tx_ch_get,
+ tdm_tx_ch_put),
+ SOC_ENUM_EXT("PRIM_MI2S_RX Channels", prim_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("SEC_MI2S_RX Channels", sec_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("TERT_MI2S_RX Channels", tert_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("QUAT_MI2S_RX Channels", quat_mi2s_rx_chs,
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("PRIM_MI2S_TX Channels", prim_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("SEC_MI2S_TX Channels", sec_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("TERT_MI2S_TX Channels", tert_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("QUAT_MI2S_TX Channels", quat_mi2s_tx_chs,
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("BT SampleRate", bt_sample_rate,
+ msm_bt_sample_rate_get,
+ msm_bt_sample_rate_put),
+ SOC_ENUM_EXT("BT SampleRate RX", bt_sample_rate_rx,
+ msm_bt_sample_rate_rx_get,
+ msm_bt_sample_rate_rx_put),
+ SOC_ENUM_EXT("BT SampleRate TX", bt_sample_rate_tx,
+ msm_bt_sample_rate_tx_get,
+ msm_bt_sample_rate_tx_put),
+ SOC_ENUM_EXT("AFE_LOOPBACK_TX Channels", afe_loopback_tx_chs,
+ afe_loopback_tx_ch_get, afe_loopback_tx_ch_put),
+ SOC_ENUM_EXT("VI_FEED_TX Channels", vi_feed_tx_chs,
+ msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
+};
+
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+ SOC_ENUM_EXT("PRIM_AUX_PCM_RX Format", aux_pcm_rx_format,
+ msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_TX Format", aux_pcm_tx_format,
+ msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate,
+ aux_pcm_rx_sample_rate_get,
+ aux_pcm_rx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_AUX_PCM_TX SampleRate", prim_aux_pcm_tx_sample_rate,
+ aux_pcm_tx_sample_rate_get,
+ aux_pcm_tx_sample_rate_put),
+};
+
+static int bengal_send_island_va_config(int32_t be_id)
+{
+ int rc = 0;
+ int port_id = 0xFFFF;
+
+ port_id = msm_get_port_id(be_id);
+ if (port_id < 0) {
+ pr_err("%s: Invalid island interface, be_id: %d\n",
+ __func__, be_id);
+ rc = -EINVAL;
+ } else {
+ /*
+ * send island mode config
+ * This should be the first configuration
+ */
+ rc = afe_send_port_island_mode(port_id);
+ if (rc)
+ pr_err("%s: afe send island mode failed %d\n",
+ __func__, rc);
+ }
+
+ return rc;
+}
+
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ int idx = 0;
+
+ pr_debug("%s: format = %d, rate = %d\n",
+ __func__, params_format(params), params_rate(params));
+
+ switch (dai_link->id) {
+ case MSM_BACKEND_DAI_USB_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ usb_rx_cfg.bit_format);
+ rate->min = rate->max = usb_rx_cfg.sample_rate;
+ channels->min = channels->max = usb_rx_cfg.channels;
+ break;
+
+ case MSM_BACKEND_DAI_USB_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ usb_tx_cfg.bit_format);
+ rate->min = rate->max = usb_tx_cfg.sample_rate;
+ channels->min = channels->max = usb_tx_cfg.channels;
+ break;
+
+ case MSM_BACKEND_DAI_AFE_PCM_RX:
+ channels->min = channels->max = proxy_rx_cfg.channels;
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_PRI][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_PRI][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_PRI][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_PRI][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_PRI][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_PRI][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_SEC][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_TERT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_TERT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_TERT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_TERT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_TERT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_TERT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_TDM_RX_0:
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_TDM_TX_0:
+ channels->min = channels->max =
+ tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_tx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max = tdm_tx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ break;
+
+ case MSM_BACKEND_DAI_AUXPCM_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_rx_cfg[PRIM_AUX_PCM].bit_format);
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[PRIM_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_AUXPCM_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_tx_cfg[PRIM_AUX_PCM].bit_format);
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[PRIM_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[PRIM_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_AUXPCM_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_rx_cfg[SEC_AUX_PCM].bit_format);
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[SEC_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[SEC_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SEC_AUXPCM_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_tx_cfg[SEC_AUX_PCM].bit_format);
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[SEC_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[SEC_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_AUXPCM_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_rx_cfg[TERT_AUX_PCM].bit_format);
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[TERT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[TERT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERT_AUXPCM_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_tx_cfg[TERT_AUX_PCM].bit_format);
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[TERT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[TERT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_AUXPCM_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_rx_cfg[QUAT_AUX_PCM].bit_format);
+ rate->min = rate->max =
+ aux_pcm_rx_cfg[QUAT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_rx_cfg[QUAT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUAT_AUXPCM_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ aux_pcm_tx_cfg[QUAT_AUX_PCM].bit_format);
+ rate->min = rate->max =
+ aux_pcm_tx_cfg[QUAT_AUX_PCM].sample_rate;
+ channels->min = channels->max =
+ aux_pcm_tx_cfg[QUAT_AUX_PCM].channels;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_MI2S_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_rx_cfg[PRIM_MI2S].bit_format);
+ rate->min = rate->max = mi2s_rx_cfg[PRIM_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[PRIM_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_PRI_MI2S_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_tx_cfg[PRIM_MI2S].bit_format);
+ rate->min = rate->max = mi2s_tx_cfg[PRIM_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[PRIM_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_rx_cfg[SEC_MI2S].bit_format);
+ rate->min = rate->max = mi2s_rx_cfg[SEC_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[SEC_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SECONDARY_MI2S_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_tx_cfg[SEC_MI2S].bit_format);
+ rate->min = rate->max = mi2s_tx_cfg[SEC_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[SEC_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_rx_cfg[TERT_MI2S].bit_format);
+ rate->min = rate->max = mi2s_rx_cfg[TERT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[TERT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TERTIARY_MI2S_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_tx_cfg[TERT_MI2S].bit_format);
+ rate->min = rate->max = mi2s_tx_cfg[TERT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[TERT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_rx_cfg[QUAT_MI2S].bit_format);
+ rate->min = rate->max = mi2s_rx_cfg[QUAT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_rx_cfg[QUAT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_tx_cfg[QUAT_MI2S].bit_format);
+ rate->min = rate->max = mi2s_tx_cfg[QUAT_MI2S].sample_rate;
+ channels->min = channels->max =
+ mi2s_tx_cfg[QUAT_MI2S].channels;
+ break;
+
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_0:
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_1:
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_2:
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_3:
+ idx = msm_cdc_dma_get_idx_from_beid(dai_link->id);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ cdc_dma_rx_cfg[idx].bit_format);
+ rate->min = rate->max = cdc_dma_rx_cfg[idx].sample_rate;
+ channels->min = channels->max = cdc_dma_rx_cfg[idx].channels;
+ break;
+
+ case MSM_BACKEND_DAI_TX_CDC_DMA_TX_0:
+ case MSM_BACKEND_DAI_TX_CDC_DMA_TX_3:
+ case MSM_BACKEND_DAI_TX_CDC_DMA_TX_4:
+ 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:
+ idx = msm_cdc_dma_get_idx_from_beid(dai_link->id);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ cdc_dma_tx_cfg[idx].bit_format);
+ rate->min = rate->max = cdc_dma_tx_cfg[idx].sample_rate;
+ channels->min = channels->max = cdc_dma_tx_cfg[idx].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_7_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim_rx_cfg[SLIM_RX_7].bit_format);
+ rate->min = rate->max = slim_rx_cfg[SLIM_RX_7].sample_rate;
+ channels->min = channels->max =
+ slim_rx_cfg[SLIM_RX_7].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_7_TX:
+ rate->min = rate->max = slim_tx_cfg[SLIM_TX_7].sample_rate;
+ channels->min = channels->max =
+ slim_tx_cfg[SLIM_TX_7].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_8_TX:
+ rate->min = rate->max = slim_tx_cfg[SLIM_TX_8].sample_rate;
+ channels->min = channels->max =
+ slim_tx_cfg[SLIM_TX_8].channels;
+ break;
+
+ case MSM_BACKEND_DAI_AFE_LOOPBACK_TX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ afe_loopback_tx_cfg[idx].bit_format);
+ rate->min = rate->max = afe_loopback_tx_cfg[idx].sample_rate;
+ channels->min = channels->max =
+ afe_loopback_tx_cfg[idx].channels;
+ break;
+
+ default:
+ rate->min = rate->max = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ return 0;
+}
+
+static bool msm_usbc_swap_gnd_mic(struct snd_soc_component *component,
+ bool active)
+{
+ struct snd_soc_card *card = component->card;
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(card);
+
+ if (!pdata->fsa_handle)
+ return false;
+
+ return fsa4480_switch_event(pdata->fsa_handle, FSA_MIC_GND_SWAP);
+}
+
+static bool msm_swap_gnd_mic(struct snd_soc_component *component, bool active)
+{
+ int value = 0;
+ bool ret = false;
+ struct snd_soc_card *card;
+ struct msm_asoc_mach_data *pdata;
+
+ if (!component) {
+ pr_err("%s component is NULL\n", __func__);
+ return false;
+ }
+ card = component->card;
+ pdata = snd_soc_card_get_drvdata(card);
+
+ if (!pdata)
+ return false;
+
+ if (wcd_mbhc_cfg.enable_usbc_analog)
+ return msm_usbc_swap_gnd_mic(component, active);
+
+ /* if usbc is not defined, swap using us_euro_gpio_p */
+ if (pdata->us_euro_gpio_p) {
+ value = msm_cdc_pinctrl_get_state(
+ pdata->us_euro_gpio_p);
+ if (value)
+ msm_cdc_pinctrl_select_sleep_state(
+ pdata->us_euro_gpio_p);
+ else
+ msm_cdc_pinctrl_select_active_state(
+ pdata->us_euro_gpio_p);
+ dev_dbg(component->dev, "%s: swap select switch %d to %d\n",
+ __func__, value, !value);
+ ret = true;
+ }
+
+ return ret;
+}
+
+static int bengal_tdm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ int slot_width = 32;
+ int channels, slots;
+ unsigned int slot_mask, rate, clk_freq;
+ unsigned int slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+
+ pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
+
+ /* currently only supporting TDM_RX_0 and TDM_TX_0 */
+ switch (cpu_dai->id) {
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ slots = tdm_rx_cfg[TDM_PRI][TDM_0].channels;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ slots = tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ slots = tdm_rx_cfg[TDM_TERT][TDM_0].channels;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ slots = tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+ break;
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ slots = tdm_tx_cfg[TDM_PRI][TDM_0].channels;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ slots = tdm_tx_cfg[TDM_SEC][TDM_0].channels;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ slots = tdm_tx_cfg[TDM_TERT][TDM_0].channels;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ slots = tdm_tx_cfg[TDM_QUAT][TDM_0].channels;
+ break;
+
+ default:
+ pr_err("%s: dai id 0x%x not supported\n",
+ __func__, cpu_dai->id);
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /*2 slot config - bits 0 and 1 set for the first two slots */
+ slot_mask = 0x0000FFFF >> (16 - slots);
+ channels = slots;
+
+ pr_debug("%s: tdm rx slot_width %d slots %d\n",
+ __func__, slot_width, slots);
+
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm rx slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ 0, NULL, channels, slot_offset);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm rx channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ /*2 slot config - bits 0 and 1 set for the first two slots */
+ slot_mask = 0x0000FFFF >> (16 - slots);
+ channels = slots;
+
+ pr_debug("%s: tdm tx slot_width %d slots %d\n",
+ __func__, slot_width, slots);
+
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm tx slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ channels, slot_offset, 0, NULL);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm tx channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ ret = -EINVAL;
+ pr_err("%s: invalid use case, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ rate = params_rate(params);
+ clk_freq = rate * slot_width * slots;
+ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, clk_freq, SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ pr_err("%s: failed to set tdm clk, err:%d\n",
+ __func__, ret);
+
+end:
+ return ret;
+}
+
+static int msm_get_tdm_mode(u32 port_id)
+{
+ int tdm_mode;
+
+ switch (port_id) {
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ tdm_mode = TDM_PRI;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ tdm_mode = TDM_SEC;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ tdm_mode = TDM_TERT;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ tdm_mode = TDM_QUAT;
+ break;
+ default:
+ pr_err("%s: Invalid port id: %d\n", __func__, port_id);
+ tdm_mode = -EINVAL;
+ }
+ return tdm_mode;
+}
+
+static int bengal_tdm_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int tdm_mode = msm_get_tdm_mode(cpu_dai->id);
+
+ if (tdm_mode >= TDM_INTERFACE_MAX || tdm_mode < 0) {
+ ret = -EINVAL;
+ pr_err("%s: Invalid TDM interface %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (pdata->mi2s_gpio_p[tdm_mode]) {
+ if (atomic_read(&(pdata->mi2s_gpio_ref_count[tdm_mode]))
+ == 0) {
+ ret = msm_cdc_pinctrl_select_active_state(
+ pdata->mi2s_gpio_p[tdm_mode]);
+ if (ret) {
+ pr_err("%s: TDM GPIO pinctrl set active failed with %d\n",
+ __func__, ret);
+ goto done;
+ }
+ }
+ atomic_inc(&(pdata->mi2s_gpio_ref_count[tdm_mode]));
+ }
+
+done:
+ return ret;
+}
+
+static void bengal_tdm_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int tdm_mode = msm_get_tdm_mode(cpu_dai->id);
+
+ if (tdm_mode >= TDM_INTERFACE_MAX || tdm_mode < 0) {
+ ret = -EINVAL;
+ pr_err("%s: Invalid TDM interface %d\n",
+ __func__, ret);
+ return;
+ }
+
+ if (pdata->mi2s_gpio_p[tdm_mode]) {
+ atomic_dec(&(pdata->mi2s_gpio_ref_count[tdm_mode]));
+ if (atomic_read(&(pdata->mi2s_gpio_ref_count[tdm_mode]))
+ == 0) {
+ ret = msm_cdc_pinctrl_select_sleep_state(
+ pdata->mi2s_gpio_p[tdm_mode]);
+ if (ret)
+ pr_err("%s: TDM GPIO pinctrl set sleep failed with %d\n",
+ __func__, ret);
+ }
+ }
+}
+
+static int bengal_aux_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ u32 aux_mode = cpu_dai->id - 1;
+
+ if (aux_mode >= AUX_PCM_MAX) {
+ ret = -EINVAL;
+ pr_err("%s: Invalid AUX interface %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (pdata->mi2s_gpio_p[aux_mode]) {
+ if (atomic_read(&(pdata->mi2s_gpio_ref_count[aux_mode]))
+ == 0) {
+ ret = msm_cdc_pinctrl_select_active_state(
+ pdata->mi2s_gpio_p[aux_mode]);
+ if (ret) {
+ pr_err("%s: AUX GPIO pinctrl set active failed with %d\n",
+ __func__, ret);
+ goto done;
+ }
+ }
+ atomic_inc(&(pdata->mi2s_gpio_ref_count[aux_mode]));
+ }
+
+done:
+ return ret;
+}
+
+static void bengal_aux_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ u32 aux_mode = cpu_dai->id - 1;
+
+ if (aux_mode >= AUX_PCM_MAX) {
+ pr_err("%s: Invalid AUX interface %d\n",
+ __func__, ret);
+ return;
+ }
+
+ if (pdata->mi2s_gpio_p[aux_mode]) {
+ atomic_dec(&(pdata->mi2s_gpio_ref_count[aux_mode]));
+ if (atomic_read(&(pdata->mi2s_gpio_ref_count[aux_mode]))
+ == 0) {
+ ret = msm_cdc_pinctrl_select_sleep_state(
+ pdata->mi2s_gpio_p[aux_mode]);
+ if (ret)
+ pr_err("%s: AUX GPIO pinctrl set sleep failed with %d\n",
+ __func__, ret);
+ }
+ }
+}
+
+static int msm_snd_cdc_dma_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+
+ 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:
+ ret = bengal_send_island_va_config(dai_link->id);
+ if (ret)
+ pr_err("%s: send island va cfg failed, err: %d\n",
+ __func__, ret);
+ break;
+ }
+
+ return ret;
+}
+
+static int msm_snd_cdc_dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+
+ int ret = 0;
+ u32 rx_ch_cdc_dma, tx_ch_cdc_dma;
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ u32 user_set_tx_ch = 0;
+ u32 user_set_rx_ch = 0;
+ u32 ch_id;
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, &tx_ch_cdc_dma, &rx_ch_cnt,
+ &rx_ch_cdc_dma);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto err;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (dai_link->id) {
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_0:
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_1:
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_2:
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_3:
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_4:
+ case MSM_BACKEND_DAI_RX_CDC_DMA_RX_5:
+ {
+ ch_id = msm_cdc_dma_get_idx_from_beid(dai_link->id);
+ pr_debug("%s: id %d rx_ch=%d\n", __func__,
+ ch_id, cdc_dma_rx_cfg[ch_id].channels);
+ user_set_rx_ch = cdc_dma_rx_cfg[ch_id].channels;
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ user_set_rx_ch, &rx_ch_cdc_dma);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto err;
+ }
+
+ }
+ break;
+ }
+ } else {
+ switch (dai_link->id) {
+ case MSM_BACKEND_DAI_TX_CDC_DMA_TX_0:
+ case MSM_BACKEND_DAI_TX_CDC_DMA_TX_3:
+ case MSM_BACKEND_DAI_TX_CDC_DMA_TX_4:
+ 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:
+ {
+ ch_id = msm_cdc_dma_get_idx_from_beid(dai_link->id);
+ pr_debug("%s: id %d tx_ch=%d\n", __func__,
+ ch_id, cdc_dma_tx_cfg[ch_id].channels);
+ user_set_tx_ch = cdc_dma_tx_cfg[ch_id].channels;
+ }
+ break;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, user_set_tx_ch,
+ &tx_ch_cdc_dma, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto err;
+ }
+ }
+
+err:
+ return ret;
+}
+
+static int msm_fe_qos_prepare(struct snd_pcm_substream *substream)
+{
+ cpumask_t mask;
+
+ if (pm_qos_request_active(&substream->latency_pm_qos_req))
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
+
+ cpumask_clear(&mask);
+ cpumask_set_cpu(1, &mask); /* affine to core 1 */
+ cpumask_set_cpu(2, &mask); /* affine to core 2 */
+ cpumask_copy(&substream->latency_pm_qos_req.cpus_affine, &mask);
+
+ substream->latency_pm_qos_req.type = PM_QOS_REQ_AFFINE_CORES;
+
+ pm_qos_add_request(&substream->latency_pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY,
+ MSM_LL_QOS_VALUE);
+ return 0;
+}
+
+static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int index = cpu_dai->id;
+ unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+ dev_dbg(rtd->card->dev,
+ "%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
+ __func__, substream->name, substream->stream,
+ cpu_dai->name, cpu_dai->id);
+
+ if (index < PRIM_MI2S || index >= MI2S_MAX) {
+ ret = -EINVAL;
+ dev_err(rtd->card->dev,
+ "%s: CPU DAI id (%d) out of range\n",
+ __func__, cpu_dai->id);
+ goto err;
+ }
+ /*
+ * Mutex protection in case the same MI2S
+ * interface using for both TX and RX so
+ * that the same clock won't be enable twice.
+ */
+ mutex_lock(&mi2s_intf_conf[index].lock);
+ if (++mi2s_intf_conf[index].ref_cnt == 1) {
+ /* Check if msm needs to provide the clock to the interface */
+ if (!mi2s_intf_conf[index].msm_is_mi2s_master) {
+ mi2s_clk[index].clk_id = mi2s_ebit_clk[index];
+ fmt = SND_SOC_DAIFMT_CBM_CFM;
+ }
+ ret = msm_mi2s_set_sclk(substream, true);
+ if (ret < 0) {
+ dev_err(rtd->card->dev,
+ "%s: afe lpass clock failed to enable MI2S clock, err:%d\n",
+ __func__, ret);
+ goto clean_up;
+ }
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret < 0) {
+ pr_err("%s: set fmt cpu dai failed for MI2S (%d), err:%d\n",
+ __func__, index, ret);
+ goto clk_off;
+ }
+ if (pdata->mi2s_gpio_p[index]) {
+ if (atomic_read(&(pdata->mi2s_gpio_ref_count[index]))
+ == 0) {
+ ret = msm_cdc_pinctrl_select_active_state(
+ pdata->mi2s_gpio_p[index]);
+ if (ret) {
+ pr_err("%s: MI2S GPIO pinctrl set active failed with %d\n",
+ __func__, ret);
+ goto clk_off;
+ }
+ }
+ atomic_inc(&(pdata->mi2s_gpio_ref_count[index]));
+ }
+ }
+clk_off:
+ if (ret < 0)
+ msm_mi2s_set_sclk(substream, false);
+clean_up:
+ if (ret < 0)
+ mi2s_intf_conf[index].ref_cnt--;
+ mutex_unlock(&mi2s_intf_conf[index].lock);
+err:
+ return ret;
+}
+
+static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int index = rtd->cpu_dai->id;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+ if (index < PRIM_MI2S || index >= MI2S_MAX) {
+ pr_err("%s:invalid MI2S DAI(%d)\n", __func__, index);
+ return;
+ }
+
+ mutex_lock(&mi2s_intf_conf[index].lock);
+ if (--mi2s_intf_conf[index].ref_cnt == 0) {
+ if (pdata->mi2s_gpio_p[index]) {
+ atomic_dec(&(pdata->mi2s_gpio_ref_count[index]));
+ if (atomic_read(&(pdata->mi2s_gpio_ref_count[index]))
+ == 0) {
+ ret = msm_cdc_pinctrl_select_sleep_state(
+ pdata->mi2s_gpio_p[index]);
+ if (ret)
+ pr_err("%s: MI2S GPIO pinctrl set sleep failed with %d\n",
+ __func__, ret);
+ }
+ }
+
+ ret = msm_mi2s_set_sclk(substream, false);
+ if (ret < 0)
+ pr_err("%s:clock disable failed for MI2S (%d); ret=%d\n",
+ __func__, index, ret);
+ }
+ mutex_unlock(&mi2s_intf_conf[index].lock);
+}
+
+static int msm_wcn_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ u32 rx_ch[WCN_CDC_SLIM_RX_CH_MAX], tx_ch[WCN_CDC_SLIM_TX_CH_MAX];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ int ret = 0;
+
+ dev_dbg(rtd->dev, "%s: %s_tx_dai_id_%d\n", __func__,
+ codec_dai->name, codec_dai->id);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret) {
+ dev_err(rtd->dev,
+ "%s: failed to get BTFM codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto err;
+ }
+
+ dev_dbg(rtd->dev, "%s: tx_ch_cnt(%d) BE id %d\n",
+ __func__, tx_ch_cnt, dai_link->id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ tx_ch_cnt, tx_ch, rx_ch_cnt, rx_ch);
+ if (ret)
+ dev_err(rtd->dev, "%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+
+err:
+ return ret;
+}
+
+static struct snd_soc_ops bengal_aux_be_ops = {
+ .startup = bengal_aux_snd_startup,
+ .shutdown = bengal_aux_snd_shutdown
+};
+
+static struct snd_soc_ops bengal_tdm_be_ops = {
+ .hw_params = bengal_tdm_snd_hw_params,
+ .startup = bengal_tdm_snd_startup,
+ .shutdown = bengal_tdm_snd_shutdown
+};
+
+static struct snd_soc_ops msm_mi2s_be_ops = {
+ .startup = msm_mi2s_snd_startup,
+ .shutdown = msm_mi2s_snd_shutdown,
+};
+
+static struct snd_soc_ops msm_fe_qos_ops = {
+ .prepare = msm_fe_qos_prepare,
+};
+
+static struct snd_soc_ops msm_cdc_dma_be_ops = {
+ .startup = msm_snd_cdc_dma_startup,
+ .hw_params = msm_snd_cdc_dma_hw_params,
+};
+
+static struct snd_soc_ops msm_wcn_ops = {
+ .hw_params = msm_wcn_hw_params,
+};
+
+static int msm_dmic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct msm_asoc_mach_data *pdata = NULL;
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ int ret = 0;
+ u32 dmic_idx;
+ int *dmic_gpio_cnt;
+ struct device_node *dmic_gpio;
+ char *wname;
+
+ wname = strpbrk(w->name, "0123");
+ if (!wname) {
+ dev_err(component->dev, "%s: widget not found\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = kstrtouint(wname, 10, &dmic_idx);
+ if (ret < 0) {
+ dev_err(component->dev, "%s: Invalid DMIC line on the codec\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ pdata = snd_soc_card_get_drvdata(component->card);
+
+ switch (dmic_idx) {
+ case 0:
+ case 1:
+ dmic_gpio_cnt = &dmic_0_1_gpio_cnt;
+ dmic_gpio = pdata->dmic01_gpio_p;
+ break;
+ case 2:
+ case 3:
+ dmic_gpio_cnt = &dmic_2_3_gpio_cnt;
+ dmic_gpio = pdata->dmic23_gpio_p;
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid DMIC Selection\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(component->dev, "%s: event %d DMIC%d dmic_gpio_cnt %d\n",
+ __func__, event, dmic_idx, *dmic_gpio_cnt);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ (*dmic_gpio_cnt)++;
+ if (*dmic_gpio_cnt == 1) {
+ ret = msm_cdc_pinctrl_select_active_state(
+ dmic_gpio);
+ if (ret < 0) {
+ pr_err("%s: gpio set cannot be activated %sd",
+ __func__, "dmic_gpio");
+ return ret;
+ }
+ }
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ (*dmic_gpio_cnt)--;
+ if (*dmic_gpio_cnt == 0) {
+ ret = msm_cdc_pinctrl_select_sleep_state(
+ dmic_gpio);
+ if (ret < 0) {
+ pr_err("%s: gpio set cannot be de-activated %sd",
+ __func__, "dmic_gpio");
+ return ret;
+ }
+ }
+ break;
+ default:
+ pr_err("%s: invalid DAPM event %d\n", __func__, event);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget msm_int_dapm_widgets[] = {
+ SND_SOC_DAPM_MIC("Analog Mic1", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic2", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic3", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic4", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic0", msm_dmic_event),
+ SND_SOC_DAPM_MIC("Digital Mic1", msm_dmic_event),
+ SND_SOC_DAPM_MIC("Digital Mic2", msm_dmic_event),
+ SND_SOC_DAPM_MIC("Digital Mic3", msm_dmic_event),
+};
+
+static int msm_wcn_init(struct snd_soc_pcm_runtime *rtd)
+{
+ unsigned int rx_ch[WCN_CDC_SLIM_RX_CH_MAX] = {157, 158};
+ unsigned int tx_ch[WCN_CDC_SLIM_TX_CH_MAX] = {159, 160, 161};
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ return snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+}
+
+static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = -EINVAL;
+ struct snd_soc_component *component;
+ struct snd_soc_dapm_context *dapm;
+ struct snd_card *card;
+ struct snd_info_entry *entry;
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(rtd->card);
+
+ component = snd_soc_rtdcom_lookup(rtd, "bolero_codec");
+ if (!component) {
+ pr_err("%s: could not find component for bolero_codec\n",
+ __func__);
+ return ret;
+ }
+
+ dapm = snd_soc_component_get_dapm(component);
+
+ ret = snd_soc_add_component_controls(component, msm_int_snd_controls,
+ ARRAY_SIZE(msm_int_snd_controls));
+ if (ret < 0) {
+ pr_err("%s: add_component_controls failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ ret = snd_soc_add_component_controls(component, msm_common_snd_controls,
+ ARRAY_SIZE(msm_common_snd_controls));
+ if (ret < 0) {
+ pr_err("%s: add common snd controls failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ snd_soc_dapm_new_controls(dapm, msm_int_dapm_widgets,
+ ARRAY_SIZE(msm_int_dapm_widgets));
+
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
+ snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3");
+
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic1");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic2");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic3");
+ snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
+
+ snd_soc_dapm_sync(dapm);
+
+ bolero_set_port_map(component, ARRAY_SIZE(sm_port_map),
+ sm_port_map);
+ card = rtd->card->snd_card;
+ if (!pdata->codec_root) {
+ entry = snd_info_create_subdir(card->module, "codecs",
+ card->proc_root);
+ if (!entry) {
+ pr_debug("%s: Cannot create codecs module entry\n",
+ __func__);
+ ret = 0;
+ goto err;
+ }
+ pdata->codec_root = entry;
+ }
+ bolero_info_create_codec_entry(pdata->codec_root, component);
+ bolero_register_wake_irq(component, false);
+ codec_reg_done = true;
+ return 0;
+err:
+ return ret;
+}
+
+static void *def_wcd_mbhc_cal(void)
+{
+ void *wcd_mbhc_cal;
+ struct wcd_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_high;
+
+ wcd_mbhc_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
+ WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL);
+ if (!wcd_mbhc_cal)
+ return NULL;
+
+ WCD_MBHC_CAL_PLUG_TYPE_PTR(wcd_mbhc_cal)->v_hs_max = WCD_MBHC_HS_V_MAX;
+ WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal)->num_btn = WCD_MBHC_DEF_BUTTONS;
+ btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal);
+ btn_high = ((void *)&btn_cfg->_v_btn_low) +
+ (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
+
+ btn_high[0] = 75;
+ btn_high[1] = 150;
+ btn_high[2] = 237;
+ btn_high[3] = 500;
+ btn_high[4] = 500;
+ btn_high[5] = 500;
+ btn_high[6] = 500;
+ btn_high[7] = 500;
+
+ return wcd_mbhc_cal;
+}
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_common_dai_links[] = {
+ /* FrontEnd DAI Links */
+ {/* hw:x,0 */
+ .name = MSM_DAILINK_NAME(Media1),
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+ {/* hw:x,1 */
+ .name = MSM_DAILINK_NAME(Media2),
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
+ {/* hw:x,2 */
+ .name = "VoiceMMode1",
+ .stream_name = "VoiceMMode1",
+ .cpu_dai_name = "VoiceMMode1",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .id = MSM_FRONTEND_DAI_VOICEMMODE1,
+ },
+ {/* hw:x,3 */
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {/* hw:x,4 */
+ .name = MSM_DAILINK_NAME(ULL),
+ .stream_name = "MultiMedia3",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-dsp.2",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ {/* hw:x,5 */
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .dpcm_playback = 1,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {/* hw:x,6 */
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .dpcm_capture = 1,
+ .ignore_suspend = 1,
+ },
+ {/* hw:x,7 */
+ .name = MSM_DAILINK_NAME(Compress1),
+ .stream_name = "Compress1",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS,
+ .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,
+ /* this dainlink has playback support */
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ /* Hostless PCM purpose */
+ {/* hw:x,8 */
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,9 */
+ .name = MSM_DAILINK_NAME(LowLatency),
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ .ops = &msm_fe_qos_ops,
+ },
+ {/* hw:x,10 */
+ .name = "Listen 1 Audio Service",
+ .stream_name = "Listen 1 Audio Service",
+ .cpu_dai_name = "LSM1",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .id = MSM_FRONTEND_DAI_LSM1,
+ },
+ /* Multiple Tunnel instances */
+ {/* hw:x,11 */
+ .name = MSM_DAILINK_NAME(Compress2),
+ .stream_name = "Compress2",
+ .cpu_dai_name = "MultiMedia7",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA7,
+ },
+ {/* hw:x,12 */
+ .name = MSM_DAILINK_NAME(MultiMedia10),
+ .stream_name = "MultiMedia10",
+ .cpu_dai_name = "MultiMedia10",
+ .platform_name = "msm-pcm-dsp.1",
+ .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,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA10,
+ },
+ {/* hw:x,13 */
+ .name = MSM_DAILINK_NAME(ULL_NOIRQ),
+ .stream_name = "MM_NOIRQ",
+ .cpu_dai_name = "MultiMedia8",
+ .platform_name = "msm-pcm-dsp-noirq",
+ .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,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+ .ops = &msm_fe_qos_ops,
+ },
+ /* HDMI Hostless */
+ {/* hw:x,14 */
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,15 */
+ .name = "VoiceMMode2",
+ .stream_name = "VoiceMMode2",
+ .cpu_dai_name = "VoiceMMode2",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .id = MSM_FRONTEND_DAI_VOICEMMODE2,
+ },
+ /* LSM FE */
+ {/* hw:x,16 */
+ .name = "Listen 2 Audio Service",
+ .stream_name = "Listen 2 Audio Service",
+ .cpu_dai_name = "LSM2",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .id = MSM_FRONTEND_DAI_LSM2,
+ },
+ {/* hw:x,17 */
+ .name = "Listen 3 Audio Service",
+ .stream_name = "Listen 3 Audio Service",
+ .cpu_dai_name = "LSM3",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .id = MSM_FRONTEND_DAI_LSM3,
+ },
+ {/* hw:x,18 */
+ .name = "Listen 4 Audio Service",
+ .stream_name = "Listen 4 Audio Service",
+ .cpu_dai_name = "LSM4",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .id = MSM_FRONTEND_DAI_LSM4,
+ },
+ {/* hw:x,19 */
+ .name = "Listen 5 Audio Service",
+ .stream_name = "Listen 5 Audio Service",
+ .cpu_dai_name = "LSM5",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .id = MSM_FRONTEND_DAI_LSM5,
+ },
+ {/* hw:x,20 */
+ .name = "Listen 6 Audio Service",
+ .stream_name = "Listen 6 Audio Service",
+ .cpu_dai_name = "LSM6",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .id = MSM_FRONTEND_DAI_LSM6,
+ },
+ {/* hw:x,21 */
+ .name = "Listen 7 Audio Service",
+ .stream_name = "Listen 7 Audio Service",
+ .cpu_dai_name = "LSM7",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .id = MSM_FRONTEND_DAI_LSM7,
+ },
+ {/* hw:x,22 */
+ .name = "Listen 8 Audio Service",
+ .stream_name = "Listen 8 Audio Service",
+ .cpu_dai_name = "LSM8",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .id = MSM_FRONTEND_DAI_LSM8,
+ },
+ {/* hw:x,23 */
+ .name = MSM_DAILINK_NAME(Media9),
+ .stream_name = "MultiMedia9",
+ .cpu_dai_name = "MultiMedia9",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA9,
+ },
+ {/* hw:x,24 */
+ .name = MSM_DAILINK_NAME(Compress4),
+ .stream_name = "Compress4",
+ .cpu_dai_name = "MultiMedia11",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA11,
+ },
+ {/* hw:x,25 */
+ .name = MSM_DAILINK_NAME(Compress5),
+ .stream_name = "Compress5",
+ .cpu_dai_name = "MultiMedia12",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA12,
+ },
+ {/* hw:x,26 */
+ .name = MSM_DAILINK_NAME(Compress6),
+ .stream_name = "Compress6",
+ .cpu_dai_name = "MultiMedia13",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA13,
+ },
+ {/* hw:x,27 */
+ .name = MSM_DAILINK_NAME(Compress7),
+ .stream_name = "Compress7",
+ .cpu_dai_name = "MultiMedia14",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA14,
+ },
+ {/* hw:x,28 */
+ .name = MSM_DAILINK_NAME(Compress8),
+ .stream_name = "Compress8",
+ .cpu_dai_name = "MultiMedia15",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA15,
+ },
+ {/* hw:x,29 */
+ .name = MSM_DAILINK_NAME(ULL_NOIRQ_2),
+ .stream_name = "MM_NOIRQ_2",
+ .cpu_dai_name = "MultiMedia16",
+ .platform_name = "msm-pcm-dsp-noirq",
+ .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,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA16,
+ .ops = &msm_fe_qos_ops,
+ },
+ {/* hw:x,30 */
+ .name = "CDC_DMA Hostless",
+ .stream_name = "CDC_DMA Hostless",
+ .cpu_dai_name = "CDC_DMA_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dailink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,31 */
+ .name = "TX3_CDC_DMA Hostless",
+ .stream_name = "TX3_CDC_DMA Hostless",
+ .cpu_dai_name = "TX3_CDC_DMA_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,32 */
+ .name = "Tertiary MI2S TX_Hostless",
+ .stream_name = "Tertiary MI2S_TX Hostless Capture",
+ .cpu_dai_name = "TERT_MI2S_TX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+};
+
+static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
+ {/* hw:x,34 */
+ .name = MSM_DAILINK_NAME(ASM Loopback),
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
+ {/* hw:x,35 */
+ .name = "USB Audio Hostless",
+ .stream_name = "USB Audio Hostless",
+ .cpu_dai_name = "USBAUDIO_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,36 */
+ .name = "SLIMBUS_7 Hostless",
+ .stream_name = "SLIMBUS_7 Hostless",
+ .cpu_dai_name = "SLIMBUS7_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,37 */
+ .name = "Compress Capture",
+ .stream_name = "Compress9",
+ .cpu_dai_name = "MultiMedia17",
+ .platform_name = "msm-compress-dsp",
+ .dynamic = 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_MULTIMEDIA17,
+ },
+ {/* hw:x,38 */
+ .name = "SLIMBUS_8 Hostless",
+ .stream_name = "SLIMBUS_8 Hostless",
+ .cpu_dai_name = "SLIMBUS8_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,39 */
+ .name = LPASS_BE_TX_CDC_DMA_TX_5,
+ .stream_name = "TX CDC DMA5 Capture",
+ .cpu_dai_name = "msm-dai-cdc-dma-dev.45115",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "bolero_codec",
+ .codec_dai_name = "tx_macro_tx3",
+ .id = MSM_BACKEND_DAI_TX_CDC_DMA_TX_5,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_cdc_dma_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link msm_common_be_dai_links[] = {
+ /* Backend AFE DAI Links */
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ /* Incall Music 2 BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE2_PLAYBACK_TX,
+ .stream_name = "Voice2 Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32770",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_USB_AUDIO_RX,
+ .stream_name = "USB Audio Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.28672",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .dynamic_be = 1,
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_USB_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_USB_AUDIO_TX,
+ .stream_name = "USB Audio Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.28673",
+ .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_USB_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_RX_0,
+ .stream_name = "Primary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36864",
+ .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_PRI_TDM_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_tdm_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_TDM_TX_0,
+ .stream_name = "Primary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36865",
+ .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_PRI_TDM_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_RX_0,
+ .stream_name = "Secondary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36880",
+ .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_SEC_TDM_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_tdm_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_TDM_TX_0,
+ .stream_name = "Secondary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36881",
+ .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_SEC_TDM_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_TDM_RX_0,
+ .stream_name = "Tertiary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36896",
+ .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_TERT_TDM_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_tdm_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_TDM_TX_0,
+ .stream_name = "Tertiary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36897",
+ .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_TERT_TDM_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_RX_0,
+ .stream_name = "Quaternary TDM0 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36912",
+ .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_QUAT_TDM_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_tdm_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_TDM_TX_0,
+ .stream_name = "Quaternary TDM0 Capture",
+ .cpu_dai_name = "msm-dai-q6-tdm.36913",
+ .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_QUAT_TDM_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_wcn_btfm_be_dai_links[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_7_RX,
+ .stream_name = "Slimbus7 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16398",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ /* BT codec driver determines capabilities based on
+ * dai name, bt codecdai name should always contains
+ * supported usecase information
+ */
+ .codec_dai_name = "btfm_bt_sco_a2dp_slim_rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .init = &msm_wcn_init,
+ .ops = &msm_wcn_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_7_TX,
+ .stream_name = "Slimbus7 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16399",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_bt_sco_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_8_TX,
+ .stream_name = "Slimbus8 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16401",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_fm_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = {
+ {
+ .name = LPASS_BE_PRI_MI2S_RX,
+ .stream_name = "Primary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_PRI_MI2S_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_MI2S_TX,
+ .stream_name = "Primary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_PRI_MI2S_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_MI2S_RX,
+ .stream_name = "Secondary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_MI2S_TX,
+ .stream_name = "Secondary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_RX,
+ .stream_name = "Tertiary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_MI2S_TX,
+ .stream_name = "Tertiary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_MI2S_RX,
+ .stream_name = "Quaternary MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_MI2S_TX,
+ .stream_name = "Quaternary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = {
+ /* Primary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_aux_be_ops,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_aux_be_ops,
+ .ignore_suspend = 1,
+ },
+ /* Secondary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_SEC_AUXPCM_RX,
+ .stream_name = "Sec AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_aux_be_ops,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SEC_AUXPCM_TX,
+ .stream_name = "Sec AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_aux_be_ops,
+ .ignore_suspend = 1,
+ },
+ /* Tertiary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_TERT_AUXPCM_RX,
+ .stream_name = "Tert AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_TERT_AUXPCM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_aux_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_TERT_AUXPCM_TX,
+ .stream_name = "Tert AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_TERT_AUXPCM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_aux_be_ops,
+ .ignore_suspend = 1,
+ },
+ /* Quaternary AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_QUAT_AUXPCM_RX,
+ .stream_name = "Quat AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.4",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_QUAT_AUXPCM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_aux_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_QUAT_AUXPCM_TX,
+ .stream_name = "Quat AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.4",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_QUAT_AUXPCM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &bengal_aux_be_ops,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = {
+ /* RX CDC DMA Backend DAI Links */
+ {
+ .name = LPASS_BE_RX_CDC_DMA_RX_0,
+ .stream_name = "RX CDC DMA0 Playback",
+ .cpu_dai_name = "msm-dai-cdc-dma-dev.45104",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "bolero_codec",
+ .codec_dai_name = "rx_macro_rx1",
+ .dynamic_be = 1,
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_RX_CDC_DMA_RX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_cdc_dma_be_ops,
+ },
+ {
+ .name = LPASS_BE_RX_CDC_DMA_RX_1,
+ .stream_name = "RX CDC DMA1 Playback",
+ .cpu_dai_name = "msm-dai-cdc-dma-dev.45106",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "bolero_codec",
+ .codec_dai_name = "rx_macro_rx2",
+ .dynamic_be = 1,
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_RX_CDC_DMA_RX_1,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_cdc_dma_be_ops,
+ },
+ {
+ .name = LPASS_BE_RX_CDC_DMA_RX_2,
+ .stream_name = "RX CDC DMA2 Playback",
+ .cpu_dai_name = "msm-dai-cdc-dma-dev.45108",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "bolero_codec",
+ .codec_dai_name = "rx_macro_rx3",
+ .dynamic_be = 1,
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_RX_CDC_DMA_RX_2,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_cdc_dma_be_ops,
+ },
+ {
+ .name = LPASS_BE_RX_CDC_DMA_RX_3,
+ .stream_name = "RX CDC DMA3 Playback",
+ .cpu_dai_name = "msm-dai-cdc-dma-dev.45110",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "bolero_codec",
+ .codec_dai_name = "rx_macro_rx4",
+ .dynamic_be = 1,
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_RX_CDC_DMA_RX_3,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_cdc_dma_be_ops,
+ },
+ /* TX CDC DMA Backend DAI Links */
+ {
+ .name = LPASS_BE_TX_CDC_DMA_TX_3,
+ .stream_name = "TX CDC DMA3 Capture",
+ .cpu_dai_name = "msm-dai-cdc-dma-dev.45111",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "bolero_codec",
+ .codec_dai_name = "tx_macro_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_TX_CDC_DMA_TX_3,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_cdc_dma_be_ops,
+ },
+ {
+ .name = LPASS_BE_TX_CDC_DMA_TX_4,
+ .stream_name = "TX CDC DMA4 Capture",
+ .cpu_dai_name = "msm-dai-cdc-dma-dev.45113",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "bolero_codec",
+ .codec_dai_name = "tx_macro_tx2",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_TX_CDC_DMA_TX_4,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_cdc_dma_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link msm_va_cdc_dma_be_dai_links[] = {
+ {
+ .name = LPASS_BE_VA_CDC_DMA_TX_0,
+ .stream_name = "VA CDC DMA0 Capture",
+ .cpu_dai_name = "msm-dai-cdc-dma-dev.45089",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "bolero_codec",
+ .codec_dai_name = "va_macro_tx1",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .init = &msm_int_audrx_init,
+ .id = MSM_BACKEND_DAI_VA_CDC_DMA_TX_0,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_cdc_dma_be_ops,
+ },
+ {
+ .name = LPASS_BE_VA_CDC_DMA_TX_1,
+ .stream_name = "VA CDC DMA1 Capture",
+ .cpu_dai_name = "msm-dai-cdc-dma-dev.45091",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "bolero_codec",
+ .codec_dai_name = "va_macro_tx2",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_VA_CDC_DMA_TX_1,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_cdc_dma_be_ops,
+ },
+ {
+ .name = LPASS_BE_VA_CDC_DMA_TX_2,
+ .stream_name = "VA CDC DMA2 Capture",
+ .cpu_dai_name = "msm-dai-cdc-dma-dev.45093",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "bolero_codec",
+ .codec_dai_name = "va_macro_tx3",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_VA_CDC_DMA_TX_2,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_cdc_dma_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link msm_afe_rxtx_lb_be_dai_link[] = {
+ {
+ .name = LPASS_BE_AFE_LOOPBACK_TX,
+ .stream_name = "AFE Loopback Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.24577",
+ .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_AFE_LOOPBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link msm_bengal_dai_links[
+ ARRAY_SIZE(msm_common_dai_links) +
+ ARRAY_SIZE(msm_common_misc_fe_dai_links) +
+ ARRAY_SIZE(msm_common_be_dai_links) +
+ ARRAY_SIZE(msm_mi2s_be_dai_links) +
+ ARRAY_SIZE(msm_auxpcm_be_dai_links) +
+ ARRAY_SIZE(msm_rx_tx_cdc_dma_be_dai_links) +
+ ARRAY_SIZE(msm_va_cdc_dma_be_dai_links) +
+ ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link) +
+ ARRAY_SIZE(msm_wcn_btfm_be_dai_links)];
+
+static int msm_populate_dai_link_component_of_node(
+ struct snd_soc_card *card)
+{
+ int i, index, ret = 0;
+ struct device *cdev = card->dev;
+ struct snd_soc_dai_link *dai_link = card->dai_link;
+ struct device_node *np;
+
+ if (!cdev) {
+ dev_err(cdev, "%s: Sound card device memory NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < card->num_links; i++) {
+ if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node)
+ continue;
+
+ /* populate platform_of_node for snd card dai links */
+ if (dai_link[i].platform_name &&
+ !dai_link[i].platform_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-platform-names",
+ dai_link[i].platform_name);
+ if (index < 0) {
+ dev_err(cdev,
+ "%s: No match found for platform name: %s\n",
+ __func__, dai_link[i].platform_name);
+ ret = index;
+ goto err;
+ }
+ np = of_parse_phandle(cdev->of_node, "asoc-platform",
+ index);
+ if (!np) {
+ dev_err(cdev,
+ "%s: retrieving phandle for platform %s, index %d failed\n",
+ __func__, dai_link[i].platform_name,
+ index);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].platform_of_node = np;
+ dai_link[i].platform_name = NULL;
+ }
+
+ /* populate cpu_of_node for snd card dai links */
+ if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-cpu-names",
+ dai_link[i].cpu_dai_name);
+ if (index >= 0) {
+ np = of_parse_phandle(cdev->of_node, "asoc-cpu",
+ index);
+ if (!np) {
+ dev_err(cdev,
+ "%s: retrieving phandle for cpu dai %s failed\n",
+ __func__,
+ dai_link[i].cpu_dai_name);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].cpu_of_node = np;
+ dai_link[i].cpu_dai_name = NULL;
+ }
+ }
+
+ /* populate codec_of_node for snd card dai links */
+ if (dai_link[i].codec_name && !dai_link[i].codec_of_node) {
+ index = of_property_match_string(cdev->of_node,
+ "asoc-codec-names",
+ dai_link[i].codec_name);
+ if (index < 0)
+ continue;
+ np = of_parse_phandle(cdev->of_node, "asoc-codec",
+ index);
+ if (!np) {
+ dev_err(cdev,
+ "%s: retrieving phandle for codec %s failed\n",
+ __func__, dai_link[i].codec_name);
+ ret = -ENODEV;
+ goto err;
+ }
+ dai_link[i].codec_of_node = np;
+ dai_link[i].codec_name = NULL;
+ }
+ }
+
+err:
+ return ret;
+}
+
+static int msm_audrx_stub_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = -EINVAL;
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, "msm-stub-codec");
+
+ if (!component) {
+ pr_err("* %s: No match for msm-stub-codec component\n",
+ __func__);
+ return ret;
+ }
+
+ ret = snd_soc_add_component_controls(component, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+ if (ret < 0) {
+ dev_err(component->dev,
+ "%s: add_codec_controls failed, err = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int msm_snd_stub_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ return 0;
+}
+
+static struct snd_soc_ops msm_stub_be_ops = {
+ .hw_params = msm_snd_stub_hw_params,
+};
+
+struct snd_soc_card snd_soc_card_stub_msm = {
+ .name = "bengal-stub-snd-card",
+};
+
+static struct snd_soc_dai_link msm_stub_fe_dai_links[] = {
+ /* FrontEnd DAI Links */
+ {
+ .name = "MSMSTUB Media1",
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp.0",
+ .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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+};
+
+static struct snd_soc_dai_link msm_stub_be_dai_links[] = {
+ /* Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .init = &msm_audrx_stub_init,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ .ops = &msm_stub_be_ops,
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6-auxpcm.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ .ops = &msm_stub_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link msm_stub_dai_links[
+ ARRAY_SIZE(msm_stub_fe_dai_links) +
+ ARRAY_SIZE(msm_stub_be_dai_links)];
+
+static const struct of_device_id bengal_asoc_machine_of_match[] = {
+ { .compatible = "qcom,bengal-asoc-snd",
+ .data = "codec"},
+ { .compatible = "qcom,bengal-asoc-snd-stub",
+ .data = "stub_codec"},
+ {},
+};
+
+static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
+{
+ struct snd_soc_card *card = NULL;
+ struct snd_soc_dai_link *dailink = NULL;
+ int len_1 = 0;
+ int len_2 = 0;
+ int total_links = 0;
+ int rc = 0;
+ u32 mi2s_audio_intf = 0;
+ u32 auxpcm_audio_intf = 0;
+ u32 rxtx_bolero_codec = 0;
+ u32 va_bolero_codec = 0;
+ u32 val = 0;
+ u32 wcn_btfm_intf = 0;
+ const struct of_device_id *match;
+
+ match = of_match_node(bengal_asoc_machine_of_match, dev->of_node);
+ if (!match) {
+ dev_err(dev, "%s: No DT match found for sound card\n",
+ __func__);
+ return NULL;
+ }
+
+ if (!strcmp(match->data, "codec")) {
+ card = &snd_soc_card_bengal_msm;
+
+ memcpy(msm_bengal_dai_links + total_links,
+ msm_common_dai_links,
+ sizeof(msm_common_dai_links));
+ total_links += ARRAY_SIZE(msm_common_dai_links);
+
+ memcpy(msm_bengal_dai_links + total_links,
+ msm_common_misc_fe_dai_links,
+ sizeof(msm_common_misc_fe_dai_links));
+ total_links += ARRAY_SIZE(msm_common_misc_fe_dai_links);
+
+ memcpy(msm_bengal_dai_links + total_links,
+ msm_common_be_dai_links,
+ sizeof(msm_common_be_dai_links));
+ total_links += ARRAY_SIZE(msm_common_be_dai_links);
+
+ rc = of_property_read_u32(dev->of_node,
+ "qcom,rxtx-bolero-codec",
+ &rxtx_bolero_codec);
+ if (rc) {
+ dev_dbg(dev, "%s: No DT match RXTX Macro codec\n",
+ __func__);
+ } else {
+ if (rxtx_bolero_codec) {
+ memcpy(msm_bengal_dai_links + total_links,
+ msm_rx_tx_cdc_dma_be_dai_links,
+ sizeof(msm_rx_tx_cdc_dma_be_dai_links));
+ total_links +=
+ ARRAY_SIZE(
+ msm_rx_tx_cdc_dma_be_dai_links);
+ }
+ }
+
+ rc = of_property_read_u32(dev->of_node, "qcom,va-bolero-codec",
+ &va_bolero_codec);
+ if (rc) {
+ dev_dbg(dev, "%s: No DT match VA Macro codec\n",
+ __func__);
+ } else {
+ if (va_bolero_codec) {
+ memcpy(msm_bengal_dai_links + total_links,
+ msm_va_cdc_dma_be_dai_links,
+ sizeof(msm_va_cdc_dma_be_dai_links));
+ total_links +=
+ ARRAY_SIZE(msm_va_cdc_dma_be_dai_links);
+ }
+ }
+
+ rc = of_property_read_u32(dev->of_node, "qcom,mi2s-audio-intf",
+ &mi2s_audio_intf);
+ if (rc) {
+ dev_dbg(dev, "%s: No DT match MI2S audio interface\n",
+ __func__);
+ } else {
+ if (mi2s_audio_intf) {
+ memcpy(msm_bengal_dai_links + total_links,
+ msm_mi2s_be_dai_links,
+ sizeof(msm_mi2s_be_dai_links));
+ total_links +=
+ ARRAY_SIZE(msm_mi2s_be_dai_links);
+ }
+ }
+
+ rc = of_property_read_u32(dev->of_node,
+ "qcom,auxpcm-audio-intf",
+ &auxpcm_audio_intf);
+ if (rc) {
+ dev_dbg(dev, "%s: No DT match Aux PCM interface\n",
+ __func__);
+ } else {
+ if (auxpcm_audio_intf) {
+ memcpy(msm_bengal_dai_links + total_links,
+ msm_auxpcm_be_dai_links,
+ sizeof(msm_auxpcm_be_dai_links));
+ total_links +=
+ ARRAY_SIZE(msm_auxpcm_be_dai_links);
+ }
+ }
+
+ rc = of_property_read_u32(dev->of_node, "qcom,afe-rxtx-lb",
+ &val);
+ if (!rc && val) {
+ memcpy(msm_bengal_dai_links + total_links,
+ msm_afe_rxtx_lb_be_dai_link,
+ sizeof(msm_afe_rxtx_lb_be_dai_link));
+ total_links +=
+ ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link);
+ }
+
+ rc = of_property_read_u32(dev->of_node, "qcom,wcn-btfm",
+ &wcn_btfm_intf);
+ if (rc) {
+ dev_dbg(dev, "%s: No DT match wcn btfm interface\n",
+ __func__);
+ } else {
+ if (wcn_btfm_intf) {
+ memcpy(msm_bengal_dai_links + total_links,
+ msm_wcn_btfm_be_dai_links,
+ sizeof(msm_wcn_btfm_be_dai_links));
+ total_links +=
+ ARRAY_SIZE(msm_wcn_btfm_be_dai_links);
+ }
+ }
+ dailink = msm_bengal_dai_links;
+ } else if (!strcmp(match->data, "stub_codec")) {
+ card = &snd_soc_card_stub_msm;
+ len_1 = ARRAY_SIZE(msm_stub_fe_dai_links);
+ len_2 = len_1 + ARRAY_SIZE(msm_stub_be_dai_links);
+
+ memcpy(msm_stub_dai_links,
+ msm_stub_fe_dai_links,
+ sizeof(msm_stub_fe_dai_links));
+ memcpy(msm_stub_dai_links + len_1,
+ msm_stub_be_dai_links,
+ sizeof(msm_stub_be_dai_links));
+
+ dailink = msm_stub_dai_links;
+ total_links = len_2;
+ }
+
+ if (card) {
+ card->dai_link = dailink;
+ card->num_links = total_links;
+ }
+
+ return card;
+}
+
+static int msm_aux_codec_init(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ int ret = 0;
+ void *mbhc_calibration;
+ struct snd_info_entry *entry;
+ struct snd_card *card = component->card->snd_card;
+ struct msm_asoc_mach_data *pdata;
+
+ snd_soc_dapm_ignore_suspend(dapm, "EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "AUX");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
+ snd_soc_dapm_sync(dapm);
+
+ pdata = snd_soc_card_get_drvdata(component->card);
+ if (!pdata->codec_root) {
+ entry = snd_info_create_subdir(card->module, "codecs",
+ card->proc_root);
+ if (!entry) {
+ dev_dbg(component->dev, "%s: Cannot create codecs module entry\n",
+ __func__);
+ ret = 0;
+ goto mbhc_cfg_cal;
+ }
+ pdata->codec_root = entry;
+ }
+ wcd937x_info_create_codec_entry(pdata->codec_root, component);
+
+mbhc_cfg_cal:
+ mbhc_calibration = def_wcd_mbhc_cal();
+ if (!mbhc_calibration)
+ return -ENOMEM;
+ wcd_mbhc_cfg.calibration = mbhc_calibration;
+ ret = wcd937x_mbhc_hs_detect(component, &wcd_mbhc_cfg);
+ if (ret) {
+ dev_err(component->dev, "%s: mbhc hs detect failed, err:%d\n",
+ __func__, ret);
+ goto err_hs_detect;
+ }
+ return 0;
+
+err_hs_detect:
+ kfree(mbhc_calibration);
+ return ret;
+}
+
+static int msm_init_aux_dev(struct platform_device *pdev,
+ struct snd_soc_card *card)
+{
+ struct device_node *wsa_of_node;
+ struct device_node *aux_codec_of_node;
+ u32 wsa_max_devs;
+ u32 wsa_dev_cnt;
+ 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;
+ const char *auxdev_name_prefix[1];
+ char *dev_name_str = NULL;
+ int found = 0;
+ int codecs_found = 0;
+ int ret = 0;
+
+ /* Get maximum WSA device count for this platform */
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,wsa-max-devs", &wsa_max_devs);
+ if (ret) {
+ dev_info(&pdev->dev,
+ "%s: wsa-max-devs property missing in DT %s, ret = %d\n",
+ __func__, pdev->dev.of_node->full_name, ret);
+ wsa_max_devs = 0;
+ goto codec_aux_dev;
+ }
+ if (wsa_max_devs == 0) {
+ dev_warn(&pdev->dev,
+ "%s: Max WSA devices is 0 for this target?\n",
+ __func__);
+ goto codec_aux_dev;
+ }
+
+ /* Get count of WSA device phandles for this platform */
+ wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node,
+ "qcom,wsa-devs", NULL);
+ if (wsa_dev_cnt == -ENOENT) {
+ dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n",
+ __func__);
+ goto err;
+ } else if (wsa_dev_cnt <= 0) {
+ dev_err(&pdev->dev,
+ "%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n",
+ __func__, wsa_dev_cnt);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /*
+ * Expect total phandles count to be NOT less than maximum possible
+ * WSA count. However, if it is less, then assign same value to
+ * max count as well.
+ */
+ if (wsa_dev_cnt < wsa_max_devs) {
+ dev_dbg(&pdev->dev,
+ "%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n",
+ __func__, wsa_max_devs, wsa_dev_cnt);
+ wsa_max_devs = wsa_dev_cnt;
+ }
+
+ /* Make sure prefix string passed for each WSA device */
+ ret = of_property_count_strings(pdev->dev.of_node,
+ "qcom,wsa-aux-dev-prefix");
+ if (ret != wsa_dev_cnt) {
+ dev_err(&pdev->dev,
+ "%s: expecting %d wsa prefix. Defined only %d in DT\n",
+ __func__, wsa_dev_cnt, ret);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /*
+ * Alloc mem to store phandle and index info of WSA device, if already
+ * registered with ALSA core
+ */
+ wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs,
+ sizeof(struct msm_wsa881x_dev_info),
+ GFP_KERNEL);
+ if (!wsa881x_dev_info) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /*
+ * search and check whether all WSA devices are already
+ * registered with ALSA core or not. If found a node, store
+ * the node and the index in a local array of struct for later
+ * use.
+ */
+ for (i = 0; i < wsa_dev_cnt; i++) {
+ wsa_of_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,wsa-devs", i);
+ if (unlikely(!wsa_of_node)) {
+ /* we should not be here */
+ dev_err(&pdev->dev,
+ "%s: wsa dev node is not present\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ if (soc_find_component(wsa_of_node, NULL)) {
+ /* WSA device registered with ALSA core */
+ wsa881x_dev_info[found].of_node = wsa_of_node;
+ wsa881x_dev_info[found].index = i;
+ found++;
+ if (found == wsa_max_devs)
+ break;
+ }
+ }
+
+ if (found < wsa_max_devs) {
+ dev_dbg(&pdev->dev,
+ "%s: failed to find %d components. Found only %d\n",
+ __func__, wsa_max_devs, found);
+ return -EPROBE_DEFER;
+ }
+ dev_info(&pdev->dev,
+ "%s: found %d wsa881x devices registered with ALSA core\n",
+ __func__, found);
+
+codec_aux_dev:
+ /* Get maximum aux codec device count for this platform */
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,codec-max-aux-devs",
+ &codec_max_aux_devs);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: codec-max-aux-devs property missing in DT %s, ret = %d\n",
+ __func__, pdev->dev.of_node->full_name, ret);
+ codec_max_aux_devs = 0;
+ goto aux_dev_register;
+ }
+ if (codec_max_aux_devs == 0) {
+ dev_dbg(&pdev->dev,
+ "%s: Max aux codec devices is 0 for this target?\n",
+ __func__);
+ goto aux_dev_register;
+ }
+
+ /* Get count of aux codec device phandles for this platform */
+ codec_aux_dev_cnt = of_count_phandle_with_args(
+ pdev->dev.of_node,
+ "qcom,codec-aux-devs", NULL);
+ if (codec_aux_dev_cnt == -ENOENT) {
+ dev_warn(&pdev->dev, "%s: No aux codec defined in DT.\n",
+ __func__);
+ goto err;
+ } else if (codec_aux_dev_cnt <= 0) {
+ dev_err(&pdev->dev,
+ "%s: Error reading aux codec device from DT, dev_cnt=%d\n",
+ __func__, codec_aux_dev_cnt);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /*
+ * Expect total phandles count to be NOT less than maximum possible
+ * AUX device count. However, if it is less, then assign same value to
+ * max count as well.
+ */
+ if (codec_aux_dev_cnt < codec_max_aux_devs) {
+ dev_dbg(&pdev->dev,
+ "%s: codec_max_aux_devs = %d cannot exceed codec_aux_dev_cnt = %d\n",
+ __func__, codec_max_aux_devs,
+ codec_aux_dev_cnt);
+ codec_max_aux_devs = codec_aux_dev_cnt;
+ }
+
+ /*
+ * Alloc mem to store phandle and index info of aux codec
+ * if already registered with ALSA core
+ */
+ aux_cdc_dev_info = devm_kcalloc(&pdev->dev, codec_aux_dev_cnt,
+ sizeof(struct aux_codec_dev_info),
+ GFP_KERNEL);
+ if (!aux_cdc_dev_info) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /*
+ * search and check whether all aux codecs are already
+ * registered with ALSA core or not. If found a node, store
+ * the node and the index in a local array of struct for later
+ * use.
+ */
+ for (i = 0; i < codec_aux_dev_cnt; i++) {
+ aux_codec_of_node = of_parse_phandle(pdev->dev.of_node,
+ "qcom,codec-aux-devs", i);
+ if (unlikely(!aux_codec_of_node)) {
+ /* we should not be here */
+ dev_err(&pdev->dev,
+ "%s: aux codec dev node is not present\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ if (soc_find_component(aux_codec_of_node, NULL)) {
+ /* AUX codec registered with ALSA core */
+ aux_cdc_dev_info[codecs_found].of_node =
+ aux_codec_of_node;
+ aux_cdc_dev_info[codecs_found].index = i;
+ codecs_found++;
+ }
+ }
+
+ if (codecs_found < codec_aux_dev_cnt) {
+ dev_dbg(&pdev->dev,
+ "%s: failed to find %d components. Found only %d\n",
+ __func__, codec_aux_dev_cnt, codecs_found);
+ return -EPROBE_DEFER;
+ }
+ dev_info(&pdev->dev,
+ "%s: found %d AUX codecs registered with ALSA core\n",
+ __func__, codecs_found);
+
+aux_dev_register:
+ card->num_aux_devs = wsa_max_devs + codec_aux_dev_cnt;
+ card->num_configs = wsa_max_devs + codec_aux_dev_cnt;
+
+ /* Alloc array of AUX devs struct */
+ msm_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs,
+ sizeof(struct snd_soc_aux_dev),
+ GFP_KERNEL);
+ if (!msm_aux_dev) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* Alloc array of codec conf struct */
+ msm_codec_conf = devm_kcalloc(&pdev->dev, card->num_configs,
+ sizeof(struct snd_soc_codec_conf),
+ GFP_KERNEL);
+ if (!msm_codec_conf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < wsa_max_devs; i++) {
+ dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN,
+ GFP_KERNEL);
+ if (!dev_name_str) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = of_property_read_string_index(pdev->dev.of_node,
+ "qcom,wsa-aux-dev-prefix",
+ wsa881x_dev_info[i].index,
+ auxdev_name_prefix);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: failed to read wsa aux dev prefix, ret = %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i);
+ msm_aux_dev[i].name = dev_name_str;
+ msm_aux_dev[i].codec_name = NULL;
+ msm_aux_dev[i].codec_of_node =
+ wsa881x_dev_info[i].of_node;
+ msm_aux_dev[i].init = NULL;
+ msm_codec_conf[i].dev_name = NULL;
+ msm_codec_conf[i].name_prefix = auxdev_name_prefix[0];
+ msm_codec_conf[i].of_node =
+ wsa881x_dev_info[i].of_node;
+ }
+
+ for (i = 0; i < codec_aux_dev_cnt; i++) {
+ msm_aux_dev[wsa_max_devs + i].name = NULL;
+ msm_aux_dev[wsa_max_devs + i].codec_name = NULL;
+ msm_aux_dev[wsa_max_devs + i].codec_of_node =
+ aux_cdc_dev_info[i].of_node;
+ msm_aux_dev[wsa_max_devs + i].init = msm_aux_codec_init;
+ msm_codec_conf[wsa_max_devs + i].dev_name = NULL;
+ msm_codec_conf[wsa_max_devs + i].name_prefix =
+ NULL;
+ msm_codec_conf[wsa_max_devs + i].of_node =
+ aux_cdc_dev_info[i].of_node;
+ }
+
+ card->codec_conf = msm_codec_conf;
+ card->aux_dev = msm_aux_dev;
+err:
+ return ret;
+}
+
+static void msm_i2s_auxpcm_init(struct platform_device *pdev)
+{
+ int count = 0;
+ u32 mi2s_master_slave[MI2S_MAX];
+ int ret = 0;
+
+ for (count = 0; count < MI2S_MAX; count++) {
+ mutex_init(&mi2s_intf_conf[count].lock);
+ mi2s_intf_conf[count].ref_cnt = 0;
+ }
+
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-mi2s-master",
+ mi2s_master_slave, MI2S_MAX);
+ if (ret) {
+ dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-master in DT node\n",
+ __func__);
+ } else {
+ for (count = 0; count < MI2S_MAX; count++) {
+ mi2s_intf_conf[count].msm_is_mi2s_master =
+ mi2s_master_slave[count];
+ }
+ }
+}
+
+static void msm_i2s_auxpcm_deinit(void)
+{
+ int count = 0;
+
+ for (count = 0; count < MI2S_MAX; count++) {
+ mutex_destroy(&mi2s_intf_conf[count].lock);
+ mi2s_intf_conf[count].ref_cnt = 0;
+ mi2s_intf_conf[count].msm_is_mi2s_master = 0;
+ }
+}
+
+static int bengal_ssr_enable(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ if (!card) {
+ dev_err(dev, "%s: card is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (!strcmp(card->name, "bengal-stub-snd-card")) {
+ /* TODO */
+ dev_dbg(dev, "%s: TODO\n", __func__);
+ }
+
+ snd_soc_card_change_online_state(card, 1);
+ dev_dbg(dev, "%s: setting snd_card to ONLINE\n", __func__);
+
+err:
+ return ret;
+}
+
+static void bengal_ssr_disable(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ if (!card) {
+ dev_err(dev, "%s: card is NULL\n", __func__);
+ return;
+ }
+
+ dev_dbg(dev, "%s: setting snd_card to OFFLINE\n", __func__);
+ snd_soc_card_change_online_state(card, 0);
+
+ if (!strcmp(card->name, "bengal-stub-snd-card")) {
+ /* TODO */
+ dev_dbg(dev, "%s: TODO\n", __func__);
+ }
+}
+
+static const struct snd_event_ops bengal_ssr_ops = {
+ .enable = bengal_ssr_enable,
+ .disable = bengal_ssr_disable,
+};
+
+static int msm_audio_ssr_compare(struct device *dev, void *data)
+{
+ struct device_node *node = data;
+
+ dev_dbg(dev, "%s: dev->of_node = 0x%p, node = 0x%p\n",
+ __func__, dev->of_node, node);
+ return (dev->of_node && dev->of_node == node);
+}
+
+static int msm_audio_ssr_register(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct snd_event_clients *ssr_clients = NULL;
+ struct device_node *node = NULL;
+ int ret = 0;
+ int i = 0;
+
+ for (i = 0; ; i++) {
+ node = of_parse_phandle(np, "qcom,msm_audio_ssr_devs", i);
+ if (!node)
+ break;
+ snd_event_mstr_add_client(&ssr_clients,
+ msm_audio_ssr_compare, node);
+ }
+
+ ret = snd_event_master_register(dev, &bengal_ssr_ops,
+ ssr_clients, NULL);
+ if (!ret)
+ snd_event_notify(dev, SND_EVENT_UP);
+
+ return ret;
+}
+
+static int msm_asoc_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = NULL;
+ struct msm_asoc_mach_data *pdata = NULL;
+ const char *mbhc_audio_jack_type = NULL;
+ int ret = 0;
+ uint index = 0;
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev,
+ "%s: No platform supplied from device tree\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm_asoc_mach_data), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ card = populate_snd_card_dailinks(&pdev->dev);
+ if (!card) {
+ dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, pdata);
+
+ ret = snd_soc_of_parse_card_name(card, "qcom,model");
+ if (ret) {
+ dev_err(&pdev->dev, "%s: parse card name failed, err:%d\n",
+ __func__, ret);
+ goto err;
+ }
+
+ ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing");
+ if (ret) {
+ dev_err(&pdev->dev, "%s: parse audio routing failed, err:%d\n",
+ __func__, ret);
+ goto err;
+ }
+
+ ret = msm_populate_dai_link_component_of_node(card);
+ if (ret) {
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+
+ ret = msm_init_aux_dev(pdev, card);
+ if (ret)
+ goto err;
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret == -EPROBE_DEFER) {
+ if (codec_reg_done)
+ ret = -EINVAL;
+ goto err;
+ } else if (ret) {
+ dev_err(&pdev->dev, "%s: snd_soc_register_card failed (%d)\n",
+ __func__, ret);
+ goto err;
+ }
+ dev_info(&pdev->dev, "%s: Sound card %s registered\n",
+ __func__, card->name);
+
+ pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,hph-en1-gpio", 0);
+ if (!pdata->hph_en1_gpio_p) {
+ dev_dbg(&pdev->dev, "%s: property %s not detected in node %s\n",
+ __func__, "qcom,hph-en1-gpio",
+ pdev->dev.of_node->full_name);
+ }
+
+ pdata->hph_en0_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,hph-en0-gpio", 0);
+ if (!pdata->hph_en0_gpio_p) {
+ dev_dbg(&pdev->dev, "%s: property %s not detected in node %s\n",
+ __func__, "qcom,hph-en0-gpio",
+ pdev->dev.of_node->full_name);
+ }
+
+ ret = of_property_read_string(pdev->dev.of_node,
+ "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type);
+ if (ret) {
+ dev_dbg(&pdev->dev, "%s: Looking up %s property in node %s failed\n",
+ __func__, "qcom,mbhc-audio-jack-type",
+ pdev->dev.of_node->full_name);
+ dev_dbg(&pdev->dev, "Jack type properties set to default\n");
+ } else {
+ if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) {
+ wcd_mbhc_cfg.enable_anc_mic_detect = false;
+ dev_dbg(&pdev->dev, "This hardware has 4 pole jack");
+ } else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) {
+ wcd_mbhc_cfg.enable_anc_mic_detect = true;
+ dev_dbg(&pdev->dev, "This hardware has 5 pole jack");
+ } else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) {
+ wcd_mbhc_cfg.enable_anc_mic_detect = true;
+ dev_dbg(&pdev->dev, "This hardware has 6 pole jack");
+ } else {
+ wcd_mbhc_cfg.enable_anc_mic_detect = false;
+ dev_dbg(&pdev->dev, "Unknown value, set to default\n");
+ }
+ }
+ /*
+ * Parse US-Euro gpio info from DT. Report no error if us-euro
+ * entry is not found in DT file as some targets do not support
+ * US-Euro detection
+ */
+ pdata->us_euro_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,us-euro-gpios", 0);
+ if (!pdata->us_euro_gpio_p) {
+ dev_dbg(&pdev->dev, "property %s not detected in node %s",
+ "qcom,us-euro-gpios", pdev->dev.of_node->full_name);
+ } else {
+ dev_dbg(&pdev->dev, "%s detected\n",
+ "qcom,us-euro-gpios");
+ wcd_mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic;
+ }
+
+ if (wcd_mbhc_cfg.enable_usbc_analog)
+ wcd_mbhc_cfg.swap_gnd_mic = msm_usbc_swap_gnd_mic;
+
+ pdata->fsa_handle = of_parse_phandle(pdev->dev.of_node,
+ "fsa4480-i2c-handle", 0);
+ if (!pdata->fsa_handle)
+ dev_dbg(&pdev->dev, "property %s not detected in node %s\n",
+ "fsa4480-i2c-handle", pdev->dev.of_node->full_name);
+
+ msm_i2s_auxpcm_init(pdev);
+ pdata->dmic01_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,cdc-dmic01-gpios",
+ 0);
+ pdata->dmic23_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,cdc-dmic23-gpios",
+ 0);
+
+ pdata->mi2s_gpio_p[PRIM_MI2S] = of_parse_phandle(pdev->dev.of_node,
+ "qcom,pri-mi2s-gpios", 0);
+ pdata->mi2s_gpio_p[SEC_MI2S] = of_parse_phandle(pdev->dev.of_node,
+ "qcom,sec-mi2s-gpios", 0);
+ pdata->mi2s_gpio_p[TERT_MI2S] = of_parse_phandle(pdev->dev.of_node,
+ "qcom,tert-mi2s-gpios", 0);
+ pdata->mi2s_gpio_p[QUAT_MI2S] = of_parse_phandle(pdev->dev.of_node,
+ "qcom,quat-mi2s-gpios", 0);
+ for (index = PRIM_MI2S; index < MI2S_MAX; index++)
+ atomic_set(&(pdata->mi2s_gpio_ref_count[index]), 0);
+
+ ret = msm_audio_ssr_register(&pdev->dev);
+ if (ret)
+ pr_err("%s: Registration with SND event FWK failed ret = %d\n",
+ __func__, ret);
+
+ is_initial_boot = true;
+
+ return 0;
+err:
+ devm_kfree(&pdev->dev, pdata);
+ return ret;
+}
+
+static int msm_asoc_machine_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ snd_event_master_deregister(&pdev->dev);
+ snd_soc_unregister_card(card);
+ msm_i2s_auxpcm_deinit();
+
+ return 0;
+}
+
+static struct platform_driver bengal_asoc_machine_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = bengal_asoc_machine_of_match,
+ .suppress_bind_attrs = true,
+ },
+ .probe = msm_asoc_machine_probe,
+ .remove = msm_asoc_machine_remove,
+};
+module_platform_driver(bengal_asoc_machine_driver);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, bengal_asoc_machine_of_match);
diff --git a/asoc/codecs/Android.mk b/asoc/codecs/Android.mk
index fb00efb..5e3114e 100644
--- a/asoc/codecs/Android.mk
+++ b/asoc/codecs/Android.mk
@@ -31,6 +31,10 @@
AUDIO_SELECT := CONFIG_SND_SOC_LITO=m
endif
+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,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike),true)
@@ -107,6 +111,7 @@
include $(DLKM_DIR)/AndroidKernelModule.mk
endif
###########################################################
+ifneq ($(call is-board-platform-in-list, bengal),true)
include $(CLEAR_VARS)
LOCAL_MODULE := $(AUDIO_CHIPSET)_wsa881x.ko
LOCAL_MODULE_KBUILD_NAME := wsa881x_dlkm.ko
@@ -114,6 +119,17 @@
LOCAL_MODULE_DEBUG_ENABLE := true
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk
+endif
+###########################################################
+ifeq ($(call is-board-platform-in-list, bengal),true)
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(AUDIO_CHIPSET)_wsa881x_analog.ko
+LOCAL_MODULE_KBUILD_NAME := wsa881x_analog_dlkm.ko
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/AndroidKernelModule.mk
+endif
###########################################################
include $(CLEAR_VARS)
LOCAL_MODULE := $(AUDIO_CHIPSET)_mbhc.ko
@@ -132,6 +148,7 @@
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk
###########################################################
+ifneq ($(call is-board-platform-in-list, bengal),true)
include $(CLEAR_VARS)
LOCAL_MODULE := $(AUDIO_CHIPSET)_hdmi.ko
LOCAL_MODULE_KBUILD_NAME := hdmi_dlkm.ko
@@ -139,6 +156,7 @@
LOCAL_MODULE_DEBUG_ENABLE := true
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk
+endif
###########################################################
endif # DLKM check
diff --git a/asoc/codecs/Kbuild b/asoc/codecs/Kbuild
index b8abfc4..1ce059e 100644
--- a/asoc/codecs/Kbuild
+++ b/asoc/codecs/Kbuild
@@ -51,9 +51,9 @@
INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
endif
ifeq ($(CONFIG_ARCH_BENGAL), y)
- include $(AUDIO_ROOT)/config/litoauto.conf
+ include $(AUDIO_ROOT)/config/bengalauto.conf
export
- INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
+ INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
endif
ifeq ($(CONFIG_ARCH_SDMSHRIKE), y)
include $(AUDIO_ROOT)/config/sm8150auto.conf
@@ -143,6 +143,12 @@
WSA881X_OBJS += wsa881x-temp-sensor.o
endif
+ifdef CONFIG_SND_SOC_WSA881X_ANALOG
+ WSA881X_ANALOG_OBJS += wsa881x-analog.o
+ WSA881X_ANALOG_OBJS += wsa881x-tables-analog.o
+ WSA881X_ANALOG_OBJS += wsa881x-regmap-analog.o
+ WSA881X_ANALOG_OBJS += wsa881x-temp-sensor.o
+endif
ifdef CONFIG_SND_SOC_MSM_STUB
STUB_OBJS += msm_stub.o
endif
@@ -235,6 +241,9 @@
obj-$(CONFIG_SND_SOC_WSA881X) += wsa881x_dlkm.o
wsa881x_dlkm-y := $(WSA881X_OBJS)
+obj-$(CONFIG_SND_SOC_WSA881X_ANALOG) += wsa881x_analog_dlkm.o
+wsa881x_analog_dlkm-y := $(WSA881X_ANALOG_OBJS)
+
obj-$(CONFIG_SND_SOC_MSM_STUB) += stub_dlkm.o
stub_dlkm-y := $(STUB_OBJS)
diff --git a/asoc/codecs/bolero/Android.mk b/asoc/codecs/bolero/Android.mk
index 9d1274f..5764412 100644
--- a/asoc/codecs/bolero/Android.mk
+++ b/asoc/codecs/bolero/Android.mk
@@ -15,6 +15,10 @@
AUDIO_SELECT := CONFIG_SND_SOC_LITO=m
endif
+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) kona lito bengal),true)
@@ -52,6 +56,7 @@
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk
###########################################################
+ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) kona lito),true)
include $(CLEAR_VARS)
LOCAL_MODULE := $(AUDIO_CHIPSET)_wsa_macro.ko
LOCAL_MODULE_KBUILD_NAME := wsa_macro_dlkm.ko
@@ -59,6 +64,7 @@
LOCAL_MODULE_DEBUG_ENABLE := true
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk
+endif
###########################################################
include $(CLEAR_VARS)
LOCAL_MODULE := $(AUDIO_CHIPSET)_va_macro.ko
diff --git a/asoc/codecs/bolero/Kbuild b/asoc/codecs/bolero/Kbuild
index e6517f8..15e5dc5 100644
--- a/asoc/codecs/bolero/Kbuild
+++ b/asoc/codecs/bolero/Kbuild
@@ -36,9 +36,9 @@
INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
endif
ifeq ($(CONFIG_ARCH_BENGAL), y)
- include $(AUDIO_ROOT)/config/litoauto.conf
+ include $(AUDIO_ROOT)/config/bengalauto.conf
export
- INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
+ INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
endif
ifeq ($(CONFIG_ARCH_QCS405), y)
include $(AUDIO_ROOT)/config/qcs405auto.conf
diff --git a/asoc/codecs/bolero/bolero-cdc-registers.h b/asoc/codecs/bolero/bolero-cdc-registers.h
index 99890cc..e68e314 100644
--- a/asoc/codecs/bolero/bolero-cdc-registers.h
+++ b/asoc/codecs/bolero/bolero-cdc-registers.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#ifndef _BOLERO_CDC_REGISTERS_H
@@ -696,6 +696,7 @@
#define BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL (VA_START_OFFSET + 0x0000)
#define BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL \
(VA_START_OFFSET + 0x0004)
+#define BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL (VA_START_OFFSET + 0x0008)
#define BOLERO_CDC_VA_TOP_CSR_TOP_CFG0 (VA_START_OFFSET + 0x0080)
#define BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL (VA_START_OFFSET + 0x0084)
#define BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL (VA_START_OFFSET + 0x0088)
@@ -715,6 +716,11 @@
#define BOLERO_CDC_VA_MACRO_TOP_MAX 0x34 /* 0x0CC/4 = 0x33 + 1 = 0x34 */
+#define BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL0 (VA_START_OFFSET + 0x00D0)
+#define BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL1 (VA_START_OFFSET + 0x00D4)
+#define BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL2 (VA_START_OFFSET + 0x00D8)
+#define BOLERO_CDC_VA_TOP_CSR_SWR_CTRL (VA_START_OFFSET + 0x00DC)
+
#define BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0 (VA_START_OFFSET + 0x0100)
#define BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1 (VA_START_OFFSET + 0x0104)
#define BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0 (VA_START_OFFSET + 0x0108)
diff --git a/asoc/codecs/bolero/bolero-cdc-regmap.c b/asoc/codecs/bolero/bolero-cdc-regmap.c
index a0ecd83..77f5420 100644
--- a/asoc/codecs/bolero/bolero-cdc-regmap.c
+++ b/asoc/codecs/bolero/bolero-cdc-regmap.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/regmap.h>
@@ -609,6 +609,7 @@
/* VA macro */
{ BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL, 0x00},
{ BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00},
+ { BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL, 0x00},
{ BOLERO_CDC_VA_TOP_CSR_TOP_CFG0, 0x00},
{ BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL, 0x00},
{ BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL, 0x00},
@@ -624,6 +625,10 @@
{ BOLERO_CDC_VA_TOP_CSR_CORE_ID_1, 0x00},
{ BOLERO_CDC_VA_TOP_CSR_CORE_ID_2, 0x00},
{ BOLERO_CDC_VA_TOP_CSR_CORE_ID_3, 0x00},
+ { BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL0, 0xEE},
+ { BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL1, 0xEE},
+ { BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL2, 0xEE},
+ { BOLERO_CDC_VA_TOP_CSR_SWR_CTRL, 0x06},
/* VA core */
{ BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0, 0x00},
@@ -809,9 +814,13 @@
case BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB:
case BOLERO_CDC_WSA_SPLINE_ASRC1_STATUS_FIFO:
case BOLERO_CDC_RX_TOP_HPHL_COMP_RD_LSB:
+ case BOLERO_CDC_RX_TOP_HPHL_COMP_WR_LSB:
case BOLERO_CDC_RX_TOP_HPHL_COMP_RD_MSB:
+ case BOLERO_CDC_RX_TOP_HPHL_COMP_WR_MSB:
case BOLERO_CDC_RX_TOP_HPHR_COMP_RD_LSB:
+ case BOLERO_CDC_RX_TOP_HPHR_COMP_WR_LSB:
case BOLERO_CDC_RX_TOP_HPHR_COMP_RD_MSB:
+ case BOLERO_CDC_RX_TOP_HPHR_COMP_WR_MSB:
case BOLERO_CDC_RX_TOP_DSD0_DEBUG_CFG2:
case BOLERO_CDC_RX_TOP_DSD1_DEBUG_CFG2:
case BOLERO_CDC_RX_BCL_VBAT_GAIN_MON_VAL:
diff --git a/asoc/codecs/bolero/bolero-cdc-tables.c b/asoc/codecs/bolero/bolero-cdc-tables.c
index 5298763..5d0d353 100644
--- a/asoc/codecs/bolero/bolero-cdc-tables.c
+++ b/asoc/codecs/bolero/bolero-cdc-tables.c
@@ -149,6 +149,96 @@
[BOLERO_REG(BOLERO_CDC_TX7_TX_PATH_SEC6)] = RD_WR_REG,
};
+u8 bolero_tx_reg_access_v2[BOLERO_CDC_TX_MACRO_MAX] = {
+ [BOLERO_REG(BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_TOP_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_ANC_CFG)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_CTRL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_FREQ_MCLK)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_DEBUG_BUS)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_DEBUG_EN)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_TX_I2S_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_I2S_CLK)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_I2S_RESET)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_DMIC0_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_DMIC1_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_DMIC2_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_DMIC3_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_AMIC0_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_TOP_CSR_SWR_AMIC1_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_CLK_RESET_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_MODE_1_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_MODE_2_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_FF_SHIFT)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_FB_SHIFT)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_LPF_FF_A_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_LPF_FF_B_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_LPF_FB_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_SMLPF_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_DCFLT_SHIFT_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_IIR_ADAPT_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_IIR_COEFF_1_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_IIR_COEFF_2_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_FF_A_GAIN_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_FF_B_GAIN_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_ANC0_FB_GAIN_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX0_TX_VOL_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC6)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX0_TX_PATH_SEC7)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX1_TX_VOL_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX1_TX_PATH_SEC6)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX2_TX_VOL_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX2_TX_PATH_SEC6)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX3_TX_VOL_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_TX3_TX_PATH_SEC6)] = RD_WR_REG,
+};
+
u8 bolero_rx_reg_access[BOLERO_CDC_RX_MACRO_MAX] = {
[BOLERO_REG(BOLERO_CDC_RX_TOP_TOP_CFG0)] = RD_WR_REG,
[BOLERO_REG(BOLERO_CDC_RX_TOP_SWR_CTRL)] = RD_WR_REG,
@@ -442,6 +532,7 @@
u8 bolero_va_reg_access[BOLERO_CDC_VA_MACRO_MAX] = {
[BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG,
[BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG,
[BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TOP_CFG0)] = RD_WR_REG,
[BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL)] = RD_WR_REG,
[BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL)] = RD_WR_REG,
@@ -567,6 +658,7 @@
u8 bolero_va_top_reg_access[BOLERO_CDC_VA_MACRO_TOP_MAX] = {
[BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG,
[BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG,
[BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TOP_CFG0)] = RD_WR_REG,
[BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL)] = RD_WR_REG,
[BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL)] = RD_WR_REG,
@@ -579,6 +671,132 @@
[BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_3)] = RD_REG,
};
+u8 bolero_va_reg_access_v2[BOLERO_CDC_VA_MACRO_MAX] = {
+ [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TOP_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC_CFG)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DEBUG_BUS)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DEBUG_EN)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TX_I2S_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_I2S_CLK)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_I2S_RESET)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_0)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_1)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_2)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_3)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_CTRL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_VOL_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC6)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC7)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_VOL_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC6)] = RD_WR_REG,
+};
+
+u8 bolero_va_reg_access_v3[BOLERO_CDC_VA_MACRO_MAX] = {
+ [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TOP_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DMIC_CFG)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DEBUG_BUS)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_DEBUG_EN)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_TX_I2S_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_I2S_CLK)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_I2S_RESET)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_0)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_1)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_2)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_CORE_ID_3)] = RD_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_MIC_CTL2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TOP_CSR_SWR_CTRL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_VOL_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC6)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX0_TX_PATH_SEC7)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_VOL_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX1_TX_PATH_SEC6)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_VOL_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX2_TX_PATH_SEC6)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_CFG0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_CFG1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_VOL_CTL)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC0)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC1)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC2)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC3)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC4)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC5)] = RD_WR_REG,
+ [BOLERO_REG(BOLERO_CDC_VA_TX3_TX_PATH_SEC6)] = RD_WR_REG,
+};
+
u8 bolero_wsa_reg_access[BOLERO_CDC_WSA_MACRO_MAX] = {
[BOLERO_REG(BOLERO_CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL)] = RD_WR_REG,
[BOLERO_REG(BOLERO_CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL)] = RD_WR_REG,
diff --git a/asoc/codecs/bolero/bolero-cdc-utils.c b/asoc/codecs/bolero/bolero-cdc-utils.c
index b2fd153..f2e4ec4 100644
--- a/asoc/codecs/bolero/bolero-cdc-utils.c
+++ b/asoc/codecs/bolero/bolero-cdc-utils.c
@@ -68,12 +68,9 @@
reg_p = (u16 *)reg;
macro_id = bolero_get_macro_id(priv->va_without_decimation,
reg_p[0]);
- if (macro_id < 0 || !priv->macros_supported[macro_id]) {
- dev_err_ratelimited(dev,
- "%s: Unsupported macro %d or reg 0x%x is invalid\n",
- __func__, macro_id, reg_p[0]);
- return ret;
- }
+ if (macro_id < 0 || !priv->macros_supported[macro_id])
+ return 0;
+
mutex_lock(&priv->io_lock);
for (i = 0; i < val_size; i++) {
__reg = (reg_p[0] + i * 4) - macro_id_base_offset[macro_id];
@@ -121,12 +118,9 @@
reg_p = (u16 *)reg;
macro_id = bolero_get_macro_id(priv->va_without_decimation,
reg_p[0]);
- if (macro_id < 0 || !priv->macros_supported[macro_id]) {
- dev_err_ratelimited(dev,
- "%s: Unsupported macro-id %d or reg 0x%x is invalid\n",
- __func__, macro_id, reg_p[0]);
- return ret;
- }
+ if (macro_id < 0 || !priv->macros_supported[macro_id])
+ return 0;
+
mutex_lock(&priv->io_lock);
for (i = 0; i < val_size; i++) {
__reg = (reg_p[0] + i * 4) - macro_id_base_offset[macro_id];
diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c
index 76c9d40..fb182a2 100644
--- a/asoc/codecs/bolero/bolero-cdc.c
+++ b/asoc/codecs/bolero/bolero-cdc.c
@@ -20,9 +20,6 @@
#define DRV_NAME "bolero_codec"
-#define BOLERO_VERSION_1_0 0x0001
-#define BOLERO_VERSION_1_1 0x0002
-#define BOLERO_VERSION_1_2 0x0003
#define BOLERO_VERSION_ENTRY_SIZE 32
#define BOLERO_CDC_STRING_LEN 80
@@ -107,21 +104,25 @@
if (priv->macro_params[VA_MACRO].dev)
pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
- /* Request Clk before register access */
- ret = bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev,
+ if (priv->version < BOLERO_VERSION_2_0) {
+ /* Request Clk before register access */
+ ret = bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev,
priv->macro_params[macro_id].default_clk_id,
priv->macro_params[macro_id].clk_id_req,
true);
- if (ret < 0) {
- dev_err_ratelimited(priv->dev,
- "%s: Failed to enable clock, ret:%d\n", __func__, ret);
- goto err;
+ if (ret < 0) {
+ dev_err_ratelimited(priv->dev,
+ "%s: Failed to enable clock, ret:%d\n",
+ __func__, ret);
+ goto err;
+ }
}
bolero_ahb_read_device(
priv->macro_params[macro_id].io_base, reg, val);
- bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev,
+ if (priv->version < BOLERO_VERSION_2_0)
+ bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev,
priv->macro_params[macro_id].default_clk_id,
priv->macro_params[macro_id].clk_id_req,
false);
@@ -151,21 +152,25 @@
if (priv->macro_params[VA_MACRO].dev)
pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
- /* Request Clk before register access */
- ret = bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev,
+ if (priv->version < BOLERO_VERSION_2_0) {
+ /* Request Clk before register access */
+ ret = bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev,
priv->macro_params[macro_id].default_clk_id,
priv->macro_params[macro_id].clk_id_req,
true);
- if (ret < 0) {
- dev_err_ratelimited(priv->dev,
- "%s: Failed to enable clock, ret:%d\n", __func__, ret);
- goto err;
+ if (ret < 0) {
+ dev_err_ratelimited(priv->dev,
+ "%s: Failed to enable clock, ret:%d\n",
+ __func__, ret);
+ goto err;
+ }
}
bolero_ahb_write_device(
priv->macro_params[macro_id].io_base, reg, val);
- bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev,
+ if (priv->version < BOLERO_VERSION_2_0)
+ bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev,
priv->macro_params[macro_id].default_clk_id,
priv->macro_params[macro_id].clk_id_req,
false);
@@ -214,6 +219,12 @@
priv->component,
BOLERO_MACRO_EVT_RX_COMPANDER_SOFT_RST, data);
break;
+ case WCD_BOLERO_EVT_BCS_CLK_OFF:
+ if (priv->macro_params[TX_MACRO].event_handler)
+ priv->macro_params[TX_MACRO].event_handler(
+ priv->component,
+ BOLERO_MACRO_EVT_BCS_CLK_OFF, data);
+ break;
default:
dev_err(priv->dev, "%s: Invalid event %d trigger from wcd\n",
__func__, event);
@@ -507,11 +518,17 @@
priv->macro_params[macro_id].reg_evt_listener =
ops->reg_evt_listener;
}
-
+ if (priv->version == BOLERO_VERSION_2_1) {
+ if (macro_id == VA_MACRO)
+ priv->macro_params[macro_id].reg_wake_irq =
+ ops->reg_wake_irq;
+ }
priv->num_dais += ops->num_dais;
priv->num_macros_registered++;
priv->macros_supported[macro_id] = true;
+ dev_dbg(dev, "%s: register macro successful:%d\n", macro_id);
+
if (priv->num_macros_registered == priv->num_macros) {
ret = bolero_copy_dais_from_macro(priv);
if (ret < 0) {
@@ -604,6 +621,28 @@
}
EXPORT_SYMBOL(bolero_wsa_pa_on);
+int bolero_get_version(struct device *dev)
+{
+ struct bolero_priv *priv;
+
+ if (!dev) {
+ pr_err("%s: dev is null\n", __func__);
+ return -EINVAL;
+ }
+ if (!bolero_is_valid_child_dev(dev)) {
+ dev_err(dev, "%s: child device for macro not added yet\n",
+ __func__);
+ return -EINVAL;
+ }
+ priv = dev_get_drvdata(dev->parent);
+ if (!priv) {
+ dev_err(dev, "%s: priv is null\n", __func__);
+ return -EINVAL;
+ }
+ return priv->version;
+}
+EXPORT_SYMBOL(bolero_get_version);
+
static ssize_t bolero_version_read(struct snd_info_entry *entry,
void *file_private_data,
struct file *file,
@@ -630,6 +669,9 @@
case BOLERO_VERSION_1_2:
len = snprintf(buffer, sizeof(buffer), "BOLERO_1_2\n");
break;
+ case BOLERO_VERSION_2_1:
+ len = snprintf(buffer, sizeof(buffer), "BOLERO_2_1\n");
+ break;
default:
len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
}
@@ -661,7 +703,11 @@
priv->dev_up = true;
mutex_unlock(&priv->clk_lock);
regcache_mark_dirty(priv->regmap);
+ bolero_clk_rsc_enable_all_clocks(priv->clk_dev, true);
regcache_sync(priv->regmap);
+ /* 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);
/* 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)
@@ -679,6 +725,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);
@@ -790,9 +842,15 @@
return -EINVAL;
}
- if (priv->macro_params[TX_MACRO].reg_wake_irq)
- priv->macro_params[TX_MACRO].reg_wake_irq(
- component, ipc_wakeup);
+ if (priv->version == BOLERO_VERSION_2_1) {
+ if (priv->macro_params[VA_MACRO].reg_wake_irq)
+ priv->macro_params[VA_MACRO].reg_wake_irq(
+ component, ipc_wakeup);
+ } else {
+ if (priv->macro_params[TX_MACRO].reg_wake_irq)
+ priv->macro_params[TX_MACRO].reg_wake_irq(
+ component, ipc_wakeup);
+ }
return 0;
}
@@ -871,6 +929,29 @@
snd_soc_component_init_regmap(component, priv->regmap);
+ if (!priv->version) {
+ /*
+ * In order for the ADIE RTC to differentiate between targets
+ * version info is used.
+ * Assign 1.0 for target with only one macro
+ * Assign 1.1 for target with two macros
+ * Assign 1.2 for target with more than two macros
+ */
+ if (priv->num_macros_registered == 1)
+ priv->version = BOLERO_VERSION_1_0;
+ else if (priv->num_macros_registered == 2)
+ priv->version = BOLERO_VERSION_1_1;
+ else if (priv->num_macros_registered > 2)
+ priv->version = BOLERO_VERSION_1_2;
+ }
+
+ /* Assign bolero version 2.1 for bolero 2.1 */
+ if ((snd_soc_component_read32(component,
+ BOLERO_CDC_VA_TOP_CSR_CORE_ID_0) == 0x2) &&
+ (snd_soc_component_read32(component,
+ BOLERO_CDC_VA_TOP_CSR_CORE_ID_1) == 0xE))
+ priv->version = BOLERO_VERSION_2_1;
+
/* call init for supported macros */
for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) {
if (priv->macro_params[macro_idx].init) {
@@ -884,19 +965,6 @@
}
}
priv->component = component;
- /*
- * In order for the ADIE RTC to differentiate between targets
- * version info is used.
- * Assign 1.0 for target with only one macro
- * Assign 1.1 for target with two macros
- * Assign 1.2 for target with more than two macros
- */
- if (priv->num_macros_registered == 1)
- priv->version = BOLERO_VERSION_1_0;
- else if (priv->num_macros_registered == 2)
- priv->version = BOLERO_VERSION_1_1;
- else if (priv->num_macros_registered > 2)
- priv->version = BOLERO_VERSION_1_2;
ret = snd_event_client_register(priv->dev, &bolero_ssr_ops, priv);
if (!ret) {
@@ -981,10 +1049,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) {
@@ -1040,6 +1107,20 @@
if (priv->va_without_decimation)
bolero_reg_access[VA_MACRO] = bolero_va_top_reg_access;
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,bolero-version", &priv->version);
+ if (ret) {
+ dev_dbg(&pdev->dev, "%s:bolero version not specified\n",
+ __func__);
+ ret = 0;
+ }
+ if (priv->version == BOLERO_VERSION_2_1) {
+ bolero_reg_access[TX_MACRO] = bolero_tx_reg_access_v2;
+ bolero_reg_access[VA_MACRO] = bolero_va_reg_access_v2;
+ } else if (priv->version == BOLERO_VERSION_2_0) {
+ bolero_reg_access[VA_MACRO] = bolero_va_reg_access_v3;
+ }
+
priv->dev = &pdev->dev;
priv->dev_up = true;
priv->initial_boot = true;
@@ -1111,12 +1192,12 @@
struct bolero_priv *priv = dev_get_drvdata(dev->parent);
int ret = 0;
+ mutex_lock(&priv->vote_lock);
if (priv->lpass_core_hw_vote == NULL) {
dev_dbg(dev, "%s: Invalid lpass core hw node\n", __func__);
- return 0;
+ goto audio_vote;
}
- mutex_lock(&priv->vote_lock);
if (priv->core_hw_vote_count == 0) {
ret = clk_prepare_enable(priv->lpass_core_hw_vote);
if (ret < 0) {
@@ -1180,6 +1261,21 @@
}
EXPORT_SYMBOL(bolero_runtime_suspend);
+bool bolero_check_core_votes(struct device *dev)
+{
+ struct bolero_priv *priv = dev_get_drvdata(dev->parent);
+ bool ret = true;
+
+ mutex_lock(&priv->vote_lock);
+ if ((priv->lpass_core_hw_vote && !priv->core_hw_vote_count) ||
+ (priv->lpass_audio_hw_vote && !priv->core_audio_vote_count))
+ ret = false;
+ mutex_unlock(&priv->vote_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(bolero_check_core_votes);
+
static const struct of_device_id bolero_dt_match[] = {
{.compatible = "qcom,bolero-codec"},
{}
diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h
index 957389c..2ec4617 100644
--- a/asoc/codecs/bolero/bolero-cdc.h
+++ b/asoc/codecs/bolero/bolero-cdc.h
@@ -8,6 +8,12 @@
#include <sound/soc.h>
#include <linux/regmap.h>
+#define BOLERO_VERSION_1_0 0x0001
+#define BOLERO_VERSION_1_1 0x0002
+#define BOLERO_VERSION_1_2 0x0003
+#define BOLERO_VERSION_2_0 0x0004
+#define BOLERO_VERSION_2_1 0x0005
+
enum {
START_MACRO,
TX_MACRO = START_MACRO,
@@ -40,7 +46,8 @@
BOLERO_MACRO_EVT_WAIT_VA_CLK_RESET,
BOLERO_MACRO_EVT_CLK_RESET,
BOLERO_MACRO_EVT_REG_WAKE_IRQ,
- BOLERO_MACRO_EVT_RX_COMPANDER_SOFT_RST
+ BOLERO_MACRO_EVT_RX_COMPANDER_SOFT_RST,
+ BOLERO_MACRO_EVT_BCS_CLK_OFF
};
struct macro_ops {
@@ -84,6 +91,8 @@
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_get_version(struct device *dev);
#else
static inline int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb)
{
@@ -158,5 +167,15 @@
static void bolero_wsa_pa_on(struct device *dev)
{
}
+
+static inline bool bolero_check_core_votes(struct device *dev)
+{
+ return false;
+}
+
+static int bolero_get_version(struct device *dev)
+{
+ 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 4940f67..b80a267 100644
--- a/asoc/codecs/bolero/bolero-clk-rsc.c
+++ b/asoc/codecs/bolero/bolero-clk-rsc.c
@@ -137,6 +137,49 @@
}
EXPORT_SYMBOL(bolero_rsc_clk_reset);
+void bolero_clk_rsc_enable_all_clocks(struct device *dev, bool enable)
+{
+ struct device *clk_dev = NULL;
+ struct bolero_clk_rsc *priv = NULL;
+ int i = 0;
+
+ if (!dev) {
+ pr_err("%s: dev is null %d\n", __func__);
+ return;
+ }
+
+ clk_dev = bolero_get_rsc_clk_device_ptr(dev->parent);
+ if (!clk_dev) {
+ pr_err("%s: Invalid rsc clk device\n", __func__);
+ return;
+ }
+
+ priv = dev_get_drvdata(clk_dev);
+ if (!priv) {
+ pr_err("%s: Invalid rsc clk private data\n", __func__);
+ return;
+ }
+ mutex_lock(&priv->rsc_clk_lock);
+ for (i = 0; i < MAX_CLK - NPL_CLK_OFFSET; i++) {
+ if (enable) {
+ if (priv->clk[i])
+ clk_prepare_enable(priv->clk[i]);
+ if (priv->clk[i + NPL_CLK_OFFSET])
+ clk_prepare_enable(
+ priv->clk[i + NPL_CLK_OFFSET]);
+ } else {
+ if (priv->clk[i + NPL_CLK_OFFSET])
+ clk_disable_unprepare(
+ priv->clk[i + NPL_CLK_OFFSET]);
+ if (priv->clk[i])
+ clk_disable_unprepare(priv->clk[i]);
+ }
+ }
+ mutex_unlock(&priv->rsc_clk_lock);
+ return;
+}
+EXPORT_SYMBOL(bolero_clk_rsc_enable_all_clocks);
+
static int bolero_clk_rsc_mux0_clk_request(struct bolero_clk_rsc *priv,
int clk_id,
bool enable)
diff --git a/asoc/codecs/bolero/bolero-clk-rsc.h b/asoc/codecs/bolero/bolero-clk-rsc.h
index fc3c02f..cc8ee39 100644
--- a/asoc/codecs/bolero/bolero-clk-rsc.h
+++ b/asoc/codecs/bolero/bolero-clk-rsc.h
@@ -19,6 +19,7 @@
int clk_id_req,
bool enable);
int bolero_rsc_clk_reset(struct device *dev, int clk_id);
+void bolero_clk_rsc_enable_all_clocks(struct device *dev, bool enable);
#else
static inline void bolero_clk_rsc_fs_gen_request(struct device *dev,
bool enable)
@@ -42,5 +43,10 @@
{
return 0;
}
+static inline void bolero_clk_rsc_enable_all_clocks(struct device *dev,
+ bool enable)
+{
+ return;
+}
#endif /* CONFIG_SND_SOC_BOLERO */
#endif /* BOLERO_CLK_RSC_H */
diff --git a/asoc/codecs/bolero/internal.h b/asoc/codecs/bolero/internal.h
index d3f6894..d18568b 100644
--- a/asoc/codecs/bolero/internal.h
+++ b/asoc/codecs/bolero/internal.h
@@ -31,6 +31,7 @@
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,
};
struct wcd_ctrl_platform_data {
@@ -90,6 +91,9 @@
extern const struct regmap_config bolero_regmap_config;
extern u8 *bolero_reg_access[MAX_MACRO];
extern u8 bolero_va_top_reg_access[BOLERO_CDC_VA_MACRO_TOP_MAX];
+extern u8 bolero_va_reg_access_v2[BOLERO_CDC_VA_MACRO_MAX];
+extern u8 bolero_va_reg_access_v3[BOLERO_CDC_VA_MACRO_MAX];
+extern u8 bolero_tx_reg_access_v2[BOLERO_CDC_TX_MACRO_MAX];
extern const u16 macro_id_base_offset[MAX_MACRO];
#endif
diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c
index 07b7b30..a9ec81a 100644
--- a/asoc/codecs/bolero/rx-macro.c
+++ b/asoc/codecs/bolero/rx-macro.c
@@ -1350,10 +1350,8 @@
goto done;
reg = BOLERO_CDC_RX_COMPANDER0_CTL0 +
(rx_idx * RX_MACRO_COMP_OFFSET);
- snd_soc_component_update_bits(component, reg,
- 0x20, 0x20);
- snd_soc_component_update_bits(component, reg,
- 0x20, 0x00);
+ snd_soc_component_write(component, reg,
+ snd_soc_component_read32(component, reg));
break;
case BOLERO_MACRO_EVT_IMPED_TRUE:
rx_macro_wcd_clsh_imped_config(component, data, true);
@@ -3592,7 +3590,10 @@
pm_runtime_mark_last_busy(rx_priv->dev);
}
- return 0;
+ if (bolero_check_core_votes(rx_priv->dev))
+ return 0;
+ else
+ return -EINVAL;
}
static int rx_swrm_clock(void *handle, bool enable)
@@ -4062,6 +4063,7 @@
pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
+ pm_suspend_ignore_children(&pdev->dev, true);
pm_runtime_enable(&pdev->dev);
return 0;
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index 97d9f7e..31745d6 100644
--- a/asoc/codecs/bolero/tx-macro.c
+++ b/asoc/codecs/bolero/tx-macro.c
@@ -160,6 +160,8 @@
s32 dmic_4_5_clk_cnt;
s32 dmic_6_7_clk_cnt;
u16 dmic_clk_div;
+ u32 version;
+ u32 is_used_tx_swr_gpio;
unsigned long active_ch_mask[TX_MACRO_MAX_DAIS];
unsigned long active_ch_cnt[TX_MACRO_MAX_DAIS];
char __iomem *tx_io_base;
@@ -172,6 +174,8 @@
int tx_clk_status;
bool bcs_enable;
int dec_mode[NUM_DECIMATORS];
+ bool bcs_clk_en;
+ bool hs_slow_insert_complete;
};
static bool tx_macro_get_data(struct snd_soc_component *component,
@@ -387,6 +391,15 @@
case BOLERO_MACRO_EVT_CLK_RESET:
bolero_rsc_clk_reset(tx_dev, TX_CORE_CLK);
break;
+ case BOLERO_MACRO_EVT_BCS_CLK_OFF:
+ if (tx_priv->bcs_clk_en)
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_TX0_TX_PATH_SEC7, 0x40, data << 6);
+ if (data)
+ tx_priv->hs_slow_insert_complete = true;
+ else
+ tx_priv->hs_slow_insert_complete = false;
+ break;
}
return 0;
}
@@ -450,10 +463,10 @@
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);
+ 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, 0x03, 0x01);
+ snd_soc_component_update_bits(component, hpf_gate_reg, 0x02, 0x00);
}
static void tx_macro_mute_update_callback(struct work_struct *work)
@@ -865,6 +878,10 @@
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);
hpf_cut_off_freq = (
snd_soc_component_read32(component, dec_cfg_reg) &
@@ -887,7 +904,7 @@
&tx_priv->tx_hpf_work[decimator].dwork,
msecs_to_jiffies(300));
snd_soc_component_update_bits(component,
- hpf_gate_reg, 0x02, 0x02);
+ hpf_gate_reg, 0x03, 0x03);
/*
* Minimum 1 clk cycle delay is required as per HW spec
*/
@@ -902,8 +919,11 @@
if (tx_priv->bcs_enable) {
snd_soc_component_update_bits(component, dec_cfg_reg,
0x01, 0x01);
- snd_soc_component_update_bits(component,
- BOLERO_CDC_TX0_TX_PATH_SEC7, 0x40, 0x40);
+ tx_priv->bcs_clk_en = true;
+ if (tx_priv->hs_slow_insert_complete)
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_TX0_TX_PATH_SEC7, 0x40,
+ 0x40);
}
break;
case SND_SOC_DAPM_PRE_PMD:
@@ -946,6 +966,7 @@
0x01, 0x00);
snd_soc_component_update_bits(component,
BOLERO_CDC_TX0_TX_PATH_SEC7, 0x40, 0x00);
+ tx_priv->bcs_clk_en = false;
}
break;
}
@@ -1210,6 +1231,44 @@
0, smic_mux_text, snd_soc_dapm_get_enum_double,
tx_macro_put_dec_enum);
+static const char * const smic_mux_text_v2[] = {
+ "ZERO", "SWR_MIC0", "SWR_MIC1", "SWR_MIC2", "SWR_MIC3",
+ "SWR_MIC4", "SWR_MIC5", "SWR_MIC6", "SWR_MIC7",
+ "SWR_MIC8", "SWR_MIC9", "SWR_MIC10", "SWR_MIC11"
+};
+
+TX_MACRO_DAPM_ENUM_EXT(tx_smic0_v2, BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0,
+ 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+ tx_macro_put_dec_enum);
+
+TX_MACRO_DAPM_ENUM_EXT(tx_smic1_v2, BOLERO_CDC_TX_INP_MUX_ADC_MUX1_CFG0,
+ 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+ tx_macro_put_dec_enum);
+
+TX_MACRO_DAPM_ENUM_EXT(tx_smic2_v2, BOLERO_CDC_TX_INP_MUX_ADC_MUX2_CFG0,
+ 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+ tx_macro_put_dec_enum);
+
+TX_MACRO_DAPM_ENUM_EXT(tx_smic3_v2, BOLERO_CDC_TX_INP_MUX_ADC_MUX3_CFG0,
+ 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+ tx_macro_put_dec_enum);
+
+TX_MACRO_DAPM_ENUM_EXT(tx_smic4_v3, BOLERO_CDC_TX_INP_MUX_ADC_MUX4_CFG0,
+ 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+ tx_macro_put_dec_enum);
+
+TX_MACRO_DAPM_ENUM_EXT(tx_smic5_v3, BOLERO_CDC_TX_INP_MUX_ADC_MUX5_CFG0,
+ 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+ tx_macro_put_dec_enum);
+
+TX_MACRO_DAPM_ENUM_EXT(tx_smic6_v3, BOLERO_CDC_TX_INP_MUX_ADC_MUX6_CFG0,
+ 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+ tx_macro_put_dec_enum);
+
+TX_MACRO_DAPM_ENUM_EXT(tx_smic7_v3, BOLERO_CDC_TX_INP_MUX_ADC_MUX7_CFG0,
+ 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+ tx_macro_put_dec_enum);
+
static const char * const dec_mode_mux_text[] = {
"ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF",
};
@@ -1275,6 +1334,205 @@
tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
};
+static const struct snd_kcontrol_new tx_aif1_cap_mixer_v2[] = {
+ SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0,
+ tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0,
+ tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0,
+ tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0,
+ tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new tx_aif2_cap_mixer_v2[] = {
+ SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0,
+ tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0,
+ tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0,
+ tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0,
+ tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new tx_aif3_cap_mixer_v2[] = {
+ SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, TX_MACRO_DEC0, 1, 0,
+ tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, TX_MACRO_DEC1, 1, 0,
+ tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, TX_MACRO_DEC2, 1, 0,
+ tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, TX_MACRO_DEC3, 1, 0,
+ tx_macro_tx_mixer_get, tx_macro_tx_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_common[] = {
+ SND_SOC_DAPM_AIF_OUT("TX_AIF1 CAP", "TX_AIF1 Capture", 0,
+ SND_SOC_NOPM, TX_MACRO_AIF1_CAP, 0),
+
+ SND_SOC_DAPM_AIF_OUT("TX_AIF2 CAP", "TX_AIF2 Capture", 0,
+ SND_SOC_NOPM, TX_MACRO_AIF2_CAP, 0),
+
+ SND_SOC_DAPM_AIF_OUT("TX_AIF3 CAP", "TX_AIF3 Capture", 0,
+ SND_SOC_NOPM, TX_MACRO_AIF3_CAP, 0),
+
+ TX_MACRO_DAPM_MUX("TX DMIC MUX0", 0, tx_dmic0),
+ TX_MACRO_DAPM_MUX("TX DMIC MUX1", 0, tx_dmic1),
+ TX_MACRO_DAPM_MUX("TX DMIC MUX2", 0, tx_dmic2),
+ TX_MACRO_DAPM_MUX("TX DMIC MUX3", 0, tx_dmic3),
+
+ TX_MACRO_DAPM_MUX("TX SMIC MUX0", 0, tx_smic0_v2),
+ TX_MACRO_DAPM_MUX("TX SMIC MUX1", 0, tx_smic1_v2),
+ TX_MACRO_DAPM_MUX("TX SMIC MUX2", 0, tx_smic2_v2),
+ TX_MACRO_DAPM_MUX("TX SMIC MUX3", 0, tx_smic3_v2),
+
+ SND_SOC_DAPM_MICBIAS_E("TX MIC BIAS1", SND_SOC_NOPM, 0, 0,
+ tx_macro_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("TX DMIC0", NULL, SND_SOC_NOPM, 0, 0,
+ tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("TX DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+ tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("TX DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+ tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("TX DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+ tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("TX DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+ tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("TX DMIC5", NULL, SND_SOC_NOPM, 0, 0,
+ tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("TX DMIC6", NULL, SND_SOC_NOPM, 0, 0,
+ tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("TX DMIC7", NULL, SND_SOC_NOPM, 0, 0,
+ tx_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("TX SWR_MIC0"),
+ SND_SOC_DAPM_INPUT("TX SWR_MIC1"),
+ SND_SOC_DAPM_INPUT("TX SWR_MIC2"),
+ SND_SOC_DAPM_INPUT("TX SWR_MIC3"),
+ SND_SOC_DAPM_INPUT("TX SWR_MIC4"),
+ SND_SOC_DAPM_INPUT("TX SWR_MIC5"),
+ SND_SOC_DAPM_INPUT("TX SWR_MIC6"),
+ SND_SOC_DAPM_INPUT("TX SWR_MIC7"),
+ SND_SOC_DAPM_INPUT("TX SWR_MIC8"),
+ SND_SOC_DAPM_INPUT("TX SWR_MIC9"),
+ SND_SOC_DAPM_INPUT("TX SWR_MIC10"),
+ SND_SOC_DAPM_INPUT("TX SWR_MIC11"),
+
+ SND_SOC_DAPM_MUX_E("TX DEC0 MUX", SND_SOC_NOPM,
+ TX_MACRO_DEC0, 0,
+ &tx_dec0_mux, tx_macro_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("TX DEC1 MUX", SND_SOC_NOPM,
+ TX_MACRO_DEC1, 0,
+ &tx_dec1_mux, tx_macro_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("TX DEC2 MUX", SND_SOC_NOPM,
+ TX_MACRO_DEC2, 0,
+ &tx_dec2_mux, tx_macro_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("TX DEC3 MUX", SND_SOC_NOPM,
+ TX_MACRO_DEC3, 0,
+ &tx_dec3_mux, tx_macro_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("TX_MCLK", 0, SND_SOC_NOPM, 0, 0,
+ tx_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v2[] = {
+ SND_SOC_DAPM_MIXER("TX_AIF1_CAP Mixer", SND_SOC_NOPM,
+ TX_MACRO_AIF1_CAP, 0,
+ tx_aif1_cap_mixer_v2, ARRAY_SIZE(tx_aif1_cap_mixer_v2)),
+
+ SND_SOC_DAPM_MIXER("TX_AIF2_CAP Mixer", SND_SOC_NOPM,
+ TX_MACRO_AIF2_CAP, 0,
+ tx_aif2_cap_mixer_v2, ARRAY_SIZE(tx_aif2_cap_mixer_v2)),
+
+ SND_SOC_DAPM_MIXER("TX_AIF3_CAP Mixer", SND_SOC_NOPM,
+ TX_MACRO_AIF3_CAP, 0,
+ tx_aif3_cap_mixer_v2, ARRAY_SIZE(tx_aif3_cap_mixer_v2)),
+};
+
+static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v3[] = {
+ SND_SOC_DAPM_MIXER("TX_AIF1_CAP Mixer", SND_SOC_NOPM,
+ TX_MACRO_AIF1_CAP, 0,
+ tx_aif1_cap_mixer, ARRAY_SIZE(tx_aif1_cap_mixer)),
+
+ SND_SOC_DAPM_MIXER("TX_AIF2_CAP Mixer", SND_SOC_NOPM,
+ TX_MACRO_AIF2_CAP, 0,
+ tx_aif2_cap_mixer, ARRAY_SIZE(tx_aif2_cap_mixer)),
+
+ SND_SOC_DAPM_MIXER("TX_AIF3_CAP Mixer", SND_SOC_NOPM,
+ TX_MACRO_AIF3_CAP, 0,
+ tx_aif3_cap_mixer, ARRAY_SIZE(tx_aif3_cap_mixer)),
+
+ TX_MACRO_DAPM_MUX("TX DMIC MUX4", 0, tx_dmic4),
+ TX_MACRO_DAPM_MUX("TX DMIC MUX5", 0, tx_dmic5),
+ TX_MACRO_DAPM_MUX("TX DMIC MUX6", 0, tx_dmic6),
+ TX_MACRO_DAPM_MUX("TX DMIC MUX7", 0, tx_dmic7),
+
+ TX_MACRO_DAPM_MUX("TX SMIC MUX4", 0, tx_smic4_v3),
+ TX_MACRO_DAPM_MUX("TX SMIC MUX5", 0, tx_smic5_v3),
+ TX_MACRO_DAPM_MUX("TX SMIC MUX6", 0, tx_smic6_v3),
+ TX_MACRO_DAPM_MUX("TX SMIC MUX7", 0, tx_smic7_v3),
+
+ SND_SOC_DAPM_MUX_E("TX DEC4 MUX", SND_SOC_NOPM,
+ TX_MACRO_DEC4, 0,
+ &tx_dec4_mux, tx_macro_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("TX DEC5 MUX", SND_SOC_NOPM,
+ TX_MACRO_DEC5, 0,
+ &tx_dec5_mux, tx_macro_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("TX DEC6 MUX", SND_SOC_NOPM,
+ TX_MACRO_DEC6, 0,
+ &tx_dec6_mux, tx_macro_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("TX DEC7 MUX", SND_SOC_NOPM,
+ TX_MACRO_DEC7, 0,
+ &tx_dec7_mux, tx_macro_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("TX_SWR_CLK", 0, SND_SOC_NOPM, 0, 0,
+ tx_macro_tx_swr_clk_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("VA_SWR_CLK", 0, SND_SOC_NOPM, 0, 0,
+ tx_macro_va_swr_clk_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT("TX_AIF1 CAP", "TX_AIF1 Capture", 0,
SND_SOC_NOPM, TX_MACRO_AIF1_CAP, 0),
@@ -1421,6 +1679,259 @@
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
+static const struct snd_soc_dapm_route tx_audio_map_common[] = {
+ {"TX_AIF1 CAP", NULL, "TX_MCLK"},
+ {"TX_AIF2 CAP", NULL, "TX_MCLK"},
+ {"TX_AIF3 CAP", NULL, "TX_MCLK"},
+
+ {"TX_AIF1 CAP", NULL, "TX_AIF1_CAP Mixer"},
+ {"TX_AIF2 CAP", NULL, "TX_AIF2_CAP Mixer"},
+ {"TX_AIF3 CAP", NULL, "TX_AIF3_CAP Mixer"},
+
+ {"TX_AIF1_CAP Mixer", "DEC0", "TX DEC0 MUX"},
+ {"TX_AIF1_CAP Mixer", "DEC1", "TX DEC1 MUX"},
+ {"TX_AIF1_CAP Mixer", "DEC2", "TX DEC2 MUX"},
+ {"TX_AIF1_CAP Mixer", "DEC3", "TX DEC3 MUX"},
+
+ {"TX_AIF2_CAP Mixer", "DEC0", "TX DEC0 MUX"},
+ {"TX_AIF2_CAP Mixer", "DEC1", "TX DEC1 MUX"},
+ {"TX_AIF2_CAP Mixer", "DEC2", "TX DEC2 MUX"},
+ {"TX_AIF2_CAP Mixer", "DEC3", "TX DEC3 MUX"},
+
+ {"TX_AIF3_CAP Mixer", "DEC0", "TX DEC0 MUX"},
+ {"TX_AIF3_CAP Mixer", "DEC1", "TX DEC1 MUX"},
+ {"TX_AIF3_CAP Mixer", "DEC2", "TX DEC2 MUX"},
+ {"TX_AIF3_CAP Mixer", "DEC3", "TX DEC3 MUX"},
+
+ {"TX DEC0 MUX", NULL, "TX_MCLK"},
+ {"TX DEC1 MUX", NULL, "TX_MCLK"},
+ {"TX DEC2 MUX", NULL, "TX_MCLK"},
+ {"TX DEC3 MUX", NULL, "TX_MCLK"},
+
+ {"TX DEC0 MUX", "MSM_DMIC", "TX DMIC MUX0"},
+ {"TX DMIC MUX0", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX0", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX0", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX0", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX0", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX0", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX0", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX0", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"},
+ {"TX SMIC MUX0", "SWR_MIC0", "TX SWR_MIC0"},
+ {"TX SMIC MUX0", "SWR_MIC1", "TX SWR_MIC1"},
+ {"TX SMIC MUX0", "SWR_MIC2", "TX SWR_MIC2"},
+ {"TX SMIC MUX0", "SWR_MIC3", "TX SWR_MIC3"},
+ {"TX SMIC MUX0", "SWR_MIC4", "TX SWR_MIC4"},
+ {"TX SMIC MUX0", "SWR_MIC5", "TX SWR_MIC5"},
+ {"TX SMIC MUX0", "SWR_MIC6", "TX SWR_MIC6"},
+ {"TX SMIC MUX0", "SWR_MIC7", "TX SWR_MIC7"},
+ {"TX SMIC MUX0", "SWR_MIC8", "TX SWR_MIC8"},
+ {"TX SMIC MUX0", "SWR_MIC9", "TX SWR_MIC9"},
+ {"TX SMIC MUX0", "SWR_MIC10", "TX SWR_MIC10"},
+ {"TX SMIC MUX0", "SWR_MIC11", "TX SWR_MIC11"},
+
+ {"TX DEC1 MUX", "MSM_DMIC", "TX DMIC MUX1"},
+ {"TX DMIC MUX1", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX1", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX1", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX1", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX1", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX1", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX1", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX1", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"},
+ {"TX SMIC MUX1", "SWR_MIC0", "TX SWR_MIC0"},
+ {"TX SMIC MUX1", "SWR_MIC1", "TX SWR_MIC1"},
+ {"TX SMIC MUX1", "SWR_MIC2", "TX SWR_MIC2"},
+ {"TX SMIC MUX1", "SWR_MIC3", "TX SWR_MIC3"},
+ {"TX SMIC MUX1", "SWR_MIC4", "TX SWR_MIC4"},
+ {"TX SMIC MUX1", "SWR_MIC5", "TX SWR_MIC5"},
+ {"TX SMIC MUX1", "SWR_MIC6", "TX SWR_MIC6"},
+ {"TX SMIC MUX1", "SWR_MIC7", "TX SWR_MIC7"},
+ {"TX SMIC MUX1", "SWR_MIC8", "TX SWR_MIC8"},
+ {"TX SMIC MUX1", "SWR_MIC9", "TX SWR_MIC9"},
+ {"TX SMIC MUX1", "SWR_MIC10", "TX SWR_MIC10"},
+ {"TX SMIC MUX1", "SWR_MIC11", "TX SWR_MIC11"},
+
+ {"TX DEC2 MUX", "MSM_DMIC", "TX DMIC MUX2"},
+ {"TX DMIC MUX2", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX2", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX2", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX2", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX2", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX2", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX2", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX2", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"},
+ {"TX SMIC MUX2", "SWR_MIC0", "TX SWR_MIC0"},
+ {"TX SMIC MUX2", "SWR_MIC1", "TX SWR_MIC1"},
+ {"TX SMIC MUX2", "SWR_MIC2", "TX SWR_MIC2"},
+ {"TX SMIC MUX2", "SWR_MIC3", "TX SWR_MIC3"},
+ {"TX SMIC MUX2", "SWR_MIC4", "TX SWR_MIC4"},
+ {"TX SMIC MUX2", "SWR_MIC5", "TX SWR_MIC5"},
+ {"TX SMIC MUX2", "SWR_MIC6", "TX SWR_MIC6"},
+ {"TX SMIC MUX2", "SWR_MIC7", "TX SWR_MIC7"},
+ {"TX SMIC MUX2", "SWR_MIC8", "TX SWR_MIC8"},
+ {"TX SMIC MUX2", "SWR_MIC9", "TX SWR_MIC9"},
+ {"TX SMIC MUX2", "SWR_MIC10", "TX SWR_MIC10"},
+ {"TX SMIC MUX2", "SWR_MIC11", "TX SWR_MIC11"},
+
+ {"TX DEC3 MUX", "MSM_DMIC", "TX DMIC MUX3"},
+ {"TX DMIC MUX3", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX3", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX3", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX3", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX3", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX3", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX3", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX3", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"},
+ {"TX SMIC MUX3", "SWR_MIC0", "TX SWR_MIC0"},
+ {"TX SMIC MUX3", "SWR_MIC1", "TX SWR_MIC1"},
+ {"TX SMIC MUX3", "SWR_MIC2", "TX SWR_MIC2"},
+ {"TX SMIC MUX3", "SWR_MIC3", "TX SWR_MIC3"},
+ {"TX SMIC MUX3", "SWR_MIC4", "TX SWR_MIC4"},
+ {"TX SMIC MUX3", "SWR_MIC5", "TX SWR_MIC5"},
+ {"TX SMIC MUX3", "SWR_MIC6", "TX SWR_MIC6"},
+ {"TX SMIC MUX3", "SWR_MIC7", "TX SWR_MIC7"},
+ {"TX SMIC MUX3", "SWR_MIC8", "TX SWR_MIC8"},
+ {"TX SMIC MUX3", "SWR_MIC9", "TX SWR_MIC9"},
+ {"TX SMIC MUX3", "SWR_MIC10", "TX SWR_MIC10"},
+ {"TX SMIC MUX3", "SWR_MIC11", "TX SWR_MIC11"},
+};
+
+static const struct snd_soc_dapm_route tx_audio_map_v3[] = {
+ {"TX_AIF1_CAP Mixer", "DEC4", "TX DEC4 MUX"},
+ {"TX_AIF1_CAP Mixer", "DEC5", "TX DEC5 MUX"},
+ {"TX_AIF1_CAP Mixer", "DEC6", "TX DEC6 MUX"},
+ {"TX_AIF1_CAP Mixer", "DEC7", "TX DEC7 MUX"},
+
+ {"TX_AIF2_CAP Mixer", "DEC4", "TX DEC4 MUX"},
+ {"TX_AIF2_CAP Mixer", "DEC5", "TX DEC5 MUX"},
+ {"TX_AIF2_CAP Mixer", "DEC6", "TX DEC6 MUX"},
+ {"TX_AIF2_CAP Mixer", "DEC7", "TX DEC7 MUX"},
+
+ {"TX_AIF3_CAP Mixer", "DEC4", "TX DEC4 MUX"},
+ {"TX_AIF3_CAP Mixer", "DEC5", "TX DEC5 MUX"},
+ {"TX_AIF3_CAP Mixer", "DEC6", "TX DEC6 MUX"},
+ {"TX_AIF3_CAP Mixer", "DEC7", "TX DEC7 MUX"},
+
+ {"TX DEC4 MUX", NULL, "TX_MCLK"},
+ {"TX DEC5 MUX", NULL, "TX_MCLK"},
+ {"TX DEC6 MUX", NULL, "TX_MCLK"},
+ {"TX DEC7 MUX", NULL, "TX_MCLK"},
+
+ {"TX DEC4 MUX", "MSM_DMIC", "TX DMIC MUX4"},
+ {"TX DMIC MUX4", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX4", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX4", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX4", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX4", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX4", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX4", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX4", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"},
+ {"TX SMIC MUX4", "SWR_MIC0", "TX SWR_MIC0"},
+ {"TX SMIC MUX4", "SWR_MIC1", "TX SWR_MIC1"},
+ {"TX SMIC MUX4", "SWR_MIC2", "TX SWR_MIC2"},
+ {"TX SMIC MUX4", "SWR_MIC3", "TX SWR_MIC3"},
+ {"TX SMIC MUX4", "SWR_MIC4", "TX SWR_MIC4"},
+ {"TX SMIC MUX4", "SWR_MIC5", "TX SWR_MIC5"},
+ {"TX SMIC MUX4", "SWR_MIC6", "TX SWR_MIC6"},
+ {"TX SMIC MUX4", "SWR_MIC7", "TX SWR_MIC7"},
+ {"TX SMIC MUX4", "SWR_MIC8", "TX SWR_MIC8"},
+ {"TX SMIC MUX4", "SWR_MIC9", "TX SWR_MIC9"},
+ {"TX SMIC MUX4", "SWR_MIC10", "TX SWR_MIC10"},
+ {"TX SMIC MUX4", "SWR_MIC11", "TX SWR_MIC11"},
+
+ {"TX DEC5 MUX", "MSM_DMIC", "TX DMIC MUX5"},
+ {"TX DMIC MUX5", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX5", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX5", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX5", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX5", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX5", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX5", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX5", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"},
+ {"TX SMIC MUX5", "SWR_MIC0", "TX SWR_MIC0"},
+ {"TX SMIC MUX5", "SWR_MIC1", "TX SWR_MIC1"},
+ {"TX SMIC MUX5", "SWR_MIC2", "TX SWR_MIC2"},
+ {"TX SMIC MUX5", "SWR_MIC3", "TX SWR_MIC3"},
+ {"TX SMIC MUX5", "SWR_MIC4", "TX SWR_MIC4"},
+ {"TX SMIC MUX5", "SWR_MIC5", "TX SWR_MIC5"},
+ {"TX SMIC MUX5", "SWR_MIC6", "TX SWR_MIC6"},
+ {"TX SMIC MUX5", "SWR_MIC7", "TX SWR_MIC7"},
+ {"TX SMIC MUX5", "SWR_MIC8", "TX SWR_MIC8"},
+ {"TX SMIC MUX5", "SWR_MIC9", "TX SWR_MIC9"},
+ {"TX SMIC MUX5", "SWR_MIC10", "TX SWR_MIC10"},
+ {"TX SMIC MUX5", "SWR_MIC11", "TX SWR_MIC11"},
+
+ {"TX DEC6 MUX", "MSM_DMIC", "TX DMIC MUX6"},
+ {"TX DMIC MUX6", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX6", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX6", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX6", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX6", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX6", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX6", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX6", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"},
+ {"TX SMIC MUX6", "SWR_MIC0", "TX SWR_MIC0"},
+ {"TX SMIC MUX6", "SWR_MIC1", "TX SWR_MIC1"},
+ {"TX SMIC MUX6", "SWR_MIC2", "TX SWR_MIC2"},
+ {"TX SMIC MUX6", "SWR_MIC3", "TX SWR_MIC3"},
+ {"TX SMIC MUX6", "SWR_MIC4", "TX SWR_MIC4"},
+ {"TX SMIC MUX6", "SWR_MIC5", "TX SWR_MIC5"},
+ {"TX SMIC MUX6", "SWR_MIC6", "TX SWR_MIC6"},
+ {"TX SMIC MUX6", "SWR_MIC7", "TX SWR_MIC7"},
+ {"TX SMIC MUX6", "SWR_MIC8", "TX SWR_MIC8"},
+ {"TX SMIC MUX6", "SWR_MIC9", "TX SWR_MIC9"},
+ {"TX SMIC MUX6", "SWR_MIC10", "TX SWR_MIC10"},
+ {"TX SMIC MUX6", "SWR_MIC11", "TX SWR_MIC11"},
+
+ {"TX DEC7 MUX", "MSM_DMIC", "TX DMIC MUX7"},
+ {"TX DMIC MUX7", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX7", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX7", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX7", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX7", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX7", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX7", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX7", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"},
+ {"TX SMIC MUX7", "SWR_MIC0", "TX SWR_MIC0"},
+ {"TX SMIC MUX7", "SWR_MIC1", "TX SWR_MIC1"},
+ {"TX SMIC MUX7", "SWR_MIC2", "TX SWR_MIC2"},
+ {"TX SMIC MUX7", "SWR_MIC3", "TX SWR_MIC3"},
+ {"TX SMIC MUX7", "SWR_MIC4", "TX SWR_MIC4"},
+ {"TX SMIC MUX7", "SWR_MIC5", "TX SWR_MIC5"},
+ {"TX SMIC MUX7", "SWR_MIC6", "TX SWR_MIC6"},
+ {"TX SMIC MUX7", "SWR_MIC7", "TX SWR_MIC7"},
+ {"TX SMIC MUX7", "SWR_MIC8", "TX SWR_MIC8"},
+ {"TX SMIC MUX7", "SWR_MIC9", "TX SWR_MIC9"},
+ {"TX SMIC MUX7", "SWR_MIC10", "TX SWR_MIC10"},
+ {"TX SMIC MUX7", "SWR_MIC11", "TX SWR_MIC11"},
+
+ {"TX SMIC MUX0", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX1", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX2", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX3", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX4", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX5", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX6", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX7", NULL, "TX_SWR_CLK"},
+};
+
static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX_AIF1 CAP", NULL, "TX_MCLK"},
{"TX_AIF2 CAP", NULL, "TX_MCLK"},
@@ -1667,6 +2178,63 @@
{"TX SMIC MUX7", "SWR_DMIC7", "TX SWR_DMIC7"},
};
+static const struct snd_kcontrol_new tx_macro_snd_controls_common[] = {
+ SOC_SINGLE_SX_TLV("TX_DEC0 Volume",
+ BOLERO_CDC_TX0_TX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("TX_DEC1 Volume",
+ BOLERO_CDC_TX1_TX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("TX_DEC2 Volume",
+ BOLERO_CDC_TX2_TX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("TX_DEC3 Volume",
+ BOLERO_CDC_TX3_TX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+
+ SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC1 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC2 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC3 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_SINGLE_EXT("DEC0_BCS Switch", SND_SOC_NOPM, 0, 1, 0,
+ tx_macro_get_bcs, tx_macro_set_bcs),
+};
+
+static const struct snd_kcontrol_new tx_macro_snd_controls_v3[] = {
+ SOC_SINGLE_SX_TLV("TX_DEC4 Volume",
+ BOLERO_CDC_TX4_TX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("TX_DEC5 Volume",
+ BOLERO_CDC_TX5_TX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("TX_DEC6 Volume",
+ BOLERO_CDC_TX6_TX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("TX_DEC7 Volume",
+ BOLERO_CDC_TX7_TX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+
+ SOC_ENUM_EXT("DEC4 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC5 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC6 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+
+ SOC_ENUM_EXT("DEC7 MODE", dec_mode_mux_enum,
+ tx_macro_dec_mode_get, tx_macro_dec_mode_put),
+};
+
static const struct snd_kcontrol_new tx_macro_snd_controls[] = {
SOC_SINGLE_SX_TLV("TX_DEC0 Volume",
BOLERO_CDC_TX0_TX_VOL_CTL,
@@ -1952,7 +2520,6 @@
static int tx_macro_core_vote(void *handle, bool enable)
{
struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle;
- int ret = 0;
if (tx_priv == NULL) {
pr_err("%s: tx priv data is NULL\n", __func__);
@@ -1964,7 +2531,10 @@
pm_runtime_mark_last_busy(tx_priv->dev);
}
- return ret;
+ if (bolero_check_core_votes(tx_priv->dev))
+ return 0;
+ else
+ return -EINVAL;
}
static int tx_macro_swrm_clock(void *handle, bool enable)
@@ -2124,18 +2694,65 @@
"%s: priv is null for macro!\n", __func__);
return -EINVAL;
}
- ret = snd_soc_dapm_new_controls(dapm, tx_macro_dapm_widgets,
+ tx_priv->version = bolero_get_version(tx_dev);
+ if (tx_priv->version >= BOLERO_VERSION_2_0) {
+ ret = snd_soc_dapm_new_controls(dapm,
+ tx_macro_dapm_widgets_common,
+ ARRAY_SIZE(tx_macro_dapm_widgets_common));
+ if (ret < 0) {
+ dev_err(tx_dev, "%s: Failed to add controls\n",
+ __func__);
+ return ret;
+ }
+ if (tx_priv->version == BOLERO_VERSION_2_1)
+ ret = snd_soc_dapm_new_controls(dapm,
+ tx_macro_dapm_widgets_v2,
+ ARRAY_SIZE(tx_macro_dapm_widgets_v2));
+ else if (tx_priv->version == BOLERO_VERSION_2_0)
+ ret = snd_soc_dapm_new_controls(dapm,
+ tx_macro_dapm_widgets_v3,
+ ARRAY_SIZE(tx_macro_dapm_widgets_v3));
+ if (ret < 0) {
+ dev_err(tx_dev, "%s: Failed to add controls\n",
+ __func__);
+ return ret;
+ }
+ } else {
+ ret = snd_soc_dapm_new_controls(dapm, tx_macro_dapm_widgets,
ARRAY_SIZE(tx_macro_dapm_widgets));
- if (ret < 0) {
- dev_err(tx_dev, "%s: Failed to add controls\n", __func__);
- return ret;
+ if (ret < 0) {
+ dev_err(tx_dev, "%s: Failed to add controls\n",
+ __func__);
+ return ret;
+ }
}
- ret = snd_soc_dapm_add_routes(dapm, tx_audio_map,
+ if (tx_priv->version >= BOLERO_VERSION_2_0) {
+ ret = snd_soc_dapm_add_routes(dapm,
+ tx_audio_map_common,
+ ARRAY_SIZE(tx_audio_map_common));
+ if (ret < 0) {
+ dev_err(tx_dev, "%s: Failed to add routes\n",
+ __func__);
+ return ret;
+ }
+ if (tx_priv->version == BOLERO_VERSION_2_0)
+ ret = snd_soc_dapm_add_routes(dapm,
+ tx_audio_map_v3,
+ ARRAY_SIZE(tx_audio_map_v3));
+ if (ret < 0) {
+ dev_err(tx_dev, "%s: Failed to add routes\n",
+ __func__);
+ return ret;
+ }
+ } else {
+ ret = snd_soc_dapm_add_routes(dapm, tx_audio_map,
ARRAY_SIZE(tx_audio_map));
- if (ret < 0) {
- dev_err(tx_dev, "%s: Failed to add routes\n", __func__);
- return ret;
+ if (ret < 0) {
+ dev_err(tx_dev, "%s: Failed to add routes\n",
+ __func__);
+ return ret;
+ }
}
ret = snd_soc_dapm_new_widgets(dapm->card);
@@ -2144,28 +2761,65 @@
return ret;
}
- ret = snd_soc_add_component_controls(component, tx_macro_snd_controls,
- ARRAY_SIZE(tx_macro_snd_controls));
- if (ret < 0) {
- dev_err(tx_dev, "%s: Failed to add snd_ctls\n", __func__);
- return ret;
+ if (tx_priv->version >= BOLERO_VERSION_2_0) {
+ ret = snd_soc_add_component_controls(component,
+ tx_macro_snd_controls_common,
+ ARRAY_SIZE(tx_macro_snd_controls_common));
+ if (ret < 0) {
+ dev_err(tx_dev, "%s: Failed to add snd_ctls\n",
+ __func__);
+ return ret;
+ }
+ if (tx_priv->version == BOLERO_VERSION_2_0)
+ ret = snd_soc_add_component_controls(component,
+ tx_macro_snd_controls_v3,
+ ARRAY_SIZE(tx_macro_snd_controls_v3));
+ if (ret < 0) {
+ dev_err(tx_dev, "%s: Failed to add snd_ctls\n",
+ __func__);
+ return ret;
+ }
+ } else {
+ ret = snd_soc_add_component_controls(component,
+ tx_macro_snd_controls,
+ ARRAY_SIZE(tx_macro_snd_controls));
+ if (ret < 0) {
+ dev_err(tx_dev, "%s: Failed to add snd_ctls\n",
+ __func__);
+ return ret;
+ }
}
snd_soc_dapm_ignore_suspend(dapm, "TX_AIF1 Capture");
snd_soc_dapm_ignore_suspend(dapm, "TX_AIF2 Capture");
snd_soc_dapm_ignore_suspend(dapm, "TX_AIF3 Capture");
- snd_soc_dapm_ignore_suspend(dapm, "TX SWR_ADC0");
- snd_soc_dapm_ignore_suspend(dapm, "TX SWR_ADC1");
- snd_soc_dapm_ignore_suspend(dapm, "TX SWR_ADC2");
- snd_soc_dapm_ignore_suspend(dapm, "TX SWR_ADC3");
- snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC0");
- snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC1");
- snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC2");
- snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC3");
- snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC4");
- snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC5");
- snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC6");
- snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC7");
+ if (tx_priv->version >= BOLERO_VERSION_2_0) {
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_MIC0");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_MIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_MIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_MIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_MIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_MIC5");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_MIC6");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_MIC7");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_MIC8");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_MIC9");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_MIC10");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_MIC11");
+ } else {
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_ADC0");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_ADC1");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_ADC2");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_ADC3");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC0");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC5");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC6");
+ snd_soc_dapm_ignore_suspend(dapm, "TX SWR_DMIC7");
+ }
snd_soc_dapm_sync(dapm);
for (i = 0; i < NUM_DECIMATORS; i++) {
@@ -2189,6 +2843,13 @@
tx_macro_reg_init[i].mask,
tx_macro_reg_init[i].val);
+ if (tx_priv->version == BOLERO_VERSION_2_1)
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_VA_TOP_CSR_SWR_CTRL, 0xF0, 0xA0);
+ else if (tx_priv->version == BOLERO_VERSION_2_0)
+ snd_soc_component_update_bits(component,
+ BOLERO_CDC_TX_TOP_CSR_SWR_CTRL, 0xF0, 0xA0);
+
return 0;
}
@@ -2421,19 +3082,21 @@
sample_rate, tx_priv) == TX_MACRO_DMIC_SAMPLE_RATE_UNDEFINED)
return -EINVAL;
}
- tx_priv->reset_swr = true;
- INIT_WORK(&tx_priv->tx_macro_add_child_devices_work,
- tx_macro_add_child_devices);
- tx_priv->swr_plat_data.handle = (void *) tx_priv;
- tx_priv->swr_plat_data.read = NULL;
- tx_priv->swr_plat_data.write = NULL;
- tx_priv->swr_plat_data.bulk_write = NULL;
- tx_priv->swr_plat_data.clk = tx_macro_swrm_clock;
- tx_priv->swr_plat_data.core_vote = tx_macro_core_vote;
- tx_priv->swr_plat_data.handle_irq = NULL;
-
+ if (is_used_tx_swr_gpio) {
+ tx_priv->reset_swr = true;
+ INIT_WORK(&tx_priv->tx_macro_add_child_devices_work,
+ tx_macro_add_child_devices);
+ tx_priv->swr_plat_data.handle = (void *) tx_priv;
+ tx_priv->swr_plat_data.read = NULL;
+ tx_priv->swr_plat_data.write = NULL;
+ tx_priv->swr_plat_data.bulk_write = NULL;
+ tx_priv->swr_plat_data.clk = tx_macro_swrm_clock;
+ tx_priv->swr_plat_data.core_vote = tx_macro_core_vote;
+ tx_priv->swr_plat_data.handle_irq = NULL;
+ mutex_init(&tx_priv->swr_clk_lock);
+ }
+ tx_priv->is_used_tx_swr_gpio = is_used_tx_swr_gpio;
mutex_init(&tx_priv->mclk_lock);
- mutex_init(&tx_priv->swr_clk_lock);
tx_macro_init_ops(&ops, tx_io_base);
ops.clk_id_req = TX_CORE_CLK;
ops.default_clk_id = TX_CORE_CLK;
@@ -2443,8 +3106,8 @@
"%s: register macro failed\n", __func__);
goto err_reg_macro;
}
-
- schedule_work(&tx_priv->tx_macro_add_child_devices_work);
+ if (is_used_tx_swr_gpio)
+ schedule_work(&tx_priv->tx_macro_add_child_devices_work);
pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
@@ -2454,7 +3117,8 @@
return 0;
err_reg_macro:
mutex_destroy(&tx_priv->mclk_lock);
- mutex_destroy(&tx_priv->swr_clk_lock);
+ if (is_used_tx_swr_gpio)
+ mutex_destroy(&tx_priv->swr_clk_lock);
return ret;
}
@@ -2468,16 +3132,20 @@
if (!tx_priv)
return -EINVAL;
- if (tx_priv->swr_ctrl_data)
- kfree(tx_priv->swr_ctrl_data);
- for (count = 0; count < tx_priv->child_count &&
- count < TX_MACRO_CHILD_DEVICES_MAX; count++)
- platform_device_unregister(tx_priv->pdev_child_devices[count]);
+ if (tx_priv->is_used_tx_swr_gpio) {
+ if (tx_priv->swr_ctrl_data)
+ kfree(tx_priv->swr_ctrl_data);
+ for (count = 0; count < tx_priv->child_count &&
+ count < TX_MACRO_CHILD_DEVICES_MAX; count++)
+ platform_device_unregister(
+ tx_priv->pdev_child_devices[count]);
+ }
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
mutex_destroy(&tx_priv->mclk_lock);
- mutex_destroy(&tx_priv->swr_clk_lock);
+ if (tx_priv->is_used_tx_swr_gpio)
+ mutex_destroy(&tx_priv->swr_clk_lock);
bolero_unregister_macro(&pdev->dev, TX_MACRO);
return 0;
}
diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c
index b7d6fe0..c5f0ef9 100644
--- a/asoc/codecs/bolero/va-macro.c
+++ b/asoc/codecs/bolero/va-macro.c
@@ -13,6 +13,9 @@
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <linux/pm_runtime.h>
+#include <asoc/msm-cdc-pinctrl.h>
+#include <soc/swr-common.h>
+#include <soc/swr-wcd.h>
#include "bolero-cdc.h"
#include "bolero-cdc-registers.h"
#include "bolero-clk-rsc.h"
@@ -46,6 +49,9 @@
#define BOLERO_CDC_VA_TX_UNMUTE_DELAY_MS 40
#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;
module_param(va_tx_unmute_delay, int, 0664);
@@ -85,6 +91,11 @@
SWR_MIC,
};
+enum {
+ TX_MCLK,
+ VA_MCLK,
+};
+
struct va_mute_work {
struct va_macro_priv *va_priv;
u32 decimator;
@@ -98,12 +109,31 @@
struct delayed_work dwork;
};
+/* Hold instance to soundwire platform device */
+struct va_macro_swr_ctrl_data {
+ struct platform_device *va_swr_pdev;
+};
+
+struct va_macro_swr_ctrl_platform_data {
+ void *handle; /* holds codec private data */
+ int (*read)(void *handle, int reg);
+ 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 (*handle_irq)(void *handle,
+ irqreturn_t (*swrm_irq_handler)(int irq,
+ void *data),
+ void *swrm_handle,
+ int action);
+};
+
struct va_macro_priv {
struct device *dev;
bool dec_active[VA_MACRO_NUM_DECIMATORS];
bool va_without_decimation;
struct clk *lpass_audio_hw_vote;
struct mutex mclk_lock;
+ struct mutex swr_clk_lock;
struct snd_soc_component *component;
struct hpf_work va_hpf_work[VA_MACRO_NUM_DECIMATORS];
struct va_mute_work va_mute_dwork[VA_MACRO_NUM_DECIMATORS];
@@ -115,15 +145,29 @@
s32 dmic_6_7_clk_cnt;
u16 dmic_clk_div;
u16 va_mclk_users;
+ int swr_clk_users;
+ bool reset_swr;
+ struct device_node *va_swr_gpio_p;
+ struct va_macro_swr_ctrl_data *swr_ctrl_data;
+ struct va_macro_swr_ctrl_platform_data swr_plat_data;
+ struct work_struct va_macro_add_child_devices_work;
+ int child_count;
u16 mclk_mux_sel;
char __iomem *va_io_base;
char __iomem *va_island_mode_muxsel;
+ struct platform_device *pdev_child_devices
+ [VA_MACRO_CHILD_DEVICES_MAX];
struct regulator *micb_supply;
u32 micb_voltage;
u32 micb_current;
+ u32 version;
+ u32 is_used_va_swr_gpio;
int micb_users;
u16 default_clk_id;
u16 clk_id;
+ int tx_swr_clk_cnt;
+ int va_swr_clk_cnt;
+ int va_clk_status;
int tx_clk_status;
};
@@ -249,10 +293,25 @@
bolero_clk_rsc_request_clock(va_priv->dev,
va_priv->default_clk_id,
VA_CORE_CLK, false);
+ /* reset swr after ssr/pdr */
+ va_priv->reset_swr = true;
+ if (va_priv->swr_ctrl_data)
+ swrm_wcd_notify(
+ va_priv->swr_ctrl_data[0].va_swr_pdev,
+ SWR_DEVICE_SSR_UP, NULL);
+ break;
case BOLERO_MACRO_EVT_CLK_RESET:
bolero_rsc_clk_reset(va_dev, VA_CORE_CLK);
break;
case BOLERO_MACRO_EVT_SSR_DOWN:
+ 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) ||
!pm_runtime_suspended(va_dev))) {
ret = bolero_runtime_suspend(va_dev);
@@ -269,6 +328,54 @@
return 0;
}
+static int va_macro_swr_pwr_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);
+ int ret = 0;
+ 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++;
+ if (va_priv->swr_ctrl_data) {
+ ret = swrm_wcd_notify(
+ va_priv->swr_ctrl_data[0].va_swr_pdev,
+ SWR_REQ_CLK_SWITCH, NULL);
+ if (ret)
+ dev_dbg(va_dev, "%s: clock switch failed\n",
+ __func__);
+ }
+ msm_cdc_pinctrl_set_wakeup_capable(
+ va_priv->va_swr_gpio_p, false);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ msm_cdc_pinctrl_set_wakeup_capable(
+ va_priv->va_swr_gpio_p, true);
+ if (va_priv->swr_ctrl_data) {
+ ret = swrm_wcd_notify(
+ va_priv->swr_ctrl_data[0].va_swr_pdev,
+ SWR_REQ_CLK_SWITCH, NULL);
+ 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,
+ "%s: invalid DAPM event %d\n", __func__, event);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
static int va_macro_swr_pwr_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -312,6 +419,25 @@
return ret;
}
+static int va_macro_tx_swr_clk_event_v2(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct device *va_dev = NULL;
+ struct va_macro_priv *va_priv = NULL;
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+
+ if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
+ return -EINVAL;
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ ++va_priv->tx_swr_clk_cnt;
+ if (SND_SOC_DAPM_EVENT_OFF(event))
+ --va_priv->tx_swr_clk_cnt;
+
+ return 0;
+}
+
static int va_macro_mclk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -336,6 +462,8 @@
ret = va_macro_mclk_enable(va_priv, 1, true);
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->tx_clk_status > 0) {
bolero_clk_rsc_request_clock(va_priv->dev,
@@ -353,6 +481,204 @@
return ret;
}
+static int va_macro_tx_va_mclk_enable(struct va_macro_priv *va_priv,
+ struct regmap *regmap, int clk_type,
+ bool enable)
+{
+ int ret = 0, clk_tx_ret = 0;
+
+ dev_dbg(va_priv->dev,
+ "%s: clock type %s, enable: %s tx_mclk_users: %d\n",
+ __func__, (clk_type ? "VA_MCLK" : "TX_MCLK"),
+ (enable ? "enable" : "disable"), va_priv->va_mclk_users);
+
+ if (enable) {
+ if (va_priv->swr_clk_users == 0)
+ msm_cdc_pinctrl_select_active_state(
+ va_priv->va_swr_gpio_p);
+ clk_tx_ret = bolero_clk_rsc_request_clock(va_priv->dev,
+ TX_CORE_CLK,
+ TX_CORE_CLK,
+ true);
+ if (clk_type == TX_MCLK) {
+ ret = bolero_clk_rsc_request_clock(va_priv->dev,
+ TX_CORE_CLK,
+ TX_CORE_CLK,
+ true);
+ if (ret < 0) {
+ if (va_priv->swr_clk_users == 0)
+ msm_cdc_pinctrl_select_sleep_state(
+ va_priv->va_swr_gpio_p);
+ dev_err_ratelimited(va_priv->dev,
+ "%s: swr request clk failed\n",
+ __func__);
+ goto done;
+ }
+ bolero_clk_rsc_fs_gen_request(va_priv->dev,
+ true);
+ }
+ if (clk_type == VA_MCLK) {
+ ret = va_macro_mclk_enable(va_priv, 1, true);
+ if (ret < 0) {
+ if (va_priv->swr_clk_users == 0)
+ msm_cdc_pinctrl_select_sleep_state(
+ va_priv->va_swr_gpio_p);
+ dev_err_ratelimited(va_priv->dev,
+ "%s: request clock enable failed\n",
+ __func__);
+ goto done;
+ }
+ }
+ if (va_priv->swr_clk_users == 0) {
+ dev_dbg(va_priv->dev, "%s: reset_swr: %d\n",
+ __func__, va_priv->reset_swr);
+ if (va_priv->reset_swr)
+ regmap_update_bits(regmap,
+ BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
+ 0x02, 0x02);
+ regmap_update_bits(regmap,
+ BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
+ 0x01, 0x01);
+ if (va_priv->reset_swr)
+ regmap_update_bits(regmap,
+ BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
+ 0x02, 0x00);
+ va_priv->reset_swr = false;
+ }
+ if (!clk_tx_ret)
+ ret = bolero_clk_rsc_request_clock(va_priv->dev,
+ TX_CORE_CLK,
+ TX_CORE_CLK,
+ false);
+ va_priv->swr_clk_users++;
+ } else {
+ if (va_priv->swr_clk_users <= 0) {
+ dev_err_ratelimited(va_priv->dev,
+ "va swrm clock users already 0\n");
+ va_priv->swr_clk_users = 0;
+ return 0;
+ }
+ clk_tx_ret = bolero_clk_rsc_request_clock(va_priv->dev,
+ TX_CORE_CLK,
+ TX_CORE_CLK,
+ true);
+ va_priv->swr_clk_users--;
+ if (va_priv->swr_clk_users == 0)
+ regmap_update_bits(regmap,
+ BOLERO_CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
+ 0x01, 0x00);
+ if (clk_type == VA_MCLK)
+ va_macro_mclk_enable(va_priv, 0, true);
+ if (clk_type == TX_MCLK) {
+ bolero_clk_rsc_fs_gen_request(va_priv->dev,
+ false);
+ ret = bolero_clk_rsc_request_clock(va_priv->dev,
+ TX_CORE_CLK,
+ TX_CORE_CLK,
+ false);
+ if (ret < 0) {
+ dev_err_ratelimited(va_priv->dev,
+ "%s: swr request clk failed\n",
+ __func__);
+ goto done;
+ }
+ }
+ if (!clk_tx_ret)
+ ret = bolero_clk_rsc_request_clock(va_priv->dev,
+ TX_CORE_CLK,
+ TX_CORE_CLK,
+ false);
+ if (va_priv->swr_clk_users == 0)
+ msm_cdc_pinctrl_select_sleep_state(
+ va_priv->va_swr_gpio_p);
+ }
+ return 0;
+
+done:
+ if (!clk_tx_ret)
+ bolero_clk_rsc_request_clock(va_priv->dev,
+ TX_CORE_CLK,
+ TX_CORE_CLK,
+ false);
+ return ret;
+}
+
+static int va_macro_swrm_clock(void *handle, bool enable)
+{
+ struct va_macro_priv *va_priv = (struct va_macro_priv *) handle;
+ struct regmap *regmap = dev_get_regmap(va_priv->dev->parent, NULL);
+ int ret = 0;
+
+ if (regmap == NULL) {
+ dev_err(va_priv->dev, "%s: regmap is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&va_priv->swr_clk_lock);
+ dev_dbg(va_priv->dev,
+ "%s: swrm clock %s tx_swr_clk_cnt: %d va_swr_clk_cnt: %d\n",
+ __func__, (enable ? "enable" : "disable"),
+ va_priv->tx_swr_clk_cnt, va_priv->va_swr_clk_cnt);
+
+ if (enable) {
+ pm_runtime_get_sync(va_priv->dev);
+ 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)
+ goto done;
+ va_priv->va_clk_status++;
+ } else {
+ ret = va_macro_tx_va_mclk_enable(va_priv, regmap,
+ TX_MCLK, enable);
+ if (ret)
+ goto done;
+ va_priv->tx_clk_status++;
+ }
+ pm_runtime_mark_last_busy(va_priv->dev);
+ pm_runtime_put_autosuspend(va_priv->dev);
+ } else {
+ if (va_priv->va_clk_status && !va_priv->tx_clk_status) {
+ ret = va_macro_tx_va_mclk_enable(va_priv, regmap,
+ VA_MCLK, enable);
+ if (ret)
+ goto done;
+ --va_priv->va_clk_status;
+ } else if (!va_priv->va_clk_status && va_priv->tx_clk_status) {
+ ret = va_macro_tx_va_mclk_enable(va_priv, regmap,
+ TX_MCLK, enable);
+ if (ret)
+ goto done;
+ --va_priv->tx_clk_status;
+ } else if (va_priv->va_clk_status && va_priv->tx_clk_status) {
+ 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)
+ goto done;
+ --va_priv->va_clk_status;
+ } else {
+ ret = va_macro_tx_va_mclk_enable(va_priv, regmap,
+ TX_MCLK, enable);
+ if (ret)
+ goto done;
+ --va_priv->tx_clk_status;
+ }
+
+ } else {
+ dev_dbg(va_priv->dev,
+ "%s: Both clocks are disabled\n", __func__);
+ }
+ }
+ dev_dbg(va_priv->dev,
+ "%s: swrm clock users %d tx_clk_sts_cnt: %d va_clk_sts_cnt: %d\n",
+ __func__, va_priv->swr_clk_users, va_priv->tx_clk_status,
+ va_priv->va_clk_status);
+done:
+ mutex_unlock(&va_priv->swr_clk_lock);
+ return ret;
+}
+
static void va_macro_tx_hpf_corner_freq_callback(struct work_struct *work)
{
struct delayed_work *hpf_delayed_work;
@@ -393,10 +719,10 @@
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);
+ 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, 0x03, 0x01);
+ snd_soc_component_update_bits(component, hpf_gate_reg, 0x02, 0x00);
}
static void va_macro_mute_update_callback(struct work_struct *work)
@@ -688,6 +1014,10 @@
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);
hpf_cut_off_freq = (snd_soc_component_read32(
component, dec_cfg_reg) &
@@ -700,7 +1030,7 @@
TX_HPF_CUT_OFF_FREQ_MASK,
CF_MIN_3DB_150HZ << 5);
snd_soc_component_update_bits(component,
- hpf_gate_reg, 0x02, 0x02);
+ hpf_gate_reg, 0x03, 0x03);
/*
* Minimum 1 clk cycle delay is required as per HW spec
*/
@@ -775,6 +1105,8 @@
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,
@@ -1118,6 +1450,28 @@
0, smic_mux_text, snd_soc_dapm_get_enum_double,
va_macro_put_dec_enum);
+static const char * const smic_mux_text_v2[] = {
+ "ZERO", "SWR_MIC0", "SWR_MIC1", "SWR_MIC2", "SWR_MIC3",
+ "SWR_MIC4", "SWR_MIC5", "SWR_MIC6", "SWR_MIC7",
+ "SWR_MIC8", "SWR_MIC9", "SWR_MIC10", "SWR_MIC11"
+};
+
+VA_MACRO_DAPM_ENUM_EXT(va_smic0_v2, BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0,
+ 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+ va_macro_put_dec_enum);
+
+VA_MACRO_DAPM_ENUM_EXT(va_smic1_v2, BOLERO_CDC_VA_INP_MUX_ADC_MUX1_CFG0,
+ 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+ va_macro_put_dec_enum);
+
+VA_MACRO_DAPM_ENUM_EXT(va_smic2_v3, BOLERO_CDC_VA_INP_MUX_ADC_MUX2_CFG0,
+ 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+ va_macro_put_dec_enum);
+
+VA_MACRO_DAPM_ENUM_EXT(va_smic3_v3, BOLERO_CDC_VA_INP_MUX_ADC_MUX3_CFG0,
+ 0, smic_mux_text_v2, snd_soc_dapm_get_enum_double,
+ va_macro_put_dec_enum);
+
static const struct snd_kcontrol_new va_aif1_cap_mixer[] = {
SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
va_macro_tx_mixer_get, va_macro_tx_mixer_put),
@@ -1175,6 +1529,202 @@
va_macro_tx_mixer_get, va_macro_tx_mixer_put),
};
+static const struct snd_kcontrol_new va_aif1_cap_mixer_v2[] = {
+ SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new va_aif2_cap_mixer_v2[] = {
+ SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new va_aif3_cap_mixer_v2[] = {
+ SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new va_aif1_cap_mixer_v3[] = {
+ SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new va_aif2_cap_mixer_v3[] = {
+ SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new va_aif3_cap_mixer_v3[] = {
+ SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+ SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0,
+ va_macro_tx_mixer_get, va_macro_tx_mixer_put),
+};
+
+static const struct snd_soc_dapm_widget va_macro_dapm_widgets_common[] = {
+ SND_SOC_DAPM_AIF_OUT_E("VA_AIF1 CAP", "VA_AIF1 Capture", 0,
+ SND_SOC_NOPM, VA_MACRO_AIF1_CAP, 0,
+ va_macro_enable_tx, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("VA_AIF2 CAP", "VA_AIF2 Capture", 0,
+ SND_SOC_NOPM, VA_MACRO_AIF2_CAP, 0,
+ va_macro_enable_tx, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_AIF_OUT_E("VA_AIF3 CAP", "VA_AIF3 Capture", 0,
+ SND_SOC_NOPM, VA_MACRO_AIF3_CAP, 0,
+ va_macro_enable_tx, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ VA_MACRO_DAPM_MUX("VA DMIC MUX0", 0, va_dmic0),
+ VA_MACRO_DAPM_MUX("VA DMIC MUX1", 0, va_dmic1),
+
+ VA_MACRO_DAPM_MUX("VA SMIC MUX0", 0, va_smic0_v2),
+ VA_MACRO_DAPM_MUX("VA SMIC MUX1", 0, va_smic1_v2),
+
+ SND_SOC_DAPM_INPUT("VA SWR_MIC0"),
+ SND_SOC_DAPM_INPUT("VA SWR_MIC1"),
+ SND_SOC_DAPM_INPUT("VA SWR_MIC2"),
+ SND_SOC_DAPM_INPUT("VA SWR_MIC3"),
+ SND_SOC_DAPM_INPUT("VA SWR_MIC4"),
+ SND_SOC_DAPM_INPUT("VA SWR_MIC5"),
+ SND_SOC_DAPM_INPUT("VA SWR_MIC6"),
+ SND_SOC_DAPM_INPUT("VA SWR_MIC7"),
+ SND_SOC_DAPM_INPUT("VA SWR_MIC8"),
+ SND_SOC_DAPM_INPUT("VA SWR_MIC9"),
+ SND_SOC_DAPM_INPUT("VA SWR_MIC10"),
+ SND_SOC_DAPM_INPUT("VA SWR_MIC11"),
+
+ SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS1", SND_SOC_NOPM, 0, 0,
+ va_macro_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("VA DMIC0", NULL, SND_SOC_NOPM, 0, 0,
+ va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("VA DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+ va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("VA DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+ va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("VA DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+ va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("VA DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+ va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("VA DMIC5", NULL, SND_SOC_NOPM, 0, 0,
+ va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("VA DMIC6", NULL, SND_SOC_NOPM, 0, 0,
+ va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("VA DMIC7", NULL, SND_SOC_NOPM, 0, 0,
+ va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("VA DEC0 MUX", SND_SOC_NOPM, VA_MACRO_DEC0, 0,
+ &va_dec0_mux, va_macro_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("VA DEC1 MUX", SND_SOC_NOPM, VA_MACRO_DEC1, 0,
+ &va_dec1_mux, va_macro_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("VA_MCLK", -1, SND_SOC_NOPM, 0, 0,
+ va_macro_mclk_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_widget va_macro_dapm_widgets_v2[] = {
+ SND_SOC_DAPM_MIXER("VA_AIF1_CAP Mixer", SND_SOC_NOPM,
+ VA_MACRO_AIF1_CAP, 0,
+ va_aif1_cap_mixer_v2, ARRAY_SIZE(va_aif1_cap_mixer_v2)),
+
+ SND_SOC_DAPM_MIXER("VA_AIF2_CAP Mixer", SND_SOC_NOPM,
+ VA_MACRO_AIF2_CAP, 0,
+ va_aif2_cap_mixer_v2, ARRAY_SIZE(va_aif2_cap_mixer_v2)),
+
+ SND_SOC_DAPM_MIXER("VA_AIF3_CAP Mixer", SND_SOC_NOPM,
+ VA_MACRO_AIF3_CAP, 0,
+ va_aif3_cap_mixer_v2, ARRAY_SIZE(va_aif3_cap_mixer_v2)),
+
+ SND_SOC_DAPM_SUPPLY_S("VA_SWR_PWR", -1, SND_SOC_NOPM, 0, 0,
+ va_macro_swr_pwr_event_v2,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ 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),
+};
+
+static const struct snd_soc_dapm_widget va_macro_dapm_widgets_v3[] = {
+ SND_SOC_DAPM_MIXER("VA_AIF1_CAP Mixer", SND_SOC_NOPM,
+ VA_MACRO_AIF1_CAP, 0,
+ va_aif1_cap_mixer_v3, ARRAY_SIZE(va_aif1_cap_mixer_v3)),
+
+ SND_SOC_DAPM_MIXER("VA_AIF2_CAP Mixer", SND_SOC_NOPM,
+ VA_MACRO_AIF2_CAP, 0,
+ va_aif2_cap_mixer_v3, ARRAY_SIZE(va_aif2_cap_mixer_v3)),
+
+ SND_SOC_DAPM_MIXER("VA_AIF3_CAP Mixer", SND_SOC_NOPM,
+ VA_MACRO_AIF3_CAP, 0,
+ va_aif3_cap_mixer_v3, ARRAY_SIZE(va_aif3_cap_mixer_v3)),
+
+ VA_MACRO_DAPM_MUX("VA DMIC MUX2", 0, va_dmic2),
+ VA_MACRO_DAPM_MUX("VA DMIC MUX3", 0, va_dmic3),
+
+ VA_MACRO_DAPM_MUX("VA SMIC MUX2", 0, va_smic2_v3),
+ VA_MACRO_DAPM_MUX("VA SMIC MUX3", 0, va_smic3_v3),
+
+ SND_SOC_DAPM_MUX_E("VA DEC2 MUX", SND_SOC_NOPM, VA_MACRO_DEC2, 0,
+ &va_dec2_mux, va_macro_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("VA DEC3 MUX", SND_SOC_NOPM, VA_MACRO_DEC3, 0,
+ &va_dec3_mux, va_macro_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("VA_SWR_PWR", -1, SND_SOC_NOPM, 0, 0,
+ va_macro_swr_pwr_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT_E("VA_AIF1 CAP", "VA_AIF1 Capture", 0,
SND_SOC_NOPM, VA_MACRO_AIF1_CAP, 0,
@@ -1325,6 +1875,146 @@
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
+static const struct snd_soc_dapm_route va_audio_map_common[] = {
+ {"VA_AIF1 CAP", NULL, "VA_MCLK"},
+ {"VA_AIF2 CAP", NULL, "VA_MCLK"},
+ {"VA_AIF3 CAP", NULL, "VA_MCLK"},
+
+ {"VA_AIF1 CAP", NULL, "VA_AIF1_CAP Mixer"},
+ {"VA_AIF2 CAP", NULL, "VA_AIF2_CAP Mixer"},
+ {"VA_AIF3 CAP", NULL, "VA_AIF3_CAP Mixer"},
+
+ {"VA_AIF1_CAP Mixer", "DEC0", "VA DEC0 MUX"},
+ {"VA_AIF1_CAP Mixer", "DEC1", "VA DEC1 MUX"},
+
+ {"VA_AIF2_CAP Mixer", "DEC0", "VA DEC0 MUX"},
+ {"VA_AIF2_CAP Mixer", "DEC1", "VA DEC1 MUX"},
+
+ {"VA_AIF3_CAP Mixer", "DEC0", "VA DEC0 MUX"},
+ {"VA_AIF3_CAP Mixer", "DEC1", "VA DEC1 MUX"},
+
+ {"VA DEC0 MUX", "MSM_DMIC", "VA DMIC MUX0"},
+ {"VA DMIC MUX0", "DMIC0", "VA DMIC0"},
+ {"VA DMIC MUX0", "DMIC1", "VA DMIC1"},
+ {"VA DMIC MUX0", "DMIC2", "VA DMIC2"},
+ {"VA DMIC MUX0", "DMIC3", "VA DMIC3"},
+ {"VA DMIC MUX0", "DMIC4", "VA DMIC4"},
+ {"VA DMIC MUX0", "DMIC5", "VA DMIC5"},
+ {"VA DMIC MUX0", "DMIC6", "VA DMIC6"},
+ {"VA DMIC MUX0", "DMIC7", "VA DMIC7"},
+
+ {"VA DEC0 MUX", "SWR_MIC", "VA SMIC MUX0"},
+ {"VA SMIC MUX0", "SWR_MIC0", "VA SWR_MIC0"},
+ {"VA SMIC MUX0", "SWR_MIC1", "VA SWR_MIC1"},
+ {"VA SMIC MUX0", "SWR_MIC2", "VA SWR_MIC2"},
+ {"VA SMIC MUX0", "SWR_MIC3", "VA SWR_MIC3"},
+ {"VA SMIC MUX0", "SWR_MIC4", "VA SWR_MIC4"},
+ {"VA SMIC MUX0", "SWR_MIC5", "VA SWR_MIC5"},
+ {"VA SMIC MUX0", "SWR_MIC6", "VA SWR_MIC6"},
+ {"VA SMIC MUX0", "SWR_MIC7", "VA SWR_MIC7"},
+ {"VA SMIC MUX0", "SWR_MIC8", "VA SWR_MIC8"},
+ {"VA SMIC MUX0", "SWR_MIC9", "VA SWR_MIC9"},
+ {"VA SMIC MUX0", "SWR_MIC10", "VA SWR_MIC10"},
+ {"VA SMIC MUX0", "SWR_MIC11", "VA SWR_MIC11"},
+
+ {"VA DEC1 MUX", "MSM_DMIC", "VA DMIC MUX1"},
+ {"VA DMIC MUX1", "DMIC0", "VA DMIC0"},
+ {"VA DMIC MUX1", "DMIC1", "VA DMIC1"},
+ {"VA DMIC MUX1", "DMIC2", "VA DMIC2"},
+ {"VA DMIC MUX1", "DMIC3", "VA DMIC3"},
+ {"VA DMIC MUX1", "DMIC4", "VA DMIC4"},
+ {"VA DMIC MUX1", "DMIC5", "VA DMIC5"},
+ {"VA DMIC MUX1", "DMIC6", "VA DMIC6"},
+ {"VA DMIC MUX1", "DMIC7", "VA DMIC7"},
+
+ {"VA DEC1 MUX", "SWR_MIC", "VA SMIC MUX1"},
+ {"VA SMIC MUX1", "SWR_MIC0", "VA SWR_MIC0"},
+ {"VA SMIC MUX1", "SWR_MIC1", "VA SWR_MIC1"},
+ {"VA SMIC MUX1", "SWR_MIC2", "VA SWR_MIC2"},
+ {"VA SMIC MUX1", "SWR_MIC3", "VA SWR_MIC3"},
+ {"VA SMIC MUX1", "SWR_MIC4", "VA SWR_MIC4"},
+ {"VA SMIC MUX1", "SWR_MIC5", "VA SWR_MIC5"},
+ {"VA SMIC MUX1", "SWR_MIC6", "VA SWR_MIC6"},
+ {"VA SMIC MUX1", "SWR_MIC7", "VA SWR_MIC7"},
+ {"VA SMIC MUX1", "SWR_MIC8", "VA SWR_MIC8"},
+ {"VA SMIC MUX1", "SWR_MIC9", "VA SWR_MIC9"},
+ {"VA SMIC MUX1", "SWR_MIC10", "VA SWR_MIC10"},
+ {"VA SMIC MUX1", "SWR_MIC11", "VA SWR_MIC11"},
+
+ {"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"},
+ {"VA SWR_MIC8", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC9", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC10", NULL, "VA_SWR_PWR"},
+ {"VA SWR_MIC11", NULL, "VA_SWR_PWR"},
+
+};
+
+static const struct snd_soc_dapm_route va_audio_map_v3[] = {
+ {"VA_AIF1_CAP Mixer", "DEC2", "VA DEC2 MUX"},
+ {"VA_AIF1_CAP Mixer", "DEC3", "VA DEC3 MUX"},
+
+ {"VA_AIF2_CAP Mixer", "DEC2", "VA DEC2 MUX"},
+ {"VA_AIF2_CAP Mixer", "DEC3", "VA DEC3 MUX"},
+
+ {"VA_AIF3_CAP Mixer", "DEC2", "VA DEC2 MUX"},
+ {"VA_AIF3_CAP Mixer", "DEC3", "VA DEC3 MUX"},
+
+ {"VA DEC2 MUX", "MSM_DMIC", "VA DMIC MUX2"},
+ {"VA DMIC MUX2", "DMIC0", "VA DMIC0"},
+ {"VA DMIC MUX2", "DMIC1", "VA DMIC1"},
+ {"VA DMIC MUX2", "DMIC2", "VA DMIC2"},
+ {"VA DMIC MUX2", "DMIC3", "VA DMIC3"},
+ {"VA DMIC MUX2", "DMIC4", "VA DMIC4"},
+ {"VA DMIC MUX2", "DMIC5", "VA DMIC5"},
+ {"VA DMIC MUX2", "DMIC6", "VA DMIC6"},
+ {"VA DMIC MUX2", "DMIC7", "VA DMIC7"},
+
+ {"VA DEC2 MUX", "SWR_MIC", "VA SMIC MUX2"},
+ {"VA SMIC MUX2", "SWR_MIC0", "VA SWR_MIC0"},
+ {"VA SMIC MUX2", "SWR_MIC1", "VA SWR_MIC1"},
+ {"VA SMIC MUX2", "SWR_MIC2", "VA SWR_MIC2"},
+ {"VA SMIC MUX2", "SWR_MIC3", "VA SWR_MIC3"},
+ {"VA SMIC MUX2", "SWR_MIC4", "VA SWR_MIC4"},
+ {"VA SMIC MUX2", "SWR_MIC5", "VA SWR_MIC5"},
+ {"VA SMIC MUX2", "SWR_MIC6", "VA SWR_MIC6"},
+ {"VA SMIC MUX2", "SWR_MIC7", "VA SWR_MIC7"},
+ {"VA SMIC MUX2", "SWR_MIC8", "VA SWR_MIC8"},
+ {"VA SMIC MUX2", "SWR_MIC9", "VA SWR_MIC9"},
+ {"VA SMIC MUX2", "SWR_MIC10", "VA SWR_MIC10"},
+ {"VA SMIC MUX2", "SWR_MIC11", "VA SWR_MIC11"},
+
+ {"VA DEC3 MUX", "MSM_DMIC", "VA DMIC MUX3"},
+ {"VA DMIC MUX3", "DMIC0", "VA DMIC0"},
+ {"VA DMIC MUX3", "DMIC1", "VA DMIC1"},
+ {"VA DMIC MUX3", "DMIC2", "VA DMIC2"},
+ {"VA DMIC MUX3", "DMIC3", "VA DMIC3"},
+ {"VA DMIC MUX3", "DMIC4", "VA DMIC4"},
+ {"VA DMIC MUX3", "DMIC5", "VA DMIC5"},
+ {"VA DMIC MUX3", "DMIC6", "VA DMIC6"},
+ {"VA DMIC MUX3", "DMIC7", "VA DMIC7"},
+
+ {"VA DEC3 MUX", "SWR_MIC", "VA SMIC MUX3"},
+ {"VA SMIC MUX3", "SWR_MIC0", "VA SWR_MIC0"},
+ {"VA SMIC MUX3", "SWR_MIC1", "VA SWR_MIC1"},
+ {"VA SMIC MUX3", "SWR_MIC2", "VA SWR_MIC2"},
+ {"VA SMIC MUX3", "SWR_MIC3", "VA SWR_MIC3"},
+ {"VA SMIC MUX3", "SWR_MIC4", "VA SWR_MIC4"},
+ {"VA SMIC MUX3", "SWR_MIC5", "VA SWR_MIC5"},
+ {"VA SMIC MUX3", "SWR_MIC6", "VA SWR_MIC6"},
+ {"VA SMIC MUX3", "SWR_MIC7", "VA SWR_MIC7"},
+ {"VA SMIC MUX3", "SWR_MIC8", "VA SWR_MIC8"},
+ {"VA SMIC MUX3", "SWR_MIC9", "VA SWR_MIC9"},
+ {"VA SMIC MUX3", "SWR_MIC10", "VA SWR_MIC10"},
+ {"VA SMIC MUX3", "SWR_MIC11", "VA SWR_MIC11"},
+};
+
static const struct snd_soc_dapm_route va_audio_map[] = {
{"VA_AIF1 CAP", NULL, "VA_MCLK"},
{"VA_AIF2 CAP", NULL, "VA_MCLK"},
@@ -1586,6 +2276,24 @@
0, -84, 40, digital_gain),
};
+static const struct snd_kcontrol_new va_macro_snd_controls_common[] = {
+ SOC_SINGLE_SX_TLV("VA_DEC0 Volume",
+ BOLERO_CDC_VA_TX0_TX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("VA_DEC1 Volume",
+ BOLERO_CDC_VA_TX1_TX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+};
+
+static const struct snd_kcontrol_new va_macro_snd_controls_v3[] = {
+ SOC_SINGLE_SX_TLV("VA_DEC2 Volume",
+ BOLERO_CDC_VA_TX2_TX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("VA_DEC3 Volume",
+ BOLERO_CDC_VA_TX3_TX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+};
+
static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate,
struct va_macro_priv *va_priv)
{
@@ -1670,18 +2378,65 @@
return 0;
}
- ret = snd_soc_dapm_new_controls(dapm, va_macro_dapm_widgets,
+ va_priv->version = bolero_get_version(va_dev);
+ if (va_priv->version >= BOLERO_VERSION_2_0) {
+ ret = snd_soc_dapm_new_controls(dapm,
+ va_macro_dapm_widgets_common,
+ ARRAY_SIZE(va_macro_dapm_widgets_common));
+ if (ret < 0) {
+ dev_err(va_dev, "%s: Failed to add controls\n",
+ __func__);
+ return ret;
+ }
+ if (va_priv->version == BOLERO_VERSION_2_1)
+ ret = snd_soc_dapm_new_controls(dapm,
+ va_macro_dapm_widgets_v2,
+ ARRAY_SIZE(va_macro_dapm_widgets_v2));
+ else if (va_priv->version == BOLERO_VERSION_2_0)
+ ret = snd_soc_dapm_new_controls(dapm,
+ va_macro_dapm_widgets_v3,
+ ARRAY_SIZE(va_macro_dapm_widgets_v3));
+ if (ret < 0) {
+ dev_err(va_dev, "%s: Failed to add controls\n",
+ __func__);
+ return ret;
+ }
+ } else {
+ ret = snd_soc_dapm_new_controls(dapm, va_macro_dapm_widgets,
ARRAY_SIZE(va_macro_dapm_widgets));
- if (ret < 0) {
- dev_err(va_dev, "%s: Failed to add controls\n", __func__);
- return ret;
+ if (ret < 0) {
+ dev_err(va_dev, "%s: Failed to add controls\n",
+ __func__);
+ return ret;
+ }
}
- ret = snd_soc_dapm_add_routes(dapm, va_audio_map,
+ if (va_priv->version >= BOLERO_VERSION_2_0) {
+ ret = snd_soc_dapm_add_routes(dapm,
+ va_audio_map_common,
+ ARRAY_SIZE(va_audio_map_common));
+ if (ret < 0) {
+ dev_err(va_dev, "%s: Failed to add routes\n",
+ __func__);
+ return ret;
+ }
+ 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;
+ }
+ } else {
+ ret = snd_soc_dapm_add_routes(dapm, va_audio_map,
ARRAY_SIZE(va_audio_map));
- 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;
+ }
}
ret = snd_soc_dapm_new_widgets(dapm->card);
@@ -1689,28 +2444,65 @@
dev_err(va_dev, "%s: Failed to add widgets\n", __func__);
return ret;
}
- ret = snd_soc_add_component_controls(component, va_macro_snd_controls,
- ARRAY_SIZE(va_macro_snd_controls));
- if (ret < 0) {
- dev_err(va_dev, "%s: Failed to add snd_ctls\n", __func__);
- return ret;
+ if (va_priv->version >= BOLERO_VERSION_2_0) {
+ ret = snd_soc_add_component_controls(component,
+ va_macro_snd_controls_common,
+ ARRAY_SIZE(va_macro_snd_controls_common));
+ if (ret < 0) {
+ dev_err(va_dev, "%s: Failed to add snd_ctls\n",
+ __func__);
+ return ret;
+ }
+ if (va_priv->version == BOLERO_VERSION_2_0)
+ ret = snd_soc_add_component_controls(component,
+ va_macro_snd_controls_v3,
+ ARRAY_SIZE(va_macro_snd_controls_v3));
+ if (ret < 0) {
+ dev_err(va_dev, "%s: Failed to add snd_ctls\n",
+ __func__);
+ return ret;
+ }
+ } else {
+ ret = snd_soc_add_component_controls(component,
+ va_macro_snd_controls,
+ ARRAY_SIZE(va_macro_snd_controls));
+ if (ret < 0) {
+ dev_err(va_dev, "%s: Failed to add snd_ctls\n",
+ __func__);
+ return ret;
+ }
}
snd_soc_dapm_ignore_suspend(dapm, "VA_AIF1 Capture");
snd_soc_dapm_ignore_suspend(dapm, "VA_AIF2 Capture");
snd_soc_dapm_ignore_suspend(dapm, "VA_AIF3 Capture");
- snd_soc_dapm_ignore_suspend(dapm, "VA SWR_ADC0");
- snd_soc_dapm_ignore_suspend(dapm, "VA SWR_ADC1");
- snd_soc_dapm_ignore_suspend(dapm, "VA SWR_ADC2");
- snd_soc_dapm_ignore_suspend(dapm, "VA SWR_ADC3");
- snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC0");
- snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC1");
- snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC2");
- snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC3");
- snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC4");
- snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC5");
- snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC6");
- snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC7");
+ if (va_priv->version >= BOLERO_VERSION_2_0) {
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC0");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC5");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC6");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC7");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC8");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC9");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC10");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC11");
+ } else {
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_ADC0");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_ADC1");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_ADC2");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_ADC3");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC0");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC4");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC5");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC6");
+ snd_soc_dapm_ignore_suspend(dapm, "VA SWR_MIC7");
+ }
snd_soc_dapm_sync(dapm);
for (i = 0; i < VA_MACRO_NUM_DECIMATORS; i++) {
@@ -1743,6 +2535,156 @@
return 0;
}
+static void va_macro_add_child_devices(struct work_struct *work)
+{
+ struct va_macro_priv *va_priv = NULL;
+ struct platform_device *pdev = NULL;
+ struct device_node *node = NULL;
+ struct va_macro_swr_ctrl_data *swr_ctrl_data = NULL, *temp = NULL;
+ int ret = 0;
+ u16 count = 0, ctrl_num = 0;
+ struct va_macro_swr_ctrl_platform_data *platdata = NULL;
+ char plat_dev_name[VA_MACRO_SWR_STRING_LEN] = "";
+ bool va_swr_master_node = false;
+
+ va_priv = container_of(work, struct va_macro_priv,
+ va_macro_add_child_devices_work);
+ if (!va_priv) {
+ pr_err("%s: Memory for va_priv does not exist\n",
+ __func__);
+ return;
+ }
+
+ if (!va_priv->dev) {
+ pr_err("%s: VA dev does not exist\n", __func__);
+ return;
+ }
+
+ if (!va_priv->dev->of_node) {
+ dev_err(va_priv->dev,
+ "%s: DT node for va_priv does not exist\n", __func__);
+ return;
+ }
+
+ platdata = &va_priv->swr_plat_data;
+ va_priv->child_count = 0;
+
+ for_each_available_child_of_node(va_priv->dev->of_node, node) {
+ va_swr_master_node = false;
+ if (strnstr(node->name, "va_swr_master",
+ strlen("va_swr_master")) != NULL)
+ va_swr_master_node = true;
+
+ if (va_swr_master_node)
+ strlcpy(plat_dev_name, "va_swr_ctrl",
+ (VA_MACRO_SWR_STRING_LEN - 1));
+ else
+ strlcpy(plat_dev_name, node->name,
+ (VA_MACRO_SWR_STRING_LEN - 1));
+
+ pdev = platform_device_alloc(plat_dev_name, -1);
+ if (!pdev) {
+ dev_err(va_priv->dev, "%s: pdev memory alloc failed\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+ pdev->dev.parent = va_priv->dev;
+ pdev->dev.of_node = node;
+
+ if (va_swr_master_node) {
+ ret = platform_device_add_data(pdev, platdata,
+ sizeof(*platdata));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: cannot add plat data ctrl:%d\n",
+ __func__, ctrl_num);
+ goto fail_pdev_add;
+ }
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Cannot add platform device\n",
+ __func__);
+ goto fail_pdev_add;
+ }
+
+ if (va_swr_master_node) {
+ temp = krealloc(swr_ctrl_data,
+ (ctrl_num + 1) * sizeof(
+ struct va_macro_swr_ctrl_data),
+ GFP_KERNEL);
+ if (!temp) {
+ ret = -ENOMEM;
+ goto fail_pdev_add;
+ }
+ swr_ctrl_data = temp;
+ swr_ctrl_data[ctrl_num].va_swr_pdev = pdev;
+ ctrl_num++;
+ dev_dbg(&pdev->dev,
+ "%s: Added soundwire ctrl device(s)\n",
+ __func__);
+ va_priv->swr_ctrl_data = swr_ctrl_data;
+ }
+ if (va_priv->child_count < VA_MACRO_CHILD_DEVICES_MAX)
+ va_priv->pdev_child_devices[
+ va_priv->child_count++] = pdev;
+ else
+ goto err;
+ }
+ return;
+fail_pdev_add:
+ for (count = 0; count < va_priv->child_count; count++)
+ platform_device_put(va_priv->pdev_child_devices[count]);
+err:
+ return;
+}
+
+static int va_macro_set_port_map(struct snd_soc_component *component,
+ u32 usecase, u32 size, void *data)
+{
+ struct device *va_dev = NULL;
+ struct va_macro_priv *va_priv = NULL;
+ struct swrm_port_config port_cfg;
+ int ret = 0;
+
+ if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
+ return -EINVAL;
+
+ memset(&port_cfg, 0, sizeof(port_cfg));
+ port_cfg.uc = usecase;
+ port_cfg.size = size;
+ port_cfg.params = data;
+
+ if (va_priv->swr_ctrl_data)
+ ret = swrm_wcd_notify(
+ va_priv->swr_ctrl_data[0].va_swr_pdev,
+ SWR_SET_PORT_MAP, &port_cfg);
+
+ return ret;
+}
+
+static int va_macro_reg_wake_irq(struct snd_soc_component *component,
+ u32 data)
+{
+ struct device *va_dev = NULL;
+ struct va_macro_priv *va_priv = NULL;
+ u32 ipc_wakeup = data;
+ int ret = 0;
+
+ if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
+ return -EINVAL;
+
+ if (va_priv->swr_ctrl_data)
+ ret = swrm_wcd_notify(
+ va_priv->swr_ctrl_data[0].va_swr_pdev,
+ SWR_REGISTER_WAKE_IRQ, &ipc_wakeup);
+
+ return ret;
+}
+
static void va_macro_init_ops(struct macro_ops *ops,
char __iomem *va_io_base,
bool va_without_decimation)
@@ -1759,6 +2701,8 @@
ops->exit = va_macro_deinit;
ops->io_base = va_io_base;
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;
}
static int va_macro_probe(struct platform_device *pdev)
@@ -1776,6 +2720,8 @@
const char *dmic_sample_rate = "qcom,va-dmic-sample-rate";
u32 default_clk_id = 0;
struct clk *lpass_audio_hw_vote = NULL;
+ u32 is_used_va_swr_gpio = 0;
+ const char *is_used_va_swr_gpio_dt = "qcom,is-used-swr-gpio";
va_priv = devm_kzalloc(&pdev->dev, sizeof(struct va_macro_priv),
GFP_KERNEL);
@@ -1806,6 +2752,31 @@
return -EINVAL;
}
+ if (of_find_property(pdev->dev.of_node, is_used_va_swr_gpio_dt,
+ NULL)) {
+ ret = of_property_read_u32(pdev->dev.of_node,
+ is_used_va_swr_gpio_dt,
+ &is_used_va_swr_gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: error reading %s in dt\n",
+ __func__, is_used_va_swr_gpio_dt);
+ is_used_va_swr_gpio = 0;
+ }
+ }
+ va_priv->va_swr_gpio_p = of_parse_phandle(pdev->dev.of_node,
+ "qcom,va-swr-gpios", 0);
+ if (!va_priv->va_swr_gpio_p && is_used_va_swr_gpio) {
+ dev_err(&pdev->dev, "%s: swr_gpios handle not provided!\n",
+ __func__);
+ return -EINVAL;
+ }
+ if ((msm_cdc_pinctrl_get_state(va_priv->va_swr_gpio_p) < 0) &&
+ is_used_va_swr_gpio) {
+ dev_err(&pdev->dev, "%s: failed to get swr pin state\n",
+ __func__);
+ return -EPROBE_DEFER;
+ }
+
va_io_base = devm_ioremap(&pdev->dev, va_base_addr,
VA_MACRO_MAX_OFFSET);
if (!va_io_base) {
@@ -1865,6 +2836,20 @@
va_priv->clk_id = VA_CORE_CLK;
va_priv->default_clk_id = default_clk_id;
+ if (is_used_va_swr_gpio) {
+ va_priv->reset_swr = true;
+ INIT_WORK(&va_priv->va_macro_add_child_devices_work,
+ va_macro_add_child_devices);
+ va_priv->swr_plat_data.handle = (void *) va_priv;
+ va_priv->swr_plat_data.read = NULL;
+ 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.handle_irq = NULL;
+ mutex_init(&va_priv->swr_clk_lock);
+ }
+ va_priv->is_used_va_swr_gpio = is_used_va_swr_gpio;
+
mutex_init(&va_priv->mclk_lock);
dev_set_drvdata(&pdev->dev, va_priv);
va_macro_init_ops(&ops, va_io_base, va_without_decimation);
@@ -1875,29 +2860,46 @@
dev_err(&pdev->dev, "%s: register macro failed\n", __func__);
goto reg_macro_fail;
}
+ if (is_used_va_swr_gpio)
+ schedule_work(&va_priv->va_macro_add_child_devices_work);
pm_runtime_set_autosuspend_delay(&pdev->dev, VA_AUTO_SUSPEND_DELAY);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
+ pm_suspend_ignore_children(&pdev->dev, true);
pm_runtime_enable(&pdev->dev);
return ret;
reg_macro_fail:
mutex_destroy(&va_priv->mclk_lock);
+ if (is_used_va_swr_gpio)
+ mutex_destroy(&va_priv->swr_clk_lock);
return ret;
}
static int va_macro_remove(struct platform_device *pdev)
{
struct va_macro_priv *va_priv;
+ int count = 0;
va_priv = dev_get_drvdata(&pdev->dev);
if (!va_priv)
return -EINVAL;
+ if (va_priv->is_used_va_swr_gpio) {
+ if (va_priv->swr_ctrl_data)
+ kfree(va_priv->swr_ctrl_data);
+ for (count = 0; count < va_priv->child_count &&
+ count < VA_MACRO_CHILD_DEVICES_MAX; count++)
+ platform_device_unregister(
+ va_priv->pdev_child_devices[count]);
+ }
+
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
bolero_unregister_macro(&pdev->dev, VA_MACRO);
mutex_destroy(&va_priv->mclk_lock);
+ if (va_priv->is_used_va_swr_gpio)
+ mutex_destroy(&va_priv->swr_clk_lock);
return 0;
}
diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c
index 623af37..03bea4e 100644
--- a/asoc/codecs/bolero/wsa-macro.c
+++ b/asoc/codecs/bolero/wsa-macro.c
@@ -2802,7 +2802,6 @@
static int wsa_macro_core_vote(void *handle, bool enable)
{
struct wsa_macro_priv *wsa_priv = (struct wsa_macro_priv *) handle;
- int ret = 0;
if (wsa_priv == NULL) {
pr_err("%s: wsa priv data is NULL\n", __func__);
@@ -2814,7 +2813,10 @@
pm_runtime_mark_last_busy(wsa_priv->dev);
}
- return ret;
+ if (bolero_check_core_votes(wsa_priv->dev))
+ return 0;
+ else
+ return -EINVAL;
}
static int wsa_swrm_clock(void *handle, bool enable)
@@ -3199,6 +3201,7 @@
pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
+ pm_suspend_ignore_children(&pdev->dev, true);
pm_runtime_enable(&pdev->dev);
return ret;
diff --git a/asoc/codecs/msm-cdc-pinctrl.c b/asoc/codecs/msm-cdc-pinctrl.c
index a10a681..5c6ca49 100644
--- a/asoc/codecs/msm-cdc-pinctrl.c
+++ b/asoc/codecs/msm-cdc-pinctrl.c
@@ -4,6 +4,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -23,8 +24,12 @@
int gpio;
bool state;
u32 tlmm_gpio[MAX_GPIOS];
+ char __iomem *chip_wakeup_register[MAX_GPIOS];
+ u32 chip_wakeup_maskbit[MAX_GPIOS];
u32 count;
+ u32 wakeup_reg_count;
bool wakeup_capable;
+ bool chip_wakeup_reg;
};
static struct msm_cdc_pinctrl_info *msm_cdc_pinctrl_get_gpiodata(
@@ -154,7 +159,7 @@
{
struct msm_cdc_pinctrl_info *gpio_data;
int ret = 0;
- u32 i = 0;
+ u32 i = 0, temp = 0;
gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
if (!gpio_data)
@@ -168,6 +173,18 @@
goto exit;
}
}
+ if (gpio_data->chip_wakeup_reg) {
+ for (i = 0; i < gpio_data->wakeup_reg_count; i++) {
+ temp = ioread32(gpio_data->chip_wakeup_register[i]);
+ if (enable)
+ temp |= (1 <<
+ gpio_data->chip_wakeup_maskbit[i]);
+ else
+ temp &= ~(1 <<
+ gpio_data->chip_wakeup_maskbit[i]);
+ iowrite32(temp, gpio_data->chip_wakeup_register[i]);
+ }
+ }
exit:
return ret;
}
@@ -178,7 +195,9 @@
int ret = 0;
struct msm_cdc_pinctrl_info *gpio_data;
u32 tlmm_gpio[MAX_GPIOS] = {0};
- u32 i = 0;
+ u32 chip_wakeup_reg[MAX_GPIOS] = {0};
+ u32 chip_wakeup_default_val[MAX_GPIOS] = {0};
+ u32 i = 0, temp = 0;
int count = 0;
gpio_data = devm_kzalloc(&pdev->dev,
@@ -223,6 +242,41 @@
}
+ count = of_property_count_u32_elems(pdev->dev.of_node, "qcom,chip-wakeup-reg");
+ if (count <= 0)
+ goto cdc_tlmm_gpio;
+ if (!of_property_read_u32_array(pdev->dev.of_node, "qcom,chip-wakeup-reg",
+ chip_wakeup_reg, count)) {
+ if (of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,chip-wakeup-maskbit",
+ gpio_data->chip_wakeup_maskbit, count)) {
+ dev_err(&pdev->dev,
+ "chip-wakeup-maskbit needed if chip-wakeup-reg is defined!\n");
+ goto cdc_tlmm_gpio;
+ }
+ gpio_data->chip_wakeup_reg = true;
+ for (i = 0; i < count; i++) {
+ 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,
+ "qcom,chip-wakeup-default-val",
+ chip_wakeup_default_val, count)) {
+ for (i = 0; i < count; i++) {
+ temp = ioread32(gpio_data->chip_wakeup_register[i]);
+ if (chip_wakeup_default_val[i])
+ temp |= (1 <<
+ gpio_data->chip_wakeup_maskbit[i]);
+ else
+ temp &= ~(1 <<
+ gpio_data->chip_wakeup_maskbit[i]);
+ iowrite32(temp, gpio_data->chip_wakeup_register[i]);
+ }
+ }
+ gpio_data->wakeup_reg_count = count;
+ }
+
+cdc_tlmm_gpio:
count = of_property_count_u32_elems(pdev->dev.of_node, "qcom,tlmm-gpio");
if (count <= 0)
goto cdc_rst;
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/wcd-mbhc-adc.c b/asoc/codecs/wcd-mbhc-adc.c
index 4de19de..0635d54 100644
--- a/asoc/codecs/wcd-mbhc-adc.c
+++ b/asoc/codecs/wcd-mbhc-adc.c
@@ -689,6 +689,14 @@
}
correct_plug_type:
+ /*
+ * Callback to disable BCS slow insertion detection
+ */
+ if (plug_type == MBHC_PLUG_TYPE_HEADSET ||
+ plug_type == MBHC_PLUG_TYPE_HEADPHONE)
+ 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)) {
if (mbhc->hs_detect_work_stop) {
@@ -833,6 +841,11 @@
wrk_complete = false;
}
}
+ if ((plug_type == MBHC_PLUG_TYPE_HEADSET ||
+ plug_type == MBHC_PLUG_TYPE_HEADPHONE))
+ if (mbhc->mbhc_cb->bcs_enable)
+ mbhc->mbhc_cb->bcs_enable(mbhc, true);
+
if (!wrk_complete) {
/*
* If plug_tye is headset, we might have already reported either
diff --git a/asoc/codecs/wcd-mbhc-v2.c b/asoc/codecs/wcd-mbhc-v2.c
index 01544aa..fd55715 100644
--- a/asoc/codecs/wcd-mbhc-v2.c
+++ b/asoc/codecs/wcd-mbhc-v2.c
@@ -883,7 +883,8 @@
detection_type);
ret = true;
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1);
- WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_DET_EN, 1);
+ if (mbhc->mbhc_cfg->gnd_det_en)
+ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_DET_EN, 1);
} else {
mbhc->mbhc_cb->mbhc_moisture_polling_ctrl(mbhc, false);
mbhc->mbhc_cb->mbhc_moisture_detect_en(mbhc, false);
@@ -1023,7 +1024,7 @@
mbhc->component, false);
}
- if (mbhc->mbhc_cfg->moisture_en &&
+ if (mbhc->mbhc_cfg->moisture_en ||
mbhc->mbhc_cfg->moisture_duty_cycle_en) {
if (mbhc->mbhc_cb->mbhc_moisture_polling_ctrl)
mbhc->mbhc_cb->mbhc_moisture_polling_ctrl(mbhc,
@@ -1055,6 +1056,10 @@
struct wcd_mbhc *mbhc = data;
pr_debug("%s: enter\n", __func__);
+ if (mbhc == NULL) {
+ pr_err("%s: NULL irq data\n", __func__);
+ return IRQ_NONE;
+ }
if (unlikely((mbhc->mbhc_cb->lock_sleep(mbhc, true)) == false)) {
pr_warn("%s: failed to hold suspend\n", __func__);
r = IRQ_NONE;
diff --git a/asoc/codecs/wcd-spi.c b/asoc/codecs/wcd-spi.c
index 0173e15..4c7a853 100644
--- a/asoc/codecs/wcd-spi.c
+++ b/asoc/codecs/wcd-spi.c
@@ -815,6 +815,15 @@
return -EINVAL;
}
+ WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex);
+ if (wcd_spi_is_suspended(wcd_spi)) {
+ dev_dbg(&spi->dev,
+ "%s: SPI suspended, cannot perform transfer\n",
+ __func__);
+ ret = -EIO;
+ goto done;
+ }
+
WCD_SPI_MUTEX_LOCK(spi, wcd_spi->xfer_mutex);
if (msg->len == WCD_SPI_WORD_BYTE_CNT) {
if (xfer_req == WCD_SPI_XFER_WRITE)
@@ -827,7 +836,8 @@
ret = wcd_spi_transfer_split(spi, msg, xfer_req);
}
WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->xfer_mutex);
-
+done:
+ WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex);
return ret;
}
diff --git a/asoc/codecs/wcd937x/Android.mk b/asoc/codecs/wcd937x/Android.mk
index cbd0877..4168dd1 100644
--- a/asoc/codecs/wcd937x/Android.mk
+++ b/asoc/codecs/wcd937x/Android.mk
@@ -7,9 +7,13 @@
AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m
endif
+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)),true)
+ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) bengal),true)
LOCAL_PATH := $(call my-dir)
diff --git a/asoc/codecs/wcd937x/Kbuild b/asoc/codecs/wcd937x/Kbuild
index b8db202..e353e8a 100644
--- a/asoc/codecs/wcd937x/Kbuild
+++ b/asoc/codecs/wcd937x/Kbuild
@@ -26,6 +26,11 @@
export
INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h
endif
+ 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:
diff --git a/asoc/codecs/wcd937x/internal.h b/asoc/codecs/wcd937x/internal.h
index cd11c85..faf0118 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_BCS_CLK_OFF,
};
enum {
@@ -164,6 +165,9 @@
WCD937X_NUM_IRQS,
};
+extern void wcd937x_disable_bcs_before_slow_insert(
+ struct snd_soc_component *component,
+ bool bcs_disable);
extern struct wcd937x_mbhc *wcd937x_soc_get_mbhc(
struct snd_soc_component *component);
extern int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
diff --git a/asoc/codecs/wcd937x/wcd937x-mbhc.c b/asoc/codecs/wcd937x/wcd937x-mbhc.c
index 2159cab..039f511 100644
--- a/asoc/codecs/wcd937x/wcd937x-mbhc.c
+++ b/asoc/codecs/wcd937x/wcd937x-mbhc.c
@@ -810,6 +810,15 @@
0x04, (enable << 2));
}
+static void wcd937x_mbhc_bcs_enable(struct wcd_mbhc *mbhc,
+ bool bcs_enable)
+{
+ if (bcs_enable)
+ wcd937x_disable_bcs_before_slow_insert(mbhc->component, false);
+ else
+ wcd937x_disable_bcs_before_slow_insert(mbhc->component, true);
+}
+
static const struct wcd_mbhc_cb mbhc_cb = {
.request_irq = wcd937x_mbhc_request_irq,
.irq_control = wcd937x_mbhc_irq_control,
@@ -834,6 +843,7 @@
.mbhc_get_moisture_status = wcd937x_mbhc_get_moisture_status,
.mbhc_moisture_polling_ctrl = wcd937x_mbhc_moisture_polling_ctrl,
.mbhc_moisture_detect_en = wcd937x_mbhc_moisture_detect_en,
+ .bcs_enable = wcd937x_mbhc_bcs_enable,
};
static int wcd937x_get_hph_type(struct snd_kcontrol *kcontrol,
diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c
index 1799599..21325ae 100644
--- a/asoc/codecs/wcd937x/wcd937x.c
+++ b/asoc/codecs/wcd937x/wcd937x.c
@@ -1310,7 +1310,7 @@
/* Enable BCS for Headset mic */
if (w->shift == 1 && !(snd_soc_component_read32(component,
WCD937X_TX_NEW_TX_CH2_SEL) & 0x80)) {
- wcd937x_tx_connect_port(codec, MBHC, true);
+ wcd937x_tx_connect_port(component, MBHC, true);
set_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask);
}
wcd937x_tx_connect_port(component, ADC1 + (w->shift), true);
@@ -1319,7 +1319,7 @@
wcd937x_tx_connect_port(component, ADC1 + (w->shift), false);
if (w->shift == 1 &&
test_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask)) {
- wcd937x_tx_connect_port(codec, MBHC, false);
+ wcd937x_tx_connect_port(component, MBHC, false);
clear_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask);
}
snd_soc_component_update_bits(component,
@@ -1517,6 +1517,21 @@
}
EXPORT_SYMBOL(wcd937x_micbias_control);
+void wcd937x_disable_bcs_before_slow_insert(struct snd_soc_component *component,
+ bool bcs_disable)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ if (wcd937x->update_wcd_event) {
+ if (bcs_disable)
+ wcd937x->update_wcd_event(wcd937x->handle,
+ WCD_BOLERO_EVT_BCS_CLK_OFF, 0);
+ else
+ wcd937x->update_wcd_event(wcd937x->handle,
+ WCD_BOLERO_EVT_BCS_CLK_OFF, 1);
+ }
+}
+
static int wcd937x_get_logical_addr(struct swr_device *swr_dev)
{
int ret = 0;
@@ -1642,6 +1657,51 @@
return __wcd937x_codec_enable_micbias(w, event);
}
+static int __wcd937x_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:
+ wcd937x_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:
+ wcd937x_micbias_control(component, micb_num,
+ MICB_PULLUP_DISABLE, true);
+ break;
+ };
+
+ return 0;
+
+}
+
+static int wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ return __wcd937x_codec_enable_micbias_pullup(w, event);
+}
+
static int wcd937x_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2052,6 +2112,20 @@
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,
+ wcd937x_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,
+ wcd937x_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,
+ wcd937x_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
};
static const struct snd_soc_dapm_widget wcd9375_dapm_widgets[] = {
diff --git a/asoc/codecs/wcd938x/Android.mk b/asoc/codecs/wcd938x/Android.mk
index 49aa2d4..96fb6f5 100644
--- a/asoc/codecs/wcd938x/Android.mk
+++ b/asoc/codecs/wcd938x/Android.mk
@@ -13,7 +13,7 @@
AUDIO_CHIPSET := audio
# Build/Package only in case of supported target
-ifeq ($(call is-board-platform-in-list,kona lito bengal),true)
+ifeq ($(call is-board-platform-in-list,kona lito),true)
LOCAL_PATH := $(call my-dir)
diff --git a/asoc/codecs/wcd938x/Kbuild b/asoc/codecs/wcd938x/Kbuild
index 99d7195..3dfe142 100644
--- a/asoc/codecs/wcd938x/Kbuild
+++ b/asoc/codecs/wcd938x/Kbuild
@@ -23,11 +23,6 @@
export
INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
endif
- ifeq ($(CONFIG_ARCH_BENGAL), y)
- include $(AUDIO_ROOT)/config/litoauto.conf
- export
- INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
- endif
endif
diff --git a/asoc/codecs/wcd938x/internal.h b/asoc/codecs/wcd938x/internal.h
index 098a60d..46d61a0 100644
--- a/asoc/codecs/wcd938x/internal.h
+++ b/asoc/codecs/wcd938x/internal.h
@@ -149,6 +149,7 @@
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 {
@@ -182,6 +183,9 @@
extern struct wcd938x_mbhc *wcd938x_soc_get_mbhc(
struct snd_soc_component *component);
+extern void wcd938x_disable_bcs_before_slow_insert(
+ struct snd_soc_component *component,
+ bool bcs_disable);
extern int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
int volt, int micb_num);
extern int wcd938x_get_micb_vout_ctl_val(u32 micb_mv);
diff --git a/asoc/codecs/wcd938x/wcd938x-mbhc.c b/asoc/codecs/wcd938x/wcd938x-mbhc.c
index 27566ee..0687de6 100644
--- a/asoc/codecs/wcd938x/wcd938x-mbhc.c
+++ b/asoc/codecs/wcd938x/wcd938x-mbhc.c
@@ -803,6 +803,15 @@
0x04, (enable << 2));
}
+static void wcd938x_mbhc_bcs_enable(struct wcd_mbhc *mbhc,
+ bool bcs_enable)
+{
+ if (bcs_enable)
+ wcd938x_disable_bcs_before_slow_insert(mbhc->component, false);
+ else
+ wcd938x_disable_bcs_before_slow_insert(mbhc->component, true);
+}
+
static const struct wcd_mbhc_cb mbhc_cb = {
.request_irq = wcd938x_mbhc_request_irq,
.irq_control = wcd938x_mbhc_irq_control,
@@ -827,6 +836,7 @@
.mbhc_get_moisture_status = wcd938x_mbhc_get_moisture_status,
.mbhc_moisture_polling_ctrl = wcd938x_mbhc_moisture_polling_ctrl,
.mbhc_moisture_detect_en = wcd938x_mbhc_moisture_detect_en,
+ .bcs_enable = wcd938x_mbhc_bcs_enable,
};
static int wcd938x_get_hph_type(struct snd_kcontrol *kcontrol,
diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c
index 9bc75a0..3db8fc5 100644
--- a/asoc/codecs/wcd938x/wcd938x.c
+++ b/asoc/codecs/wcd938x/wcd938x.c
@@ -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,
@@ -1022,6 +1024,9 @@
snd_soc_component_update_bits(component,
WCD938X_DIGITAL_PDM_WD_CTL0,
0x17, 0x13);
+ if (!wcd938x->comp1_enable)
+ snd_soc_component_update_bits(component,
+ WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x80);
break;
case SND_SOC_DAPM_POST_PMU:
/* 6 msec delay as per HW requirement */
@@ -1065,6 +1070,9 @@
}
break;
case SND_SOC_DAPM_POST_PMD:
+ if (!wcd938x->comp1_enable)
+ snd_soc_component_update_bits(component,
+ WCD938X_ANA_EAR_COMPANDER_CTL, 0x80, 0x00);
/* 7 msec delay as per HW requirement */
usleep_range(7000, 7010);
if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX)
@@ -1517,6 +1525,21 @@
return 0;
}
+void wcd938x_disable_bcs_before_slow_insert(struct snd_soc_component *component,
+ bool bcs_disable)
+{
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+ if (wcd938x->update_wcd_event) {
+ if (bcs_disable)
+ wcd938x->update_wcd_event(wcd938x->handle,
+ WCD_BOLERO_EVT_BCS_CLK_OFF, 0);
+ else
+ wcd938x->update_wcd_event(wcd938x->handle,
+ WCD_BOLERO_EVT_BCS_CLK_OFF, 1);
+ }
+}
+
int wcd938x_tx_channel_config(struct snd_soc_component *component,
int channel, int mode)
{
@@ -1621,18 +1644,30 @@
switch (w->shift) {
case 0:
snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0x0F,
+ 0x00);
+ snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x10, 0x00);
break;
case 1:
snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0xF0,
+ 0x00);
+ snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x20, 0x00);
break;
case 2:
snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0x0F,
+ 0x00);
+ snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x40, 0x00);
break;
case 3:
snd_soc_component_update_bits(component,
+ WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0xF0,
+ 0x00);
+ snd_soc_component_update_bits(component,
WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0x80, 0x00);
break;
default:
@@ -1809,15 +1844,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 %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;
}
@@ -1871,8 +1909,12 @@
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);
@@ -2126,6 +2168,48 @@
return 0;
}
+static int wcd938x_ear_pa_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain = 0;
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+
+ ear_pa_gain = snd_soc_component_read32(component,
+ WCD938X_ANA_EAR_COMPANDER_CTL);
+
+ ear_pa_gain = (ear_pa_gain & 0x7C) >> 2;
+
+ ucontrol->value.integer.value[0] = ear_pa_gain;
+
+ dev_dbg(component->dev, "%s: ear_pa_gain = 0x%x\n", __func__,
+ ear_pa_gain);
+
+ return 0;
+}
+
+static int wcd938x_ear_pa_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain = 0;
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ ear_pa_gain = ucontrol->value.integer.value[0] << 2;
+
+ if (!wcd938x->comp1_enable) {
+ snd_soc_component_update_bits(component,
+ WCD938X_ANA_EAR_COMPANDER_CTL,
+ 0x7C, ear_pa_gain);
+ }
+
+ return 0;
+}
+
static int wcd938x_get_compander(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2211,10 +2295,21 @@
"CLS_AB_LOHIFI",
};
+static const char * const wcd938x_ear_pa_gain_text[] = {
+ "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB", "G_0_DB",
+ "G_M1P5_DB", "G_M3_DB", "G_M4P5_DB",
+ "G_M6_DB", "G_7P5_DB", "G_M9_DB",
+ "G_M10P5_DB", "G_M12_DB", "G_M13P5_DB",
+ "G_M15_DB", "G_M16P5_DB", "G_M18_DB",
+};
+
static const struct soc_enum rx_hph_mode_mux_enum_wcd9380 =
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text_wcd9380),
rx_hph_mode_mux_text_wcd9380);
+static SOC_ENUM_SINGLE_EXT_DECL(wcd938x_ear_pa_gain_enum,
+ wcd938x_ear_pa_gain_text);
+
static const char * const rx_hph_mode_mux_text[] = {
"CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI",
"CLS_H_ULP", "CLS_AB_HIFI", "CLS_AB_LP", "CLS_AB_LOHIFI",
@@ -2225,6 +2320,9 @@
rx_hph_mode_mux_text);
static const struct snd_kcontrol_new wcd9380_snd_controls[] = {
+ SOC_ENUM_EXT("EAR PA GAIN", wcd938x_ear_pa_gain_enum,
+ wcd938x_ear_pa_gain_get, wcd938x_ear_pa_gain_put),
+
SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum_wcd9380,
wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put),
diff --git a/asoc/codecs/wcd_cpe_core.c b/asoc/codecs/wcd_cpe_core.c
index 4c776d1..5b5291f 100644
--- a/asoc/codecs/wcd_cpe_core.c
+++ b/asoc/codecs/wcd_cpe_core.c
@@ -2896,6 +2896,7 @@
struct cmi_obm_msg obm_msg;
struct cpe_param_data *param_d;
+ memset(&obm_msg, 0, sizeof(obm_msg));
ret = fill_cmi_header(&obm_msg.hdr, session->id,
CMI_CPE_LSM_SERVICE_ID, 0, 20,
diff --git a/asoc/codecs/wsa881x-analog.c b/asoc/codecs/wsa881x-analog.c
new file mode 100644
index 0000000..c6b4066
--- /dev/null
+++ b/asoc/codecs/wsa881x-analog.c
@@ -0,0 +1,1543 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015-2016, 2018-2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/bitops.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <soc/soundwire.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <dsp/q6afe-v2.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <soc/internal.h>
+#include <linux/regmap.h>
+#include <asoc/msm-cdc-pinctrl.h>
+#include "wsa881x-analog.h"
+#include "wsa881x-temp-sensor.h"
+
+#define SPK_GAIN_12DB 4
+#define WIDGET_NAME_MAX_SIZE 80
+
+/*
+ * Private data Structure for wsa881x. All parameters related to
+ * WSA881X codec needs to be defined here.
+ */
+struct wsa881x_pdata {
+ struct regmap *regmap[2];
+ struct i2c_client *client[2];
+ struct snd_soc_component *component;
+
+ /* track wsa881x status during probe */
+ int status;
+ bool boost_enable;
+ bool visense_enable;
+ int spk_pa_gain;
+ struct i2c_msg xfer_msg[2];
+ struct mutex xfer_lock;
+ bool regmap_flag;
+ bool wsa_active;
+ int index;
+ struct wsa881x_tz_priv tz_pdata;
+ struct clk *wsa_mclk;
+ int bg_cnt;
+ int clk_cnt;
+ int enable_cnt;
+ int version;
+ struct mutex bg_lock;
+ struct mutex res_lock;
+ struct delayed_work ocp_ctl_work;
+ struct device_node *wsa_vi_gpio_p;
+ struct device_node *wsa_clk_gpio_p;
+ struct device_node *wsa_reset_gpio_p;
+};
+
+enum {
+ WSA881X_STATUS_PROBING,
+ WSA881X_STATUS_I2C,
+};
+
+#define WSA881X_OCP_CTL_TIMER_SEC 2
+#define WSA881X_OCP_CTL_TEMP_CELSIUS 25
+#define WSA881X_OCP_CTL_POLL_TIMER_SEC 60
+
+static int wsa881x_ocp_poll_timer_sec = WSA881X_OCP_CTL_POLL_TIMER_SEC;
+module_param(wsa881x_ocp_poll_timer_sec, int, 0664);
+MODULE_PARM_DESC(wsa881x_ocp_poll_timer_sec, "timer for ocp ctl polling");
+
+static int32_t wsa881x_resource_acquire(struct snd_soc_component *component,
+ bool enable);
+
+const char *wsa_tz_names[] = {"wsa881x.0e", "wsa881x.0f"};
+
+struct wsa881x_pdata wsa_pdata[MAX_WSA881X_DEVICE];
+
+static bool pinctrl_init;
+
+static int wsa881x_populate_dt_pdata(struct device *dev, int wsa881x_index);
+static int wsa881x_reset(struct wsa881x_pdata *pdata, bool enable);
+static int wsa881x_startup(struct wsa881x_pdata *pdata);
+static int wsa881x_shutdown(struct wsa881x_pdata *pdata);
+
+static int delay_array_msec[] = {10, 20, 30, 40, 50};
+
+static int wsa881x_i2c_addr = -1;
+static int wsa881x_probing_count;
+static int wsa881x_presence_count;
+
+static const char * const wsa881x_spk_pa_gain_text[] = {
+"POS_13P5_DB", "POS_12_DB", "POS_10P5_DB", "POS_9_DB", "POS_7P5_DB",
+"POS_6_DB", "POS_4P5_DB", "POS_3_DB", "POS_1P5_DB", "POS_0_DB"};
+
+static const struct soc_enum wsa881x_spk_pa_gain_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa881x_spk_pa_gain_text),
+ wsa881x_spk_pa_gain_text),
+};
+
+static int wsa881x_spk_pa_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wsa881x->spk_pa_gain;
+
+ dev_dbg(component->dev, "%s: spk_pa_gain = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int wsa881x_spk_pa_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ if (ucontrol->value.integer.value[0] < 0 ||
+ ucontrol->value.integer.value[0] > 0xC) {
+ dev_err(component->dev, "%s: Unsupported gain val %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+ return -EINVAL;
+ }
+ wsa881x->spk_pa_gain = ucontrol->value.integer.value[0];
+ dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int get_i2c_wsa881x_device_index(u16 reg)
+{
+ u16 mask = 0x0f00;
+ int value = 0;
+
+ value = ((reg & mask) >> 8) & 0x000f;
+
+ switch (value) {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static int wsa881x_i2c_write_device(struct wsa881x_pdata *wsa881x,
+ unsigned int reg, unsigned int val)
+{
+ int i = 0, rc = 0;
+ int wsa881x_index;
+ struct i2c_msg *msg;
+ int ret = 0;
+ int bytes = 1;
+ u8 reg_addr = 0;
+ u8 data[2];
+
+ wsa881x_index = get_i2c_wsa881x_device_index(reg);
+ if (wsa881x_index < 0) {
+ pr_err_ratelimited("%s:invalid register to write\n", __func__);
+ return -EINVAL;
+ }
+ if (wsa881x->regmap_flag) {
+ rc = regmap_write(wsa881x->regmap[wsa881x_index], reg, val);
+ for (i = 0; rc && i < ARRAY_SIZE(delay_array_msec); i++) {
+ pr_err_ratelimited("Failed writing reg=%u-retry(%d)\n",
+ reg, i);
+ /* retry after delay of increasing order */
+ msleep(delay_array_msec[i]);
+ rc = regmap_write(wsa881x->regmap[wsa881x_index],
+ reg, val);
+ }
+ if (rc)
+ pr_err_ratelimited("Failed writing reg=%u rc=%d\n",
+ reg, rc);
+ else
+ pr_debug("write success register = %x val = %x\n",
+ reg, val);
+ } else {
+ reg_addr = (u8)reg;
+ msg = &wsa881x->xfer_msg[0];
+ msg->addr = wsa881x->client[wsa881x_index]->addr;
+ msg->len = bytes + 1;
+ msg->flags = 0;
+ data[0] = reg;
+ data[1] = (u8)val;
+ msg->buf = data;
+ ret = i2c_transfer(wsa881x->client[wsa881x_index]->adapter,
+ wsa881x->xfer_msg, 1);
+ /* Try again if the write fails */
+ if (ret != 1) {
+ ret = i2c_transfer(
+ wsa881x->client[wsa881x_index]->adapter,
+ wsa881x->xfer_msg, 1);
+ if (ret != 1) {
+ pr_err_ratelimited("failed to write the device\n");
+ return ret;
+ }
+ }
+ pr_debug("write success reg = %x val = %x\n", reg, data[1]);
+ }
+ return rc;
+}
+
+static int wsa881x_i2c_read_device(struct wsa881x_pdata *wsa881x,
+ unsigned int reg)
+{
+ int wsa881x_index;
+ int i = 0, rc = 0;
+ unsigned int val;
+ struct i2c_msg *msg;
+ int ret = 0;
+ u8 reg_addr = 0;
+ u8 dest[5] = {0};
+
+ wsa881x_index = get_i2c_wsa881x_device_index(reg);
+ if (wsa881x_index < 0) {
+ pr_err_ratelimited("%s:invalid register to read\n", __func__);
+ return -EINVAL;
+ }
+ if (wsa881x->regmap_flag) {
+ rc = regmap_read(wsa881x->regmap[wsa881x_index], reg, &val);
+ for (i = 0; rc && i < ARRAY_SIZE(delay_array_msec); i++) {
+ pr_err_ratelimited("Failed reading reg=%u - retry(%d)\n",
+ reg, i);
+ /* retry after delay of increasing order */
+ msleep(delay_array_msec[i]);
+ rc = regmap_read(wsa881x->regmap[wsa881x_index],
+ reg, &val);
+ }
+ if (rc) {
+ pr_err_ratelimited("Failed reading reg=%u rc=%d\n",
+ reg, rc);
+ return rc;
+ }
+ pr_debug("read success reg = %x val = %x\n",
+ reg, val);
+ } else {
+ reg_addr = (u8)reg;
+ msg = &wsa881x->xfer_msg[0];
+ msg->addr = wsa881x->client[wsa881x_index]->addr;
+ msg->len = 1;
+ msg->flags = 0;
+ msg->buf = ®_addr;
+
+ msg = &wsa881x->xfer_msg[1];
+ msg->addr = wsa881x->client[wsa881x_index]->addr;
+ msg->len = 1;
+ msg->flags = I2C_M_RD;
+ msg->buf = dest;
+ ret = i2c_transfer(wsa881x->client[wsa881x_index]->adapter,
+ wsa881x->xfer_msg, 2);
+
+ /* Try again if read fails first time */
+ if (ret != 2) {
+ ret = i2c_transfer(
+ wsa881x->client[wsa881x_index]->adapter,
+ wsa881x->xfer_msg, 2);
+ if (ret != 2) {
+ pr_err_ratelimited("failed to read wsa register:%d\n",
+ reg);
+ return ret;
+ }
+ }
+ val = dest[0];
+ }
+ return val;
+}
+
+static unsigned int wsa881x_i2c_read(struct snd_soc_component *component,
+ unsigned int reg)
+{
+ struct wsa881x_pdata *wsa881x;
+ int wsa881x_index;
+
+ if (component == NULL) {
+ pr_err_ratelimited("%s: invalid component\n", __func__);
+ return -EINVAL;
+ }
+ wsa881x = snd_soc_component_get_drvdata(component);
+ if (!wsa881x->wsa_active)
+ return 0;
+
+ wsa881x_index = get_i2c_wsa881x_device_index(reg);
+ if (wsa881x_index < 0) {
+ pr_err_ratelimited("%s:invalid register to read\n", __func__);
+ return -EINVAL;
+ }
+ return wsa881x_i2c_read_device(wsa881x, reg);
+}
+
+static int wsa881x_i2c_write(struct snd_soc_component *component,
+ unsigned int reg,
+ unsigned int val)
+{
+ struct wsa881x_pdata *wsa881x;
+ int wsa881x_index;
+
+ if (component == NULL) {
+ pr_err_ratelimited("%s: invalid component\n", __func__);
+ return -EINVAL;
+ }
+ wsa881x = snd_soc_component_get_drvdata(component);
+ if (!wsa881x->wsa_active)
+ return 0;
+
+ wsa881x_index = get_i2c_wsa881x_device_index(reg);
+ if (wsa881x_index < 0) {
+ pr_err_ratelimited("%s:invalid register to read\n", __func__);
+ return -EINVAL;
+ }
+ return wsa881x_i2c_write_device(wsa881x, reg, val);
+}
+
+static int wsa881x_i2c_get_client_index(struct i2c_client *client,
+ int *wsa881x_index)
+{
+ int ret = 0;
+
+ switch (client->addr) {
+ case WSA881X_I2C_SPK0_SLAVE0_ADDR:
+ case WSA881X_I2C_SPK0_SLAVE1_ADDR:
+ *wsa881x_index = WSA881X_I2C_SPK0_SLAVE0;
+ break;
+ case WSA881X_I2C_SPK1_SLAVE0_ADDR:
+ case WSA881X_I2C_SPK1_SLAVE1_ADDR:
+ *wsa881x_index = WSA881X_I2C_SPK1_SLAVE0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int wsa881x_boost_ctrl(struct snd_soc_component *component, bool enable)
+{
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+
+ pr_debug("%s: enable:%d\n", __func__, enable);
+ if (enable) {
+ if (!WSA881X_IS_2_0(wsa881x->version)) {
+ snd_soc_component_update_bits(component,
+ WSA881X_ANA_CTL, 0x01, 0x01);
+ snd_soc_component_update_bits(component,
+ WSA881X_ANA_CTL, 0x04, 0x04);
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_PS_CTL,
+ 0x40, 0x00);
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_PRESET_OUT1,
+ 0xF0, 0xB0);
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_ZX_CTL,
+ 0x20, 0x00);
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_EN_CTL,
+ 0x80, 0x80);
+ } else {
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_LOOP_STABILITY,
+ 0x03, 0x03);
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_MISC2_CTL,
+ 0xFF, 0x14);
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_START_CTL,
+ 0x80, 0x80);
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_START_CTL,
+ 0x03, 0x00);
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
+ 0x0C, 0x04);
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
+ 0x03, 0x00);
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_PRESET_OUT1,
+ 0xF0, 0x70);
+ snd_soc_component_update_bits(component,
+ WSA881X_ANA_CTL, 0x03, 0x01);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DRV_EN,
+ 0x08, 0x08);
+ snd_soc_component_update_bits(component,
+ WSA881X_ANA_CTL, 0x04, 0x04);
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_CURRENT_LIMIT,
+ 0x0F, 0x08);
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_EN_CTL,
+ 0x80, 0x80);
+ }
+ /* For WSA8810, start-up time is 1500us as per qcrg sequence */
+ usleep_range(1500, 1510);
+ } else {
+ /* ENSURE: Class-D amp is shutdown. CLK is still on */
+ snd_soc_component_update_bits(component,
+ WSA881X_BOOST_EN_CTL, 0x80, 0x00);
+ /* boost settle time is 1500us as per qcrg sequence */
+ usleep_range(1500, 1510);
+ }
+ return 0;
+}
+
+static int wsa881x_visense_txfe_ctrl(struct snd_soc_component *component,
+ bool enable,
+ u8 isense1_gain, u8 isense2_gain,
+ u8 vsense_gain)
+{
+ u8 value = 0;
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ pr_debug("%s: enable:%d\n", __func__, enable);
+
+ if (enable) {
+ if (WSA881X_IS_2_0(wsa881x->version)) {
+ snd_soc_component_update_bits(component,
+ WSA881X_OTP_REG_28,
+ 0x3F, 0x3A);
+ snd_soc_component_update_bits(component,
+ WSA881X_BONGO_RESRV_REG1,
+ 0xFF, 0xB2);
+ snd_soc_component_update_bits(component,
+ WSA881X_BONGO_RESRV_REG2,
+ 0xFF, 0x05);
+ }
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PROT_FE_VSENSE_VCM,
+ 0x08, 0x00);
+ if (WSA881X_IS_2_0(wsa881x->version)) {
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PROT_ATEST2,
+ 0x1C, 0x04);
+ } else {
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PROT_ATEST2,
+ 0x08, 0x08);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PROT_ATEST2,
+ 0x02, 0x02);
+ }
+ value = ((isense2_gain << 6) | (isense1_gain << 4) |
+ (vsense_gain << 3));
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PROT_FE_GAIN,
+ 0xF8, value);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PROT_FE_GAIN,
+ 0x01, 0x01);
+ } else {
+ if (WSA881X_IS_2_0(wsa881x->version))
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x10, 0x10);
+ else
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x08, 0x08);
+ /*
+ * 200us sleep is needed after visense txfe disable as per
+ * HW requirement.
+ */
+ usleep_range(200, 210);
+
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PROT_FE_GAIN,
+ 0x01, 0x00);
+ }
+ return 0;
+}
+
+static int wsa881x_visense_adc_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ pr_debug("%s: enable:%d\n", __func__, enable);
+ if (enable) {
+ if (!WSA881X_IS_2_0(wsa881x->version))
+ snd_soc_component_update_bits(component,
+ WSA881X_ADC_SEL_IBIAS,
+ 0x70, 0x40);
+ snd_soc_component_update_bits(component,
+ WSA881X_ADC_EN_SEL_IBIAS,
+ 0x07, 0x04);
+ snd_soc_component_update_bits(component,
+ WSA881X_ADC_EN_MODU_V, 0x80, 0x80);
+ snd_soc_component_update_bits(component,
+ WSA881X_ADC_EN_MODU_I, 0x80, 0x80);
+ } else {
+ /* Ensure: Speaker Protection has been stopped */
+ snd_soc_component_update_bits(component,
+ WSA881X_ADC_EN_MODU_V, 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ WSA881X_ADC_EN_MODU_I, 0x80, 0x00);
+ }
+
+ return 0;
+}
+
+static void wsa881x_bandgap_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s: enable:%d, bg_count:%d\n", __func__,
+ enable, wsa881x->bg_cnt);
+ mutex_lock(&wsa881x->bg_lock);
+ if (enable) {
+ ++wsa881x->bg_cnt;
+ if (wsa881x->bg_cnt == 1) {
+ snd_soc_component_update_bits(component,
+ WSA881X_TEMP_OP, 0x08, 0x08);
+ /* 400usec sleep is needed as per HW requirement */
+ usleep_range(400, 410);
+ snd_soc_component_update_bits(component,
+ WSA881X_TEMP_OP, 0x04, 0x04);
+ }
+ } else {
+ --wsa881x->bg_cnt;
+ if (wsa881x->bg_cnt <= 0) {
+ WARN_ON(wsa881x->bg_cnt < 0);
+ wsa881x->bg_cnt = 0;
+ snd_soc_component_update_bits(component,
+ WSA881X_TEMP_OP, 0x04, 0x00);
+ snd_soc_component_update_bits(component,
+ WSA881X_TEMP_OP, 0x08, 0x00);
+ }
+ }
+ mutex_unlock(&wsa881x->bg_lock);
+}
+
+static void wsa881x_clk_ctrl(struct snd_soc_component *component, bool enable)
+{
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s:ss enable:%d, clk_count:%d\n", __func__,
+ enable, wsa881x->clk_cnt);
+ mutex_lock(&wsa881x->res_lock);
+ if (enable) {
+ ++wsa881x->clk_cnt;
+ if (wsa881x->clk_cnt == 1) {
+ snd_soc_component_write(component,
+ WSA881X_CDC_RST_CTL, 0x02);
+ snd_soc_component_write(component,
+ WSA881X_CDC_RST_CTL, 0x03);
+ snd_soc_component_write(component,
+ WSA881X_CLOCK_CONFIG, 0x01);
+
+ snd_soc_component_write(component,
+ WSA881X_CDC_DIG_CLK_CTL, 0x01);
+ snd_soc_component_write(component,
+ WSA881X_CDC_ANA_CLK_CTL, 0x01);
+
+ }
+ } else {
+ --wsa881x->clk_cnt;
+ if (wsa881x->clk_cnt <= 0) {
+ WARN_ON(wsa881x->clk_cnt < 0);
+ wsa881x->clk_cnt = 0;
+ snd_soc_component_write(component,
+ WSA881X_CDC_ANA_CLK_CTL, 0x00);
+ snd_soc_component_write(component,
+ WSA881X_CDC_DIG_CLK_CTL, 0x00);
+ if (WSA881X_IS_2_0(wsa881x->version))
+ snd_soc_component_update_bits(component,
+ WSA881X_CDC_TOP_CLK_CTL, 0x01, 0x00);
+ }
+ }
+ mutex_unlock(&wsa881x->res_lock);
+}
+
+static int wsa881x_rdac_ctrl(struct snd_soc_component *component, bool enable)
+{
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ pr_debug("%s: enable:%d\n", __func__, enable);
+ if (enable) {
+ snd_soc_component_update_bits(component,
+ WSA881X_ANA_CTL, 0x08, 0x00);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DRV_GAIN, 0x08, 0x08);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DAC_CTL, 0x20, 0x20);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DAC_CTL, 0x20, 0x00);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DAC_CTL, 0x40, 0x40);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DAC_CTL, 0x80, 0x80);
+ if (WSA881X_IS_2_0(wsa881x->version)) {
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_BIAS_CAL, 0x01, 0x01);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_OCP_CTL, 0x30, 0x30);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_OCP_CTL, 0x0C, 0x00);
+ }
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DRV_GAIN, 0xF0, 0x40);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_MISC_CTL1, 0x01, 0x01);
+ } else {
+ /* Ensure class-D amp is off */
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DAC_CTL, 0x80, 0x00);
+ }
+ return 0;
+}
+
+static int wsa881x_spkr_pa_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ int ret = 0;
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ pr_debug("%s: enable:%d\n", __func__, enable);
+ if (enable) {
+ /*
+ * Ensure: Boost is enabled and stable, Analog input is up
+ * and outputting silence
+ */
+ if (!WSA881X_IS_2_0(wsa881x->version)) {
+ snd_soc_component_update_bits(component,
+ WSA881X_ADC_EN_DET_TEST_I,
+ 0xFF, 0x01);
+ snd_soc_component_update_bits(component,
+ WSA881X_ADC_EN_MODU_V,
+ 0x02, 0x02);
+ snd_soc_component_update_bits(component,
+ WSA881X_ADC_EN_DET_TEST_V,
+ 0xFF, 0x10);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PWRSTG_DBG,
+ 0xA0, 0xA0);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DRV_EN,
+ 0x80, 0x80);
+ usleep_range(700, 710);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PWRSTG_DBG,
+ 0x00, 0x00);
+ snd_soc_component_update_bits(component,
+ WSA881X_ADC_EN_DET_TEST_V,
+ 0xFF, 0x00);
+ snd_soc_component_update_bits(component,
+ WSA881X_ADC_EN_MODU_V,
+ 0x02, 0x00);
+ snd_soc_component_update_bits(component,
+ WSA881X_ADC_EN_DET_TEST_I,
+ 0xFF, 0x00);
+ } else
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DRV_EN, 0x80, 0x80);
+ /* add 1000us delay as per qcrg */
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DRV_EN, 0x01, 0x01);
+ if (WSA881X_IS_2_0(wsa881x->version))
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_BIAS_CAL,
+ 0x01, 0x00);
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DRV_GAIN,
+ 0xF0, (wsa881x->spk_pa_gain << 4));
+ if (wsa881x->visense_enable) {
+ ret = msm_cdc_pinctrl_select_active_state(
+ wsa881x->wsa_vi_gpio_p);
+ if (ret) {
+ pr_err("%s: gpio set cannot be activated %s\n",
+ __func__, "wsa_vi");
+ return ret;
+ }
+ wsa881x_visense_txfe_ctrl(component, true,
+ 0x00, 0x01, 0x00);
+ wsa881x_visense_adc_ctrl(component, true);
+ }
+ } else {
+ /*
+ * Ensure: Boost is still on, Stream from Analog input and
+ * Speaker Protection has been stopped and input is at 0V
+ */
+ if (WSA881X_IS_2_0(wsa881x->version)) {
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_BIAS_CAL,
+ 0x01, 0x01);
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_BIAS_CAL,
+ 0x01, 0x00);
+ msleep(20);
+ snd_soc_component_update_bits(component,
+ WSA881X_ANA_CTL, 0x03, 0x00);
+ usleep_range(200, 210);
+ }
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DRV_EN, 0x80, 0x00);
+ }
+ return 0;
+}
+
+static int wsa881x_get_boost(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wsa881x->boost_enable;
+ return 0;
+}
+
+static int wsa881x_set_boost(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+ int value = ucontrol->value.integer.value[0];
+
+ dev_dbg(component->dev, "%s: Boost enable current %d, new %d\n",
+ __func__, wsa881x->boost_enable, value);
+ wsa881x->boost_enable = value;
+ return 0;
+}
+
+static int wsa881x_get_visense(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wsa881x->visense_enable;
+ return 0;
+}
+
+static int wsa881x_set_visense(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+ int value = ucontrol->value.integer.value[0];
+
+ dev_dbg(component->dev, "%s: VIsense enable current %d, new %d\n",
+ __func__, wsa881x->visense_enable, value);
+ wsa881x->visense_enable = value;
+ return 0;
+}
+
+static const struct snd_kcontrol_new wsa881x_snd_controls[] = {
+ SOC_SINGLE_EXT("BOOST Switch", SND_SOC_NOPM, 0, 1, 0,
+ wsa881x_get_boost, wsa881x_set_boost),
+
+ SOC_SINGLE_EXT("VISENSE Switch", SND_SOC_NOPM, 0, 1, 0,
+ wsa881x_get_visense, wsa881x_set_visense),
+
+ SOC_ENUM_EXT("WSA_SPK PA Gain", wsa881x_spk_pa_gain_enum[0],
+ wsa881x_spk_pa_gain_get, wsa881x_spk_pa_gain_put),
+};
+
+static const char * const rdac_text[] = {
+ "ZERO", "Switch",
+};
+
+static const struct soc_enum rdac_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(rdac_text), rdac_text);
+
+static const struct snd_kcontrol_new rdac_mux[] = {
+ SOC_DAPM_ENUM("RDAC", rdac_enum)
+};
+
+static int wsa881x_rdac_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 wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ dev_dbg(component->dev, "%s: %s %d boost %d visense %d\n",
+ __func__, w->name, event,
+ wsa881x->boost_enable, wsa881x->visense_enable);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = wsa881x_startup(wsa881x);
+ if (ret) {
+ pr_err("%s: wsa startup failed ret: %d", __func__, ret);
+ return ret;
+ }
+ wsa881x_clk_ctrl(component, true);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_DAC_CTL, 0x02, 0x02);
+ if (!WSA881X_IS_2_0(wsa881x->version))
+ snd_soc_component_update_bits(component,
+ WSA881X_BIAS_REF_CTRL,
+ 0x0F, 0x08);
+ wsa881x_bandgap_ctrl(component, true);
+ if (!WSA881X_IS_2_0(wsa881x->version))
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_BBM_CTL,
+ 0x02, 0x02);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_MISC_CTL1, 0xC0, 0x80);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_MISC_CTL1, 0x06, 0x06);
+ if (!WSA881X_IS_2_0(wsa881x->version)) {
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_MISC_CTL2,
+ 0x04, 0x04);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_BIAS_INT,
+ 0x09, 0x09);
+ }
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PA_INT, 0xF0, 0x20);
+ if (WSA881X_IS_2_0(wsa881x->version))
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_PA_INT,
+ 0x0E, 0x0E);
+ if (wsa881x->boost_enable)
+ wsa881x_boost_ctrl(component, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ wsa881x_rdac_ctrl(component, true);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wsa881x_rdac_ctrl(component, false);
+ if (wsa881x->visense_enable) {
+ wsa881x_visense_adc_ctrl(component, false);
+ wsa881x_visense_txfe_ctrl(component, false,
+ 0x00, 0x01, 0x00);
+ ret = msm_cdc_pinctrl_select_sleep_state(
+ wsa881x->wsa_vi_gpio_p);
+ if (ret) {
+ pr_err("%s: gpio set cannot be suspended %s\n",
+ __func__, "wsa_vi");
+ return ret;
+ }
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (wsa881x->boost_enable)
+ wsa881x_boost_ctrl(component, false);
+ wsa881x_clk_ctrl(component, false);
+ wsa881x_bandgap_ctrl(component, false);
+ ret = wsa881x_shutdown(wsa881x);
+ if (ret < 0) {
+ pr_err("%s: wsa shutdown failed ret: %d",
+ __func__, ret);
+ return ret;
+ }
+ break;
+ default:
+ pr_err("%s: invalid event:%d\n", __func__, event);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void wsa881x_ocp_ctl_work(struct work_struct *work)
+{
+ struct wsa881x_pdata *wsa881x;
+ struct delayed_work *dwork;
+ struct snd_soc_component *component;
+ int temp_val;
+
+ dwork = to_delayed_work(work);
+ wsa881x = container_of(dwork, struct wsa881x_pdata, ocp_ctl_work);
+
+ if (!wsa881x)
+ return;
+
+ component = wsa881x->component;
+ wsa881x_get_temp(wsa881x->tz_pdata.tz_dev, &temp_val);
+ dev_dbg(component->dev, " temp = %d\n", temp_val);
+
+ if (temp_val <= WSA881X_OCP_CTL_TEMP_CELSIUS)
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_OCP_CTL, 0xC0, 0x00);
+ else
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_OCP_CTL, 0xC0, 0xC0);
+
+ schedule_delayed_work(&wsa881x->ocp_ctl_work,
+ msecs_to_jiffies(wsa881x_ocp_poll_timer_sec * 1000));
+}
+
+static int wsa881x_spkr_pa_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 wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ pr_debug("%s: %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_OCP_CTL, 0xC0, 0x80);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ wsa881x_spkr_pa_ctrl(component, true);
+ schedule_delayed_work(&wsa881x->ocp_ctl_work,
+ msecs_to_jiffies(WSA881X_OCP_CTL_TIMER_SEC * 1000));
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wsa881x_spkr_pa_ctrl(component, false);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
+ snd_soc_component_update_bits(component,
+ WSA881X_SPKR_OCP_CTL, 0xC0, 0xC0);
+ break;
+ default:
+ pr_err("%s: invalid event:%d\n", __func__, event);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget wsa881x_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("WSA_IN"),
+
+ SND_SOC_DAPM_DAC_E("RDAC Analog", NULL, SND_SOC_NOPM, 0, 0,
+ wsa881x_rdac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("WSA_RDAC", SND_SOC_NOPM, 0, 0,
+ rdac_mux),
+
+ SND_SOC_DAPM_PGA_S("WSA_SPKR PGA", 1, SND_SOC_NOPM, 0, 0,
+ wsa881x_spkr_pa_event,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_OUTPUT("WSA_SPKR"),
+};
+
+static const struct snd_soc_dapm_route wsa881x_audio_map[] = {
+ {"WSA_RDAC", "Switch", "WSA_IN"},
+ {"RDAC Analog", NULL, "WSA_RDAC"},
+ {"WSA_SPKR PGA", NULL, "RDAC Analog"},
+ {"WSA_SPKR", NULL, "WSA_SPKR PGA"},
+};
+
+
+static int wsa881x_startup(struct wsa881x_pdata *pdata)
+{
+ int ret = 0;
+
+ pr_debug("%s(): wsa startup, enable_cnt:%d\n", __func__,
+ pdata->enable_cnt);
+
+ if (pdata->enable_cnt++ > 0)
+ return 0;
+ ret = msm_cdc_pinctrl_select_active_state(pdata->wsa_clk_gpio_p);
+ if (ret) {
+ pr_err("%s: gpio set cannot be activated %s\n",
+ __func__, "wsa_clk");
+ return ret;
+ }
+ ret = clk_prepare_enable(pdata->wsa_mclk);
+ if (ret) {
+ pr_err("%s: WSA MCLK enable failed\n",
+ __func__);
+ return ret;
+ }
+ ret = wsa881x_reset(pdata, true);
+ return ret;
+}
+
+static int wsa881x_shutdown(struct wsa881x_pdata *pdata)
+{
+ int ret = 0;
+
+ pr_debug("%s(): wsa shutdown, enable_cnt:%d\n", __func__,
+ pdata->enable_cnt);
+ if (--pdata->enable_cnt > 0)
+ return 0;
+ ret = wsa881x_reset(pdata, false);
+ if (ret) {
+ pr_err("%s: wsa reset failed suspend %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ clk_disable_unprepare(pdata->wsa_mclk);
+
+ ret = msm_cdc_pinctrl_select_sleep_state(pdata->wsa_clk_gpio_p);
+ if (ret) {
+ pr_err("%s: gpio set cannot be suspended %s\n",
+ __func__, "wsa_clk");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int32_t wsa881x_resource_acquire(struct snd_soc_component *component,
+ bool enable)
+{
+ int ret = 0;
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ if (enable) {
+ ret = wsa881x_startup(wsa881x);
+ if (ret < 0) {
+ dev_err_ratelimited(component->dev,
+ "%s: failed to startup\n", __func__);
+ return ret;
+ }
+ }
+ wsa881x_clk_ctrl(component, enable);
+ wsa881x_bandgap_ctrl(component, enable);
+ if (!enable) {
+ ret = wsa881x_shutdown(wsa881x);
+ if (ret < 0)
+ dev_err_ratelimited(component->dev,
+ "%s: failed to shutdown\n", __func__);
+ }
+ return ret;
+}
+
+static int32_t wsa881x_temp_reg_read(struct snd_soc_component *component,
+ struct wsa_temp_register *wsa_temp_reg)
+{
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ if (!wsa881x) {
+ dev_err(component->dev, "%s: wsa881x is NULL\n", __func__);
+ return -EINVAL;
+ }
+ ret = wsa881x_resource_acquire(component, true);
+ if (ret) {
+ dev_err_ratelimited(component->dev,
+ "%s: resource acquire fail\n", __func__);
+ return ret;
+ }
+
+ if (WSA881X_IS_2_0(wsa881x->version)) {
+ snd_soc_component_update_bits(component,
+ WSA881X_TADC_VALUE_CTL, 0x01, 0x00);
+ wsa_temp_reg->dmeas_msb =
+ snd_soc_component_read32(component,
+ WSA881X_TEMP_MSB);
+ wsa_temp_reg->dmeas_lsb =
+ snd_soc_component_read32(component,
+ WSA881X_TEMP_LSB);
+ snd_soc_component_update_bits(component,
+ WSA881X_TADC_VALUE_CTL, 0x01, 0x01);
+ } else {
+ wsa_temp_reg->dmeas_msb = snd_soc_component_read32(component,
+ WSA881X_TEMP_DOUT_MSB);
+ wsa_temp_reg->dmeas_lsb = snd_soc_component_read32(component,
+ WSA881X_TEMP_DOUT_LSB);
+ }
+ wsa_temp_reg->d1_msb = snd_soc_component_read32(component,
+ WSA881X_OTP_REG_1);
+ wsa_temp_reg->d1_lsb = snd_soc_component_read32(component,
+ WSA881X_OTP_REG_2);
+ wsa_temp_reg->d2_msb = snd_soc_component_read32(component,
+ WSA881X_OTP_REG_3);
+ wsa_temp_reg->d2_lsb = snd_soc_component_read32(component,
+ WSA881X_OTP_REG_4);
+
+ ret = wsa881x_resource_acquire(component, false);
+ if (ret)
+ dev_err_ratelimited(component->dev,
+ "%s: resource release fail\n", __func__);
+
+ return ret;
+}
+
+static int wsa881x_probe(struct snd_soc_component *component)
+{
+ struct i2c_client *client;
+ int ret = 0;
+ int wsa881x_index = 0;
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ char *widget_name = NULL;
+ struct snd_soc_card *card = component->card;
+ struct snd_soc_codec_conf *codec_conf = card->codec_conf;
+
+ client = dev_get_drvdata(component->dev);
+ ret = wsa881x_i2c_get_client_index(client, &wsa881x_index);
+ if (ret != 0) {
+ dev_err(&client->dev, "%s: I2C get codec I2C\n"
+ "client failed\n", __func__);
+ return ret;
+ }
+ mutex_init(&wsa_pdata[wsa881x_index].bg_lock);
+ mutex_init(&wsa_pdata[wsa881x_index].res_lock);
+ snprintf(wsa_pdata[wsa881x_index].tz_pdata.name, 100, "%s",
+ wsa_tz_names[wsa881x_index]);
+ wsa_pdata[wsa881x_index].component = component;
+ wsa_pdata[wsa881x_index].spk_pa_gain = SPK_GAIN_12DB;
+ wsa_pdata[wsa881x_index].component = component;
+ wsa_pdata[wsa881x_index].tz_pdata.component = component;
+ wsa_pdata[wsa881x_index].tz_pdata.wsa_temp_reg_read =
+ wsa881x_temp_reg_read;
+ snd_soc_component_set_drvdata(component, &wsa_pdata[wsa881x_index]);
+ wsa881x_init_thermal(&wsa_pdata[wsa881x_index].tz_pdata);
+ INIT_DELAYED_WORK(&wsa_pdata[wsa881x_index].ocp_ctl_work,
+ wsa881x_ocp_ctl_work);
+
+ if (codec_conf->name_prefix) {
+ widget_name = kcalloc(WIDGET_NAME_MAX_SIZE, sizeof(char),
+ GFP_KERNEL);
+ if (!widget_name)
+ return -ENOMEM;
+
+ snprintf(widget_name, WIDGET_NAME_MAX_SIZE,
+ "%s WSA_SPKR", codec_conf->name_prefix);
+ snd_soc_dapm_ignore_suspend(dapm, widget_name);
+ snprintf(widget_name, WIDGET_NAME_MAX_SIZE,
+ "%s WSA_IN", codec_conf->name_prefix);
+ snd_soc_dapm_ignore_suspend(dapm, widget_name);
+ kfree(widget_name);
+ } else {
+ snd_soc_dapm_ignore_suspend(dapm, "WSA_SPKR");
+ snd_soc_dapm_ignore_suspend(dapm, "WSA_IN");
+ }
+
+ snd_soc_dapm_sync(dapm);
+
+ return 0;
+}
+
+static void wsa881x_remove(struct snd_soc_component *component)
+{
+ struct wsa881x_pdata *wsa881x =
+ snd_soc_component_get_drvdata(component);
+
+ if (wsa881x->tz_pdata.tz_dev)
+ wsa881x_deinit_thermal(wsa881x->tz_pdata.tz_dev);
+
+ mutex_destroy(&wsa881x->bg_lock);
+ mutex_destroy(&wsa881x->res_lock);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wsa881x = {
+ .probe = wsa881x_probe,
+ .remove = wsa881x_remove,
+
+ .read = wsa881x_i2c_read,
+ .write = wsa881x_i2c_write,
+
+ .controls = wsa881x_snd_controls,
+ .num_controls = ARRAY_SIZE(wsa881x_snd_controls),
+ .dapm_widgets = wsa881x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wsa881x_dapm_widgets),
+ .dapm_routes = wsa881x_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(wsa881x_audio_map),
+};
+
+static int wsa881x_reset(struct wsa881x_pdata *pdata, bool enable)
+{
+ int ret = 0;
+
+ /*
+ * shutdown the GPIOs WSA_EN, WSA_MCLK, regulators
+ * and restore defaults in soc cache when shutdown.
+ * Enable regulators, GPIOs WSA_MCLK, WSA_EN when powerup.
+ */
+ if (enable) {
+ if (pdata->wsa_active)
+ return 0;
+ ret = msm_cdc_pinctrl_select_active_state(
+ pdata->wsa_reset_gpio_p);
+ if (ret) {
+ pr_err("%s: gpio set cannot be activated %s\n",
+ __func__, "wsa_reset");
+ return ret;
+ }
+ ret = msm_cdc_pinctrl_select_sleep_state(
+ pdata->wsa_reset_gpio_p);
+ if (ret) {
+ pr_err("%s: gpio set cannot be suspended(powerup) %s\n",
+ __func__, "wsa_reset");
+ return ret;
+ }
+ ret = msm_cdc_pinctrl_select_active_state(
+ pdata->wsa_reset_gpio_p);
+ if (ret) {
+ pr_err("%s: gpio set cannot be activated %s\n",
+ __func__, "wsa_reset");
+ return ret;
+ }
+ pdata->wsa_active = true;
+ } else {
+ if (!pdata->wsa_active)
+ return 0;
+ ret = msm_cdc_pinctrl_select_sleep_state(
+ pdata->wsa_reset_gpio_p);
+ if (ret) {
+ pr_err("%s: gpio set cannot be suspended %s\n",
+ __func__, "wsa_reset");
+ return ret;
+ }
+ pdata->wsa_active = false;
+ }
+ return ret;
+}
+
+int wsa881x_get_client_index(void)
+{
+ return wsa881x_i2c_addr;
+}
+EXPORT_SYMBOL(wsa881x_get_client_index);
+
+int wsa881x_get_probing_count(void)
+{
+ return wsa881x_probing_count;
+}
+EXPORT_SYMBOL(wsa881x_get_probing_count);
+
+int wsa881x_get_presence_count(void)
+{
+ return wsa881x_presence_count;
+}
+EXPORT_SYMBOL(wsa881x_get_presence_count);
+
+static int check_wsa881x_presence(struct i2c_client *client)
+{
+ int ret = 0;
+ int wsa881x_index = 0;
+
+ ret = wsa881x_i2c_get_client_index(client, &wsa881x_index);
+ if (ret != 0) {
+ dev_err(&client->dev, "%s: I2C get codec I2C\n"
+ "client failed\n", __func__);
+ return ret;
+ }
+ ret = wsa881x_i2c_read_device(&wsa_pdata[wsa881x_index],
+ WSA881X_CDC_RST_CTL);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to read wsa881x with addr %x\n",
+ client->addr);
+ return ret;
+ }
+ ret = wsa881x_i2c_write_device(&wsa_pdata[wsa881x_index],
+ WSA881X_CDC_RST_CTL, 0x01);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed write addr %x reg:0x5 val:0x1\n",
+ client->addr);
+ return ret;
+ }
+ /* allow 20ms before trigger next write to verify wsa881x presence */
+ msleep(20);
+ ret = wsa881x_i2c_write_device(&wsa_pdata[wsa881x_index],
+ WSA881X_CDC_RST_CTL, 0x00);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed write addr %x reg:0x5 val:0x0\n",
+ client->addr);
+ return ret;
+ }
+ return ret;
+}
+
+static int wsa881x_populate_dt_pdata(struct device *dev, int wsa881x_index)
+{
+ int ret = 0;
+ struct wsa881x_pdata *pdata = &wsa_pdata[wsa881x_index];
+
+ /* reading the gpio configurations from dtsi file */
+ pdata->wsa_vi_gpio_p = of_parse_phandle(dev->of_node,
+ "qcom,wsa-analog-vi-gpio", 0);
+ pdata->wsa_clk_gpio_p = of_parse_phandle(dev->of_node,
+ "qcom,wsa-analog-clk-gpio", 0);
+ pdata->wsa_reset_gpio_p = of_parse_phandle(dev->of_node,
+ "qcom,wsa-analog-reset-gpio", 0);
+ pinctrl_init = true;
+ return ret;
+}
+
+static int wsa881x_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ int wsa881x_index = 0;
+ struct wsa881x_pdata *pdata = NULL;
+ struct clk *wsa_mclk = NULL;
+
+ ret = wsa881x_i2c_get_client_index(client, &wsa881x_index);
+ if (ret != 0) {
+ dev_err(&client->dev, "%s: I2C get codec I2C\n"
+ "client failed\n", __func__);
+ return ret;
+ }
+
+ pdata = &wsa_pdata[wsa881x_index];
+ if ((client->addr == WSA881X_I2C_SPK0_SLAVE1_ADDR ||
+ client->addr == WSA881X_I2C_SPK1_SLAVE1_ADDR) &&
+ (pdata->status == WSA881X_STATUS_PROBING)) {
+ wsa881x_probing_count++;
+ return -EPROBE_DEFER;
+ }
+
+ if (pdata->status == WSA881X_STATUS_I2C) {
+ dev_dbg(&client->dev, "%s:probe for other slaves\n"
+ "devices of codec I2C slave Addr = %x\n",
+ __func__, client->addr);
+ dev_dbg(&client->dev, "%s:wsa_idx = %d SLAVE = %d\n",
+ __func__, wsa881x_index, WSA881X_ANALOG_SLAVE);
+ pdata->regmap[WSA881X_ANALOG_SLAVE] =
+ devm_regmap_init_i2c(
+ client,
+ &wsa881x_ana_regmap_config[WSA881X_ANALOG_SLAVE]);
+ regcache_cache_bypass(pdata->regmap[WSA881X_ANALOG_SLAVE],
+ true);
+ if (IS_ERR(pdata->regmap[WSA881X_ANALOG_SLAVE])) {
+ ret = PTR_ERR(pdata->regmap[WSA881X_ANALOG_SLAVE]);
+ dev_err(&client->dev,
+ "%s: regmap_init failed %d\n",
+ __func__, ret);
+ }
+ client->dev.platform_data = pdata;
+ i2c_set_clientdata(client, pdata);
+ pdata->client[WSA881X_ANALOG_SLAVE] = client;
+ if (pdata->version == WSA881X_2_0)
+ wsa881x_update_regmap_2_0(
+ pdata->regmap[WSA881X_ANALOG_SLAVE],
+ WSA881X_ANALOG_SLAVE);
+
+ wsa881x_probing_count++;
+ return ret;
+ } else if (pdata->status == WSA881X_STATUS_PROBING) {
+ pdata->index = wsa881x_index;
+ if (client->dev.of_node) {
+ dev_dbg(&client->dev, "%s:Platform data\n"
+ "from device tree\n", __func__);
+ ret = wsa881x_populate_dt_pdata(
+ &client->dev, wsa881x_index);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "%s: Fail to obtain pdata from device tree\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ client->dev.platform_data = pdata;
+ } else {
+ dev_dbg(&client->dev, "%s:Platform data from\n"
+ "board file\n", __func__);
+ pdata = client->dev.platform_data;
+ }
+ if (!pdata) {
+ dev_dbg(&client->dev, "no platform data?\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ wsa_mclk = devm_clk_get(&client->dev, "wsa_mclk");
+ if (IS_ERR(wsa_mclk)) {
+ ret = PTR_ERR(wsa_mclk);
+ dev_dbg(&client->dev, "%s: clk get %s failed %d\n",
+ __func__, "wsa_mclk", ret);
+ wsa_mclk = NULL;
+ goto err;
+ }
+ pdata->wsa_mclk = wsa_mclk;
+ dev_set_drvdata(&client->dev, client);
+
+ pdata->regmap[WSA881X_DIGITAL_SLAVE] =
+ devm_regmap_init_i2c(
+ client,
+ &wsa881x_ana_regmap_config[WSA881X_DIGITAL_SLAVE]);
+ regcache_cache_bypass(pdata->regmap[WSA881X_DIGITAL_SLAVE],
+ true);
+ if (IS_ERR(pdata->regmap[WSA881X_DIGITAL_SLAVE])) {
+ ret = PTR_ERR(pdata->regmap[WSA881X_DIGITAL_SLAVE]);
+ dev_err(&client->dev, "%s: regmap_init failed %d\n",
+ __func__, ret);
+ goto err;
+ }
+
+ /* bus reset sequence */
+ ret = wsa881x_reset(pdata, true);
+ if (ret < 0) {
+ wsa881x_probing_count++;
+ dev_err(&client->dev, "%s: WSA enable Failed %d\n",
+ __func__, ret);
+ goto err;
+ }
+ pdata->client[WSA881X_DIGITAL_SLAVE] = client;
+ pdata->regmap_flag = true;
+ ret = check_wsa881x_presence(client);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "failed to ping wsa with addr:%x, ret = %d\n",
+ client->addr, ret);
+ wsa881x_probing_count++;
+ goto err1;
+ }
+ pdata->version = wsa881x_i2c_read_device(pdata,
+ WSA881X_CHIP_ID1);
+ pr_debug("%s: wsa881x version: %d\n", __func__, pdata->version);
+ if (pdata->version == WSA881X_2_0) {
+ wsa881x_update_reg_defaults_2_0();
+ wsa881x_update_regmap_2_0(
+ pdata->regmap[WSA881X_DIGITAL_SLAVE],
+ WSA881X_DIGITAL_SLAVE);
+ }
+ wsa881x_presence_count++;
+ wsa881x_probing_count++;
+ ret = snd_soc_register_component(&client->dev,
+ &soc_component_dev_wsa881x,
+ NULL, 0);
+ if (ret < 0)
+ goto err1;
+ pdata->status = WSA881X_STATUS_I2C;
+ }
+err1:
+ wsa881x_reset(pdata, false);
+err:
+ return ret;
+}
+
+static int wsa881x_i2c_remove(struct i2c_client *client)
+{
+ struct wsa881x_pdata *wsa881x = client->dev.platform_data;
+
+ snd_soc_unregister_component(&client->dev);
+ i2c_set_clientdata(client, NULL);
+ kfree(wsa881x);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int wsa881x_i2c_suspend(struct device *dev)
+{
+ pr_debug("%s: system suspend\n", __func__);
+ return 0;
+}
+
+static int wsa881x_i2c_resume(struct device *dev)
+{
+ pr_debug("%s: system resume\n", __func__);
+ return 0;
+}
+
+static const struct dev_pm_ops wsa881x_i2c_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(wsa881x_i2c_suspend, wsa881x_i2c_resume)
+};
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct i2c_device_id wsa881x_i2c_id[] = {
+ {"wsa881x-i2c-dev", WSA881X_I2C_SPK0_SLAVE0_ADDR},
+ {"wsa881x-i2c-dev", WSA881X_I2C_SPK0_SLAVE1_ADDR},
+ {"wsa881x-i2c-dev", WSA881X_I2C_SPK1_SLAVE0_ADDR},
+ {"wsa881x-i2c-dev", WSA881X_I2C_SPK1_SLAVE1_ADDR},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, wsa881x_i2c_id);
+
+
+static const struct of_device_id msm_match_table[] = {
+ {.compatible = "qcom,wsa881x-i2c-codec"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_match_table);
+
+static struct i2c_driver wsa881x_codec_driver = {
+ .driver = {
+ .name = "wsa881x-i2c-codec",
+ .owner = THIS_MODULE,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+#ifdef CONFIG_PM_SLEEP
+ .pm = &wsa881x_i2c_pm_ops,
+#endif
+ .of_match_table = msm_match_table,
+ },
+ .id_table = wsa881x_i2c_id,
+ .probe = wsa881x_i2c_probe,
+ .remove = wsa881x_i2c_remove,
+};
+
+static int __init wsa881x_codec_init(void)
+{
+ int i = 0;
+
+ for (i = 0; i < MAX_WSA881X_DEVICE; i++)
+ wsa_pdata[i].status = WSA881X_STATUS_PROBING;
+ return i2c_add_driver(&wsa881x_codec_driver);
+}
+module_init(wsa881x_codec_init);
+
+static void __exit wsa881x_codec_exit(void)
+{
+ i2c_del_driver(&wsa881x_codec_driver);
+}
+
+module_exit(wsa881x_codec_exit);
+
+MODULE_DESCRIPTION("WSA881x Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wsa881x-analog.h b/asoc/codecs/wsa881x-analog.h
new file mode 100644
index 0000000..0aa86a9
--- /dev/null
+++ b/asoc/codecs/wsa881x-analog.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2015, 2018-2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _WSA881X_H
+#define _WSA881X_H
+
+#include <linux/regmap.h>
+#include "wsa881x-registers-analog.h"
+#include <sound/soc.h>
+
+#define WSA881X_I2C_SPK0_SLAVE0_ADDR 0x0E
+#define WSA881X_I2C_SPK0_SLAVE1_ADDR 0x44
+#define WSA881X_I2C_SPK1_SLAVE0_ADDR 0x0F
+#define WSA881X_I2C_SPK1_SLAVE1_ADDR 0x45
+
+#define WSA881X_I2C_SPK0_SLAVE0 0
+#define WSA881X_I2C_SPK1_SLAVE0 1
+#define MAX_WSA881X_DEVICE 2
+#define WSA881X_DIGITAL_SLAVE 0
+#define WSA881X_ANALOG_SLAVE 1
+
+enum {
+ WSA881X_1_X = 0,
+ WSA881X_2_0,
+};
+
+#define WSA881X_IS_2_0(ver) \
+ ((ver == WSA881X_2_0) ? 1 : 0)
+
+extern const u8 wsa881x_ana_reg_readable[WSA881X_CACHE_SIZE];
+extern struct reg_default wsa881x_ana_reg_defaults[WSA881X_CACHE_SIZE];
+extern struct regmap_config wsa881x_ana_regmap_config[2];
+int wsa881x_get_client_index(void);
+int wsa881x_get_probing_count(void);
+int wsa881x_get_presence_count(void);
+int wsa881x_set_mclk_callback(
+ int (*enable_mclk_callback)(struct snd_soc_card *, bool));
+void wsa881x_update_reg_defaults_2_0(void);
+void wsa881x_update_regmap_2_0(struct regmap *regmap, int flag);
+
+#endif /* _WSA881X_H */
diff --git a/asoc/codecs/wsa881x-registers-analog.h b/asoc/codecs/wsa881x-registers-analog.h
new file mode 100644
index 0000000..2f24023
--- /dev/null
+++ b/asoc/codecs/wsa881x-registers-analog.h
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2015, 2018-2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef WSA881X_REGISTERS_H
+#define WSA881X_REGISTERS_H
+
+#define WSA881X_DIGITAL_BASE 0x0000
+#define WSA881X_ANALOG_BASE 0x0100
+
+#define WSA881X_CHIP_ID0 (WSA881X_DIGITAL_BASE+0x0000)
+#define WSA881X_CHIP_ID1 (WSA881X_DIGITAL_BASE+0x0001)
+#define WSA881X_CHIP_ID2 (WSA881X_DIGITAL_BASE+0x0002)
+#define WSA881X_CHIP_ID3 (WSA881X_DIGITAL_BASE+0x0003)
+#define WSA881X_BUS_ID (WSA881X_DIGITAL_BASE+0x0004)
+#define WSA881X_CDC_RST_CTL (WSA881X_DIGITAL_BASE+0x0005)
+#define WSA881X_CDC_TOP_CLK_CTL (WSA881X_DIGITAL_BASE+0x0006)
+#define WSA881X_CDC_ANA_CLK_CTL (WSA881X_DIGITAL_BASE+0x0007)
+#define WSA881X_CDC_DIG_CLK_CTL (WSA881X_DIGITAL_BASE+0x0008)
+#define WSA881X_CLOCK_CONFIG (WSA881X_DIGITAL_BASE+0x0009)
+#define WSA881X_ANA_CTL (WSA881X_DIGITAL_BASE+0x000A)
+#define WSA881X_SWR_RESET_EN (WSA881X_DIGITAL_BASE+0x000B)
+#define WSA881X_RESET_CTL (WSA881X_DIGITAL_BASE+0x000C)
+#define WSA881X_TADC_VALUE_CTL (WSA881X_DIGITAL_BASE+0x000F)
+#define WSA881X_TEMP_DETECT_CTL (WSA881X_DIGITAL_BASE+0x0010)
+#define WSA881X_TEMP_MSB (WSA881X_DIGITAL_BASE+0x0011)
+#define WSA881X_TEMP_LSB (WSA881X_DIGITAL_BASE+0x0012)
+#define WSA881X_TEMP_CONFIG0 (WSA881X_DIGITAL_BASE+0x0013)
+#define WSA881X_TEMP_CONFIG1 (WSA881X_DIGITAL_BASE+0x0014)
+#define WSA881X_CDC_CLIP_CTL (WSA881X_DIGITAL_BASE+0x0015)
+#define WSA881X_SDM_PDM9_LSB (WSA881X_DIGITAL_BASE+0x0016)
+#define WSA881X_SDM_PDM9_MSB (WSA881X_DIGITAL_BASE+0x0017)
+#define WSA881X_CDC_RX_CTL (WSA881X_DIGITAL_BASE+0x0018)
+#define WSA881X_DEM_BYPASS_DATA0 (WSA881X_DIGITAL_BASE+0x0019)
+#define WSA881X_DEM_BYPASS_DATA1 (WSA881X_DIGITAL_BASE+0x001A)
+#define WSA881X_DEM_BYPASS_DATA2 (WSA881X_DIGITAL_BASE+0x001B)
+#define WSA881X_DEM_BYPASS_DATA3 (WSA881X_DIGITAL_BASE+0x001C)
+#define WSA881X_OTP_CTRL0 (WSA881X_DIGITAL_BASE+0x001D)
+#define WSA881X_OTP_CTRL1 (WSA881X_DIGITAL_BASE+0x001E)
+#define WSA881X_HDRIVE_CTL_GROUP1 (WSA881X_DIGITAL_BASE+0x001F)
+#define WSA881X_INTR_MODE (WSA881X_DIGITAL_BASE+0x0020)
+#define WSA881X_INTR_MASK (WSA881X_DIGITAL_BASE+0x0021)
+#define WSA881X_INTR_STATUS (WSA881X_DIGITAL_BASE+0x0022)
+#define WSA881X_INTR_CLEAR (WSA881X_DIGITAL_BASE+0x0023)
+#define WSA881X_INTR_LEVEL (WSA881X_DIGITAL_BASE+0x0024)
+#define WSA881X_INTR_SET (WSA881X_DIGITAL_BASE+0x0025)
+#define WSA881X_INTR_TEST (WSA881X_DIGITAL_BASE+0x0026)
+#define WSA881X_PDM_TEST_MODE (WSA881X_DIGITAL_BASE+0x0030)
+#define WSA881X_ATE_TEST_MODE (WSA881X_DIGITAL_BASE+0x0031)
+#define WSA881X_PIN_CTL_MODE (WSA881X_DIGITAL_BASE+0x0032)
+#define WSA881X_PIN_CTL_OE (WSA881X_DIGITAL_BASE+0x0033)
+#define WSA881X_PIN_WDATA_IOPAD (WSA881X_DIGITAL_BASE+0x0034)
+#define WSA881X_PIN_STATUS (WSA881X_DIGITAL_BASE+0x0035)
+#define WSA881X_DIG_DEBUG_MODE (WSA881X_DIGITAL_BASE+0x0037)
+#define WSA881X_DIG_DEBUG_SEL (WSA881X_DIGITAL_BASE+0x0038)
+#define WSA881X_DIG_DEBUG_EN (WSA881X_DIGITAL_BASE+0x0039)
+#define WSA881X_SWR_HM_TEST1 (WSA881X_DIGITAL_BASE+0x003B)
+#define WSA881X_SWR_HM_TEST2 (WSA881X_DIGITAL_BASE+0x003C)
+#define WSA881X_TEMP_DETECT_DBG_CTL (WSA881X_DIGITAL_BASE+0x003D)
+#define WSA881X_TEMP_DEBUG_MSB (WSA881X_DIGITAL_BASE+0x003E)
+#define WSA881X_TEMP_DEBUG_LSB (WSA881X_DIGITAL_BASE+0x003F)
+#define WSA881X_SAMPLE_EDGE_SEL (WSA881X_DIGITAL_BASE+0x0044)
+#define WSA881X_IOPAD_CTL (WSA881X_DIGITAL_BASE+0x0045)
+#define WSA881X_SPARE_0 (WSA881X_DIGITAL_BASE+0x0050)
+#define WSA881X_SPARE_1 (WSA881X_DIGITAL_BASE+0x0051)
+#define WSA881X_SPARE_2 (WSA881X_DIGITAL_BASE+0x0052)
+#define WSA881X_OTP_REG_0 (WSA881X_DIGITAL_BASE+0x0080)
+#define WSA881X_OTP_REG_1 (WSA881X_DIGITAL_BASE+0x0081)
+#define WSA881X_OTP_REG_2 (WSA881X_DIGITAL_BASE+0x0082)
+#define WSA881X_OTP_REG_3 (WSA881X_DIGITAL_BASE+0x0083)
+#define WSA881X_OTP_REG_4 (WSA881X_DIGITAL_BASE+0x0084)
+#define WSA881X_OTP_REG_5 (WSA881X_DIGITAL_BASE+0x0085)
+#define WSA881X_OTP_REG_6 (WSA881X_DIGITAL_BASE+0x0086)
+#define WSA881X_OTP_REG_7 (WSA881X_DIGITAL_BASE+0x0087)
+#define WSA881X_OTP_REG_8 (WSA881X_DIGITAL_BASE+0x0088)
+#define WSA881X_OTP_REG_9 (WSA881X_DIGITAL_BASE+0x0089)
+#define WSA881X_OTP_REG_10 (WSA881X_DIGITAL_BASE+0x008A)
+#define WSA881X_OTP_REG_11 (WSA881X_DIGITAL_BASE+0x008B)
+#define WSA881X_OTP_REG_12 (WSA881X_DIGITAL_BASE+0x008C)
+#define WSA881X_OTP_REG_13 (WSA881X_DIGITAL_BASE+0x008D)
+#define WSA881X_OTP_REG_14 (WSA881X_DIGITAL_BASE+0x008E)
+#define WSA881X_OTP_REG_15 (WSA881X_DIGITAL_BASE+0x008F)
+#define WSA881X_OTP_REG_16 (WSA881X_DIGITAL_BASE+0x0090)
+#define WSA881X_OTP_REG_17 (WSA881X_DIGITAL_BASE+0x0091)
+#define WSA881X_OTP_REG_18 (WSA881X_DIGITAL_BASE+0x0092)
+#define WSA881X_OTP_REG_19 (WSA881X_DIGITAL_BASE+0x0093)
+#define WSA881X_OTP_REG_20 (WSA881X_DIGITAL_BASE+0x0094)
+#define WSA881X_OTP_REG_21 (WSA881X_DIGITAL_BASE+0x0095)
+#define WSA881X_OTP_REG_22 (WSA881X_DIGITAL_BASE+0x0096)
+#define WSA881X_OTP_REG_23 (WSA881X_DIGITAL_BASE+0x0097)
+#define WSA881X_OTP_REG_24 (WSA881X_DIGITAL_BASE+0x0098)
+#define WSA881X_OTP_REG_25 (WSA881X_DIGITAL_BASE+0x0099)
+#define WSA881X_OTP_REG_26 (WSA881X_DIGITAL_BASE+0x009A)
+#define WSA881X_OTP_REG_27 (WSA881X_DIGITAL_BASE+0x009B)
+#define WSA881X_OTP_REG_28 (WSA881X_DIGITAL_BASE+0x009C)
+#define WSA881X_OTP_REG_29 (WSA881X_DIGITAL_BASE+0x009D)
+#define WSA881X_OTP_REG_30 (WSA881X_DIGITAL_BASE+0x009E)
+#define WSA881X_OTP_REG_31 (WSA881X_DIGITAL_BASE+0x009F)
+#define WSA881X_OTP_REG_32 (WSA881X_DIGITAL_BASE+0x00A0)
+#define WSA881X_OTP_REG_33 (WSA881X_DIGITAL_BASE+0x00A1)
+#define WSA881X_OTP_REG_34 (WSA881X_DIGITAL_BASE+0x00A2)
+#define WSA881X_OTP_REG_35 (WSA881X_DIGITAL_BASE+0x00A3)
+#define WSA881X_OTP_REG_36 (WSA881X_DIGITAL_BASE+0x00A4)
+#define WSA881X_OTP_REG_37 (WSA881X_DIGITAL_BASE+0x00A5)
+#define WSA881X_OTP_REG_38 (WSA881X_DIGITAL_BASE+0x00A6)
+#define WSA881X_OTP_REG_39 (WSA881X_DIGITAL_BASE+0x00A7)
+#define WSA881X_OTP_REG_40 (WSA881X_DIGITAL_BASE+0x00A8)
+#define WSA881X_OTP_REG_41 (WSA881X_DIGITAL_BASE+0x00A9)
+#define WSA881X_OTP_REG_42 (WSA881X_DIGITAL_BASE+0x00AA)
+#define WSA881X_OTP_REG_43 (WSA881X_DIGITAL_BASE+0x00AB)
+#define WSA881X_OTP_REG_44 (WSA881X_DIGITAL_BASE+0x00AC)
+#define WSA881X_OTP_REG_45 (WSA881X_DIGITAL_BASE+0x00AD)
+#define WSA881X_OTP_REG_46 (WSA881X_DIGITAL_BASE+0x00AE)
+#define WSA881X_OTP_REG_47 (WSA881X_DIGITAL_BASE+0x00AF)
+#define WSA881X_OTP_REG_48 (WSA881X_DIGITAL_BASE+0x00B0)
+#define WSA881X_OTP_REG_49 (WSA881X_DIGITAL_BASE+0x00B1)
+#define WSA881X_OTP_REG_50 (WSA881X_DIGITAL_BASE+0x00B2)
+#define WSA881X_OTP_REG_51 (WSA881X_DIGITAL_BASE+0x00B3)
+#define WSA881X_OTP_REG_52 (WSA881X_DIGITAL_BASE+0x00B4)
+#define WSA881X_OTP_REG_53 (WSA881X_DIGITAL_BASE+0x00B5)
+#define WSA881X_OTP_REG_54 (WSA881X_DIGITAL_BASE+0x00B6)
+#define WSA881X_OTP_REG_55 (WSA881X_DIGITAL_BASE+0x00B7)
+#define WSA881X_OTP_REG_56 (WSA881X_DIGITAL_BASE+0x00B8)
+#define WSA881X_OTP_REG_57 (WSA881X_DIGITAL_BASE+0x00B9)
+#define WSA881X_OTP_REG_58 (WSA881X_DIGITAL_BASE+0x00BA)
+#define WSA881X_OTP_REG_59 (WSA881X_DIGITAL_BASE+0x00BB)
+#define WSA881X_OTP_REG_60 (WSA881X_DIGITAL_BASE+0x00BC)
+#define WSA881X_OTP_REG_61 (WSA881X_DIGITAL_BASE+0x00BD)
+#define WSA881X_OTP_REG_62 (WSA881X_DIGITAL_BASE+0x00BE)
+#define WSA881X_OTP_REG_63 (WSA881X_DIGITAL_BASE+0x00BF)
+/* Analog Register address space */
+#define WSA881X_BIAS_REF_CTRL (WSA881X_ANALOG_BASE+0x0000)
+#define WSA881X_BIAS_TEST (WSA881X_ANALOG_BASE+0x0001)
+#define WSA881X_BIAS_BIAS (WSA881X_ANALOG_BASE+0x0002)
+#define WSA881X_TEMP_OP (WSA881X_ANALOG_BASE+0x0003)
+#define WSA881X_TEMP_IREF_CTRL (WSA881X_ANALOG_BASE+0x0004)
+#define WSA881X_TEMP_ISENS_CTRL (WSA881X_ANALOG_BASE+0x0005)
+#define WSA881X_TEMP_CLK_CTRL (WSA881X_ANALOG_BASE+0x0006)
+#define WSA881X_TEMP_TEST (WSA881X_ANALOG_BASE+0x0007)
+#define WSA881X_TEMP_BIAS (WSA881X_ANALOG_BASE+0x0008)
+#define WSA881X_TEMP_ADC_CTRL (WSA881X_ANALOG_BASE+0x0009)
+#define WSA881X_TEMP_DOUT_MSB (WSA881X_ANALOG_BASE+0x000A)
+#define WSA881X_TEMP_DOUT_LSB (WSA881X_ANALOG_BASE+0x000B)
+#define WSA881X_ADC_EN_MODU_V (WSA881X_ANALOG_BASE+0x0010)
+#define WSA881X_ADC_EN_MODU_I (WSA881X_ANALOG_BASE+0x0011)
+#define WSA881X_ADC_EN_DET_TEST_V (WSA881X_ANALOG_BASE+0x0012)
+#define WSA881X_ADC_EN_DET_TEST_I (WSA881X_ANALOG_BASE+0x0013)
+#define WSA881X_ADC_SEL_IBIAS (WSA881X_ANALOG_BASE+0x0014)
+#define WSA881X_ADC_EN_SEL_IBIAS (WSA881X_ANALOG_BASE+0x0015)
+#define WSA881X_SPKR_DRV_EN (WSA881X_ANALOG_BASE+0x001A)
+#define WSA881X_SPKR_DRV_GAIN (WSA881X_ANALOG_BASE+0x001B)
+#define WSA881X_SPKR_DAC_CTL (WSA881X_ANALOG_BASE+0x001C)
+#define WSA881X_SPKR_DRV_DBG (WSA881X_ANALOG_BASE+0x001D)
+#define WSA881X_SPKR_PWRSTG_DBG (WSA881X_ANALOG_BASE+0x001E)
+#define WSA881X_SPKR_OCP_CTL (WSA881X_ANALOG_BASE+0x001F)
+#define WSA881X_SPKR_CLIP_CTL (WSA881X_ANALOG_BASE+0x0020)
+#define WSA881X_SPKR_BBM_CTL (WSA881X_ANALOG_BASE+0x0021)
+#define WSA881X_SPKR_MISC_CTL1 (WSA881X_ANALOG_BASE+0x0022)
+#define WSA881X_SPKR_MISC_CTL2 (WSA881X_ANALOG_BASE+0x0023)
+#define WSA881X_SPKR_BIAS_INT (WSA881X_ANALOG_BASE+0x0024)
+#define WSA881X_SPKR_PA_INT (WSA881X_ANALOG_BASE+0x0025)
+#define WSA881X_SPKR_BIAS_CAL (WSA881X_ANALOG_BASE+0x0026)
+#define WSA881X_SPKR_BIAS_PSRR (WSA881X_ANALOG_BASE+0x0027)
+#define WSA881X_SPKR_STATUS1 (WSA881X_ANALOG_BASE+0x0028)
+#define WSA881X_SPKR_STATUS2 (WSA881X_ANALOG_BASE+0x0029)
+#define WSA881X_BOOST_EN_CTL (WSA881X_ANALOG_BASE+0x002A)
+#define WSA881X_BOOST_CURRENT_LIMIT (WSA881X_ANALOG_BASE+0x002B)
+#define WSA881X_BOOST_PS_CTL (WSA881X_ANALOG_BASE+0x002C)
+#define WSA881X_BOOST_PRESET_OUT1 (WSA881X_ANALOG_BASE+0x002D)
+#define WSA881X_BOOST_PRESET_OUT2 (WSA881X_ANALOG_BASE+0x002E)
+#define WSA881X_BOOST_FORCE_OUT (WSA881X_ANALOG_BASE+0x002F)
+#define WSA881X_BOOST_LDO_PROG (WSA881X_ANALOG_BASE+0x0030)
+#define WSA881X_BOOST_SLOPE_COMP_ISENSE_FB (WSA881X_ANALOG_BASE+0x0031)
+#define WSA881X_BOOST_RON_CTL (WSA881X_ANALOG_BASE+0x0032)
+#define WSA881X_BOOST_LOOP_STABILITY (WSA881X_ANALOG_BASE+0x0033)
+#define WSA881X_BOOST_ZX_CTL (WSA881X_ANALOG_BASE+0x0034)
+#define WSA881X_BOOST_START_CTL (WSA881X_ANALOG_BASE+0x0035)
+#define WSA881X_BOOST_MISC1_CTL (WSA881X_ANALOG_BASE+0x0036)
+#define WSA881X_BOOST_MISC2_CTL (WSA881X_ANALOG_BASE+0x0037)
+#define WSA881X_BOOST_MISC3_CTL (WSA881X_ANALOG_BASE+0x0038)
+#define WSA881X_BOOST_ATEST_CTL (WSA881X_ANALOG_BASE+0x0039)
+#define WSA881X_SPKR_PROT_FE_GAIN (WSA881X_ANALOG_BASE+0x003A)
+#define WSA881X_SPKR_PROT_FE_CM_LDO_SET (WSA881X_ANALOG_BASE+0x003B)
+#define WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1 (WSA881X_ANALOG_BASE+0x003C)
+#define WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2 (WSA881X_ANALOG_BASE+0x003D)
+#define WSA881X_SPKR_PROT_ATEST1 (WSA881X_ANALOG_BASE+0x003E)
+#define WSA881X_SPKR_PROT_ATEST2 (WSA881X_ANALOG_BASE+0x003F)
+#define WSA881X_SPKR_PROT_FE_VSENSE_VCM (WSA881X_ANALOG_BASE+0x0040)
+#define WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1 (WSA881X_ANALOG_BASE+0x0041)
+#define WSA881X_BONGO_RESRV_REG1 (WSA881X_ANALOG_BASE+0x0042)
+#define WSA881X_BONGO_RESRV_REG2 (WSA881X_ANALOG_BASE+0x0043)
+#define WSA881X_SPKR_PROT_SAR (WSA881X_ANALOG_BASE+0x0044)
+#define WSA881X_SPKR_STATUS3 (WSA881X_ANALOG_BASE+0x0045)
+
+#define WSA881X_NUM_REGISTERS (WSA881X_SPKR_STATUS3+1)
+#define WSA881X_MAX_REGISTER (WSA881X_NUM_REGISTERS-1)
+#define WSA881X_CACHE_SIZE WSA881X_NUM_REGISTERS
+#endif /* WSA881X_REGISTERS_H */
diff --git a/asoc/codecs/wsa881x-regmap-analog.c b/asoc/codecs/wsa881x-regmap-analog.c
new file mode 100644
index 0000000..7353057
--- /dev/null
+++ b/asoc/codecs/wsa881x-regmap-analog.c
@@ -0,0 +1,491 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015, 2018-2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "wsa881x-registers-analog.h"
+#include "wsa881x-analog.h"
+
+struct reg_default wsa881x_ana_reg_defaults[] = {
+ {WSA881X_CHIP_ID0, 0x00},
+ {WSA881X_CHIP_ID1, 0x00},
+ {WSA881X_CHIP_ID2, 0x00},
+ {WSA881X_CHIP_ID3, 0x02},
+ {WSA881X_BUS_ID, 0x00},
+ {WSA881X_CDC_RST_CTL, 0x00},
+ {WSA881X_CDC_TOP_CLK_CTL, 0x03},
+ {WSA881X_CDC_ANA_CLK_CTL, 0x00},
+ {WSA881X_CDC_DIG_CLK_CTL, 0x00},
+ {WSA881X_CLOCK_CONFIG, 0x00},
+ {WSA881X_ANA_CTL, 0x08},
+ {WSA881X_SWR_RESET_EN, 0x00},
+ {WSA881X_TEMP_DETECT_CTL, 0x01},
+ {WSA881X_TEMP_MSB, 0x00},
+ {WSA881X_TEMP_LSB, 0x00},
+ {WSA881X_TEMP_CONFIG0, 0x00},
+ {WSA881X_TEMP_CONFIG1, 0x00},
+ {WSA881X_CDC_CLIP_CTL, 0x03},
+ {WSA881X_SDM_PDM9_LSB, 0x00},
+ {WSA881X_SDM_PDM9_MSB, 0x00},
+ {WSA881X_CDC_RX_CTL, 0x7E},
+ {WSA881X_DEM_BYPASS_DATA0, 0x00},
+ {WSA881X_DEM_BYPASS_DATA1, 0x00},
+ {WSA881X_DEM_BYPASS_DATA2, 0x00},
+ {WSA881X_DEM_BYPASS_DATA3, 0x00},
+ {WSA881X_OTP_CTRL0, 0x00},
+ {WSA881X_OTP_CTRL1, 0x00},
+ {WSA881X_HDRIVE_CTL_GROUP1, 0x00},
+ {WSA881X_INTR_MODE, 0x00},
+ {WSA881X_INTR_MASK, 0x1F},
+ {WSA881X_INTR_STATUS, 0x00},
+ {WSA881X_INTR_CLEAR, 0x00},
+ {WSA881X_INTR_LEVEL, 0x00},
+ {WSA881X_INTR_SET, 0x00},
+ {WSA881X_INTR_TEST, 0x00},
+ {WSA881X_PDM_TEST_MODE, 0x00},
+ {WSA881X_ATE_TEST_MODE, 0x00},
+ {WSA881X_PIN_CTL_MODE, 0x00},
+ {WSA881X_PIN_CTL_OE, 0x00},
+ {WSA881X_PIN_WDATA_IOPAD, 0x00},
+ {WSA881X_PIN_STATUS, 0x00},
+ {WSA881X_DIG_DEBUG_MODE, 0x00},
+ {WSA881X_DIG_DEBUG_SEL, 0x00},
+ {WSA881X_DIG_DEBUG_EN, 0x00},
+ {WSA881X_SWR_HM_TEST1, 0x08},
+ {WSA881X_SWR_HM_TEST2, 0x00},
+ {WSA881X_TEMP_DETECT_DBG_CTL, 0x00},
+ {WSA881X_TEMP_DEBUG_MSB, 0x00},
+ {WSA881X_TEMP_DEBUG_LSB, 0x00},
+ {WSA881X_SAMPLE_EDGE_SEL, 0x0C},
+ {WSA881X_SPARE_0, 0x00},
+ {WSA881X_SPARE_1, 0x00},
+ {WSA881X_SPARE_2, 0x00},
+ {WSA881X_OTP_REG_0, 0x01},
+ {WSA881X_OTP_REG_1, 0xFF},
+ {WSA881X_OTP_REG_2, 0xC0},
+ {WSA881X_OTP_REG_3, 0xFF},
+ {WSA881X_OTP_REG_4, 0xC0},
+ {WSA881X_OTP_REG_5, 0xFF},
+ {WSA881X_OTP_REG_6, 0xFF},
+ {WSA881X_OTP_REG_7, 0xFF},
+ {WSA881X_OTP_REG_8, 0xFF},
+ {WSA881X_OTP_REG_9, 0xFF},
+ {WSA881X_OTP_REG_10, 0xFF},
+ {WSA881X_OTP_REG_11, 0xFF},
+ {WSA881X_OTP_REG_12, 0xFF},
+ {WSA881X_OTP_REG_13, 0xFF},
+ {WSA881X_OTP_REG_14, 0xFF},
+ {WSA881X_OTP_REG_15, 0xFF},
+ {WSA881X_OTP_REG_16, 0xFF},
+ {WSA881X_OTP_REG_17, 0xFF},
+ {WSA881X_OTP_REG_18, 0xFF},
+ {WSA881X_OTP_REG_19, 0xFF},
+ {WSA881X_OTP_REG_20, 0xFF},
+ {WSA881X_OTP_REG_21, 0xFF},
+ {WSA881X_OTP_REG_22, 0xFF},
+ {WSA881X_OTP_REG_23, 0xFF},
+ {WSA881X_OTP_REG_24, 0x03},
+ {WSA881X_OTP_REG_25, 0x01},
+ {WSA881X_OTP_REG_26, 0x03},
+ {WSA881X_OTP_REG_27, 0x11},
+ {WSA881X_OTP_REG_28, 0xFF},
+ {WSA881X_OTP_REG_29, 0xFF},
+ {WSA881X_OTP_REG_30, 0xFF},
+ {WSA881X_OTP_REG_31, 0xFF},
+ {WSA881X_OTP_REG_63, 0x40},
+ /* WSA881x Analog registers */
+ {WSA881X_BIAS_REF_CTRL, 0x6C},
+ {WSA881X_BIAS_TEST, 0x16},
+ {WSA881X_BIAS_BIAS, 0xF0},
+ {WSA881X_TEMP_OP, 0x00},
+ {WSA881X_TEMP_IREF_CTRL, 0x56},
+ {WSA881X_TEMP_ISENS_CTRL, 0x47},
+ {WSA881X_TEMP_CLK_CTRL, 0x87},
+ {WSA881X_TEMP_TEST, 0x00},
+ {WSA881X_TEMP_BIAS, 0x51},
+ {WSA881X_TEMP_ADC_CTRL, 0x00},
+ {WSA881X_TEMP_DOUT_MSB, 0x00},
+ {WSA881X_TEMP_DOUT_LSB, 0x00},
+ {WSA881X_ADC_EN_MODU_V, 0x00},
+ {WSA881X_ADC_EN_MODU_I, 0x00},
+ {WSA881X_ADC_EN_DET_TEST_V, 0x00},
+ {WSA881X_ADC_EN_DET_TEST_I, 0x00},
+ {WSA881X_ADC_SEL_IBIAS, 0x25},
+ {WSA881X_ADC_EN_SEL_IBIAS, 0x10},
+ {WSA881X_SPKR_DRV_EN, 0x74},
+ {WSA881X_SPKR_DRV_GAIN, 0x01},
+ {WSA881X_SPKR_DAC_CTL, 0x40},
+ {WSA881X_SPKR_DRV_DBG, 0x15},
+ {WSA881X_SPKR_PWRSTG_DBG, 0x00},
+ {WSA881X_SPKR_OCP_CTL, 0xD4},
+ {WSA881X_SPKR_CLIP_CTL, 0x90},
+ {WSA881X_SPKR_BBM_CTL, 0x00},
+ {WSA881X_SPKR_MISC_CTL1, 0x80},
+ {WSA881X_SPKR_MISC_CTL2, 0x00},
+ {WSA881X_SPKR_BIAS_INT, 0x56},
+ {WSA881X_SPKR_PA_INT, 0x54},
+ {WSA881X_SPKR_BIAS_CAL, 0xAC},
+ {WSA881X_SPKR_BIAS_PSRR, 0x54},
+ {WSA881X_SPKR_STATUS1, 0x00},
+ {WSA881X_SPKR_STATUS2, 0x00},
+ {WSA881X_BOOST_EN_CTL, 0x18},
+ {WSA881X_BOOST_CURRENT_LIMIT, 0x7A},
+ {WSA881X_BOOST_PS_CTL, 0xC0},
+ {WSA881X_BOOST_PRESET_OUT1, 0x77},
+ {WSA881X_BOOST_PRESET_OUT2, 0x70},
+ {WSA881X_BOOST_FORCE_OUT, 0x0E},
+ {WSA881X_BOOST_LDO_PROG, 0x16},
+ {WSA881X_BOOST_SLOPE_COMP_ISENSE_FB, 0x71},
+ {WSA881X_BOOST_RON_CTL, 0x0F},
+ {WSA881X_BOOST_LOOP_STABILITY, 0xAD},
+ {WSA881X_BOOST_ZX_CTL, 0x34},
+ {WSA881X_BOOST_START_CTL, 0x23},
+ {WSA881X_BOOST_MISC1_CTL, 0x80},
+ {WSA881X_BOOST_MISC2_CTL, 0x00},
+ {WSA881X_BOOST_MISC3_CTL, 0x00},
+ {WSA881X_BOOST_ATEST_CTL, 0x00},
+ {WSA881X_SPKR_PROT_FE_GAIN, 0x46},
+ {WSA881X_SPKR_PROT_FE_CM_LDO_SET, 0x3B},
+ {WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1, 0x8D},
+ {WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2, 0x8D},
+ {WSA881X_SPKR_PROT_ATEST1, 0x01},
+ {WSA881X_SPKR_PROT_ATEST2, 0x00},
+ {WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x8D},
+ {WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1, 0x4D},
+ {WSA881X_BONGO_RESRV_REG1, 0x00},
+ {WSA881X_BONGO_RESRV_REG2, 0x00},
+ {WSA881X_SPKR_PROT_SAR, 0x00},
+ {WSA881X_SPKR_STATUS3, 0x00},
+};
+
+struct reg_default wsa881x_ana_reg_defaults_0[] = {
+ {WSA881X_CHIP_ID0, 0x00},
+ {WSA881X_CHIP_ID1, 0x00},
+ {WSA881X_CHIP_ID2, 0x00},
+ {WSA881X_CHIP_ID3, 0x02},
+ {WSA881X_BUS_ID, 0x00},
+ {WSA881X_CDC_RST_CTL, 0x00},
+ {WSA881X_CDC_TOP_CLK_CTL, 0x03},
+ {WSA881X_CDC_ANA_CLK_CTL, 0x00},
+ {WSA881X_CDC_DIG_CLK_CTL, 0x00},
+ {WSA881X_CLOCK_CONFIG, 0x00},
+ {WSA881X_ANA_CTL, 0x08},
+ {WSA881X_SWR_RESET_EN, 0x00},
+ {WSA881X_TEMP_DETECT_CTL, 0x01},
+ {WSA881X_TEMP_MSB, 0x00},
+ {WSA881X_TEMP_LSB, 0x00},
+ {WSA881X_TEMP_CONFIG0, 0x00},
+ {WSA881X_TEMP_CONFIG1, 0x00},
+ {WSA881X_CDC_CLIP_CTL, 0x03},
+ {WSA881X_SDM_PDM9_LSB, 0x00},
+ {WSA881X_SDM_PDM9_MSB, 0x00},
+ {WSA881X_CDC_RX_CTL, 0x7E},
+ {WSA881X_DEM_BYPASS_DATA0, 0x00},
+ {WSA881X_DEM_BYPASS_DATA1, 0x00},
+ {WSA881X_DEM_BYPASS_DATA2, 0x00},
+ {WSA881X_DEM_BYPASS_DATA3, 0x00},
+ {WSA881X_OTP_CTRL0, 0x00},
+ {WSA881X_OTP_CTRL1, 0x00},
+ {WSA881X_HDRIVE_CTL_GROUP1, 0x00},
+ {WSA881X_INTR_MODE, 0x00},
+ {WSA881X_INTR_MASK, 0x1F},
+ {WSA881X_INTR_STATUS, 0x00},
+ {WSA881X_INTR_CLEAR, 0x00},
+ {WSA881X_INTR_LEVEL, 0x00},
+ {WSA881X_INTR_SET, 0x00},
+ {WSA881X_INTR_TEST, 0x00},
+ {WSA881X_PDM_TEST_MODE, 0x00},
+ {WSA881X_ATE_TEST_MODE, 0x00},
+ {WSA881X_PIN_CTL_MODE, 0x00},
+ {WSA881X_PIN_CTL_OE, 0x00},
+ {WSA881X_PIN_WDATA_IOPAD, 0x00},
+ {WSA881X_PIN_STATUS, 0x00},
+ {WSA881X_DIG_DEBUG_MODE, 0x00},
+ {WSA881X_DIG_DEBUG_SEL, 0x00},
+ {WSA881X_DIG_DEBUG_EN, 0x00},
+ {WSA881X_SWR_HM_TEST1, 0x08},
+ {WSA881X_SWR_HM_TEST2, 0x00},
+ {WSA881X_TEMP_DETECT_DBG_CTL, 0x00},
+ {WSA881X_TEMP_DEBUG_MSB, 0x00},
+ {WSA881X_TEMP_DEBUG_LSB, 0x00},
+ {WSA881X_SAMPLE_EDGE_SEL, 0x0C},
+ {WSA881X_SPARE_0, 0x00},
+ {WSA881X_SPARE_1, 0x00},
+ {WSA881X_SPARE_2, 0x00},
+ {WSA881X_OTP_REG_0, 0x01},
+ {WSA881X_OTP_REG_1, 0xFF},
+ {WSA881X_OTP_REG_2, 0xC0},
+ {WSA881X_OTP_REG_3, 0xFF},
+ {WSA881X_OTP_REG_4, 0xC0},
+ {WSA881X_OTP_REG_5, 0xFF},
+ {WSA881X_OTP_REG_6, 0xFF},
+ {WSA881X_OTP_REG_7, 0xFF},
+ {WSA881X_OTP_REG_8, 0xFF},
+ {WSA881X_OTP_REG_9, 0xFF},
+ {WSA881X_OTP_REG_10, 0xFF},
+ {WSA881X_OTP_REG_11, 0xFF},
+ {WSA881X_OTP_REG_12, 0xFF},
+ {WSA881X_OTP_REG_13, 0xFF},
+ {WSA881X_OTP_REG_14, 0xFF},
+ {WSA881X_OTP_REG_15, 0xFF},
+ {WSA881X_OTP_REG_16, 0xFF},
+ {WSA881X_OTP_REG_17, 0xFF},
+ {WSA881X_OTP_REG_18, 0xFF},
+ {WSA881X_OTP_REG_19, 0xFF},
+ {WSA881X_OTP_REG_20, 0xFF},
+ {WSA881X_OTP_REG_21, 0xFF},
+ {WSA881X_OTP_REG_22, 0xFF},
+ {WSA881X_OTP_REG_23, 0xFF},
+ {WSA881X_OTP_REG_24, 0x03},
+ {WSA881X_OTP_REG_25, 0x01},
+ {WSA881X_OTP_REG_26, 0x03},
+ {WSA881X_OTP_REG_27, 0x11},
+ {WSA881X_OTP_REG_28, 0xFF},
+ {WSA881X_OTP_REG_29, 0xFF},
+ {WSA881X_OTP_REG_30, 0xFF},
+ {WSA881X_OTP_REG_31, 0xFF},
+ {WSA881X_OTP_REG_63, 0x40},
+};
+
+struct reg_default wsa881x_ana_reg_defaults_1[] = {
+ {WSA881X_BIAS_REF_CTRL - WSA881X_ANALOG_BASE, 0x6C},
+ {WSA881X_BIAS_TEST - WSA881X_ANALOG_BASE, 0x16},
+ {WSA881X_BIAS_BIAS - WSA881X_ANALOG_BASE, 0xF0},
+ {WSA881X_TEMP_OP - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_TEMP_IREF_CTRL - WSA881X_ANALOG_BASE, 0x56},
+ {WSA881X_TEMP_ISENS_CTRL - WSA881X_ANALOG_BASE, 0x47},
+ {WSA881X_TEMP_CLK_CTRL - WSA881X_ANALOG_BASE, 0x87},
+ {WSA881X_TEMP_TEST - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_TEMP_BIAS - WSA881X_ANALOG_BASE, 0x51},
+ {WSA881X_TEMP_ADC_CTRL - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_TEMP_DOUT_MSB - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_TEMP_DOUT_LSB - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_ADC_EN_MODU_V - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_ADC_EN_MODU_I - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_ADC_EN_DET_TEST_V - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_ADC_EN_DET_TEST_I - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_ADC_SEL_IBIAS - WSA881X_ANALOG_BASE, 0x25},
+ {WSA881X_ADC_EN_SEL_IBIAS - WSA881X_ANALOG_BASE, 0x10},
+ {WSA881X_SPKR_DRV_EN - WSA881X_ANALOG_BASE, 0x74},
+ {WSA881X_SPKR_DRV_GAIN - WSA881X_ANALOG_BASE, 0x01},
+ {WSA881X_SPKR_DAC_CTL - WSA881X_ANALOG_BASE, 0x40},
+ {WSA881X_SPKR_DRV_DBG - WSA881X_ANALOG_BASE, 0x15},
+ {WSA881X_SPKR_PWRSTG_DBG - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_SPKR_OCP_CTL - WSA881X_ANALOG_BASE, 0xD4},
+ {WSA881X_SPKR_CLIP_CTL - WSA881X_ANALOG_BASE, 0x90},
+ {WSA881X_SPKR_BBM_CTL - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_SPKR_MISC_CTL1 - WSA881X_ANALOG_BASE, 0x80},
+ {WSA881X_SPKR_MISC_CTL2 - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_SPKR_BIAS_INT - WSA881X_ANALOG_BASE, 0x56},
+ {WSA881X_SPKR_PA_INT - WSA881X_ANALOG_BASE, 0x54},
+ {WSA881X_SPKR_BIAS_CAL - WSA881X_ANALOG_BASE, 0xAC},
+ {WSA881X_SPKR_BIAS_PSRR - WSA881X_ANALOG_BASE, 0x54},
+ {WSA881X_SPKR_STATUS1 - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_SPKR_STATUS2 - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_BOOST_EN_CTL - WSA881X_ANALOG_BASE, 0x18},
+ {WSA881X_BOOST_CURRENT_LIMIT - WSA881X_ANALOG_BASE, 0x7A},
+ {WSA881X_BOOST_PS_CTL - WSA881X_ANALOG_BASE, 0xC0},
+ {WSA881X_BOOST_PRESET_OUT1 - WSA881X_ANALOG_BASE, 0x77},
+ {WSA881X_BOOST_PRESET_OUT2 - WSA881X_ANALOG_BASE, 0x70},
+ {WSA881X_BOOST_FORCE_OUT - WSA881X_ANALOG_BASE, 0x0E},
+ {WSA881X_BOOST_LDO_PROG - WSA881X_ANALOG_BASE, 0x16},
+ {WSA881X_BOOST_SLOPE_COMP_ISENSE_FB - WSA881X_ANALOG_BASE, 0x71},
+ {WSA881X_BOOST_RON_CTL - WSA881X_ANALOG_BASE, 0x0F},
+ {WSA881X_BOOST_LOOP_STABILITY - WSA881X_ANALOG_BASE, 0xAD},
+ {WSA881X_BOOST_ZX_CTL - WSA881X_ANALOG_BASE, 0x34},
+ {WSA881X_BOOST_START_CTL - WSA881X_ANALOG_BASE, 0x23},
+ {WSA881X_BOOST_MISC1_CTL - WSA881X_ANALOG_BASE, 0x80},
+ {WSA881X_BOOST_MISC2_CTL - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_BOOST_MISC3_CTL - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_BOOST_ATEST_CTL - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_SPKR_PROT_FE_GAIN - WSA881X_ANALOG_BASE, 0x46},
+ {WSA881X_SPKR_PROT_FE_CM_LDO_SET - WSA881X_ANALOG_BASE, 0x3B},
+ {WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1 - WSA881X_ANALOG_BASE, 0x8D},
+ {WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2 - WSA881X_ANALOG_BASE, 0x8D},
+ {WSA881X_SPKR_PROT_ATEST1 - WSA881X_ANALOG_BASE, 0x01},
+ {WSA881X_SPKR_PROT_ATEST2 - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_SPKR_PROT_FE_VSENSE_VCM - WSA881X_ANALOG_BASE, 0x8D},
+ {WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1 - WSA881X_ANALOG_BASE, 0x4D},
+ {WSA881X_BONGO_RESRV_REG1 - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_BONGO_RESRV_REG2 - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_SPKR_PROT_SAR - WSA881X_ANALOG_BASE, 0x00},
+ {WSA881X_SPKR_STATUS3 - WSA881X_ANALOG_BASE, 0x00},
+};
+
+static const struct reg_sequence wsa881x_rev_2_0_dig[] = {
+ {WSA881X_RESET_CTL, 0x00},
+ {WSA881X_TADC_VALUE_CTL, 0x01},
+ {WSA881X_INTR_MASK, 0x1B},
+ {WSA881X_IOPAD_CTL, 0x00},
+ {WSA881X_OTP_REG_28, 0x3F},
+ {WSA881X_OTP_REG_29, 0x3F},
+ {WSA881X_OTP_REG_30, 0x01},
+ {WSA881X_OTP_REG_31, 0x01},
+};
+
+static const struct reg_sequence wsa881x_rev_2_0_ana[] = {
+ {WSA881X_TEMP_ADC_CTRL, 0x03},
+ {WSA881X_ADC_SEL_IBIAS, 0x45},
+ {WSA881X_SPKR_DRV_GAIN, 0xC1},
+ {WSA881X_SPKR_DAC_CTL, 0x42},
+ {WSA881X_SPKR_BBM_CTL, 0x02},
+ {WSA881X_SPKR_MISC_CTL1, 0x40},
+ {WSA881X_SPKR_MISC_CTL2, 0x07},
+ {WSA881X_SPKR_BIAS_INT, 0x5F},
+ {WSA881X_SPKR_BIAS_PSRR, 0x44},
+ {WSA881X_BOOST_PS_CTL, 0xA0},
+ {WSA881X_BOOST_PRESET_OUT1, 0xB7},
+ {WSA881X_BOOST_LOOP_STABILITY, 0x8D},
+ {WSA881X_SPKR_PROT_ATEST2, 0x02},
+ {WSA881X_BONGO_RESRV_REG1, 0x5E},
+ {WSA881X_BONGO_RESRV_REG2, 0x07},
+};
+
+struct reg_default wsa881x_rev_2_0_regmap_ana[] = {
+ {WSA881X_TEMP_ADC_CTRL - WSA881X_ANALOG_BASE, 0x03},
+ {WSA881X_ADC_SEL_IBIAS - WSA881X_ANALOG_BASE, 0x45},
+ {WSA881X_SPKR_DRV_GAIN - WSA881X_ANALOG_BASE, 0xC1},
+ {WSA881X_SPKR_DAC_CTL - WSA881X_ANALOG_BASE, 0x42},
+ {WSA881X_SPKR_BBM_CTL - WSA881X_ANALOG_BASE, 0x02},
+ {WSA881X_SPKR_MISC_CTL1 - WSA881X_ANALOG_BASE, 0x40},
+ {WSA881X_SPKR_MISC_CTL2 - WSA881X_ANALOG_BASE, 0x07},
+ {WSA881X_SPKR_BIAS_INT - WSA881X_ANALOG_BASE, 0x5F},
+ {WSA881X_SPKR_BIAS_PSRR - WSA881X_ANALOG_BASE, 0x44},
+ {WSA881X_BOOST_PS_CTL - WSA881X_ANALOG_BASE, 0xA0},
+ {WSA881X_BOOST_PRESET_OUT1 - WSA881X_ANALOG_BASE, 0xB7},
+ {WSA881X_BOOST_LOOP_STABILITY - WSA881X_ANALOG_BASE, 0x8D},
+ {WSA881X_SPKR_PROT_ATEST2 - WSA881X_ANALOG_BASE, 0x02},
+ {WSA881X_BONGO_RESRV_REG1 - WSA881X_ANALOG_BASE, 0x5E},
+ {WSA881X_BONGO_RESRV_REG2 - WSA881X_ANALOG_BASE, 0x07},
+};
+
+/**
+ * wsa881x_update_reg_defaults_2_0 - update default values of regs for v2.0
+ *
+ * wsa881x v2.0 has different default values for certain analog and digital
+ * registers compared to v1.x. Therefore, update the values of these registers
+ * with the values from tables defined above for v2.0.
+ */
+void wsa881x_update_reg_defaults_2_0(void)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(wsa881x_rev_2_0_dig); i++) {
+ for (j = 0; j < ARRAY_SIZE(wsa881x_ana_reg_defaults); j++)
+ if (wsa881x_ana_reg_defaults[j].reg ==
+ wsa881x_rev_2_0_dig[i].reg)
+ wsa881x_ana_reg_defaults[j].def =
+ wsa881x_rev_2_0_dig[i].def;
+ }
+ for (i = 0; i < ARRAY_SIZE(wsa881x_rev_2_0_ana); i++) {
+ for (j = 0; j < ARRAY_SIZE(wsa881x_ana_reg_defaults); j++)
+ if (wsa881x_ana_reg_defaults[j].reg ==
+ wsa881x_rev_2_0_ana[i].reg)
+ wsa881x_ana_reg_defaults[j].def =
+ wsa881x_rev_2_0_ana[i].def;
+ }
+}
+EXPORT_SYMBOL(wsa881x_update_reg_defaults_2_0);
+
+/**
+ * wsa881x_update_regmap_2_0 - update regmap framework with new tables
+ * @regmap: pointer to wsa881x regmap structure
+ * @flag: indicates digital or analog wsa881x slave
+ *
+ * wsa881x v2.0 has some new registers for both analog and digital slaves.
+ * Update the regmap framework with all the new registers.
+ */
+void wsa881x_update_regmap_2_0(struct regmap *regmap, int flag)
+{
+ u16 ret = 0;
+
+ switch (flag) {
+ case WSA881X_DIGITAL_SLAVE:
+ ret = regmap_register_patch(regmap, wsa881x_rev_2_0_dig,
+ ARRAY_SIZE(wsa881x_rev_2_0_dig));
+ break;
+ case WSA881X_ANALOG_SLAVE:
+ ret = regmap_register_patch(regmap, wsa881x_rev_2_0_ana,
+ ARRAY_SIZE(wsa881x_rev_2_0_ana));
+ break;
+ default:
+ pr_debug("%s: unknown version", __func__);
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ pr_err("%s: Failed to update regmap defaults ret= %d\n",
+ __func__, ret);
+}
+EXPORT_SYMBOL(wsa881x_update_regmap_2_0);
+
+static bool wsa881x_readable_register(struct device *dev, unsigned int reg)
+{
+ return wsa881x_ana_reg_readable[reg];
+}
+
+static bool wsa881x_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WSA881X_CHIP_ID0:
+ case WSA881X_CHIP_ID1:
+ case WSA881X_CHIP_ID2:
+ case WSA881X_CHIP_ID3:
+ case WSA881X_BUS_ID:
+ case WSA881X_TEMP_MSB:
+ case WSA881X_TEMP_LSB:
+ case WSA881X_SDM_PDM9_LSB:
+ case WSA881X_SDM_PDM9_MSB:
+ case WSA881X_OTP_REG_0:
+ case WSA881X_OTP_REG_1:
+ case WSA881X_OTP_REG_2:
+ case WSA881X_OTP_REG_3:
+ case WSA881X_OTP_REG_4:
+ case WSA881X_OTP_REG_5:
+ case WSA881X_OTP_REG_31:
+ case WSA881X_TEMP_DOUT_MSB:
+ case WSA881X_TEMP_DOUT_LSB:
+ case WSA881X_TEMP_OP:
+ case WSA881X_OTP_CTRL1:
+ case WSA881X_INTR_STATUS:
+ case WSA881X_ATE_TEST_MODE:
+ case WSA881X_PIN_STATUS:
+ case WSA881X_SWR_HM_TEST2:
+ case WSA881X_SPKR_STATUS1:
+ case WSA881X_SPKR_STATUS2:
+ case WSA881X_SPKR_STATUS3:
+ case WSA881X_SPKR_PROT_SAR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+struct regmap_config wsa881x_ana_regmap_config[] = {
+{
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_NONE,
+ .reg_defaults = wsa881x_ana_reg_defaults_0,
+ .num_reg_defaults = ARRAY_SIZE(wsa881x_ana_reg_defaults_0),
+ .max_register = WSA881X_MAX_REGISTER,
+ .volatile_reg = wsa881x_volatile_register,
+ .readable_reg = wsa881x_readable_register,
+ .reg_format_endian = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+},
+{
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_NONE,
+ .reg_defaults = wsa881x_ana_reg_defaults_1,
+ .num_reg_defaults = ARRAY_SIZE(wsa881x_ana_reg_defaults_1),
+ .max_register = WSA881X_MAX_REGISTER,
+ .volatile_reg = wsa881x_volatile_register,
+ .readable_reg = wsa881x_readable_register,
+ .reg_format_endian = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+}
+};
diff --git a/asoc/codecs/wsa881x-tables-analog.c b/asoc/codecs/wsa881x-tables-analog.c
new file mode 100644
index 0000000..bbc6b90
--- /dev/null
+++ b/asoc/codecs/wsa881x-tables-analog.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015, 2018-2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "wsa881x-registers-analog.h"
+
+const u8 wsa881x_ana_reg_readable[WSA881X_CACHE_SIZE] = {
+ [WSA881X_CHIP_ID0] = 1,
+ [WSA881X_CHIP_ID1] = 1,
+ [WSA881X_CHIP_ID2] = 1,
+ [WSA881X_CHIP_ID3] = 1,
+ [WSA881X_BUS_ID] = 1,
+ [WSA881X_CDC_RST_CTL] = 1,
+ [WSA881X_CDC_TOP_CLK_CTL] = 1,
+ [WSA881X_CDC_ANA_CLK_CTL] = 1,
+ [WSA881X_CDC_DIG_CLK_CTL] = 1,
+ [WSA881X_CLOCK_CONFIG] = 1,
+ [WSA881X_ANA_CTL] = 1,
+ [WSA881X_SWR_RESET_EN] = 1,
+ [WSA881X_RESET_CTL] = 1,
+ [WSA881X_TADC_VALUE_CTL] = 1,
+ [WSA881X_TEMP_DETECT_CTL] = 1,
+ [WSA881X_TEMP_MSB] = 1,
+ [WSA881X_TEMP_LSB] = 1,
+ [WSA881X_TEMP_CONFIG0] = 1,
+ [WSA881X_TEMP_CONFIG1] = 1,
+ [WSA881X_CDC_CLIP_CTL] = 1,
+ [WSA881X_SDM_PDM9_LSB] = 1,
+ [WSA881X_SDM_PDM9_MSB] = 1,
+ [WSA881X_CDC_RX_CTL] = 1,
+ [WSA881X_DEM_BYPASS_DATA0] = 1,
+ [WSA881X_DEM_BYPASS_DATA1] = 1,
+ [WSA881X_DEM_BYPASS_DATA2] = 1,
+ [WSA881X_DEM_BYPASS_DATA3] = 1,
+ [WSA881X_OTP_CTRL0] = 1,
+ [WSA881X_OTP_CTRL1] = 1,
+ [WSA881X_HDRIVE_CTL_GROUP1] = 1,
+ [WSA881X_INTR_MODE] = 1,
+ [WSA881X_INTR_MASK] = 1,
+ [WSA881X_INTR_STATUS] = 1,
+ [WSA881X_INTR_CLEAR] = 1,
+ [WSA881X_INTR_LEVEL] = 1,
+ [WSA881X_INTR_SET] = 1,
+ [WSA881X_INTR_TEST] = 1,
+ [WSA881X_PDM_TEST_MODE] = 1,
+ [WSA881X_ATE_TEST_MODE] = 1,
+ [WSA881X_PIN_CTL_MODE] = 1,
+ [WSA881X_PIN_CTL_OE] = 1,
+ [WSA881X_PIN_WDATA_IOPAD] = 1,
+ [WSA881X_PIN_STATUS] = 1,
+ [WSA881X_DIG_DEBUG_MODE] = 1,
+ [WSA881X_DIG_DEBUG_SEL] = 1,
+ [WSA881X_DIG_DEBUG_EN] = 1,
+ [WSA881X_SWR_HM_TEST1] = 1,
+ [WSA881X_SWR_HM_TEST2] = 1,
+ [WSA881X_TEMP_DETECT_DBG_CTL] = 1,
+ [WSA881X_TEMP_DEBUG_MSB] = 1,
+ [WSA881X_TEMP_DEBUG_LSB] = 1,
+ [WSA881X_SAMPLE_EDGE_SEL] = 1,
+ [WSA881X_IOPAD_CTL] = 1,
+ [WSA881X_SPARE_0] = 1,
+ [WSA881X_SPARE_1] = 1,
+ [WSA881X_SPARE_2] = 1,
+ [WSA881X_OTP_REG_0] = 1,
+ [WSA881X_OTP_REG_1] = 1,
+ [WSA881X_OTP_REG_2] = 1,
+ [WSA881X_OTP_REG_3] = 1,
+ [WSA881X_OTP_REG_4] = 1,
+ [WSA881X_OTP_REG_5] = 1,
+ [WSA881X_OTP_REG_6] = 1,
+ [WSA881X_OTP_REG_7] = 1,
+ [WSA881X_OTP_REG_8] = 1,
+ [WSA881X_OTP_REG_9] = 1,
+ [WSA881X_OTP_REG_10] = 1,
+ [WSA881X_OTP_REG_11] = 1,
+ [WSA881X_OTP_REG_12] = 1,
+ [WSA881X_OTP_REG_13] = 1,
+ [WSA881X_OTP_REG_14] = 1,
+ [WSA881X_OTP_REG_15] = 1,
+ [WSA881X_OTP_REG_16] = 1,
+ [WSA881X_OTP_REG_17] = 1,
+ [WSA881X_OTP_REG_18] = 1,
+ [WSA881X_OTP_REG_19] = 1,
+ [WSA881X_OTP_REG_20] = 1,
+ [WSA881X_OTP_REG_21] = 1,
+ [WSA881X_OTP_REG_22] = 1,
+ [WSA881X_OTP_REG_23] = 1,
+ [WSA881X_OTP_REG_24] = 1,
+ [WSA881X_OTP_REG_25] = 1,
+ [WSA881X_OTP_REG_26] = 1,
+ [WSA881X_OTP_REG_27] = 1,
+ [WSA881X_OTP_REG_28] = 1,
+ [WSA881X_OTP_REG_29] = 1,
+ [WSA881X_OTP_REG_30] = 1,
+ [WSA881X_OTP_REG_31] = 1,
+ [WSA881X_OTP_REG_63] = 1,
+ /* Analog Registers */
+ [WSA881X_BIAS_REF_CTRL] = 1,
+ [WSA881X_BIAS_TEST] = 1,
+ [WSA881X_BIAS_BIAS] = 1,
+ [WSA881X_TEMP_OP] = 1,
+ [WSA881X_TEMP_IREF_CTRL] = 1,
+ [WSA881X_TEMP_ISENS_CTRL] = 1,
+ [WSA881X_TEMP_CLK_CTRL] = 1,
+ [WSA881X_TEMP_TEST] = 1,
+ [WSA881X_TEMP_BIAS] = 1,
+ [WSA881X_TEMP_ADC_CTRL] = 1,
+ [WSA881X_TEMP_DOUT_MSB] = 1,
+ [WSA881X_TEMP_DOUT_LSB] = 1,
+ [WSA881X_ADC_EN_MODU_V] = 1,
+ [WSA881X_ADC_EN_MODU_I] = 1,
+ [WSA881X_ADC_EN_DET_TEST_V] = 1,
+ [WSA881X_ADC_EN_DET_TEST_I] = 1,
+ [WSA881X_ADC_SEL_IBIAS] = 1,
+ [WSA881X_ADC_EN_SEL_IBIAS] = 1,
+ [WSA881X_SPKR_DRV_EN] = 1,
+ [WSA881X_SPKR_DRV_GAIN] = 1,
+ [WSA881X_SPKR_DAC_CTL] = 1,
+ [WSA881X_SPKR_DRV_DBG] = 1,
+ [WSA881X_SPKR_PWRSTG_DBG] = 1,
+ [WSA881X_SPKR_OCP_CTL] = 1,
+ [WSA881X_SPKR_CLIP_CTL] = 1,
+ [WSA881X_SPKR_BBM_CTL] = 1,
+ [WSA881X_SPKR_MISC_CTL1] = 1,
+ [WSA881X_SPKR_MISC_CTL2] = 1,
+ [WSA881X_SPKR_BIAS_INT] = 1,
+ [WSA881X_SPKR_PA_INT] = 1,
+ [WSA881X_SPKR_BIAS_CAL] = 1,
+ [WSA881X_SPKR_BIAS_PSRR] = 1,
+ [WSA881X_SPKR_STATUS1] = 1,
+ [WSA881X_SPKR_STATUS2] = 1,
+ [WSA881X_BOOST_EN_CTL] = 1,
+ [WSA881X_BOOST_CURRENT_LIMIT] = 1,
+ [WSA881X_BOOST_PS_CTL] = 1,
+ [WSA881X_BOOST_PRESET_OUT1] = 1,
+ [WSA881X_BOOST_PRESET_OUT2] = 1,
+ [WSA881X_BOOST_FORCE_OUT] = 1,
+ [WSA881X_BOOST_LDO_PROG] = 1,
+ [WSA881X_BOOST_SLOPE_COMP_ISENSE_FB] = 1,
+ [WSA881X_BOOST_RON_CTL] = 1,
+ [WSA881X_BOOST_LOOP_STABILITY] = 1,
+ [WSA881X_BOOST_ZX_CTL] = 1,
+ [WSA881X_BOOST_START_CTL] = 1,
+ [WSA881X_BOOST_MISC1_CTL] = 1,
+ [WSA881X_BOOST_MISC2_CTL] = 1,
+ [WSA881X_BOOST_MISC3_CTL] = 1,
+ [WSA881X_BOOST_ATEST_CTL] = 1,
+ [WSA881X_SPKR_PROT_FE_GAIN] = 1,
+ [WSA881X_SPKR_PROT_FE_CM_LDO_SET] = 1,
+ [WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1] = 1,
+ [WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2] = 1,
+ [WSA881X_SPKR_PROT_ATEST1] = 1,
+ [WSA881X_SPKR_PROT_ATEST2] = 1,
+ [WSA881X_SPKR_PROT_FE_VSENSE_VCM] = 1,
+ [WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1] = 1,
+ [WSA881X_BONGO_RESRV_REG1] = 1,
+ [WSA881X_BONGO_RESRV_REG2] = 1,
+ [WSA881X_SPKR_PROT_SAR] = 1,
+ [WSA881X_SPKR_STATUS3] = 1,
+};
diff --git a/asoc/codecs/wsa881x.c b/asoc/codecs/wsa881x.c
index 966fa8a..fc4f123 100644
--- a/asoc/codecs/wsa881x.c
+++ b/asoc/codecs/wsa881x.c
@@ -1395,6 +1395,7 @@
snd_soc_component_update_bits(wsa881x->component,
WSA881X_SPKR_DRV_EN,
0x80, 0x80);
+ break;
default:
break;
}
diff --git a/asoc/codecs/wsa883x/Android.mk b/asoc/codecs/wsa883x/Android.mk
new file mode 100644
index 0000000..66056e8
--- /dev/null
+++ b/asoc/codecs/wsa883x/Android.mk
@@ -0,0 +1,49 @@
+# 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,lahaina),true)
+AUDIO_SELECT := CONFIG_SND_SOC_LAHAINA=m
+endif
+
+AUDIO_CHIPSET := audio
+# Build/Package only in case of supported target
+ifeq ($(call is-board-platform-in-list,lahaina),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=wsa883x_dlkm
+KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM)
+KBUILD_OPTIONS += $(AUDIO_SELECT)
+
+###########################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(AUDIO_CHIPSET)_wsa883x.ko
+LOCAL_MODULE_KBUILD_NAME := wsa883x_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/wsa883x/Kbuild b/asoc/codecs/wsa883x/Kbuild
new file mode 100644
index 0000000..4eb844a
--- /dev/null
+++ b/asoc/codecs/wsa883x/Kbuild
@@ -0,0 +1,103 @@
+# 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 := $(shell pwd)/kernel/msm-4.19
+ AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio
+endif
+
+ifeq ($(KERNEL_BUILD), 0)
+ ifeq ($(CONFIG_ARCH_LAHAINA), y)
+ include $(AUDIO_ROOT)/config/lahainaauto.conf
+ INCS += -include $(AUDIO_ROOT)/config/lahainaautoconf.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)
+
+############ WSA883X ############
+
+# for WSA883X Codec
+ifdef CONFIG_SND_SOC_WSA883X
+ WSA883X_OBJS += wsa883x.o
+ WSA883X_OBJS += wsa883x-regmap.o
+ WSA883X_OBJS += wsa883x-tables.o
+ WSA883X_OBJS += wsa883x-temp-sensor.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_WSA883X) += wsa883x_dlkm.o
+wsa883x_dlkm-y := $(WSA883X_OBJS)
+
+# inject some build related information
+DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"
diff --git a/asoc/codecs/wsa883x/internal.h b/asoc/codecs/wsa883x/internal.h
new file mode 100644
index 0000000..509fc83
--- /dev/null
+++ b/asoc/codecs/wsa883x/internal.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef WSA883X_INTERNAL_H
+#define WSA883X_INTERNAL_H
+
+#include "wsa883x.h"
+#include "wsa883x-registers.h"
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#define SWR_SLV_MAX_REG_ADDR 0x2009
+#define SWR_SLV_START_REG_ADDR 0x40
+#define SWR_SLV_MAX_BUF_LEN 20
+#define BYTES_PER_LINE 12
+#define SWR_SLV_RD_BUF_LEN 8
+#define SWR_SLV_WR_BUF_LEN 32
+#define SWR_SLV_MAX_DEVICES 2
+#endif /* CONFIG_DEBUG_FS */
+
+#define WSA883X_DRV_NAME "wsa883x-codec"
+#define WSA883X_NUM_RETRY 5
+
+#define WSA883X_VERSION_ENTRY_SIZE 27
+
+enum {
+ G_18DB = 0,
+ G_16P5DB,
+ G_15DB,
+ G_13P5DB,
+ G_12DB,
+ G_10P5DB,
+ G_9DB,
+ G_7P5DB,
+ G_6DB,
+ G_4P5DB,
+ G_3DB,
+ G_1P5DB,
+ G_0DB,
+};
+
+enum {
+ DISABLE = 0,
+ ENABLE,
+};
+
+enum {
+ SWR_DAC_PORT,
+ SWR_COMP_PORT,
+ SWR_BOOST_PORT,
+ SWR_VISENSE_PORT,
+};
+
+struct swr_port {
+ u8 port_id;
+ u8 ch_mask;
+ u32 ch_rate;
+ u8 num_ch;
+ u8 port_type;
+};
+
+extern struct regmap_config wsa883x_regmap_config;
+
+/*
+ * Private data Structure for wsa883x. All parameters related to
+ * WSA883X codec needs to be defined here.
+ */
+struct wsa883x_priv {
+ struct regmap *regmap;
+ struct device *dev;
+ struct swr_device *swr_slave;
+ struct snd_soc_component *component;
+ bool comp_enable;
+ bool visense_enable;
+ bool ext_vdd_spk;
+ struct swr_port port[WSA883X_MAX_SWR_PORTS];
+ int global_pa_cnt;
+ int dev_mode;
+ struct mutex res_lock;
+ struct snd_info_entry *entry;
+ struct snd_info_entry *version_entry;
+ 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;
+ struct dentry *debugfs_poke;
+ struct dentry *debugfs_reg_dump;
+ unsigned int read_data;
+#endif
+};
+
+static int32_t wsa883x_resource_acquire(struct snd_soc_component *component,
+ bool enable);
+#endif /* WSA883X_INTERNAL_H */
diff --git a/asoc/codecs/wsa883x/wsa883x-registers.h b/asoc/codecs/wsa883x/wsa883x-registers.h
new file mode 100644
index 0000000..7e518d2
--- /dev/null
+++ b/asoc/codecs/wsa883x/wsa883x-registers.h
@@ -0,0 +1,376 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef WSA883X_REGISTERS_H
+#define WSA883X_REGISTERS_H
+
+#define WSA883X_BASE 0x3000
+#define WSA883X_REG(reg) (reg - WSA883X_BASE)
+
+enum {
+ REG_NO_ACCESS,
+ RD_REG,
+ WR_REG,
+ RD_WR_REG,
+};
+
+#define WSA883X_ANA_BG_TSADC_BASE (WSA883X_BASE+0x00000000)
+#define WSA883X_REF_CTRL (WSA883X_ANA_BG_TSADC_BASE+0x0000)
+#define WSA883X_TEST_CTL_0 (WSA883X_ANA_BG_TSADC_BASE+0x0001)
+#define WSA883X_BIAS_0 (WSA883X_ANA_BG_TSADC_BASE+0x0002)
+#define WSA883X_OP_CTL (WSA883X_ANA_BG_TSADC_BASE+0x0003)
+#define WSA883X_IREF_CTL (WSA883X_ANA_BG_TSADC_BASE+0x0004)
+#define WSA883X_ISENS_CTL (WSA883X_ANA_BG_TSADC_BASE+0x0005)
+#define WSA883X_CLK_CTL (WSA883X_ANA_BG_TSADC_BASE+0x0006)
+#define WSA883X_TEST_CTL_1 (WSA883X_ANA_BG_TSADC_BASE+0x0007)
+#define WSA883X_BIAS_1 (WSA883X_ANA_BG_TSADC_BASE+0x0008)
+#define WSA883X_ADC_CTL (WSA883X_ANA_BG_TSADC_BASE+0x0009)
+#define WSA883X_DOUT_MSB (WSA883X_ANA_BG_TSADC_BASE+0x000A)
+#define WSA883X_DOUT_LSB (WSA883X_ANA_BG_TSADC_BASE+0x000B)
+#define WSA883X_VBAT_SNS (WSA883X_ANA_BG_TSADC_BASE+0x000C)
+#define WSA883X_ITRIM_CODE (WSA883X_ANA_BG_TSADC_BASE+0x000D)
+
+#define WSA883X_ANA_IVSENSE_BASE (WSA883X_BASE+0x0000000F)
+#define WSA883X_EN (WSA883X_ANA_IVSENSE_BASE+0x0000)
+#define WSA883X_OVERRIDE1 (WSA883X_ANA_IVSENSE_BASE+0x0001)
+#define WSA883X_OVERRIDE2 (WSA883X_ANA_IVSENSE_BASE+0x0002)
+#define WSA883X_VSENSE1 (WSA883X_ANA_IVSENSE_BASE+0x0003)
+#define WSA883X_ISENSE1 (WSA883X_ANA_IVSENSE_BASE+0x0004)
+#define WSA883X_ISENSE2 (WSA883X_ANA_IVSENSE_BASE+0x0005)
+#define WSA883X_ISENSE_CAL (WSA883X_ANA_IVSENSE_BASE+0x0006)
+#define WSA883X_MISC (WSA883X_ANA_IVSENSE_BASE+0x0007)
+#define WSA883X_ADC_0 (WSA883X_ANA_IVSENSE_BASE+0x0008)
+#define WSA883X_ADC_1 (WSA883X_ANA_IVSENSE_BASE+0x0009)
+#define WSA883X_ADC_2 (WSA883X_ANA_IVSENSE_BASE+0x000A)
+#define WSA883X_ADC_3 (WSA883X_ANA_IVSENSE_BASE+0x000B)
+#define WSA883X_ADC_4 (WSA883X_ANA_IVSENSE_BASE+0x000C)
+#define WSA883X_ADC_5 (WSA883X_ANA_IVSENSE_BASE+0x000D)
+#define WSA883X_ADC_6 (WSA883X_ANA_IVSENSE_BASE+0x000E)
+#define WSA883X_ADC_7 (WSA883X_ANA_IVSENSE_BASE+0x000F)
+#define WSA883X_STATUS (WSA883X_ANA_IVSENSE_BASE+0x0010)
+
+#define WSA883X_ANA_SPK_TOP_BASE (WSA883X_BASE+0x00000025)
+#define WSA883X_DAC_CTRL_REG (WSA883X_ANA_SPK_TOP_BASE+0x0000)
+#define WSA883X_DAC_EN_DEBUG_REG (WSA883X_ANA_SPK_TOP_BASE+0x0001)
+#define WSA883X_DAC_OPAMP_BIAS1_REG (WSA883X_ANA_SPK_TOP_BASE+0x0002)
+#define WSA883X_DAC_OPAMP_BIAS2_REG (WSA883X_ANA_SPK_TOP_BASE+0x0003)
+#define WSA883X_DAC_VCM_CTRL_REG (WSA883X_ANA_SPK_TOP_BASE+0x0004)
+#define WSA883X_DAC_VOLTAGE_CTRL_REG (WSA883X_ANA_SPK_TOP_BASE+0x0005)
+#define WSA883X_ATEST1_REG (WSA883X_ANA_SPK_TOP_BASE+0x0006)
+#define WSA883X_ATEST2_REG (WSA883X_ANA_SPK_TOP_BASE+0x0007)
+#define WSA883X_SPKR_TOP_BIAS_REG1 (WSA883X_ANA_SPK_TOP_BASE+0x0008)
+#define WSA883X_SPKR_TOP_BIAS_REG2 (WSA883X_ANA_SPK_TOP_BASE+0x0009)
+#define WSA883X_SPKR_TOP_BIAS_REG3 (WSA883X_ANA_SPK_TOP_BASE+0x000A)
+#define WSA883X_SPKR_TOP_BIAS_REG4 (WSA883X_ANA_SPK_TOP_BASE+0x000B)
+#define WSA883X_SPKR_CLIP_DET_REG (WSA883X_ANA_SPK_TOP_BASE+0x000C)
+#define WSA883X_SPKR_DRV_LF_BLK_EN (WSA883X_ANA_SPK_TOP_BASE+0x000D)
+#define WSA883X_SPKR_DRV_LF_EN (WSA883X_ANA_SPK_TOP_BASE+0x000E)
+#define WSA883X_SPKR_DRV_LF_MASK_DCC_CTL (WSA883X_ANA_SPK_TOP_BASE+0x000F)
+#define WSA883X_SPKR_DRV_LF_MISC_CTL (WSA883X_ANA_SPK_TOP_BASE+0x0010)
+#define WSA883X_SPKR_DRV_LF_REG_GAIN (WSA883X_ANA_SPK_TOP_BASE+0x0011)
+#define WSA883X_SPKR_DRV_LF_OS_CAL_CTL1 (WSA883X_ANA_SPK_TOP_BASE+0x0012)
+#define WSA883X_SPKR_DRV_LF_OS_CAL_CTL (WSA883X_ANA_SPK_TOP_BASE+0x0013)
+#define WSA883X_SPKR_PWM_CLK_CTL (WSA883X_ANA_SPK_TOP_BASE+0x0014)
+#define WSA883X_SPKR_PDRV_HS_CTL (WSA883X_ANA_SPK_TOP_BASE+0x0015)
+#define WSA883X_SPKR_PDRV_LS_CTL (WSA883X_ANA_SPK_TOP_BASE+0x0016)
+#define WSA883X_SPKR_PWRSTG_DBG (WSA883X_ANA_SPK_TOP_BASE+0x0017)
+#define WSA883X_SPKR_OCP_CTL (WSA883X_ANA_SPK_TOP_BASE+0x0018)
+#define WSA883X_SPKR_BBM_CTL (WSA883X_ANA_SPK_TOP_BASE+0x0019)
+#define WSA883X_PA_STATUS0 (WSA883X_ANA_SPK_TOP_BASE+0x001A)
+#define WSA883X_PA_STATUS1 (WSA883X_ANA_SPK_TOP_BASE+0x001B)
+#define WSA883X_PA_STATUS2 (WSA883X_ANA_SPK_TOP_BASE+0x001C)
+
+#define WSA883X_ANA_BOOST_BASE (WSA883X_BASE+0x00000045)
+#define WSA883X_EN_CTRL (WSA883X_ANA_BOOST_BASE+0x0000)
+#define WSA883X_CURRENT_LIMIT (WSA883X_ANA_BOOST_BASE+0x0001)
+#define WSA883X_IBIAS1 (WSA883X_ANA_BOOST_BASE+0x0002)
+#define WSA883X_IBIAS2 (WSA883X_ANA_BOOST_BASE+0x0003)
+#define WSA883X_IBIAS3 (WSA883X_ANA_BOOST_BASE+0x0004)
+#define WSA883X_LDO_PROG (WSA883X_ANA_BOOST_BASE+0x0005)
+#define WSA883X_STABILITY_CTRL1 (WSA883X_ANA_BOOST_BASE+0x0006)
+#define WSA883X_STABILITY_CTRL2 (WSA883X_ANA_BOOST_BASE+0x0007)
+#define WSA883X_PWRSTAGE_CTRL1 (WSA883X_ANA_BOOST_BASE+0x0008)
+#define WSA883X_PWRSTAGE_CTRL2 (WSA883X_ANA_BOOST_BASE+0x0009)
+#define WSA883X_UVLO (WSA883X_ANA_BOOST_BASE+0x000A)
+#define WSA883X_SEQUENCE_CTRL (WSA883X_ANA_BOOST_BASE+0x000B)
+#define WSA883X_ZX_CTRL_1 (WSA883X_ANA_BOOST_BASE+0x000C)
+#define WSA883X_ZX_CTRL_2 (WSA883X_ANA_BOOST_BASE+0x000D)
+#define WSA883X_MISC1 (WSA883X_ANA_BOOST_BASE+0x000E)
+#define WSA883X_MISC2 (WSA883X_ANA_BOOST_BASE+0x000F)
+#define WSA883X_GMAMP_SUP1 (WSA883X_ANA_BOOST_BASE+0x0010)
+#define WSA883X_PWRSTAGE_CTRL3 (WSA883X_ANA_BOOST_BASE+0x0011)
+#define WSA883X_PRSTAGE_CTRL4 (WSA883X_ANA_BOOST_BASE+0x0012)
+#define WSA883X_SPARE1 (WSA883X_ANA_BOOST_BASE+0x0013)
+
+#define WSA883X_ANA_PON_LDOL_BASE (WSA883X_BASE+0x00000059)
+#define WSA883X_PON_CTL_0 (WSA883X_ANA_PON_LDOL_BASE+0x0000)
+#define WSA883X_PON_CLT_1 (WSA883X_ANA_PON_LDOL_BASE+0x0001)
+#define WSA883X_PON_CTL_2 (WSA883X_ANA_PON_LDOL_BASE+0x0002)
+#define WSA883X_PON_CTL_3 (WSA883X_ANA_PON_LDOL_BASE+0x0003)
+#define WSA883X_PON_CTL_4 (WSA883X_ANA_PON_LDOL_BASE+0x0004)
+#define WSA883X_CKWD_CTL_0 (WSA883X_ANA_PON_LDOL_BASE+0x0005)
+#define WSA883X_CKWD_CTL_1 (WSA883X_ANA_PON_LDOL_BASE+0x0006)
+#define WSA883X_CKWD_CTL_2 (WSA883X_ANA_PON_LDOL_BASE+0x0007)
+#define WSA883X_CKSK_CTL_0 (WSA883X_ANA_PON_LDOL_BASE+0x0008)
+#define WSA883X_TEST_0 (WSA883X_ANA_PON_LDOL_BASE+0x0009)
+#define WSA883X_TEST_1 (WSA883X_ANA_PON_LDOL_BASE+0x000A)
+#define WSA883X_STATUS_0 (WSA883X_ANA_PON_LDOL_BASE+0x000B)
+#define WSA883X_STATUS_1 (WSA883X_ANA_PON_LDOL_BASE+0x000C)
+
+#define WSA883X_DIG_CTRL_BASE (WSA883X_BASE+0x00000400)
+#define WSA883X_PAGE_REGISTER (WSA883X_DIG_CTRL_BASE+0x0000)
+#define WSA883X_CHIP_ID0 (WSA883X_DIG_CTRL_BASE+0x0001)
+#define WSA883X_CHIP_ID1 (WSA883X_DIG_CTRL_BASE+0x0002)
+#define WSA883X_CHIP_ID2 (WSA883X_DIG_CTRL_BASE+0x0003)
+#define WSA883X_CHIP_ID3 (WSA883X_DIG_CTRL_BASE+0x0004)
+#define WSA883X_BUS_ID (WSA883X_DIG_CTRL_BASE+0x0005)
+#define WSA883X_CDC_RST_CTL (WSA883X_DIG_CTRL_BASE+0x0006)
+#define WSA883X_TOP_CLK_CFG (WSA883X_DIG_CTRL_BASE+0x0007)
+#define WSA883X_CDC_PATH_MODE (WSA883X_DIG_CTRL_BASE+0x0008)
+#define WSA883X_CDC_CLK_CTL (WSA883X_DIG_CTRL_BASE+0x0009)
+#define WSA883X_SWR_RESET_EN (WSA883X_DIG_CTRL_BASE+0x000A)
+#define WSA883X_PA_FSM_CTL (WSA883X_DIG_CTRL_BASE+0x0010)
+#define WSA883X_PA_FSM_TIMER0 (WSA883X_DIG_CTRL_BASE+0x0011)
+#define WSA883X_PA_FSM_TIMER1 (WSA883X_DIG_CTRL_BASE+0x0012)
+#define WSA883X_PA_FSM_STA (WSA883X_DIG_CTRL_BASE+0x0013)
+#define WSA883X_PA_FSM_ERR_COND (WSA883X_DIG_CTRL_BASE+0x0014)
+#define WSA883X_PA_FSM_MSK (WSA883X_DIG_CTRL_BASE+0x0015)
+#define WSA883X_PA_FSM_BYP (WSA883X_DIG_CTRL_BASE+0x0016)
+#define WSA883X_TADC_VALUE_CTL (WSA883X_DIG_CTRL_BASE+0x0020)
+#define WSA883X_TEMP_DETECT_CTL (WSA883X_DIG_CTRL_BASE+0x0021)
+#define WSA883X_TEMP_MSB (WSA883X_DIG_CTRL_BASE+0x0022)
+#define WSA883X_TEMP_LSB (WSA883X_DIG_CTRL_BASE+0x0023)
+#define WSA883X_TEMP_CONFIG0 (WSA883X_DIG_CTRL_BASE+0x0024)
+#define WSA883X_TEMP_CONFIG1 (WSA883X_DIG_CTRL_BASE+0x0025)
+#define WSA883X_VBAT_ADC_FLT_CTL (WSA883X_DIG_CTRL_BASE+0x0026)
+#define WSA883X_VBAT_DIN_MSB (WSA883X_DIG_CTRL_BASE+0x0027)
+#define WSA883X_VBAT_DIN_LSB (WSA883X_DIG_CTRL_BASE+0x0028)
+#define WSA883X_VBAT_DOUT (WSA883X_DIG_CTRL_BASE+0x0029)
+#define WSA883X_SDM_PDM9_LSB (WSA883X_DIG_CTRL_BASE+0x002A)
+#define WSA883X_SDM_PDM9_MSB (WSA883X_DIG_CTRL_BASE+0x002B)
+#define WSA883X_CDC_RX_CTL (WSA883X_DIG_CTRL_BASE+0x0030)
+#define WSA883X_CDC_SPK_DSM_A1_0 (WSA883X_DIG_CTRL_BASE+0x0031)
+#define WSA883X_CDC_SPK_DSM_A1_1 (WSA883X_DIG_CTRL_BASE+0x0032)
+#define WSA883X_CDC_SPK_DSM_A2_0 (WSA883X_DIG_CTRL_BASE+0x0033)
+#define WSA883X_CDC_SPK_DSM_A2_1 (WSA883X_DIG_CTRL_BASE+0x0034)
+#define WSA883X_CDC_SPK_DSM_A3_0 (WSA883X_DIG_CTRL_BASE+0x0035)
+#define WSA883X_CDC_SPK_DSM_A3_1 (WSA883X_DIG_CTRL_BASE+0x0036)
+#define WSA883X_CDC_SPK_DSM_A4_0 (WSA883X_DIG_CTRL_BASE+0x0037)
+#define WSA883X_CDC_SPK_DSM_A4_1 (WSA883X_DIG_CTRL_BASE+0x0038)
+#define WSA883X_CDC_SPK_DSM_A5_0 (WSA883X_DIG_CTRL_BASE+0x0039)
+#define WSA883X_CDC_SPK_DSM_A5_1 (WSA883X_DIG_CTRL_BASE+0x003A)
+#define WSA883X_CDC_SPK_DSM_A6_0 (WSA883X_DIG_CTRL_BASE+0x003B)
+#define WSA883X_CDC_SPK_DSM_A7_0 (WSA883X_DIG_CTRL_BASE+0x003C)
+#define WSA883X_CDC_SPK_DSM_C_0 (WSA883X_DIG_CTRL_BASE+0x003D)
+#define WSA883X_CDC_SPK_DSM_C_1 (WSA883X_DIG_CTRL_BASE+0x003E)
+#define WSA883X_CDC_SPK_DSM_C_2 (WSA883X_DIG_CTRL_BASE+0x003F)
+#define WSA883X_CDC_SPK_DSM_C_3 (WSA883X_DIG_CTRL_BASE+0x0040)
+#define WSA883X_CDC_SPK_DSM_R1 (WSA883X_DIG_CTRL_BASE+0x0041)
+#define WSA883X_CDC_SPK_DSM_R2 (WSA883X_DIG_CTRL_BASE+0x0042)
+#define WSA883X_CDC_SPK_DSM_R3 (WSA883X_DIG_CTRL_BASE+0x0043)
+#define WSA883X_CDC_SPK_DSM_R4 (WSA883X_DIG_CTRL_BASE+0x0044)
+#define WSA883X_CDC_SPK_DSM_R5 (WSA883X_DIG_CTRL_BASE+0x0045)
+#define WSA883X_CDC_SPK_DSM_R6 (WSA883X_DIG_CTRL_BASE+0x0046)
+#define WSA883X_CDC_SPK_DSM_R7 (WSA883X_DIG_CTRL_BASE+0x0047)
+#define WSA883X_CDC_SPK_GAIN_PDM_0 (WSA883X_DIG_CTRL_BASE+0x0048)
+#define WSA883X_CDC_SPK_GAIN_PDM_1 (WSA883X_DIG_CTRL_BASE+0x0049)
+#define WSA883X_CDC_SPK_GAIN_PDM_2 (WSA883X_DIG_CTRL_BASE+0x004A)
+#define WSA883X_PDM_WD_CTL (WSA883X_DIG_CTRL_BASE+0x004B)
+#define WSA883X_DEM_BYPASS_DATA0 (WSA883X_DIG_CTRL_BASE+0x004C)
+#define WSA883X_DEM_BYPASS_DATA1 (WSA883X_DIG_CTRL_BASE+0x004D)
+#define WSA883X_DEM_BYPASS_DATA2 (WSA883X_DIG_CTRL_BASE+0x004E)
+#define WSA883X_DEM_BYPASS_DATA3 (WSA883X_DIG_CTRL_BASE+0x004F)
+#define WSA883X_WAVG_CTL (WSA883X_DIG_CTRL_BASE+0x0050)
+#define WSA883X_WAVG_LRA_PER_0 (WSA883X_DIG_CTRL_BASE+0x0051)
+#define WSA883X_WAVG_LRA_PER_1 (WSA883X_DIG_CTRL_BASE+0x0052)
+#define WSA883X_WAVG_DELTA_THETA_0 (WSA883X_DIG_CTRL_BASE+0x0053)
+#define WSA883X_WAVG_DELTA_THETA_1 (WSA883X_DIG_CTRL_BASE+0x0054)
+#define WSA883X_WAVG_DIRECT_AMP_0 (WSA883X_DIG_CTRL_BASE+0x0055)
+#define WSA883X_WAVG_DIRECT_AMP_1 (WSA883X_DIG_CTRL_BASE+0x0056)
+#define WSA883X_WAVG_PTRN_AMP0_0 (WSA883X_DIG_CTRL_BASE+0x0057)
+#define WSA883X_WAVG_PTRN_AMP0_1 (WSA883X_DIG_CTRL_BASE+0x0058)
+#define WSA883X_WAVG_PTRN_AMP1_0 (WSA883X_DIG_CTRL_BASE+0x0059)
+#define WSA883X_WAVG_PTRN_AMP1_1 (WSA883X_DIG_CTRL_BASE+0x005A)
+#define WSA883X_WAVG_PTRN_AMP2_0 (WSA883X_DIG_CTRL_BASE+0x005B)
+#define WSA883X_WAVG_PTRN_AMP2_1 (WSA883X_DIG_CTRL_BASE+0x005C)
+#define WSA883X_WAVG_PTRN_AMP3_0 (WSA883X_DIG_CTRL_BASE+0x005D)
+#define WSA883X_WAVG_PTRN_AMP3_1 (WSA883X_DIG_CTRL_BASE+0x005E)
+#define WSA883X_WAVG_PTRN_AMP4_0 (WSA883X_DIG_CTRL_BASE+0x005F)
+#define WSA883X_WAVG_PTRN_AMP4_1 (WSA883X_DIG_CTRL_BASE+0x0060)
+#define WSA883X_WAVG_PTRN_AMP5_0 (WSA883X_DIG_CTRL_BASE+0x0061)
+#define WSA883X_WAVG_PTRN_AMP5_1 (WSA883X_DIG_CTRL_BASE+0x0062)
+#define WSA883X_WAVG_PTRN_AMP6_0 (WSA883X_DIG_CTRL_BASE+0x0063)
+#define WSA883X_WAVG_PTRN_AMP6_1 (WSA883X_DIG_CTRL_BASE+0x0064)
+#define WSA883X_WAVG_PTRN_AMP7_0 (WSA883X_DIG_CTRL_BASE+0x0065)
+#define WSA883X_WAVG_PTRN_AMP7_1 (WSA883X_DIG_CTRL_BASE+0x0066)
+#define WSA883X_WAVG_PER_0_1 (WSA883X_DIG_CTRL_BASE+0x0067)
+#define WSA883X_WAVG_PER_2_3 (WSA883X_DIG_CTRL_BASE+0x0068)
+#define WSA883X_WAVG_PER_4_5 (WSA883X_DIG_CTRL_BASE+0x0069)
+#define WSA883X_WAVG_PER_6_7 (WSA883X_DIG_CTRL_BASE+0x006A)
+#define WSA883X_DRE_CTL_0 (WSA883X_DIG_CTRL_BASE+0x006C)
+#define WSA883X_DRE_CTL_1 (WSA883X_DIG_CTRL_BASE+0x006D)
+#define WSA883X_CLSH_CTL_0 (WSA883X_DIG_CTRL_BASE+0x0070)
+#define WSA883X_CLSH_CTL_1 (WSA883X_DIG_CTRL_BASE+0x0071)
+#define WSA883X_CLSH_V_HD_PA (WSA883X_DIG_CTRL_BASE+0x0072)
+#define WSA883X_CLSH_V_PA_MIN (WSA883X_DIG_CTRL_BASE+0x0073)
+#define WSA883X_CLSH_OVRD_VAL (WSA883X_DIG_CTRL_BASE+0x0074)
+#define WSA883X_CLSH_HARD_MAX (WSA883X_DIG_CTRL_BASE+0x0075)
+#define WSA883X_CLSH_SOFT_MAX (WSA883X_DIG_CTRL_BASE+0x0076)
+#define WSA883X_CLSH_SIG_DP (WSA883X_DIG_CTRL_BASE+0x0077)
+#define WSA883X_TAGC_CTL (WSA883X_DIG_CTRL_BASE+0x0078)
+#define WSA883X_TAGC_TIME (WSA883X_DIG_CTRL_BASE+0x0079)
+#define WSA883X_TAGC_E2E_GAIN (WSA883X_DIG_CTRL_BASE+0x007A)
+#define WSA883X_TAGC_FORCE_VAL (WSA883X_DIG_CTRL_BASE+0x007B)
+#define WSA883X_VAGC_CTL (WSA883X_DIG_CTRL_BASE+0x007C)
+#define WSA883X_VAGC_TIME (WSA883X_DIG_CTRL_BASE+0x007D)
+#define WSA883X_VAGC_ATTN_LVL_1_2 (WSA883X_DIG_CTRL_BASE+0x007E)
+#define WSA883X_VAGC_ATTN_LVL_3 (WSA883X_DIG_CTRL_BASE+0x007F)
+#define WSA883X_INTR_MODE (WSA883X_DIG_CTRL_BASE+0x0080)
+#define WSA883X_INTR_MASK0 (WSA883X_DIG_CTRL_BASE+0x0081)
+#define WSA883X_INTR_MASK1 (WSA883X_DIG_CTRL_BASE+0x0082)
+#define WSA883X_INTR_STATUS0 (WSA883X_DIG_CTRL_BASE+0x0083)
+#define WSA883X_INTR_STATUS1 (WSA883X_DIG_CTRL_BASE+0x0084)
+#define WSA883X_INTR_CLEAR0 (WSA883X_DIG_CTRL_BASE+0x0085)
+#define WSA883X_INTR_CLEAR1 (WSA883X_DIG_CTRL_BASE+0x0086)
+#define WSA883X_INTR_LEVEL0 (WSA883X_DIG_CTRL_BASE+0x0087)
+#define WSA883X_INTR_LEVEL1 (WSA883X_DIG_CTRL_BASE+0x0088)
+#define WSA883X_INTR_SET0 (WSA883X_DIG_CTRL_BASE+0x0089)
+#define WSA883X_INTR_SET1 (WSA883X_DIG_CTRL_BASE+0x008A)
+#define WSA883X_INTR_TEST0 (WSA883X_DIG_CTRL_BASE+0x008B)
+#define WSA883X_INTR_TEST1 (WSA883X_DIG_CTRL_BASE+0x008C)
+#define WSA883X_OTP_CTRL0 (WSA883X_DIG_CTRL_BASE+0x0090)
+#define WSA883X_OTP_CTRL1 (WSA883X_DIG_CTRL_BASE+0x0091)
+#define WSA883X_HDRIVE_CTL_GROUP1 (WSA883X_DIG_CTRL_BASE+0x0092)
+#define WSA883X_PIN_CTL (WSA883X_DIG_CTRL_BASE+0x0093)
+#define WSA883X_PIN_CTL_OE (WSA883X_DIG_CTRL_BASE+0x0094)
+#define WSA883X_PIN_WDATA_IOPAD (WSA883X_DIG_CTRL_BASE+0x0095)
+#define WSA883X_PIN_STATUS (WSA883X_DIG_CTRL_BASE+0x0096)
+#define WSA883X_I2C_SLAVE_CTL (WSA883X_DIG_CTRL_BASE+0x0097)
+#define WSA883X_PDM_TEST_MODE (WSA883X_DIG_CTRL_BASE+0x00A0)
+#define WSA883X_ATE_TEST_MODE (WSA883X_DIG_CTRL_BASE+0x00A1)
+#define WSA883X_DRE_TEST (WSA883X_DIG_CTRL_BASE+0x00A2)
+#define WSA883X_DIG_DEBUG_MODE (WSA883X_DIG_CTRL_BASE+0x00A3)
+#define WSA883X_DIG_DEBUG_SEL (WSA883X_DIG_CTRL_BASE+0x00A4)
+#define WSA883X_DIG_DEBUG_EN (WSA883X_DIG_CTRL_BASE+0x00A5)
+#define WSA883X_SWR_HM_TEST0 (WSA883X_DIG_CTRL_BASE+0x00A6)
+#define WSA883X_SWR_HM_TEST1 (WSA883X_DIG_CTRL_BASE+0x00A7)
+#define WSA883X_SWR_PAD_CTL (WSA883X_DIG_CTRL_BASE+0x00A8)
+#define WSA883X_TEMP_DETECT_DBG_CTL (WSA883X_DIG_CTRL_BASE+0x00A9)
+#define WSA883X_TEMP_DEBUG_MSB (WSA883X_DIG_CTRL_BASE+0x00AA)
+#define WSA883X_TEMP_DEBUG_LSB (WSA883X_DIG_CTRL_BASE+0x00AB)
+#define WSA883X_SAMPLE_EDGE_SEL (WSA883X_DIG_CTRL_BASE+0x00AC)
+#define WSA883X_TEST_MODE_CTL (WSA883X_DIG_CTRL_BASE+0x00AD)
+#define WSA883X_IOPAD_CTL (WSA883X_DIG_CTRL_BASE+0x00AE)
+#define WSA883X_SPARE_0 (WSA883X_DIG_CTRL_BASE+0x00B0)
+#define WSA883X_SPARE_1 (WSA883X_DIG_CTRL_BASE+0x00B1)
+#define WSA883X_SPARE_2 (WSA883X_DIG_CTRL_BASE+0x00B2)
+#define WSA883X_SCODE (WSA883X_DIG_CTRL_BASE+0x00C0)
+
+#define WSA883X_DIG_TRIM_BASE (WSA883X_BASE+0x00000500)
+#define WSA883X_PAGE_REGISTER (WSA883X_DIG_TRIM_BASE+0x0000)
+#define WSA883X_OTP_REG_0 (WSA883X_DIG_TRIM_BASE+0x0080)
+#define WSA883X_OTP_REG_1 (WSA883X_DIG_TRIM_BASE+0x0081)
+#define WSA883X_OTP_REG_2 (WSA883X_DIG_TRIM_BASE+0x0082)
+#define WSA883X_OTP_REG_3 (WSA883X_DIG_TRIM_BASE+0x0083)
+#define WSA883X_OTP_REG_4 (WSA883X_DIG_TRIM_BASE+0x0084)
+#define WSA883X_OTP_REG_5 (WSA883X_DIG_TRIM_BASE+0x0085)
+#define WSA883X_OTP_REG_6 (WSA883X_DIG_TRIM_BASE+0x0086)
+#define WSA883X_OTP_REG_7 (WSA883X_DIG_TRIM_BASE+0x0087)
+#define WSA883X_OTP_REG_8 (WSA883X_DIG_TRIM_BASE+0x0088)
+#define WSA883X_OTP_REG_9 (WSA883X_DIG_TRIM_BASE+0x0089)
+#define WSA883X_OTP_REG_10 (WSA883X_DIG_TRIM_BASE+0x008A)
+#define WSA883X_OTP_REG_11 (WSA883X_DIG_TRIM_BASE+0x008B)
+#define WSA883X_OTP_REG_12 (WSA883X_DIG_TRIM_BASE+0x008C)
+#define WSA883X_OTP_REG_13 (WSA883X_DIG_TRIM_BASE+0x008D)
+#define WSA883X_OTP_REG_14 (WSA883X_DIG_TRIM_BASE+0x008E)
+#define WSA883X_OTP_REG_15 (WSA883X_DIG_TRIM_BASE+0x008F)
+#define WSA883X_OTP_REG_16 (WSA883X_DIG_TRIM_BASE+0x0090)
+#define WSA883X_OTP_REG_17 (WSA883X_DIG_TRIM_BASE+0x0091)
+#define WSA883X_OTP_REG_18 (WSA883X_DIG_TRIM_BASE+0x0092)
+#define WSA883X_OTP_REG_19 (WSA883X_DIG_TRIM_BASE+0x0093)
+#define WSA883X_OTP_REG_20 (WSA883X_DIG_TRIM_BASE+0x0094)
+#define WSA883X_OTP_REG_21 (WSA883X_DIG_TRIM_BASE+0x0095)
+#define WSA883X_OTP_REG_22 (WSA883X_DIG_TRIM_BASE+0x0096)
+#define WSA883X_OTP_REG_23 (WSA883X_DIG_TRIM_BASE+0x0097)
+#define WSA883X_OTP_REG_24 (WSA883X_DIG_TRIM_BASE+0x0098)
+#define WSA883X_OTP_REG_25 (WSA883X_DIG_TRIM_BASE+0x0099)
+#define WSA883X_OTP_REG_26 (WSA883X_DIG_TRIM_BASE+0x009A)
+#define WSA883X_OTP_REG_27 (WSA883X_DIG_TRIM_BASE+0x009B)
+#define WSA883X_OTP_REG_28 (WSA883X_DIG_TRIM_BASE+0x009C)
+#define WSA883X_OTP_REG_29 (WSA883X_DIG_TRIM_BASE+0x009D)
+#define WSA883X_OTP_REG_30 (WSA883X_DIG_TRIM_BASE+0x009E)
+#define WSA883X_OTP_REG_31 (WSA883X_DIG_TRIM_BASE+0x009F)
+#define WSA883X_OTP_REG_SCODE (WSA883X_DIG_TRIM_BASE+0x00A0)
+#define WSA883X_OTP_REG_63 (WSA883X_DIG_TRIM_BASE+0x00BF)
+
+#define WSA883X_DIG_EMEM_BASE (WSA883X_BASE+0x000005C0)
+#define WSA883X_EMEM_0 (WSA883X_DIG_EMEM_BASE+0x0000)
+#define WSA883X_EMEM_1 (WSA883X_DIG_EMEM_BASE+0x0001)
+#define WSA883X_EMEM_2 (WSA883X_DIG_EMEM_BASE+0x0002)
+#define WSA883X_EMEM_3 (WSA883X_DIG_EMEM_BASE+0x0003)
+#define WSA883X_EMEM_4 (WSA883X_DIG_EMEM_BASE+0x0004)
+#define WSA883X_EMEM_5 (WSA883X_DIG_EMEM_BASE+0x0005)
+#define WSA883X_EMEM_6 (WSA883X_DIG_EMEM_BASE+0x0006)
+#define WSA883X_EMEM_7 (WSA883X_DIG_EMEM_BASE+0x0007)
+#define WSA883X_EMEM_8 (WSA883X_DIG_EMEM_BASE+0x0008)
+#define WSA883X_EMEM_9 (WSA883X_DIG_EMEM_BASE+0x0009)
+#define WSA883X_EMEM_10 (WSA883X_DIG_EMEM_BASE+0x000A)
+#define WSA883X_EMEM_11 (WSA883X_DIG_EMEM_BASE+0x000B)
+#define WSA883X_EMEM_12 (WSA883X_DIG_EMEM_BASE+0x000C)
+#define WSA883X_EMEM_13 (WSA883X_DIG_EMEM_BASE+0x000D)
+#define WSA883X_EMEM_14 (WSA883X_DIG_EMEM_BASE+0x000E)
+#define WSA883X_EMEM_15 (WSA883X_DIG_EMEM_BASE+0x000F)
+#define WSA883X_EMEM_16 (WSA883X_DIG_EMEM_BASE+0x0010)
+#define WSA883X_EMEM_17 (WSA883X_DIG_EMEM_BASE+0x0011)
+#define WSA883X_EMEM_18 (WSA883X_DIG_EMEM_BASE+0x0012)
+#define WSA883X_EMEM_19 (WSA883X_DIG_EMEM_BASE+0x0013)
+#define WSA883X_EMEM_20 (WSA883X_DIG_EMEM_BASE+0x0014)
+#define WSA883X_EMEM_21 (WSA883X_DIG_EMEM_BASE+0x0015)
+#define WSA883X_EMEM_22 (WSA883X_DIG_EMEM_BASE+0x0016)
+#define WSA883X_EMEM_23 (WSA883X_DIG_EMEM_BASE+0x0017)
+#define WSA883X_EMEM_24 (WSA883X_DIG_EMEM_BASE+0x0018)
+#define WSA883X_EMEM_25 (WSA883X_DIG_EMEM_BASE+0x0019)
+#define WSA883X_EMEM_26 (WSA883X_DIG_EMEM_BASE+0x001A)
+#define WSA883X_EMEM_27 (WSA883X_DIG_EMEM_BASE+0x001B)
+#define WSA883X_EMEM_28 (WSA883X_DIG_EMEM_BASE+0x001C)
+#define WSA883X_EMEM_29 (WSA883X_DIG_EMEM_BASE+0x001D)
+#define WSA883X_EMEM_30 (WSA883X_DIG_EMEM_BASE+0x001E)
+#define WSA883X_EMEM_31 (WSA883X_DIG_EMEM_BASE+0x001F)
+#define WSA883X_EMEM_32 (WSA883X_DIG_EMEM_BASE+0x0020)
+#define WSA883X_EMEM_33 (WSA883X_DIG_EMEM_BASE+0x0021)
+#define WSA883X_EMEM_34 (WSA883X_DIG_EMEM_BASE+0x0022)
+#define WSA883X_EMEM_35 (WSA883X_DIG_EMEM_BASE+0x0023)
+#define WSA883X_EMEM_36 (WSA883X_DIG_EMEM_BASE+0x0024)
+#define WSA883X_EMEM_37 (WSA883X_DIG_EMEM_BASE+0x0025)
+#define WSA883X_EMEM_38 (WSA883X_DIG_EMEM_BASE+0x0026)
+#define WSA883X_EMEM_39 (WSA883X_DIG_EMEM_BASE+0x0027)
+#define WSA883X_EMEM_40 (WSA883X_DIG_EMEM_BASE+0x0028)
+#define WSA883X_EMEM_41 (WSA883X_DIG_EMEM_BASE+0x0029)
+#define WSA883X_EMEM_42 (WSA883X_DIG_EMEM_BASE+0x002A)
+#define WSA883X_EMEM_43 (WSA883X_DIG_EMEM_BASE+0x002B)
+#define WSA883X_EMEM_44 (WSA883X_DIG_EMEM_BASE+0x002C)
+#define WSA883X_EMEM_45 (WSA883X_DIG_EMEM_BASE+0x002D)
+#define WSA883X_EMEM_46 (WSA883X_DIG_EMEM_BASE+0x002E)
+#define WSA883X_EMEM_47 (WSA883X_DIG_EMEM_BASE+0x002F)
+#define WSA883X_EMEM_48 (WSA883X_DIG_EMEM_BASE+0x0030)
+#define WSA883X_EMEM_49 (WSA883X_DIG_EMEM_BASE+0x0031)
+#define WSA883X_EMEM_50 (WSA883X_DIG_EMEM_BASE+0x0032)
+#define WSA883X_EMEM_51 (WSA883X_DIG_EMEM_BASE+0x0033)
+#define WSA883X_EMEM_52 (WSA883X_DIG_EMEM_BASE+0x0034)
+#define WSA883X_EMEM_53 (WSA883X_DIG_EMEM_BASE+0x0035)
+#define WSA883X_EMEM_54 (WSA883X_DIG_EMEM_BASE+0x0036)
+#define WSA883X_EMEM_55 (WSA883X_DIG_EMEM_BASE+0x0037)
+#define WSA883X_EMEM_56 (WSA883X_DIG_EMEM_BASE+0x0038)
+#define WSA883X_EMEM_57 (WSA883X_DIG_EMEM_BASE+0x0039)
+#define WSA883X_EMEM_58 (WSA883X_DIG_EMEM_BASE+0x003A)
+#define WSA883X_EMEM_59 (WSA883X_DIG_EMEM_BASE+0x003B)
+#define WSA883X_EMEM_60 (WSA883X_DIG_EMEM_BASE+0x003C)
+#define WSA883X_EMEM_61 (WSA883X_DIG_EMEM_BASE+0x003D)
+#define WSA883X_EMEM_62 (WSA883X_DIG_EMEM_BASE+0x003E)
+#define WSA883X_EMEM_63 (WSA883X_DIG_EMEM_BASE+0x003F)
+
+#define WSA883X_NUM_REGISTERS (WSA883X_EMEM_63+1)
+#define WSA883X_MAX_REGISTER (WSA883X_NUM_REGISTERS-1)
+
+#endif /* WSA883X_REGISTERS_H */
diff --git a/asoc/codecs/wsa883x/wsa883x-regmap.c b/asoc/codecs/wsa883x/wsa883x-regmap.c
new file mode 100644
index 0000000..8394e9c
--- /dev/null
+++ b/asoc/codecs/wsa883x/wsa883x-regmap.c
@@ -0,0 +1,393 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015-2016, 2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "wsa883x-registers.h"
+#include "wsa883x.h"
+
+extern const u8 wsa883x_reg_access[WSA883X_NUM_REGISTERS];
+
+static struct reg_default wsa883x_defaults[] = {
+ {WSA883X_REF_CTRL, 0x6C},
+ {WSA883X_TEST_CTL_0, 0x06},
+ {WSA883X_BIAS_0, 0xD2},
+ {WSA883X_OP_CTL, 0xE0},
+ {WSA883X_IREF_CTL, 0x58},
+ {WSA883X_ISENS_CTL, 0x47},
+ {WSA883X_CLK_CTL, 0x87},
+ {WSA883X_TEST_CTL_1, 0x00},
+ {WSA883X_BIAS_1, 0x51},
+ {WSA883X_ADC_CTL, 0x03},
+ {WSA883X_DOUT_MSB, 0x00},
+ {WSA883X_DOUT_LSB, 0x00},
+ {WSA883X_VBAT_SNS, 0x00},
+ {WSA883X_ITRIM_CODE, 0x1F},
+ {WSA883X_EN, 0x00},
+ {WSA883X_OVERRIDE1, 0x00},
+ {WSA883X_OVERRIDE2, 0x08},
+ {WSA883X_VSENSE1, 0xD3},
+ {WSA883X_ISENSE1, 0xD4},
+ {WSA883X_ISENSE2, 0x20},
+ {WSA883X_ISENSE_CAL, 0x00},
+ {WSA883X_MISC, 0x00},
+ {WSA883X_ADC_0, 0x00},
+ {WSA883X_ADC_1, 0x00},
+ {WSA883X_ADC_2, 0x00},
+ {WSA883X_ADC_3, 0x00},
+ {WSA883X_ADC_4, 0x45},
+ {WSA883X_ADC_5, 0x20},
+ {WSA883X_ADC_6, 0x10},
+ {WSA883X_ADC_7, 0x00},
+ {WSA883X_STATUS, 0x00},
+ {WSA883X_DAC_CTRL_REG, 0x41},
+ {WSA883X_DAC_EN_DEBUG_REG, 0x00},
+ {WSA883X_DAC_OPAMP_BIAS1_REG, 0x48},
+ {WSA883X_DAC_OPAMP_BIAS2_REG, 0x48},
+ {WSA883X_DAC_VCM_CTRL_REG, 0x0B},
+ {WSA883X_DAC_VOLTAGE_CTRL_REG, 0x05},
+ {WSA883X_ATEST1_REG, 0x00},
+ {WSA883X_ATEST2_REG, 0x00},
+ {WSA883X_SPKR_TOP_BIAS_REG1, 0x4A},
+ {WSA883X_SPKR_TOP_BIAS_REG2, 0x65},
+ {WSA883X_SPKR_TOP_BIAS_REG3, 0x55},
+ {WSA883X_SPKR_TOP_BIAS_REG4, 0xA9},
+ {WSA883X_SPKR_CLIP_DET_REG, 0x00},
+ {WSA883X_SPKR_DRV_LF_BLK_EN, 0x0F},
+ {WSA883X_SPKR_DRV_LF_EN, 0x0A},
+ {WSA883X_SPKR_DRV_LF_MASK_DCC_CTL, 0x00},
+ {WSA883X_SPKR_DRV_LF_MISC_CTL, 0x32},
+ {WSA883X_SPKR_DRV_LF_REG_GAIN, 0x00},
+ {WSA883X_SPKR_DRV_LF_OS_CAL_CTL1, 0x90},
+ {WSA883X_SPKR_DRV_LF_OS_CAL_CTL, 0x00},
+ {WSA883X_SPKR_PWM_CLK_CTL, 0x00},
+ {WSA883X_SPKR_PDRV_HS_CTL, 0x50},
+ {WSA883X_SPKR_PDRV_LS_CTL, 0x48},
+ {WSA883X_SPKR_PWRSTG_DBG, 0x00},
+ {WSA883X_SPKR_OCP_CTL, 0x00},
+ {WSA883X_SPKR_BBM_CTL, 0x90},
+ {WSA883X_PA_STATUS0, 0x00},
+ {WSA883X_PA_STATUS1, 0x00},
+ {WSA883X_PA_STATUS2, 0x00},
+ {WSA883X_EN_CTRL, 0x54},
+ {WSA883X_CURRENT_LIMIT, 0x90},
+ {WSA883X_IBIAS1, 0x00},
+ {WSA883X_IBIAS2, 0x00},
+ {WSA883X_IBIAS3, 0x00},
+ {WSA883X_LDO_PROG, 0x2A},
+ {WSA883X_STABILITY_CTRL1, 0x8E},
+ {WSA883X_STABILITY_CTRL2, 0x00},
+ {WSA883X_PWRSTAGE_CTRL1, 0x00},
+ {WSA883X_PWRSTAGE_CTRL2, 0x40},
+ {WSA883X_UVLO, 0xE9},
+ {WSA883X_SEQUENCE_CTRL, 0x11},
+ {WSA883X_ZX_CTRL_1, 0xF0},
+ {WSA883X_ZX_CTRL_2, 0x06},
+ {WSA883X_MISC1, 0x02},
+ {WSA883X_MISC2, 0x81},
+ {WSA883X_GMAMP_SUP1, 0x84},
+ {WSA883X_PWRSTAGE_CTRL3, 0x14},
+ {WSA883X_PRSTAGE_CTRL4, 0x5F},
+ {WSA883X_SPARE1, 0x00},
+ {WSA883X_PON_CTL_0, 0xE3},
+ {WSA883X_PON_CLT_1, 0x70},
+ {WSA883X_PON_CTL_2, 0x00},
+ {WSA883X_PON_CTL_3, 0x00},
+ {WSA883X_PON_CTL_4, 0x00},
+ {WSA883X_CKWD_CTL_0, 0x34},
+ {WSA883X_CKWD_CTL_1, 0x80},
+ {WSA883X_CKWD_CTL_2, 0x00},
+ {WSA883X_CKSK_CTL_0, 0x0A},
+ {WSA883X_TEST_0, 0x00},
+ {WSA883X_TEST_1, 0x00},
+ {WSA883X_STATUS_0, 0x00},
+ {WSA883X_STATUS_1, 0x00},
+ {WSA883X_PAGE_REGISTER, 0x00},
+ {WSA883X_CHIP_ID0, 0x00},
+ {WSA883X_CHIP_ID1, 0x00},
+ {WSA883X_CHIP_ID2, 0x02},
+ {WSA883X_CHIP_ID3, 0x02},
+ {WSA883X_BUS_ID, 0x00},
+ {WSA883X_CDC_RST_CTL, 0x01},
+ {WSA883X_TOP_CLK_CFG, 0x00},
+ {WSA883X_CDC_PATH_MODE, 0x00},
+ {WSA883X_CDC_CLK_CTL, 0xFF},
+ {WSA883X_SWR_RESET_EN, 0x00},
+ {WSA883X_PA_FSM_CTL, 0x00},
+ {WSA883X_PA_FSM_TIMER0, 0x80},
+ {WSA883X_PA_FSM_TIMER1, 0x80},
+ {WSA883X_PA_FSM_STA, 0x00},
+ {WSA883X_PA_FSM_ERR_COND, 0x00},
+ {WSA883X_PA_FSM_MSK, 0x00},
+ {WSA883X_PA_FSM_BYP, 0x00},
+ {WSA883X_TADC_VALUE_CTL, 0x03},
+ {WSA883X_TEMP_DETECT_CTL, 0x01},
+ {WSA883X_TEMP_MSB, 0x00},
+ {WSA883X_TEMP_LSB, 0x00},
+ {WSA883X_TEMP_CONFIG0, 0x00},
+ {WSA883X_TEMP_CONFIG1, 0x00},
+ {WSA883X_VBAT_ADC_FLT_CTL, 0x00},
+ {WSA883X_VBAT_DIN_MSB, 0x00},
+ {WSA883X_VBAT_DIN_LSB, 0x00},
+ {WSA883X_VBAT_DOUT, 0x00},
+ {WSA883X_SDM_PDM9_LSB, 0x00},
+ {WSA883X_SDM_PDM9_MSB, 0x00},
+ {WSA883X_CDC_RX_CTL, 0xFE},
+ {WSA883X_CDC_SPK_DSM_A1_0, 0x00},
+ {WSA883X_CDC_SPK_DSM_A1_1, 0x01},
+ {WSA883X_CDC_SPK_DSM_A2_0, 0x96},
+ {WSA883X_CDC_SPK_DSM_A2_1, 0x09},
+ {WSA883X_CDC_SPK_DSM_A3_0, 0xAB},
+ {WSA883X_CDC_SPK_DSM_A3_1, 0x05},
+ {WSA883X_CDC_SPK_DSM_A4_0, 0x1C},
+ {WSA883X_CDC_SPK_DSM_A4_1, 0x02},
+ {WSA883X_CDC_SPK_DSM_A5_0, 0x17},
+ {WSA883X_CDC_SPK_DSM_A5_1, 0x02},
+ {WSA883X_CDC_SPK_DSM_A6_0, 0xAA},
+ {WSA883X_CDC_SPK_DSM_A7_0, 0xE3},
+ {WSA883X_CDC_SPK_DSM_C_0, 0x69},
+ {WSA883X_CDC_SPK_DSM_C_1, 0x54},
+ {WSA883X_CDC_SPK_DSM_C_2, 0x02},
+ {WSA883X_CDC_SPK_DSM_C_3, 0x15},
+ {WSA883X_CDC_SPK_DSM_R1, 0xA4},
+ {WSA883X_CDC_SPK_DSM_R2, 0xB5},
+ {WSA883X_CDC_SPK_DSM_R3, 0x86},
+ {WSA883X_CDC_SPK_DSM_R4, 0x85},
+ {WSA883X_CDC_SPK_DSM_R5, 0xAA},
+ {WSA883X_CDC_SPK_DSM_R6, 0xE2},
+ {WSA883X_CDC_SPK_DSM_R7, 0x62},
+ {WSA883X_CDC_SPK_GAIN_PDM_0, 0x00},
+ {WSA883X_CDC_SPK_GAIN_PDM_1, 0xFC},
+ {WSA883X_CDC_SPK_GAIN_PDM_2, 0x05},
+ {WSA883X_PDM_WD_CTL, 0x00},
+ {WSA883X_DEM_BYPASS_DATA0, 0x00},
+ {WSA883X_DEM_BYPASS_DATA1, 0x00},
+ {WSA883X_DEM_BYPASS_DATA2, 0x00},
+ {WSA883X_DEM_BYPASS_DATA3, 0x00},
+ {WSA883X_WAVG_CTL, 0x06},
+ {WSA883X_WAVG_LRA_PER_0, 0xD1},
+ {WSA883X_WAVG_LRA_PER_1, 0x00},
+ {WSA883X_WAVG_DELTA_THETA_0, 0xE6},
+ {WSA883X_WAVG_DELTA_THETA_1, 0x04},
+ {WSA883X_WAVG_DIRECT_AMP_0, 0x50},
+ {WSA883X_WAVG_DIRECT_AMP_1, 0x00},
+ {WSA883X_WAVG_PTRN_AMP0_0, 0x50},
+ {WSA883X_WAVG_PTRN_AMP0_1, 0x00},
+ {WSA883X_WAVG_PTRN_AMP1_0, 0x50},
+ {WSA883X_WAVG_PTRN_AMP1_1, 0x00},
+ {WSA883X_WAVG_PTRN_AMP2_0, 0x50},
+ {WSA883X_WAVG_PTRN_AMP2_1, 0x00},
+ {WSA883X_WAVG_PTRN_AMP3_0, 0x50},
+ {WSA883X_WAVG_PTRN_AMP3_1, 0x00},
+ {WSA883X_WAVG_PTRN_AMP4_0, 0x50},
+ {WSA883X_WAVG_PTRN_AMP4_1, 0x00},
+ {WSA883X_WAVG_PTRN_AMP5_0, 0x50},
+ {WSA883X_WAVG_PTRN_AMP5_1, 0x00},
+ {WSA883X_WAVG_PTRN_AMP6_0, 0x50},
+ {WSA883X_WAVG_PTRN_AMP6_1, 0x00},
+ {WSA883X_WAVG_PTRN_AMP7_0, 0x50},
+ {WSA883X_WAVG_PTRN_AMP7_1, 0x00},
+ {WSA883X_WAVG_PER_0_1, 0x88},
+ {WSA883X_WAVG_PER_2_3, 0x88},
+ {WSA883X_WAVG_PER_4_5, 0x88},
+ {WSA883X_WAVG_PER_6_7, 0x88},
+ {WSA883X_DRE_CTL_0, 0x30},
+ {WSA883X_DRE_CTL_1, 0x20},
+ {WSA883X_CLSH_CTL_0, 0x37},
+ {WSA883X_CLSH_CTL_1, 0x81},
+ {WSA883X_CLSH_V_HD_PA, 0x0F},
+ {WSA883X_CLSH_V_PA_MIN, 0x00},
+ {WSA883X_CLSH_OVRD_VAL, 0x00},
+ {WSA883X_CLSH_HARD_MAX, 0xFF},
+ {WSA883X_CLSH_SOFT_MAX, 0xFF},
+ {WSA883X_CLSH_SIG_DP, 0x00},
+ {WSA883X_TAGC_CTL, 0x10},
+ {WSA883X_TAGC_TIME, 0x20},
+ {WSA883X_TAGC_E2E_GAIN, 0x02},
+ {WSA883X_TAGC_FORCE_VAL, 0x00},
+ {WSA883X_VAGC_CTL, 0x00},
+ {WSA883X_VAGC_TIME, 0x08},
+ {WSA883X_VAGC_ATTN_LVL_1_2, 0x21},
+ {WSA883X_VAGC_ATTN_LVL_3, 0x03},
+ {WSA883X_INTR_MODE, 0x00},
+ {WSA883X_INTR_MASK0, 0x1B},
+ {WSA883X_INTR_MASK1, 0x03},
+ {WSA883X_INTR_STATUS0, 0x00},
+ {WSA883X_INTR_STATUS1, 0x00},
+ {WSA883X_INTR_CLEAR0, 0x00},
+ {WSA883X_INTR_CLEAR1, 0x03},
+ {WSA883X_INTR_LEVEL0, 0x00},
+ {WSA883X_INTR_LEVEL1, 0x03},
+ {WSA883X_INTR_SET0, 0x00},
+ {WSA883X_INTR_SET1, 0x03},
+ {WSA883X_INTR_TEST0, 0x00},
+ {WSA883X_INTR_TEST1, 0x03},
+ {WSA883X_OTP_CTRL0, 0x00},
+ {WSA883X_OTP_CTRL1, 0x00},
+ {WSA883X_HDRIVE_CTL_GROUP1, 0x00},
+ {WSA883X_PIN_CTL, 0x04},
+ {WSA883X_PIN_CTL_OE, 0x00},
+ {WSA883X_PIN_WDATA_IOPAD, 0x00},
+ {WSA883X_PIN_STATUS, 0x00},
+ {WSA883X_I2C_SLAVE_CTL, 0x00},
+ {WSA883X_PDM_TEST_MODE, 0x00},
+ {WSA883X_ATE_TEST_MODE, 0x00},
+ {WSA883X_DRE_TEST, 0x00},
+ {WSA883X_DIG_DEBUG_MODE, 0x00},
+ {WSA883X_DIG_DEBUG_SEL, 0x00},
+ {WSA883X_DIG_DEBUG_EN, 0x00},
+ {WSA883X_SWR_HM_TEST0, 0x08},
+ {WSA883X_SWR_HM_TEST1, 0x00},
+ {WSA883X_SWR_PAD_CTL, 0x45},
+ {WSA883X_TEMP_DETECT_DBG_CTL, 0x00},
+ {WSA883X_TEMP_DEBUG_MSB, 0x00},
+ {WSA883X_TEMP_DEBUG_LSB, 0x00},
+ {WSA883X_SAMPLE_EDGE_SEL, 0x7F},
+ {WSA883X_TEST_MODE_CTL, 0x00},
+ {WSA883X_IOPAD_CTL, 0x00},
+ {WSA883X_SPARE_0, 0x00},
+ {WSA883X_SPARE_1, 0x00},
+ {WSA883X_SPARE_2, 0x00},
+ {WSA883X_SCODE, 0x00},
+ {WSA883X_PAGE_REGISTER, 0x00},
+ {WSA883X_OTP_REG_0, 0x01},
+ {WSA883X_OTP_REG_1, 0xFF},
+ {WSA883X_OTP_REG_2, 0xC0},
+ {WSA883X_OTP_REG_3, 0xFF},
+ {WSA883X_OTP_REG_4, 0xC0},
+ {WSA883X_OTP_REG_5, 0xFF},
+ {WSA883X_OTP_REG_6, 0xFF},
+ {WSA883X_OTP_REG_7, 0xFF},
+ {WSA883X_OTP_REG_8, 0xFF},
+ {WSA883X_OTP_REG_9, 0xFF},
+ {WSA883X_OTP_REG_10, 0xFF},
+ {WSA883X_OTP_REG_11, 0xFF},
+ {WSA883X_OTP_REG_12, 0xFF},
+ {WSA883X_OTP_REG_13, 0xFF},
+ {WSA883X_OTP_REG_14, 0xFF},
+ {WSA883X_OTP_REG_15, 0xFF},
+ {WSA883X_OTP_REG_16, 0xFF},
+ {WSA883X_OTP_REG_17, 0xFF},
+ {WSA883X_OTP_REG_18, 0xFF},
+ {WSA883X_OTP_REG_19, 0xFF},
+ {WSA883X_OTP_REG_20, 0xFF},
+ {WSA883X_OTP_REG_21, 0xFF},
+ {WSA883X_OTP_REG_22, 0xFF},
+ {WSA883X_OTP_REG_23, 0xFF},
+ {WSA883X_OTP_REG_24, 0x03},
+ {WSA883X_OTP_REG_25, 0x01},
+ {WSA883X_OTP_REG_26, 0x03},
+ {WSA883X_OTP_REG_27, 0x11},
+ {WSA883X_OTP_REG_28, 0x3F},
+ {WSA883X_OTP_REG_29, 0x3F},
+ {WSA883X_OTP_REG_30, 0x01},
+ {WSA883X_OTP_REG_31, 0x01},
+ {WSA883X_OTP_REG_SCODE, 0x00},
+ {WSA883X_OTP_REG_63, 0x40},
+ {WSA883X_EMEM_0, 0x00},
+ {WSA883X_EMEM_1, 0x00},
+ {WSA883X_EMEM_2, 0x00},
+ {WSA883X_EMEM_3, 0x00},
+ {WSA883X_EMEM_4, 0x00},
+ {WSA883X_EMEM_5, 0x00},
+ {WSA883X_EMEM_6, 0x00},
+ {WSA883X_EMEM_7, 0x00},
+ {WSA883X_EMEM_8, 0x00},
+ {WSA883X_EMEM_9, 0x00},
+ {WSA883X_EMEM_10, 0x00},
+ {WSA883X_EMEM_11, 0x00},
+ {WSA883X_EMEM_12, 0x00},
+ {WSA883X_EMEM_13, 0x00},
+ {WSA883X_EMEM_14, 0x00},
+ {WSA883X_EMEM_15, 0x00},
+ {WSA883X_EMEM_16, 0x00},
+ {WSA883X_EMEM_17, 0x00},
+ {WSA883X_EMEM_18, 0x00},
+ {WSA883X_EMEM_19, 0x00},
+ {WSA883X_EMEM_20, 0x00},
+ {WSA883X_EMEM_21, 0x00},
+ {WSA883X_EMEM_22, 0x00},
+ {WSA883X_EMEM_23, 0x00},
+ {WSA883X_EMEM_24, 0x00},
+ {WSA883X_EMEM_25, 0x00},
+ {WSA883X_EMEM_26, 0x00},
+ {WSA883X_EMEM_27, 0x00},
+ {WSA883X_EMEM_28, 0x00},
+ {WSA883X_EMEM_29, 0x00},
+ {WSA883X_EMEM_30, 0x00},
+ {WSA883X_EMEM_31, 0x00},
+ {WSA883X_EMEM_32, 0x00},
+ {WSA883X_EMEM_33, 0x00},
+ {WSA883X_EMEM_34, 0x00},
+ {WSA883X_EMEM_35, 0x00},
+ {WSA883X_EMEM_36, 0x00},
+ {WSA883X_EMEM_37, 0x00},
+ {WSA883X_EMEM_38, 0x00},
+ {WSA883X_EMEM_39, 0x00},
+ {WSA883X_EMEM_40, 0x00},
+ {WSA883X_EMEM_41, 0x00},
+ {WSA883X_EMEM_42, 0x00},
+ {WSA883X_EMEM_43, 0x00},
+ {WSA883X_EMEM_44, 0x00},
+ {WSA883X_EMEM_45, 0x00},
+ {WSA883X_EMEM_46, 0x00},
+ {WSA883X_EMEM_47, 0x00},
+ {WSA883X_EMEM_48, 0x00},
+ {WSA883X_EMEM_49, 0x00},
+ {WSA883X_EMEM_50, 0x00},
+ {WSA883X_EMEM_51, 0x00},
+ {WSA883X_EMEM_52, 0x00},
+ {WSA883X_EMEM_53, 0x00},
+ {WSA883X_EMEM_54, 0x00},
+ {WSA883X_EMEM_55, 0x00},
+ {WSA883X_EMEM_56, 0x00},
+ {WSA883X_EMEM_57, 0x00},
+ {WSA883X_EMEM_58, 0x00},
+ {WSA883X_EMEM_59, 0x00},
+ {WSA883X_EMEM_60, 0x00},
+ {WSA883X_EMEM_61, 0x00},
+ {WSA883X_EMEM_62, 0x00},
+ {WSA883X_EMEM_63, 0x00},
+};
+
+static bool wsa883x_readable_register(struct device *dev, unsigned int reg)
+{
+ if (reg <= WSA883X_BASE)
+ return 0;
+
+ return wsa883x_reg_access[WSA883X_REG(reg)] & RD_REG;
+}
+
+static bool wsa883x_writeable_register(struct device *dev, unsigned int reg)
+{
+ if (reg <= WSA883X_BASE)
+ return 0;
+
+ return wsa883x_reg_access[WSA883X_REG(reg)] & WR_REG;
+}
+
+static bool wsa883x_volatile_register(struct device *dev, unsigned int reg)
+{
+ if (reg <= WSA883X_BASE)
+ return 0;
+
+ return ((wsa883x_reg_access[WSA883X_REG(reg)] & RD_REG) &&
+ !(wsa883x_reg_access[WSA883X_REG(reg)] & WR_REG));
+}
+
+struct regmap_config wsa881x_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = wsa883x_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wsa883x_defaults),
+ .max_register = WSA883X_MAX_REGISTER,
+ .volatile_reg = wsa883x_volatile_register,
+ .readable_reg = wsa883x_readable_register,
+ .writeable_reg = wsa883x_writeable_register,
+ .reg_format_endian = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+ .can_multi_write = true,
+};
diff --git a/asoc/codecs/wsa883x/wsa883x-tables.c b/asoc/codecs/wsa883x/wsa883x-tables.c
new file mode 100644
index 0000000..16b0a88
--- /dev/null
+++ b/asoc/codecs/wsa883x/wsa883x-tables.c
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "wsa883x-registers.h"
+
+const u8 wsa883x_reg_readable[WSA883X_NUM_REGISTERS] = {
+ [WSA883X_REG(WSA883X_REF_CTRL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TEST_CTL_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_BIAS_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OP_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_IREF_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ISENS_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CLK_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TEST_CTL_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_BIAS_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ADC_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DOUT_MSB)] = RD_REG,
+ [WSA883X_REG(WSA883X_DOUT_LSB)] = RD_REG,
+ [WSA883X_REG(WSA883X_VBAT_SNS)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ITRIM_CODE)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EN)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OVERRIDE1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OVERRIDE2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_VSENSE1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ISENSE1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ISENSE2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ISENSE_CAL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_MISC)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ADC_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ADC_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ADC_2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ADC_3)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ADC_4)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ADC_5)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ADC_6)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ADC_7)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_STATUS)] = RD_REG,
+ [WSA883X_REG(WSA883X_DAC_CTRL_REG)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DAC_EN_DEBUG_REG)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DAC_OPAMP_BIAS1_REG)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DAC_OPAMP_BIAS2_REG)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DAC_VCM_CTRL_REG)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DAC_VOLTAGE_CTRL_REG)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ATEST1_REG)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ATEST2_REG)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_TOP_BIAS_REG1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_TOP_BIAS_REG2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_TOP_BIAS_REG3)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_TOP_BIAS_REG4)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_CLIP_DET_REG)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_DRV_LF_BLK_EN)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_DRV_LF_EN)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_DRV_LF_MASK_DCC_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_DRV_LF_MISC_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_DRV_LF_REG_GAIN)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_DRV_LF_OS_CAL_CTL1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_DRV_LF_OS_CAL_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_PWM_CLK_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_PDRV_HS_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_PDRV_LS_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_PWRSTG_DBG)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_OCP_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPKR_BBM_CTL)] = RD_REG,
+ [WSA883X_REG(WSA883X_PA_STATUS0)] = RD_REG,
+ [WSA883X_REG(WSA883X_PA_STATUS1)] = RD_REG,
+ [WSA883X_REG(WSA883X_PA_STATUS2)] = RD_REG,
+ [WSA883X_REG(WSA883X_EN_CTRL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CURRENT_LIMIT)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_IBIAS1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_IBIAS2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_IBIAS3)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_LDO_PROG)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_STABILITY_CTRL1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_STABILITY_CTRL2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PWRSTAGE_CTRL1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PWRSTAGE_CTRL2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_UVLO)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SEQUENCE_CTRL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ZX_CTRL_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ZX_CTRL_2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_MISC1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_MISC2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_GMAMP_SUP1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PWRSTAGE_CTRL3)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PRSTAGE_CTRL4)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPARE1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PON_CTL_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PON_CLT_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PON_CTL_2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PON_CTL_3)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PON_CTL_4)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CKWD_CTL_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CKWD_CTL_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CKWD_CTL_2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CKSK_CTL_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TEST_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TEST_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_STATUS_0)] = RD_REG,
+ [WSA883X_REG(WSA883X_STATUS_1)] = RD_REG,
+ [WSA883X_REG(WSA883X_PAGE_REGISTER)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CHIP_ID0)] = RD_REG,
+ [WSA883X_REG(WSA883X_CHIP_ID1)] = RD_REG,
+ [WSA883X_REG(WSA883X_CHIP_ID2)] = RD_REG,
+ [WSA883X_REG(WSA883X_CHIP_ID3)] = RD_REG,
+ [WSA883X_REG(WSA883X_BUS_ID)] = RD_REG,
+ [WSA883X_REG(WSA883X_CDC_RST_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TOP_CLK_CFG)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_PATH_MODE)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_CLK_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SWR_RESET_EN)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PA_FSM_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PA_FSM_TIMER0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PA_FSM_TIMER1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PA_FSM_STA)] = RD_REG,
+ [WSA883X_REG(WSA883X_PA_FSM_ERR_COND)] = RD_REG,
+ [WSA883X_REG(WSA883X_PA_FSM_MSK)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PA_FSM_BYP)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TADC_VALUE_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TEMP_DETECT_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TEMP_MSB)] = RD_REG,
+ [WSA883X_REG(WSA883X_TEMP_LSB)] = RD_REG,
+ [WSA883X_REG(WSA883X_TEMP_CONFIG0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TEMP_CONFIG1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_VBAT_ADC_FLT_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_VBAT_DIN_MSB)] = RD_REG,
+ [WSA883X_REG(WSA883X_VBAT_DIN_LSB)] = RD_REG,
+ [WSA883X_REG(WSA883X_VBAT_DOUT)] = RD_REG,
+ [WSA883X_REG(WSA883X_SDM_PDM9_LSB)] = RD_REG,
+ [WSA883X_REG(WSA883X_SDM_PDM9_MSB)] = RD_REG,
+ [WSA883X_REG(WSA883X_CDC_RX_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_A1_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_A1_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_A2_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_A2_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_A3_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_A3_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_A4_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_A4_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_A5_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_A5_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_A6_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_A7_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_C_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_C_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_C_2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_C_3)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_R1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_R2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_R3)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_R4)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_R5)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_R6)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_DSM_R7)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_GAIN_PDM_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_GAIN_PDM_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CDC_SPK_GAIN_PDM_2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PDM_WD_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DEM_BYPASS_DATA0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DEM_BYPASS_DATA1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DEM_BYPASS_DATA2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DEM_BYPASS_DATA3)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_LRA_PER_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_LRA_PER_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_DELTA_THETA_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_DELTA_THETA_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_DIRECT_AMP_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_DIRECT_AMP_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP0_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP0_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP1_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP1_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP2_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP2_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP3_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP3_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP4_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP4_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP5_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP5_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP6_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP6_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP7_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PTRN_AMP7_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PER_0_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PER_2_3)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PER_4_5)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_WAVG_PER_6_7)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DRE_CTL_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DRE_CTL_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CLSH_CTL_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CLSH_CTL_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CLSH_V_HD_PA)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CLSH_V_PA_MIN)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CLSH_OVRD_VAL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CLSH_HARD_MAX)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CLSH_SOFT_MAX)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_CLSH_SIG_DP)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TAGC_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TAGC_TIME)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TAGC_E2E_GAIN)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TAGC_FORCE_VAL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_VAGC_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_VAGC_TIME)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_VAGC_ATTN_LVL_1_2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_VAGC_ATTN_LVL_3)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_INTR_MODE)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_INTR_MASK0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_INTR_MASK1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_INTR_STATUS0)] = RD_REG,
+ [WSA883X_REG(WSA883X_INTR_STATUS1)] = RD_REG,
+ [WSA883X_REG(WSA883X_INTR_CLEAR0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_INTR_CLEAR1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_INTR_LEVEL0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_INTR_LEVEL1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_INTR_SET0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_INTR_SET1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_INTR_TEST0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_INTR_TEST1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_CTRL0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_CTRL1)] = RD_REG,
+ [WSA883X_REG(WSA883X_HDRIVE_CTL_GROUP1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PIN_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PIN_CTL_OE)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PIN_WDATA_IOPAD)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PIN_STATUS)] = RD_REG,
+ [WSA883X_REG(WSA883X_I2C_SLAVE_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PDM_TEST_MODE)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_ATE_TEST_MODE)] = RD_REG,
+ [WSA883X_REG(WSA883X_DRE_TEST)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DIG_DEBUG_MODE)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DIG_DEBUG_SEL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_DIG_DEBUG_EN)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SWR_HM_TEST0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SWR_HM_TEST1)] = RD_REG,
+ [WSA883X_REG(WSA883X_SWR_PAD_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TEMP_DETECT_DBG_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TEMP_DEBUG_MSB)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TEMP_DEBUG_LSB)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SAMPLE_EDGE_SEL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_TEST_MODE_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_IOPAD_CTL)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPARE_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPARE_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SPARE_2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_SCODE)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_PAGE_REGISTER)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_3)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_4)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_5)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_6)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_7)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_8)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_9)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_10)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_11)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_12)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_13)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_14)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_15)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_16)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_17)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_18)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_19)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_20)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_21)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_22)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_23)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_24)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_25)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_26)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_27)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_28)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_29)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_30)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_31)] = RD_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_SCODE)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_OTP_REG_63)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_0)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_1)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_2)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_3)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_4)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_5)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_6)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_7)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_8)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_9)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_10)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_11)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_12)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_13)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_14)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_15)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_16)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_17)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_18)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_19)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_20)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_21)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_22)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_23)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_24)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_25)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_26)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_27)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_28)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_29)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_30)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_31)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_32)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_33)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_34)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_35)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_36)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_37)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_38)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_39)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_40)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_41)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_42)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_43)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_44)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_45)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_46)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_47)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_48)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_49)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_50)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_51)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_52)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_53)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_54)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_55)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_56)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_57)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_58)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_59)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_60)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_61)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_62)] = RD_WR_REG,
+ [WSA883X_REG(WSA883X_EMEM_63)] = RD_WR_REG,
+};
diff --git a/asoc/codecs/wsa883x/wsa883x-temp-sensor.c b/asoc/codecs/wsa883x/wsa883x-temp-sensor.c
new file mode 100644
index 0000000..a328c75
--- /dev/null
+++ b/asoc/codecs/wsa883x/wsa883x-temp-sensor.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2015, 2017-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/suspend.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/thermal.h>
+#include <sound/soc.h>
+#include "wsa883x-temp-sensor.h"
+
+#define T1_TEMP -10
+#define T2_TEMP 150
+#define LOW_TEMP_THRESHOLD 5
+#define HIGH_TEMP_THRESHOLD 45
+#define TEMP_INVALID 0xFFFF
+#define WSA883X_TEMP_RETRY 3
+/*
+ * wsa883x_get_temp - get wsa temperature
+ * @thermal: thermal zone device
+ * @temp: temperature value
+ *
+ * Get the temperature of wsa883x.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int wsa883x_get_temp(struct thermal_zone_device *thermal,
+ int *temp)
+{
+ struct wsa883x_tz_priv *pdata;
+ struct snd_soc_component *component;
+ struct wsa_temp_register reg;
+ int dmeas, d1, d2;
+ int ret = 0;
+ int temp_val;
+ int t1 = T1_TEMP;
+ int t2 = T2_TEMP;
+ u8 retry = WSA883X_TEMP_RETRY;
+
+ if (!thermal)
+ return -EINVAL;
+
+ if (thermal->devdata) {
+ pdata = thermal->devdata;
+ if (pdata->component) {
+ component = pdata->component;
+ } else {
+ pr_err("%s: codec is NULL\n", __func__);
+ return -EINVAL;
+ }
+ } else {
+ pr_err("%s: pdata is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (atomic_cmpxchg(&pdata->is_suspend_spk, 1, 0)) {
+ /*
+ * get_temp query happens as part of POST_PM_SUSPEND
+ * from thermal core. To avoid calls to slimbus
+ * as part of this thermal query, return default temp
+ * and reset the suspend flag.
+ */
+ if (!pdata->t0_init) {
+ if (temp)
+ *temp = pdata->curr_temp;
+ return 0;
+ }
+ }
+
+temp_retry:
+ if (pdata->wsa_temp_reg_read) {
+ ret = pdata->wsa_temp_reg_read(component, ®);
+ if (ret) {
+ pr_err("%s: temp read failed: %d, current temp: %d\n",
+ __func__, ret, pdata->curr_temp);
+ if (temp)
+ *temp = pdata->curr_temp;
+ return 0;
+ }
+ } else {
+ pr_err("%s: wsa_temp_reg_read is NULL\n", __func__);
+ return -EINVAL;
+ }
+ /*
+ * Temperature register values are expected to be in the
+ * following range.
+ * d1_msb = 68 - 92 and d1_lsb = 0, 64, 128, 192
+ * d2_msb = 185 -218 and d2_lsb = 0, 64, 128, 192
+ */
+ if ((reg.d1_msb < 68 || reg.d1_msb > 92) ||
+ (!(reg.d1_lsb == 0 || reg.d1_lsb == 64 || reg.d1_lsb == 128 ||
+ reg.d1_lsb == 192)) ||
+ (reg.d2_msb < 185 || reg.d2_msb > 218) ||
+ (!(reg.d2_lsb == 0 || reg.d2_lsb == 64 || reg.d2_lsb == 128 ||
+ reg.d2_lsb == 192))) {
+ printk_ratelimited("%s: Temperature registers[%d %d %d %d] are out of range\n",
+ __func__, reg.d1_msb, reg.d1_lsb, reg.d2_msb,
+ reg.d2_lsb);
+ }
+ dmeas = ((reg.dmeas_msb << 0x8) | reg.dmeas_lsb) >> 0x6;
+ d1 = ((reg.d1_msb << 0x8) | reg.d1_lsb) >> 0x6;
+ d2 = ((reg.d2_msb << 0x8) | reg.d2_lsb) >> 0x6;
+
+ if (d1 == d2)
+ temp_val = TEMP_INVALID;
+ else
+ temp_val = t1 + (((dmeas - d1) * (t2 - t1))/(d2 - d1));
+
+ if (temp_val <= LOW_TEMP_THRESHOLD ||
+ temp_val >= HIGH_TEMP_THRESHOLD) {
+ pr_debug("%s: T0: %d is out of range[%d, %d]\n", __func__,
+ temp_val, LOW_TEMP_THRESHOLD, HIGH_TEMP_THRESHOLD);
+ if (retry--) {
+ msleep(20);
+ goto temp_retry;
+ }
+ }
+ pdata->curr_temp = temp_val;
+
+ if (temp)
+ *temp = temp_val;
+ pr_debug("%s: t0 measured: %d dmeas = %d, d1 = %d, d2 = %d\n",
+ __func__, temp_val, dmeas, d1, d2);
+ return ret;
+}
+EXPORT_SYMBOL(wsa883x_get_temp);
+
+static struct thermal_zone_device_ops wsa883x_thermal_ops = {
+ .get_temp = wsa883x_get_temp,
+};
+
+
+static int wsa883x_pm_notify(struct notifier_block *nb,
+ unsigned long mode, void *_unused)
+{
+ struct wsa883x_tz_priv *pdata =
+ container_of(nb, struct wsa883x_tz_priv, pm_nb);
+
+ switch (mode) {
+ case PM_SUSPEND_PREPARE:
+ atomic_set(&pdata->is_suspend_spk, 1);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+int wsa883x_init_thermal(struct wsa883x_tz_priv *tz_pdata)
+{
+ struct thermal_zone_device *tz_dev;
+
+ if (tz_pdata == NULL) {
+ pr_err("%s: thermal pdata is NULL\n", __func__);
+ return -EINVAL;
+ }
+ /* Register with the thermal zone */
+ tz_dev = thermal_zone_device_register(tz_pdata->name,
+ 0, 0, tz_pdata,
+ &wsa883x_thermal_ops, NULL, 0, 0);
+ if (IS_ERR(tz_dev)) {
+ pr_err("%s: thermal device register failed.\n", __func__);
+ return -EINVAL;
+ }
+ tz_pdata->tz_dev = tz_dev;
+ tz_pdata->pm_nb.notifier_call = wsa883x_pm_notify;
+ register_pm_notifier(&tz_pdata->pm_nb);
+ atomic_set(&tz_pdata->is_suspend_spk, 0);
+
+ return 0;
+}
+EXPORT_SYMBOL(wsa883x_init_thermal);
+
+void wsa883x_deinit_thermal(struct thermal_zone_device *tz_dev)
+{
+ struct wsa883x_tz_priv *pdata;
+
+ if (tz_dev && tz_dev->devdata) {
+ pdata = tz_dev->devdata;
+ if (pdata)
+ unregister_pm_notifier(&pdata->pm_nb);
+ }
+ if (tz_dev)
+ thermal_zone_device_unregister(tz_dev);
+}
+EXPORT_SYMBOL(wsa883x_deinit_thermal);
diff --git a/asoc/codecs/wsa883x/wsa883x-temp-sensor.h b/asoc/codecs/wsa883x/wsa883x-temp-sensor.h
new file mode 100644
index 0000000..5a8c387
--- /dev/null
+++ b/asoc/codecs/wsa883x/wsa883x-temp-sensor.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2015, 2018-2019, The Linux Foundation. All rights reserved.
+ */
+#ifndef WSA883X_TEMP_SENSOR_H
+#define WSA883X_TEMP_SENSOR_H
+
+#include <linux/thermal.h>
+#include <sound/soc.h>
+
+struct wsa_temp_register {
+ u8 d1_msb;
+ u8 d1_lsb;
+ u8 d2_msb;
+ u8 d2_lsb;
+ u8 dmeas_msb;
+ u8 dmeas_lsb;
+};
+typedef int32_t (*wsa_temp_register_read)(struct snd_soc_component *component,
+ struct wsa_temp_register *wsa_temp_reg);
+struct wsa883x_tz_priv {
+ struct thermal_zone_device *tz_dev;
+ struct snd_soc_component *component;
+ struct wsa_temp_register *wsa_temp_reg;
+ char name[80];
+ wsa_temp_register_read wsa_temp_reg_read;
+ struct notifier_block pm_nb;
+ atomic_t is_suspend_spk;
+ int t0_init;
+ int curr_temp;
+};
+
+int wsa883x_get_temp(struct thermal_zone_device *tz_dev, int *temp);
+int wsa883x_init_thermal(struct wsa883x_tz_priv *tz_pdata);
+void wsa883x_deinit_thermal(struct thermal_zone_device *tz_dev);
+#endif
diff --git a/asoc/codecs/wsa883x/wsa883x.c b/asoc/codecs/wsa883x/wsa883x.c
new file mode 100644
index 0000000..7869a2b
--- /dev/null
+++ b/asoc/codecs/wsa883x/wsa883x.c
@@ -0,0 +1,1305 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/bitops.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/debugfs.h>
+#include <soc/soundwire.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <asoc/msm-cdc-pinctrl.h>
+#include "wsa883x.h"
+#include "internal.h"
+
+#define T1_TEMP -10
+#define T2_TEMP 150
+#define LOW_TEMP_THRESHOLD 5
+#define HIGH_TEMP_THRESHOLD 45
+#define TEMP_INVALID 0xFFFF
+#define WSA883X_TEMP_RETRY 3
+
+enum {
+ WSA_4OHMS =4,
+ WSA_8OHMS = 8,
+ WSA_16OHMS = 16,
+ WSA_32OHMS = 32,
+};
+
+struct wsa_temp_register {
+ u8 d1_msb;
+ u8 d1_lsb;
+ u8 d2_msb;
+ u8 d2_lsb;
+ u8 dmeas_msb;
+ u8 dmeas_lsb;
+};
+
+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)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static int get_parameters(char *buf, u32 *param1, int num_of_par)
+{
+ char *token;
+ int base, cnt;
+
+ token = strsep(&buf, " ");
+ for (cnt = 0; cnt < num_of_par; cnt++) {
+ if (token) {
+ if ((token[1] == 'x') || (token[1] == 'X'))
+ base = 16;
+ else
+ base = 10;
+
+ if (kstrtou32(token, base, ¶m1[cnt]) != 0)
+ return -EINVAL;
+
+ token = strsep(&buf, " ");
+ } else {
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static bool is_swr_slave_reg_readable(int reg)
+{
+ int ret = true;
+
+ if (((reg > 0x46) && (reg < 0x4A)) ||
+ ((reg > 0x4A) && (reg < 0x50)) ||
+ ((reg > 0x55) && (reg < 0xD0)) ||
+ ((reg > 0xD0) && (reg < 0xE0)) ||
+ ((reg > 0xE0) && (reg < 0xF0)) ||
+ ((reg > 0xF0) && (reg < 0x100)) ||
+ ((reg > 0x105) && (reg < 0x120)) ||
+ ((reg > 0x205) && (reg < 0x220)) ||
+ ((reg > 0x305) && (reg < 0x320)) ||
+ ((reg > 0x405) && (reg < 0x420)) ||
+ ((reg > 0x128) && (reg < 0x130)) ||
+ ((reg > 0x228) && (reg < 0x230)) ||
+ ((reg > 0x328) && (reg < 0x330)) ||
+ ((reg > 0x428) && (reg < 0x430)) ||
+ ((reg > 0x138) && (reg < 0x205)) ||
+ ((reg > 0x238) && (reg < 0x305)) ||
+ ((reg > 0x338) && (reg < 0x405)) ||
+ ((reg > 0x405) && (reg < 0xF00)) ||
+ ((reg > 0xF05) && (reg < 0xF20)) ||
+ ((reg > 0xF25) && (reg < 0xF30)) ||
+ ((reg > 0xF35) && (reg < 0x2000)))
+ ret = false;
+
+ return ret;
+}
+
+static ssize_t swr_slave_reg_show(struct swr_device *pdev, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int i, reg_val, len;
+ ssize_t total = 0;
+ char tmp_buf[SWR_SLV_MAX_BUF_LEN];
+
+ if (!ubuf || !ppos)
+ return 0;
+
+ for (i = (((int) *ppos/BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR);
+ i <= SWR_SLV_MAX_REG_ADDR; i++) {
+ if (!is_swr_slave_reg_readable(i))
+ continue;
+ swr_read(pdev, pdev->dev_num, i, ®_val, 1);
+ len = snprintf(tmp_buf, 25, "0x%.3x: 0x%.2x\n", i,
+ (reg_val & 0xFF));
+ if ((total + len) >= count - 1)
+ break;
+ if (copy_to_user((ubuf + total), tmp_buf, len)) {
+ pr_err("%s: fail to copy reg dump\n", __func__);
+ total = -EFAULT;
+ goto copy_err;
+ }
+ total += len;
+ *ppos += len;
+ }
+
+copy_err:
+ *ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE;
+ return total;
+}
+
+static ssize_t codec_debug_dump(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct swr_device *pdev;
+
+ if (!count || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ pdev = file->private_data;
+ if (!pdev)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ return swr_slave_reg_show(pdev, ubuf, count, ppos);
+}
+
+static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char lbuf[SWR_SLV_RD_BUF_LEN];
+ struct swr_device *pdev = NULL;
+ struct wsa883x_priv *wsa883x = NULL;
+
+ if (!count || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ pdev = file->private_data;
+ if (!pdev)
+ return -EINVAL;
+
+ wsa883x = swr_get_dev_data(pdev);
+ if (!wsa883x)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ snprintf(lbuf, sizeof(lbuf), "0x%x\n",
+ (wsa883x->read_data & 0xFF));
+
+ return simple_read_from_buffer(ubuf, count, ppos, lbuf,
+ strnlen(lbuf, 7));
+}
+
+static ssize_t codec_debug_peek_write(struct file *file,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char lbuf[SWR_SLV_WR_BUF_LEN];
+ int rc = 0;
+ u32 param[5];
+ struct swr_device *pdev = NULL;
+ struct wsa883x_priv *wsa883x = NULL;
+
+ if (!cnt || !file || !ppos || !ubuf)
+ return -EINVAL;
+
+ pdev = file->private_data;
+ if (!pdev)
+ return -EINVAL;
+
+ wsa883x = swr_get_dev_data(pdev);
+ if (!wsa883x)
+ return -EINVAL;
+
+ if (*ppos < 0)
+ return -EINVAL;
+
+ if (cnt > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, cnt);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[cnt] = '\0';
+ rc = get_parameters(lbuf, param, 1);
+ if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0)))
+ return -EINVAL;
+ swr_read(pdev, pdev->dev_num, param[0], &wsa883x->read_data, 1);
+ if (rc == 0)
+ rc = cnt;
+ else
+ pr_err("%s: rc = %d\n", __func__, rc);
+
+ return rc;
+}
+
+static ssize_t codec_debug_write(struct file *file,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char lbuf[SWR_SLV_WR_BUF_LEN];
+ int rc = 0;
+ u32 param[5];
+ struct swr_device *pdev;
+
+ if (!file || !ppos || !ubuf)
+ return -EINVAL;
+
+ pdev = file->private_data;
+ if (!pdev)
+ return -EINVAL;
+
+ if (cnt > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, cnt);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[cnt] = '\0';
+ rc = get_parameters(lbuf, param, 2);
+ if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) &&
+ (param[1] <= 0xFF) && (rc == 0)))
+ return -EINVAL;
+ swr_write(pdev, pdev->dev_num, param[0], ¶m[1]);
+ if (rc == 0)
+ rc = cnt;
+ else
+ pr_err("%s: rc = %d\n", __func__, rc);
+
+ return rc;
+}
+
+static const struct file_operations codec_debug_write_ops = {
+ .open = codec_debug_open,
+ .write = codec_debug_write,
+};
+
+static const struct file_operations codec_debug_read_ops = {
+ .open = codec_debug_open,
+ .read = codec_debug_read,
+ .write = codec_debug_peek_write,
+};
+
+static const struct file_operations codec_debug_dump_ops = {
+ .open = codec_debug_open,
+ .read = codec_debug_dump,
+};
+#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"
+};
+
+static const struct soc_enum wsa_dev_mode_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa_dev_mode_text), wsa_dev_mode_text);
+
+static int wsa_dev_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wsa883x->dev_mode;
+
+ dev_dbg(component->dev, "%s: mode = 0x%x\n", __func__,
+ wsa883x->dev_mode);
+
+ return 0;
+}
+
+static int wsa_dev_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ wsa883x->dev_mode = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static const char * const wsa_pa_gain_text[] = {
+ "G_18_DB", "G_16P5_DB", "G_15_DB", "G_13P5_DB", "G_12_DB", "G_10P5_DB",
+ "G_9_DB", "G_7P5_DB", "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB",
+ "G_0_DB"
+};
+
+static const struct soc_enum wsa_pa_gain_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa_pa_gain_text), wsa_pa_gain_text);
+
+static int wsa_pa_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wsa883x->pa_gain;
+
+ dev_dbg(component->dev, "%s: PA gain = 0x%x\n", __func__,
+ wsa883x->pa_gain);
+
+ return 0;
+}
+
+static int wsa_pa_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ wsa883x->pa_gain = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int wsa883x_get_mute(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wsa883x->pa_mute;
+
+ return 0;
+}
+
+static int wsa883x_set_mute(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+ int value = ucontrol->value.integer.value[0];
+
+ dev_dbg(component->dev, "%s: mute current %d, new %d\n",
+ __func__, wsa883x->pa_mute, value);
+
+ wsa883x->pa_mute = value;
+
+ return 0;
+}
+
+static int wsa_get_temp(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ int temp = 0;
+
+ wsa883x_get_temperature(component, &temp);
+ ucontrol->value.integer.value[0] = temp;
+
+ return 0;
+}
+
+static ssize_t wsa883x_codec_version_read(struct snd_info_entry *entry,
+ void *file_private_data, struct file *file,
+ char __user *buf, size_t count, loff_t pos)
+{
+ struct wsa883x_priv *wsa883x;
+ char buffer[WSA883X_VERSION_ENTRY_SIZE];
+ int len = 0;
+
+ wsa883x = (struct wsa883x_priv *) entry->private_data;
+ if (!wsa883x) {
+ pr_err("%s: wsa883x priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ len = snprintf(buffer, sizeof(buffer), "WSA883X-SOUNDWIRE_1_0\n");
+
+ return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops wsa883x_codec_info_ops = {
+ .read = wsa883x_codec_version_read,
+};
+
+/*
+ * wsa883x_codec_info_create_codec_entry - creates wsa883x module
+ * @codec_root: The parent directory
+ * @component: Codec instance
+ *
+ * Creates wsa883x module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int wsa883x_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_component *component)
+{
+ struct snd_info_entry *version_entry;
+ struct wsa883x_priv *wsa883x;
+ struct snd_soc_card *card;
+ char name[80];
+
+ if (!codec_root || !component)
+ return -EINVAL;
+
+ wsa883x = snd_soc_component_get_drvdata(component);
+ card = component->card;
+ snprintf(name, sizeof(name), "%s.%x", "wsa883x",
+ (u32)wsa883x->swr_slave->addr);
+
+ wsa883x->entry = snd_info_create_subdir(codec_root->module,
+ (const char *)name,
+ codec_root);
+ if (!wsa883x->entry) {
+ dev_dbg(component->dev, "%s: failed to create wsa883x entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ version_entry = snd_info_create_card_entry(card->snd_card,
+ "version",
+ wsa883x->entry);
+ if (!version_entry) {
+ dev_dbg(component->dev, "%s: failed to create wsa883x version entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ version_entry->private_data = wsa883x;
+ version_entry->size = WSA883X_VERSION_ENTRY_SIZE;
+ version_entry->content = SNDRV_INFO_CONTENT_DATA;
+ version_entry->c.ops = &wsa883x_codec_info_ops;
+
+ if (snd_info_register(version_entry) < 0) {
+ snd_info_free_entry(version_entry);
+ return -ENOMEM;
+ }
+ wsa883x->version_entry = version_entry;
+
+ return 0;
+}
+EXPORT_SYMBOL(wsa883x_codec_info_create_codec_entry);
+
+static void wsa883x_regcache_sync(struct wsa883x_priv *wsa883x)
+{
+ mutex_lock(&wsa883x->res_lock);
+ regcache_mark_dirty(wsa883x->regmap);
+ regcache_sync(wsa883x->regmap);
+ mutex_unlock(&wsa883x->res_lock);
+}
+
+static int wsa883x_get_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wsa883x->comp_enable;
+ return 0;
+}
+
+static int wsa883x_set_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+ int value = ucontrol->value.integer.value[0];
+
+ dev_dbg(component->dev, "%s: Compander enable current %d, new %d\n",
+ __func__, wsa883x->comp_enable, value);
+ wsa883x->comp_enable = value;
+ return 0;
+}
+
+static int wsa883x_get_visense(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wsa883x->visense_enable;
+ return 0;
+}
+
+static int wsa883x_set_visense(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+ int value = ucontrol->value.integer.value[0];
+
+ dev_dbg(component->dev, "%s: VIsense enable current %d, new %d\n",
+ __func__, wsa883x->visense_enable, value);
+ wsa883x->visense_enable = value;
+ return 0;
+}
+
+static int wsa883x_get_ext_vdd_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wsa883x->ext_vdd_spk;
+
+ return 0;
+}
+
+static int wsa883x_put_ext_vdd_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+ int value = ucontrol->value.integer.value[0];
+
+ dev_dbg(component->dev, "%s: Ext VDD SPK enable current %d, new %d\n",
+ __func__, wsa883x->ext_vdd_spk, value);
+ wsa883x->ext_vdd_spk = value;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new wsa883x_snd_controls[] = {
+ SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum,
+ wsa_pa_gain_get, wsa_pa_gain_put),
+
+ SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0,
+ wsa883x_get_mute, wsa883x_set_mute),
+
+ SOC_SINGLE_EXT("WSA Temp", SND_SOC_NOPM, 0, 1, 0,
+ wsa_get_temp, NULL),
+
+ SOC_ENUM_EXT("WSA MODE", wsa_dev_mode_enum,
+ wsa_dev_mode_get, wsa_dev_mode_put),
+
+ SOC_SINGLE_EXT("COMP Switch", SND_SOC_NOPM, 0, 1, 0,
+ wsa883x_get_compander, wsa883x_set_compander),
+
+ SOC_SINGLE_EXT("VISENSE Switch", SND_SOC_NOPM, 0, 1, 0,
+ wsa883x_get_visense, wsa883x_set_visense),
+
+ SOC_SINGLE_EXT("External VDD_SPK", SND_SOC_NOPM, 0, 1, 0,
+ wsa883x_get_ext_vdd_spk, wsa883x_put_ext_vdd_spk),
+};
+
+static const struct snd_kcontrol_new swr_dac_port[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static int wsa883x_set_port(struct snd_soc_component *component, int port_idx,
+ u8 *port_id, u8 *num_ch, u8 *ch_mask, u32 *ch_rate,
+ u8 *port_type)
+{
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ *port_id = wsa883x->port[port_idx].port_id;
+ *num_ch = wsa883x->port[port_idx].num_ch;
+ *ch_mask = wsa883x->port[port_idx].ch_mask;
+ *ch_rate = wsa883x->port[port_idx].ch_rate;
+ *port_type = wsa883x->port[port_idx].port_type;
+ return 0;
+}
+
+static int wsa883x_enable_swr_dac_port(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 wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+ u8 port_id[WSA883X_MAX_SWR_PORTS];
+ u8 num_ch[WSA883X_MAX_SWR_PORTS];
+ u8 ch_mask[WSA883X_MAX_SWR_PORTS];
+ u32 ch_rate[WSA883X_MAX_SWR_PORTS];
+ u8 port_type[WSA883X_MAX_SWR_PORTS];
+ u8 num_port = 0;
+
+ dev_dbg(component->dev, "%s: event %d name %s\n", __func__,
+ event, w->name);
+ if (wsa883x == NULL)
+ return -EINVAL;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wsa883x_set_port(component, SWR_DAC_PORT,
+ &port_id[num_port], &num_ch[num_port],
+ &ch_mask[num_port], &ch_rate[num_port],
+ &port_type[num_port]);
+ ++num_port;
+
+ if (wsa883x->comp_enable) {
+ wsa883x_set_port(component, SWR_COMP_PORT,
+ &port_id[num_port], &num_ch[num_port],
+ &ch_mask[num_port], &ch_rate[num_port],
+ &port_type[num_port]);
+ ++num_port;
+ }
+ if (wsa883x->visense_enable) {
+ wsa883x_set_port(component, SWR_VISENSE_PORT,
+ &port_id[num_port], &num_ch[num_port],
+ &ch_mask[num_port], &ch_rate[num_port],
+ &port_type[num_port]);
+ ++num_port;
+ }
+ swr_connect_port(wsa883x->swr_slave, &port_id[0], num_port,
+ &ch_mask[0], &ch_rate[0], &num_ch[0],
+ &port_type[0]);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ swr_slvdev_datapath_control(wsa883x->swr_slave,
+ wsa883x->swr_slave->dev_num,
+ true);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ swr_slvdev_datapath_control(wsa883x->swr_slave,
+ wsa883x->swr_slave->dev_num,
+ false);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wsa883x_set_port(component, SWR_DAC_PORT,
+ &port_id[num_port], &num_ch[num_port],
+ &ch_mask[num_port], &ch_rate[num_port],
+ &port_type[num_port]);
+ ++num_port;
+
+ if (wsa883x->comp_enable) {
+ wsa883x_set_port(component, SWR_COMP_PORT,
+ &port_id[num_port], &num_ch[num_port],
+ &ch_mask[num_port], &ch_rate[num_port],
+ &port_type[num_port]);
+ ++num_port;
+ }
+ if (wsa883x->visense_enable) {
+ wsa883x_set_port(component, SWR_VISENSE_PORT,
+ &port_id[num_port], &num_ch[num_port],
+ &ch_mask[num_port], &ch_rate[num_port],
+ &port_type[num_port]);
+ ++num_port;
+ }
+ swr_disconnect_port(wsa883x->swr_slave, &port_id[0], num_port,
+ &ch_mask[0], &port_type[0]);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int wsa883x_spkr_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 wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+ int min_gain, max_gain;
+
+ dev_dbg(component->dev, "%s: %s %d\n", __func__, w->name, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* TODO Vote for Global PA */
+ break;
+
+ case SND_SOC_DAPM_POST_PMU:
+ /* Force remove group */
+ swr_remove_from_group(wsa883x->swr_slave,
+ wsa883x->swr_slave->dev_num);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* TODO Unvote for Global PA */
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget wsa883x_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("IN"),
+ SND_SOC_DAPM_MIXER_E("SWR DAC_Port", SND_SOC_NOPM, 0, 0, swr_dac_port,
+ ARRAY_SIZE(swr_dac_port), wsa883x_enable_swr_dac_port,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SPK("SPKR", wsa883x_spkr_event),
+};
+
+static const struct snd_soc_dapm_route wsa883x_audio_map[] = {
+ {"SWR DAC_Port", "Switch", "IN"},
+ {"SPKR", NULL, "SWR DAC_Port"},
+};
+
+int wsa883x_set_channel_map(struct snd_soc_component *component, u8 *port,
+ u8 num_port, unsigned int *ch_mask,
+ unsigned int *ch_rate, u8 *port_type)
+{
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+ int i;
+
+ if (!port || !ch_mask || !ch_rate ||
+ (num_port > WSA883X_MAX_SWR_PORTS)) {
+ dev_err(component->dev,
+ "%s: Invalid port=%pK, ch_mask=%pK, ch_rate=%pK\n",
+ __func__, port, ch_mask, ch_rate);
+ return -EINVAL;
+ }
+ for (i = 0; i < num_port; i++) {
+ wsa883x->port[i].port_id = port[i];
+ wsa883x->port[i].ch_mask = ch_mask[i];
+ wsa883x->port[i].ch_rate = ch_rate[i];
+ wsa883x->port[i].num_ch = __sw_hweight8(ch_mask[i]);
+ if (port_type)
+ wsa883x->port[i].port_type = port_type[i];
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(wsa883x_set_channel_map);
+
+static void wsa883x_codec_init(struct snd_soc_component *component)
+{
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ if (!wsa883x)
+ return;
+
+}
+
+static int32_t wsa883x_temp_reg_read(struct snd_soc_component *component,
+ struct wsa_temp_register *wsa_temp_reg)
+{
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ if (!wsa883x) {
+ dev_err(component->dev, "%s: wsa883x is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&wsa883x->res_lock);
+
+ /* TODO Vote for global PA */
+ snd_soc_component_update_bits(component, WSA883X_TADC_VALUE_CTL,
+ 0x01, 0x00);
+ wsa_temp_reg->dmeas_msb = snd_soc_component_read32(
+ component, WSA883X_TEMP_MSB);
+ wsa_temp_reg->dmeas_lsb = snd_soc_component_read32(
+ component, WSA883X_TEMP_LSB);
+ snd_soc_component_update_bits(component, WSA883X_TADC_VALUE_CTL,
+ 0x01, 0x01);
+ wsa_temp_reg->d1_msb = snd_soc_component_read32(
+ component, WSA883X_OTP_REG_1);
+ wsa_temp_reg->d1_lsb = snd_soc_component_read32(
+ component, WSA883X_OTP_REG_2);
+ wsa_temp_reg->d2_msb = snd_soc_component_read32(
+ component, WSA883X_OTP_REG_3);
+ wsa_temp_reg->d2_lsb = snd_soc_component_read32(
+ component, WSA883X_OTP_REG_4);
+
+ /* TODO Unvote for global PA */
+ mutex_unlock(&wsa883x->res_lock);
+
+ return 0;
+}
+
+static int wsa883x_get_temperature(struct snd_soc_component *component,
+ int *temp)
+{
+ struct snd_soc_component *component;
+ struct wsa_temp_register reg;
+ int dmeas, d1, d2;
+ int ret = 0;
+ int temp_val = 0;
+ int t1 = T1_TEMP;
+ int t2 = T2_TEMP;
+ u8 retry = WSA883X_TEMP_RETRY;
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ if (!wsa883x)
+ return -EINVAL;
+
+ do {
+ ret = wsa883x_temp_reg_read(component, ®)
+ if (ret) {
+ pr_err("%s: temp read failed: %d, current temp: %d\n",
+ __func__, ret, wsa883x->curr_temp);
+ if (temp)
+ *temp = wsa883x->curr_temp;
+ return 0;
+ }
+ /*
+ * Temperature register values are expected to be in the
+ * following range.
+ * d1_msb = 68 - 92 and d1_lsb = 0, 64, 128, 192
+ * d2_msb = 185 -218 and d2_lsb = 0, 64, 128, 192
+ */
+ if ((reg.d1_msb < 68 || reg.d1_msb > 92) ||
+ (!(reg.d1_lsb == 0 || reg.d1_lsb == 64 || reg.d1_lsb == 128 ||
+ reg.d1_lsb == 192)) ||
+ (reg.d2_msb < 185 || reg.d2_msb > 218) ||
+ (!(reg.d2_lsb == 0 || reg.d2_lsb == 64 || reg.d2_lsb == 128 ||
+ reg.d2_lsb == 192))) {
+ printk_ratelimited("%s: Temperature registers[%d %d %d %d] are out of range\n",
+ __func__, reg.d1_msb, reg.d1_lsb, reg.d2_msb,
+ reg.d2_lsb);
+ }
+ dmeas = ((reg.dmeas_msb << 0x8) | reg.dmeas_lsb) >> 0x6;
+ d1 = ((reg.d1_msb << 0x8) | reg.d1_lsb) >> 0x6;
+ d2 = ((reg.d2_msb << 0x8) | reg.d2_lsb) >> 0x6;
+
+ if (d1 == d2)
+ temp_val = TEMP_INVALID;
+ else
+ temp_val = t1 + (((dmeas - d1) * (t2 - t1))/(d2 - d1));
+
+ if (temp_val <= LOW_TEMP_THRESHOLD ||
+ temp_val >= HIGH_TEMP_THRESHOLD) {
+ pr_debug("%s: T0: %d is out of range[%d, %d]\n", __func__,
+ temp_val, LOW_TEMP_THRESHOLD, HIGH_TEMP_THRESHOLD);
+ if (retry--)
+ msleep(10);
+ } else {
+ break;
+ }
+ } while (retry);
+
+ wsa883x->curr_temp = temp_val;
+ if (temp)
+ *temp = temp_val;
+ pr_debug("%s: t0 measured: %d dmeas = %d, d1 = %d, d2 = %d\n",
+ __func__, temp_val, dmeas, d1, d2);
+
+ return ret;
+}
+
+static int wsa883x_codec_probe(struct snd_soc_component *component)
+{
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+ struct swr_device *dev;
+
+ if (!wsa883x)
+ return -EINVAL;
+ snd_soc_component_init_regmap(component, wsa883x->regmap);
+
+ dev = wsa883x->swr_slave;
+ wsa883x->component = component;
+ wsa883x_codec_init(component);
+ wsa883x->global_pa_cnt = 0;
+
+ return 0;
+}
+
+static void wsa883x_codec_remove(struct snd_soc_component *component)
+{
+ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+ if (!wsa883x)
+ return;
+
+ snd_soc_component_exit_regmap(component);
+
+ return;
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_wsa883x = {
+ .name = DRV_NAME,
+ .probe = wsa883x_codec_probe,
+ .remove = wsa883x_codec_remove,
+ .controls = wsa883x_snd_controls,
+ .num_controls = ARRAY_SIZE(wsa883x_snd_controls),
+ .dapm_widgets = wsa883x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wsa883x_dapm_widgets),
+ .dapm_routes = wsa883x_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(wsa883x_audio_map),
+};
+
+static int wsa883x_gpio_ctrl(struct wsa883x_priv *wsa883x, bool enable)
+{
+ int ret = 0;
+
+ if (enable)
+ ret = msm_cdc_pinctrl_select_active_state(
+ wsa883x->wsa_rst_np);
+ else
+ ret = msm_cdc_pinctrl_select_sleep_state(
+ wsa883x->wsa_rst_np);
+ if (ret != 0)
+ dev_err(wsa883x->dev,
+ "%s: Failed to turn state %d; ret=%d\n",
+ __func__, enable, ret);
+
+ return ret;
+}
+
+static int wsa883x_swr_probe(struct swr_device *pdev)
+{
+ int ret = 0;
+ struct wsa883x_priv *wsa883x;
+ u8 devnum = 0;
+ bool pin_state_current = false;
+
+ wsa883x = devm_kzalloc(&pdev->dev, sizeof(struct wsa883x_priv),
+ GFP_KERNEL);
+ if (!wsa883x)
+ return -ENOMEM;
+
+ wsa883x->wsa_rst_np = of_parse_phandle(pdev->dev.of_node,
+ "qcom,spkr-sd-n-node", 0);
+ if (!wsa883x->wsa_rst_np) {
+ dev_dbg(&pdev->dev, "%s: pinctrl not defined\n", __func__);
+ goto err;
+ }
+ swr_set_dev_data(pdev, wsa883x);
+ wsa883x->swr_slave = pdev;
+ pin_state_current = msm_cdc_pinctrl_get_state(wsa883x->wsa_rst_np);
+ wsa883x_gpio_ctrl(wsa883x, true);
+ /*
+ * Add 5msec delay to provide sufficient time for
+ * soundwire auto enumeration of slave devices as
+ * as per HW requirement.
+ */
+ usleep_range(5000, 5010);
+ 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);
+ goto dev_err;
+ }
+ pdev->dev_num = devnum;
+
+ wsa883x->regmap = devm_regmap_init_swr(pdev,
+ &wsa883x_regmap_config);
+ if (IS_ERR(wsa883x->regmap)) {
+ ret = PTR_ERR(wsa883x->regmap);
+ dev_err(&pdev->dev, "%s: regmap_init failed %d\n",
+ __func__, ret);
+ 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 err_irq;
+ }
+ mutex_init(&wsa883x->res_lock);
+
+#ifdef CONFIG_DEBUG_FS
+ if (!wsa883x->debugfs_dent) {
+ wsa883x->debugfs_dent = debugfs_create_dir(
+ dev_name(&pdev->dev), 0);
+ if (!IS_ERR(wsa883x->debugfs_dent)) {
+ wsa883x->debugfs_peek =
+ debugfs_create_file("swrslave_peek",
+ S_IFREG | 0444,
+ wsa883x->debugfs_dent,
+ (void *) pdev,
+ &codec_debug_read_ops);
+
+ wsa883x->debugfs_poke =
+ debugfs_create_file("swrslave_poke",
+ S_IFREG | 0444,
+ wsa883x->debugfs_dent,
+ (void *) pdev,
+ &codec_debug_write_ops);
+
+ wsa883x->debugfs_reg_dump =
+ debugfs_create_file(
+ "swrslave_reg_dump",
+ S_IFREG | 0444,
+ wsa883x->debugfs_dent,
+ (void *) pdev,
+ &codec_debug_dump_ops);
+ }
+}
+#endif
+
+ 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);
+ swr_remove_device(pdev);
+err:
+ return ret;
+}
+
+static int wsa883x_swr_remove(struct swr_device *pdev)
+{
+ struct wsa883x_priv *wsa883x;
+
+ wsa883x = swr_get_dev_data(pdev);
+ if (!wsa883x) {
+ 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);
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove_recursive(wsa883x->debugfs_dent);
+ wsa883x->debugfs_dent = NULL;
+#endif
+ mutex_destroy(&wsa883x->res_lock);
+ snd_soc_unregister_component(&pdev->dev);
+ swr_set_dev_data(pdev, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int wsa883x_swr_suspend(struct device *dev)
+{
+ dev_dbg(dev, "%s: system suspend\n", __func__);
+ return 0;
+}
+
+static int wsa883x_swr_resume(struct device *dev)
+{
+ struct wsa883x_priv *wsa883x = swr_get_dev_data(to_swr_device(dev));
+
+ if (!wsa883x) {
+ dev_err(dev, "%s: wsa883x private data is NULL\n", __func__);
+ return -EINVAL;
+ }
+ dev_dbg(dev, "%s: system resume\n", __func__);
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops wsa883x_swr_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(wsa883x_swr_suspend, wsa883x_swr_resume)
+};
+
+static const struct swr_device_id wsa883x_swr_id[] = {
+ {"wsa883x", 0},
+ {}
+};
+
+static const struct of_device_id wsa883x_swr_dt_match[] = {
+ {
+ .compatible = "qcom,wsa883x",
+ },
+ {}
+};
+
+static struct swr_driver wsa883x_swr_driver = {
+ .driver = {
+ .name = "wsa883x",
+ .owner = THIS_MODULE,
+ .pm = &wsa883x_swr_pm_ops,
+ .of_match_table = wsa883x_swr_dt_match,
+ },
+ .probe = wsa883x_swr_probe,
+ .remove = wsa883x_swr_remove,
+ .id_table = wsa883x_swr_id,
+};
+
+static int __init wsa883x_swr_init(void)
+{
+ return swr_driver_register(&wsa883x_swr_driver);
+}
+
+static void __exit wsa883x_swr_exit(void)
+{
+ swr_driver_unregister(&wsa883x_swr_driver);
+}
+
+module_init(wsa883x_swr_init);
+module_exit(wsa883x_swr_exit);
+
+MODULE_DESCRIPTION("WSA883x codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wsa883x/wsa883x.h b/asoc/codecs/wsa883x/wsa883x.h
new file mode 100644
index 0000000..e080134
--- /dev/null
+++ b/asoc/codecs/wsa883x/wsa883x.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _WSA883X_H
+#define _WSA883X_H
+
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/info.h>
+#include "wsa883x-registers.h"
+
+#define WSA883X_MAX_SWR_PORTS 4
+
+#if IS_ENABLED(CONFIG_SND_SOC_WSA883X)
+int wsa883x_set_channel_map(struct snd_soc_component *component,
+ u8 *port, u8 num_port, unsigned int *ch_mask,
+ unsigned int *ch_rate, u8 *port_type);
+
+
+int wsa883x_codec_info_create_codec_entry(
+ struct snd_info_entry *codec_root,
+ struct snd_soc_component *component);
+#else
+static int wsa883x_set_channel_map(struct snd_soc_component *component,
+ u8 *port, u8 num_port, unsigned int *ch_mask,
+ unsigned int *ch_rate, u8 *port_type)
+{
+ return 0;
+}
+
+static int wsa883x_codec_info_create_codec_entry(
+ struct snd_info_entry *codec_root,
+ struct snd_soc_component *component)
+{
+ return 0;
+}
+
+#endif
+
+#endif /* _WSA883X_H */
diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c
index 4347bec..4560299 100644
--- a/asoc/msm-compress-q6-v2.c
+++ b/asoc/msm-compress-q6-v2.c
@@ -408,8 +408,8 @@
gain_list[0] = volume_l;
gain_list[1] = volume_r;
gain_list[2] = volume_l;
- num_channels = 3;
- use_default = true;
+ if (use_default)
+ num_channels = 3;
rc = q6asm_set_multich_gain(prtd->audio_client, num_channels,
gain_list, chmap, use_default);
}
diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c
index 1b15444..e9d354b 100644
--- a/asoc/msm-dai-q6-v2.c
+++ b/asoc/msm-dai-q6-v2.c
@@ -3461,15 +3461,6 @@
.get = msm_dai_q6_afe_enc_cfg_get,
.put = msm_dai_q6_afe_enc_cfg_put,
},
- {
- .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
- SNDRV_CTL_ELEM_ACCESS_INACTIVE),
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
- .name = "SLIM_7_RX APTX_AD Enc Cfg",
- .info = msm_dai_q6_afe_enc_cfg_info,
- .get = msm_dai_q6_afe_enc_cfg_get,
- .put = msm_dai_q6_afe_enc_cfg_put,
- },
SOC_ENUM_EXT("AFE Input Channels", afe_chs_enum[0],
msm_dai_q6_afe_input_channel_get,
msm_dai_q6_afe_input_channel_put),
@@ -3482,7 +3473,16 @@
msm_dai_q6_afe_scrambler_mode_put),
SOC_ENUM_EXT("TWS Channel Mode", tws_chs_mode_enum[0],
msm_dai_q6_tws_channel_mode_get,
- msm_dai_q6_tws_channel_mode_put)
+ msm_dai_q6_tws_channel_mode_put),
+ {
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE),
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "SLIM_7_RX APTX_AD Enc Cfg",
+ .info = msm_dai_q6_afe_enc_cfg_info,
+ .get = msm_dai_q6_afe_enc_cfg_get,
+ .put = msm_dai_q6_afe_enc_cfg_put,
+ }
};
static int msm_dai_q6_afe_dec_cfg_info(struct snd_kcontrol *kcontrol,
@@ -3895,7 +3895,7 @@
dai));
rc = snd_ctl_add(dai->component->card->snd_card,
snd_ctl_new1(&afe_enc_config_controls[5],
- dai));
+ dai_data));
rc = snd_ctl_add(dai->component->card->snd_card,
snd_ctl_new1(&avd_drift_config_controls[2],
dai));
@@ -5014,6 +5014,9 @@
SOC_ENUM_EXT("QUIN MI2S RX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("SENARY MI2S RX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
SOC_ENUM_EXT("PRI MI2S TX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
@@ -5068,6 +5071,8 @@
ctrl = &mi2s_config_controls[3];
if (dai->id == MSM_QUIN_MI2S)
ctrl = &mi2s_config_controls[4];
+ if (dai->id == MSM_SENARY_MI2S)
+ ctrl = &mi2s_config_controls[5];
}
if (ctrl) {
@@ -5084,19 +5089,19 @@
ctrl = NULL;
if (mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.i2s.channel_mode) {
if (dai->id == MSM_PRIM_MI2S)
- ctrl = &mi2s_config_controls[5];
- if (dai->id == MSM_SEC_MI2S)
ctrl = &mi2s_config_controls[6];
- if (dai->id == MSM_TERT_MI2S)
+ if (dai->id == MSM_SEC_MI2S)
ctrl = &mi2s_config_controls[7];
- if (dai->id == MSM_QUAT_MI2S)
+ if (dai->id == MSM_TERT_MI2S)
ctrl = &mi2s_config_controls[8];
- if (dai->id == MSM_QUIN_MI2S)
+ if (dai->id == MSM_QUAT_MI2S)
ctrl = &mi2s_config_controls[9];
- if (dai->id == MSM_SENARY_MI2S)
+ if (dai->id == MSM_QUIN_MI2S)
ctrl = &mi2s_config_controls[10];
- if (dai->id == MSM_INT5_MI2S)
+ if (dai->id == MSM_SENARY_MI2S)
ctrl = &mi2s_config_controls[11];
+ if (dai->id == MSM_INT5_MI2S)
+ ctrl = &mi2s_config_controls[12];
}
if (ctrl) {
@@ -5510,6 +5515,10 @@
dai_data->port_config.i2s.bit_width = 24;
dai_data->bitwidth = 24;
break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ dai_data->port_config.i2s.bit_width = 32;
+ dai_data->bitwidth = 32;
+ break;
default:
pr_err("%s: format %d\n",
__func__, params_format(params));
diff --git a/asoc/msm-pcm-dtmf-v2.c b/asoc/msm-pcm-dtmf-v2.c
index 7f79471..3dc7a26 100644
--- a/asoc/msm-pcm-dtmf-v2.c
+++ b/asoc/msm-pcm-dtmf-v2.c
@@ -20,6 +20,8 @@
#define DRV_NAME "msm-pcm-dtmf-v2"
+#define DTMF_MAX_DURATION 65535
+
enum {
DTMF_IN_RX,
DTMF_IN_TX,
@@ -94,8 +96,12 @@
int64_t duration = ucontrol->value.integer.value[2];
uint16_t gain = ucontrol->value.integer.value[3];
- pr_debug("%s: low_freq=%d high_freq=%d duration=%d gain=%d\n",
+ pr_debug("%s: low_freq=%d high_freq=%d duration=%lld gain=%d\n",
__func__, low_freq, high_freq, (int)duration, gain);
+
+ if (duration == DTMF_MAX_DURATION)
+ duration = -1;
+
afe_dtmf_generate_rx(duration, high_freq, low_freq, gain);
return 0;
}
diff --git a/asoc/msm-pcm-loopback-v2.c b/asoc/msm-pcm-loopback-v2.c
index 70c94e4..19fe190 100644
--- a/asoc/msm-pcm-loopback-v2.c
+++ b/asoc/msm-pcm-loopback-v2.c
@@ -132,7 +132,7 @@
ret = -EINVAL;
goto done;
}
-
+ mutex_lock(&loopback_session_lock);
pr_debug("%s: mute=%d\n", __func__, mute);
hfp_tx_mute = mute;
for (n = 0; n < LOOPBACK_SESSION_MAX; n++) {
@@ -145,6 +145,7 @@
pr_err("%s: Send mute command failed rc=%d\n",
__func__, ret);
}
+ mutex_unlock(&loopback_session_lock);
done:
return ret;
}
@@ -347,6 +348,8 @@
if (pcm->audio_client == NULL)
return;
+
+ mutex_lock(&loopback_session_lock);
q6asm_cmd(pcm->audio_client, CMD_CLOSE);
if (pcm->playback_substream != NULL) {
@@ -361,6 +364,7 @@
}
q6asm_audio_client_free(pcm->audio_client);
pcm->audio_client = NULL;
+ mutex_unlock(&loopback_session_lock);
}
static int msm_pcm_close(struct snd_pcm_substream *substream)
@@ -537,13 +541,15 @@
rc = -ENODEV;
goto exit;
}
+ mutex_lock(&loopback_session_lock);
prtd = substream->runtime->private_data;
if (!prtd) {
rc = -ENODEV;
+ mutex_unlock(&loopback_session_lock);
goto exit;
}
rc = pcm_loopback_set_volume(prtd, volume);
-
+ mutex_unlock(&loopback_session_lock);
exit:
return rc;
}
@@ -563,13 +569,15 @@
rc = -ENODEV;
goto exit;
}
+ mutex_lock(&loopback_session_lock);
prtd = substream->runtime->private_data;
if (!prtd) {
rc = -ENODEV;
+ mutex_unlock(&loopback_session_lock);
goto exit;
}
ucontrol->value.integer.value[0] = prtd->volume;
-
+ mutex_unlock(&loopback_session_lock);
exit:
return rc;
}
@@ -855,11 +863,13 @@
session_type,
chmixer_pspd);
+ mutex_lock(&loopback_session_lock);
if (chmixer_pspd->enable && substream->runtime) {
prtd = substream->runtime->private_data;
if (!prtd) {
pr_err("%s find invalid prtd fail\n", __func__);
ret = -EINVAL;
+ mutex_unlock(&loopback_session_lock);
goto done;
}
@@ -872,7 +882,7 @@
chmixer_pspd);
}
}
-
+ mutex_unlock(&loopback_session_lock);
if (reset_override_out_ch_map)
chmixer_pspd->override_out_ch_map = false;
if (reset_override_in_ch_map)
diff --git a/asoc/msm-pcm-q6-noirq.c b/asoc/msm-pcm-q6-noirq.c
index cd69d77..12a1f12 100644
--- a/asoc/msm-pcm-q6-noirq.c
+++ b/asoc/msm-pcm-q6-noirq.c
@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/time.h>
+#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -630,6 +631,8 @@
static int msm_pcm_close(struct snd_pcm_substream *substream)
{
+ struct msm_plat_data *pdata = NULL;
+ struct snd_soc_component *component = NULL;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct msm_audio *prtd = runtime->private_data;
@@ -638,6 +641,25 @@
int dir = 0;
int ret = 0;
+ if (!soc_prtd) {
+ pr_debug("%s private_data not found\n",
+ __func__);
+ return 0;
+ }
+
+ component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: pdata not found\n", __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&pdata->lock);
if (ac) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dir = IN;
@@ -672,6 +694,7 @@
SNDRV_PCM_STREAM_CAPTURE);
kfree(prtd);
runtime->private_data = NULL;
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -696,8 +719,11 @@
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct msm_plat_data *pdata = NULL;
struct snd_pcm_substream *substream =
vol->pcm->streams[vol->stream].substream;
+ struct snd_soc_pcm_runtime *soc_prtd = NULL;
+ struct snd_soc_component *component = NULL;
struct msm_audio *prtd;
pr_debug("%s\n", __func__);
@@ -705,13 +731,29 @@
pr_err("%s substream not found\n", __func__);
return -ENODEV;
}
- if (!substream->runtime) {
- pr_debug("%s substream runtime not found\n", __func__);
+ soc_prtd = substream->private_data;
+ if (!substream->runtime || !soc_prtd) {
+ pr_debug("%s substream runtime or private_data not found\n",
+ __func__);
return 0;
}
+
+ component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: pdata not found\n", __func__);
+ return -ENODEV;
+ }
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd)
ucontrol->value.integer.value[0] = prtd->volume;
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -720,8 +762,11 @@
{
int rc = 0;
struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct msm_plat_data *pdata = NULL;
struct snd_pcm_substream *substream =
vol->pcm->streams[vol->stream].substream;
+ struct snd_soc_pcm_runtime *soc_prtd = NULL;
+ struct snd_soc_component *component = NULL;
struct msm_audio *prtd;
int volume = ucontrol->value.integer.value[0];
@@ -730,15 +775,32 @@
pr_err("%s substream not found\n", __func__);
return -ENODEV;
}
- if (!substream->runtime) {
- pr_err("%s substream runtime not found\n", __func__);
+ soc_prtd = substream->private_data;
+ if (!substream->runtime || !soc_prtd) {
+ pr_err("%s substream runtime or private_data not found\n",
+ __func__);
return 0;
}
+
+ component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: pdata not found\n", __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd) {
rc = msm_pcm_set_volume(prtd, volume);
prtd->volume = volume;
}
+ mutex_unlock(&pdata->lock);
return rc;
}
@@ -1338,6 +1400,8 @@
pdata->perf_mode = perf_mode;
+ mutex_init(&pdata->lock);
+
dev_set_drvdata(&pdev->dev, pdata);
dev_dbg(&pdev->dev, "%s: dev name %s\n",
@@ -1359,6 +1423,7 @@
dev_dbg(&pdev->dev, "Pull mode remove\n");
pdata = dev_get_drvdata(&pdev->dev);
+ mutex_destroy(&pdata->lock);
devm_kfree(&pdev->dev, pdata);
snd_soc_unregister_component(&pdev->dev);
return 0;
diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c
index 7197ad6..60e84cb 100644
--- a/asoc/msm-pcm-q6-v2.c
+++ b/asoc/msm-pcm-q6-v2.c
@@ -1309,10 +1309,10 @@
pdata = dev_get_drvdata(component->dev);
if (!pdata) {
pr_err("%s pdata is NULL\n", __func__);
- ret = -ENODEV;
- goto done;
+ return -ENODEV;
}
+ mutex_lock(&pdata->lock);
substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
if (!substream) {
pr_err("%s substream not found\n", __func__);
@@ -1339,7 +1339,6 @@
goto done;
}
- mutex_lock(&pdata->lock);
event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
(event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
@@ -1514,8 +1513,11 @@
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct msm_plat_data *pdata = NULL;
struct snd_pcm_substream *substream =
vol->pcm->streams[vol->stream].substream;
+ struct snd_soc_pcm_runtime *soc_prtd = NULL;
+ struct snd_soc_component *component = NULL;
struct msm_audio *prtd;
pr_debug("%s\n", __func__);
@@ -1523,13 +1525,30 @@
pr_err("%s substream not found\n", __func__);
return -ENODEV;
}
- if (!substream->runtime) {
- pr_debug("%s substream runtime not found\n", __func__);
+ soc_prtd = substream->private_data;
+ if (!substream->runtime || !soc_prtd) {
+ pr_debug("%s substream runtime or private_data not found\n",
+ __func__);
return 0;
}
+
+ component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
+ if (!pdata) {
+ pr_err("%s: pdata not found\n", __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd)
ucontrol->value.integer.value[0] = prtd->volume;
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -1635,9 +1654,11 @@
pr_debug("%s substream runtime not found\n", __func__);
return 0;
}
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd)
ucontrol->value.integer.value[0] = prtd->compress_enable;
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -1665,12 +1686,14 @@
pr_err("%s substream runtime not found\n", __func__);
return 0;
}
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd) {
pr_debug("%s: setting compress flag to 0x%x\n",
__func__, compress);
prtd->compress_enable = compress;
}
+ mutex_unlock(&pdata->lock);
return rc;
}
@@ -1774,11 +1797,11 @@
}
}
- if (!substream->runtime || !rtd)
+ if (!rtd)
return 0;
mutex_lock(&pdata->lock);
- prtd = substream->runtime->private_data;
+ prtd = substream->runtime ? substream->runtime->private_data : NULL;
if (prtd) {
prtd->set_channel_map = true;
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
@@ -1841,11 +1864,11 @@
memset(ucontrol->value.integer.value, 0,
sizeof(ucontrol->value.integer.value));
- if (!substream->runtime || !rtd)
+ if (!rtd)
return 0; /* no channels set */
mutex_lock(&pdata->lock);
- prtd = substream->runtime->private_data;
+ prtd = substream->runtime ? substream->runtime->private_data : NULL;
if (prtd && prtd->set_channel_map == true) {
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++)
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index 0563d8c..9cddca0 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -123,6 +123,7 @@
#define VA_CDC_DMA_TX_2_TEXT "VA_CDC_DMA_TX_2"
#define TX_CDC_DMA_TX_3_TEXT "TX_CDC_DMA_TX_3"
#define QUIN_TDM_TX_TEXT "QUIN_TDM_TX_0"
+#define TERT_TDM_TX_TEXT "TERT_TDM_TX_0"
#define LSM_FUNCTION_TEXT "LSM Function"
static const char * const lsm_port_text[] = {
@@ -131,7 +132,8 @@
SLIMBUS_3_TX_TEXT, SLIMBUS_4_TX_TEXT, SLIMBUS_5_TX_TEXT,
TERT_MI2S_TX_TEXT, QUAT_MI2S_TX_TEXT, ADM_LSM_TX_TEXT,
INT3_MI2S_TX_TEXT, VA_CDC_DMA_TX_0_TEXT, VA_CDC_DMA_TX_1_TEXT,
- VA_CDC_DMA_TX_2_TEXT, TX_CDC_DMA_TX_3_TEXT, QUIN_TDM_TX_TEXT
+ VA_CDC_DMA_TX_2_TEXT, TX_CDC_DMA_TX_3_TEXT, QUIN_TDM_TX_TEXT,
+ TERT_TDM_TX_TEXT
};
struct msm_pcm_route_bdai_pp_params {
@@ -2056,7 +2058,13 @@
pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
- if (!is_mm_lsm_fe_id(val)) {
+ if (val == MSM_FRONTEND_DAI_DTMF_RX &&
+ afe_get_port_type(msm_bedais[reg].port_id) ==
+ MSM_AFE_PORT_TYPE_RX) {
+ pr_debug("%s(): set=%d port id=0x%x for dtmf generation\n",
+ __func__, set, msm_bedais[reg].port_id);
+ afe_set_dtmf_gen_rx_portid(msm_bedais[reg].port_id, set);
+ } else if (!is_mm_lsm_fe_id(val)) {
/* recheck FE ID in the mixer control defined in this file */
pr_err("%s: bad MM ID\n", __func__);
return;
@@ -3026,6 +3034,9 @@
case 15:
lsm_port = AFE_PORT_ID_QUINARY_TDM_TX;
break;
+ case 16:
+ lsm_port = AFE_PORT_ID_TERTIARY_TDM_TX;
+ break;
default:
pr_err("Default lsm port");
break;
@@ -3043,7 +3054,7 @@
u16 port_id;
enum afe_mad_type mad_type;
- pr_debug("%s: enter\n", __func__);
+ pr_debug("%s: id name %s\n", __func__, kcontrol->id.name);
for (i = 0; i < ARRAY_SIZE(lsm_port_text); i++)
if (!strnstr(kcontrol->id.name, lsm_port_text[i],
strlen(lsm_port_text[i])))
@@ -3070,14 +3081,18 @@
strlen(lsm_port_text[10])))
port_id = AFE_PORT_ID_INT3_MI2S_TX;
- if (strnstr(kcontrol->id.name, lsm_port_text[13],
- strlen(lsm_port_text[13])))
- port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_3;
-
if (strnstr(kcontrol->id.name, lsm_port_text[14],
strlen(lsm_port_text[14])))
+ port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_3;
+
+ if (strnstr(kcontrol->id.name, lsm_port_text[15],
+ strlen(lsm_port_text[15])))
port_id = AFE_PORT_ID_QUINARY_TDM_TX;
+ if (strnstr(kcontrol->id.name, lsm_port_text[16],
+ strlen(lsm_port_text[16])))
+ port_id = AFE_PORT_ID_TERTIARY_TDM_TX;
+
mad_type = afe_port_get_mad_type(port_id);
pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
mad_type);
@@ -3111,7 +3126,7 @@
u16 port_id;
enum afe_mad_type mad_type;
- pr_debug("%s: enter\n", __func__);
+ pr_debug("%s: id name %s\n", __func__, kcontrol->id.name);
for (i = 0; i < ARRAY_SIZE(lsm_port_text); i++)
if (strnstr(kcontrol->id.name, lsm_port_text[i],
strlen(lsm_port_text[i])))
@@ -3158,14 +3173,18 @@
strlen(lsm_port_text[10])))
port_id = AFE_PORT_ID_INT3_MI2S_TX;
- if (strnstr(kcontrol->id.name, lsm_port_text[13],
- strlen(lsm_port_text[13])))
- port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_3;
-
if (strnstr(kcontrol->id.name, lsm_port_text[14],
strlen(lsm_port_text[14])))
+ port_id = AFE_PORT_ID_TX_CODEC_DMA_TX_3;
+
+ if (strnstr(kcontrol->id.name, lsm_port_text[15],
+ strlen(lsm_port_text[15])))
port_id = AFE_PORT_ID_QUINARY_TDM_TX;
+ if (strnstr(kcontrol->id.name, lsm_port_text[16],
+ strlen(lsm_port_text[16])))
+ port_id = AFE_PORT_ID_TERTIARY_TDM_TX;
+
pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
mad_type);
return afe_port_set_mad_type(port_id, mad_type);
@@ -5444,6 +5463,10 @@
*index = 37;
port_id = AFE_PORT_ID_HDMI_OVER_DP_RX;
break;
+ case 38:
+ *index = 38;
+ port_id = AFE_PORT_ID_SENARY_MI2S_RX;
+ break;
default:
*index = 0; /* NONE */
pr_err("%s: Invalid value %d\n", __func__, value);
@@ -5501,7 +5524,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",
+ "DISPLAY_PORT1", "SEN_MI2S_RX",
};
static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
@@ -7040,7 +7063,10 @@
MSM_BACKEND_DAI_PRI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA30, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
-
+ SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int0_mi2s_rx_mixer_controls[] = {
@@ -7607,6 +7633,10 @@
MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM,
MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
@@ -11191,6 +11221,73 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new quin_tdm_tx_1_mixer_controls[] = {
+ SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new quin_tdm_rx_1_mixer_controls[] = {
SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
MSM_BACKEND_DAI_QUIN_TDM_RX_1,
@@ -11270,6 +11367,73 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new quin_tdm_tx_2_mixer_controls[] = {
+ SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new quin_tdm_rx_2_mixer_controls[] = {
SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
MSM_BACKEND_DAI_QUIN_TDM_RX_2,
@@ -11349,6 +11513,73 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new quin_tdm_tx_3_mixer_controls[] = {
+ SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new quin_tdm_rx_3_mixer_controls[] = {
SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM,
MSM_BACKEND_DAI_QUIN_TDM_RX_3,
@@ -15843,6 +16074,13 @@
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new quin_tdm_rx_2_voice_mixer_controls[] = {
+ SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_2,
+ MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
static const struct snd_kcontrol_new wsa_cdc_dma_rx_0_voice_mixer_controls[] = {
SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM,
MSM_BACKEND_DAI_WSA_CDC_DMA_RX_0,
@@ -17113,6 +17351,25 @@
};
+static const struct snd_kcontrol_new rx_cdc_dma_rx_1_port_mixer_controls[] = {
+ SOC_DOUBLE_EXT("VA_CDC_DMA_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_RX_CDC_DMA_RX_1,
+ MSM_BACKEND_DAI_VA_CDC_DMA_TX_0, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_DOUBLE_EXT("TX_CDC_DMA_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_RX_CDC_DMA_RX_1,
+ MSM_BACKEND_DAI_TX_CDC_DMA_TX_3, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_RX_CDC_DMA_RX_1,
+ MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_RX_CDC_DMA_RX_1,
+ MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM,
MSM_BACKEND_DAI_SLIMBUS_0_RX,
@@ -20786,6 +21043,10 @@
MSM_BACKEND_DAI_QUIN_TDM_TX_0,
MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm2_mixer_controls[] = {
@@ -20842,6 +21103,10 @@
MSM_BACKEND_DAI_QUIN_TDM_TX_0,
MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm3_mixer_controls[] = {
@@ -20897,6 +21162,10 @@
MSM_BACKEND_DAI_QUIN_TDM_TX_0,
MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm4_mixer_controls[] = {
@@ -20952,6 +21221,10 @@
MSM_BACKEND_DAI_QUIN_TDM_TX_0,
MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm5_mixer_controls[] = {
@@ -21007,6 +21280,10 @@
MSM_BACKEND_DAI_QUIN_TDM_TX_0,
MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm6_mixer_controls[] = {
@@ -21062,6 +21339,10 @@
MSM_BACKEND_DAI_QUIN_TDM_TX_0,
MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm7_mixer_controls[] = {
@@ -21117,6 +21398,10 @@
MSM_BACKEND_DAI_QUIN_TDM_TX_0,
MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm8_mixer_controls[] = {
@@ -21172,6 +21457,10 @@
MSM_BACKEND_DAI_QUIN_TDM_TX_0,
MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new slim_fm_switch_mixer_controls =
@@ -21322,6 +21611,8 @@
msm_routing_lsm_func_get, msm_routing_lsm_func_put),
SOC_ENUM_EXT(QUIN_TDM_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(TERT_TDM_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
/* kcontrol of lsm_port */
SOC_ENUM_EXT("LSM1 Port", lsm_port_enum,
msm_routing_lsm_port_get,
@@ -23701,12 +23992,21 @@
SND_SOC_DAPM_MIXER("QUIN_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
quin_tdm_rx_1_mixer_controls,
ARRAY_SIZE(quin_tdm_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_TDM_TX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quin_tdm_tx_1_mixer_controls,
+ ARRAY_SIZE(quin_tdm_tx_1_mixer_controls)),
SND_SOC_DAPM_MIXER("QUIN_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
quin_tdm_rx_2_mixer_controls,
ARRAY_SIZE(quin_tdm_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_TDM_TX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quin_tdm_tx_2_mixer_controls,
+ ARRAY_SIZE(quin_tdm_tx_2_mixer_controls)),
SND_SOC_DAPM_MIXER("QUIN_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
quin_tdm_rx_3_mixer_controls,
ARRAY_SIZE(quin_tdm_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_TDM_TX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quin_tdm_tx_3_mixer_controls,
+ ARRAY_SIZE(quin_tdm_tx_3_mixer_controls)),
SND_SOC_DAPM_MIXER("SEN_TDM_TX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
sen_tdm_tx_0_mixer_controls,
ARRAY_SIZE(sen_tdm_tx_0_mixer_controls)),
@@ -23934,6 +24234,10 @@
SND_SOC_NOPM, 0, 0,
quat_tdm_rx_2_voice_mixer_controls,
ARRAY_SIZE(quat_tdm_rx_2_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_TDM_RX_2_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ quin_tdm_rx_2_voice_mixer_controls,
+ ARRAY_SIZE(quin_tdm_rx_2_voice_mixer_controls)),
SND_SOC_DAPM_MIXER("WSA_CDC_DMA_RX_0_Voice Mixer",
SND_SOC_NOPM, 0, 0,
wsa_cdc_dma_rx_0_voice_mixer_controls,
@@ -23942,6 +24246,10 @@
SND_SOC_NOPM, 0, 0,
rx_cdc_dma_rx_0_voice_mixer_controls,
ARRAY_SIZE(rx_cdc_dma_rx_0_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("RX_CDC_DMA_RX_1_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ rx_cdc_dma_rx_1_voice_mixer_controls,
+ ARRAY_SIZE(rx_cdc_dma_rx_1_voice_mixer_controls)),
SND_SOC_DAPM_MIXER("Voip_Tx Mixer",
SND_SOC_NOPM, 0, 0, tx_voip_mixer_controls,
ARRAY_SIZE(tx_voip_mixer_controls)),
@@ -24145,6 +24453,9 @@
SND_SOC_DAPM_MIXER("RX_CDC_DMA_RX_0 Port Mixer", SND_SOC_NOPM, 0, 0,
rx_cdc_dma_rx_0_port_mixer_controls,
ARRAY_SIZE(rx_cdc_dma_rx_0_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("RX_CDC_DMA_RX_1 Port Mixer", SND_SOC_NOPM, 0, 0,
+ rx_cdc_dma_rx_1_port_mixer_controls,
+ ARRAY_SIZE(rx_cdc_dma_rx_1_port_mixer_controls)),
SND_SOC_DAPM_MIXER("QCHAT_Tx Mixer",
SND_SOC_NOPM, 0, 0, tx_qchat_mixer_controls,
ARRAY_SIZE(tx_qchat_mixer_controls)),
@@ -24614,6 +24925,7 @@
/* incall */
{"Incall_Music Audio Mixer", "MultiMedia1", "MM_DL1"},
{"Incall_Music Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"Incall_Music Audio Mixer", "MultiMedia4", "MM_DL4"},
{"Incall_Music Audio Mixer", "MultiMedia5", "MM_DL5"},
{"Incall_Music Audio Mixer", "MultiMedia9", "MM_DL9"},
{"VOICE_PLAYBACK_TX", NULL, "Incall_Music Audio Mixer"},
@@ -24707,9 +25019,11 @@
{"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
{"MultiMedia4 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
{"MultiMedia8 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
+ {"MultiMedia9 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
{"MultiMedia4 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
{"MultiMedia8 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
+ {"MultiMedia9 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
{"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"},
{"MultiMedia1 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"},
{"MultiMedia1 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
@@ -24880,6 +25194,7 @@
{"PRI_MI2S_RX Audio Mixer", "MultiMedia16", "MM_DL16"},
{"PRI_MI2S_RX Audio Mixer", "MultiMedia26", "MM_DL26"},
{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Audio Mixer"},
+ {"PRI_MI2S_RX Audio Mixer", "DTMF", "DTMF_DL_HL"},
{"INT0_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INT0_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -26712,6 +27027,9 @@
{"QUAT_TDM_RX_2_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
{"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2_Voice Mixer"},
+ {"QUIN_TDM_RX_2_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"QUIN_TDM_RX_2", NULL, "QUIN_TDM_RX_2_Voice Mixer"},
+
{"WSA_CDC_DMA_RX_0_Voice Mixer", "Voip", "VOIP_DL"},
{"WSA_CDC_DMA_RX_0_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
{"WSA_CDC_DMA_RX_0_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
@@ -26722,6 +27040,11 @@
{"RX_CDC_DMA_RX_0_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
{"RX_CDC_DMA_RX_0", NULL, "RX_CDC_DMA_RX_0_Voice Mixer"},
+ {"RX_CDC_DMA_RX_1_Voice Mixer", "Voip", "VOIP_DL"},
+ {"RX_CDC_DMA_RX_1_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"RX_CDC_DMA_RX_1_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"},
+ {"RX_CDC_DMA_RX_1", NULL, "RX_CDC_DMA_RX_1_Voice Mixer"},
+
{"VOC_EXT_EC MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"VOC_EXT_EC MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
{"VOC_EXT_EC MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
@@ -26959,6 +27282,7 @@
{"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"},
{"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"},
@@ -26973,6 +27297,7 @@
{"LSM1 Mixer", "VA_CDC_DMA_TX_2", "VA_CDC_DMA_TX_2"},
{"LSM1 Mixer", "TX_CDC_DMA_TX_3", "TX_CDC_DMA_TX_3"},
{"LSM1 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"LSM1 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
{"LSM1_UL_HL", NULL, "LSM1 Mixer"},
{"LSM2 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
@@ -26988,6 +27313,7 @@
{"LSM2 Mixer", "VA_CDC_DMA_TX_2", "VA_CDC_DMA_TX_2"},
{"LSM2 Mixer", "TX_CDC_DMA_TX_3", "TX_CDC_DMA_TX_3"},
{"LSM2 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"LSM2 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
{"LSM2_UL_HL", NULL, "LSM2 Mixer"},
@@ -27004,6 +27330,7 @@
{"LSM3 Mixer", "VA_CDC_DMA_TX_2", "VA_CDC_DMA_TX_2"},
{"LSM3 Mixer", "TX_CDC_DMA_TX_3", "TX_CDC_DMA_TX_3"},
{"LSM3 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"LSM3 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
{"LSM3_UL_HL", NULL, "LSM3 Mixer"},
@@ -27020,6 +27347,7 @@
{"LSM4 Mixer", "VA_CDC_DMA_TX_2", "VA_CDC_DMA_TX_2"},
{"LSM4 Mixer", "TX_CDC_DMA_TX_3", "TX_CDC_DMA_TX_3"},
{"LSM4 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"LSM4 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
{"LSM4_UL_HL", NULL, "LSM4 Mixer"},
{"LSM5 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
@@ -27035,6 +27363,7 @@
{"LSM5 Mixer", "VA_CDC_DMA_TX_2", "VA_CDC_DMA_TX_2"},
{"LSM5 Mixer", "TX_CDC_DMA_TX_3", "TX_CDC_DMA_TX_3"},
{"LSM5 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"LSM5 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
{"LSM5_UL_HL", NULL, "LSM5 Mixer"},
{"LSM6 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
@@ -27048,6 +27377,7 @@
{"LSM6 Mixer", "VA_CDC_DMA_TX_2", "VA_CDC_DMA_TX_2"},
{"LSM6 Mixer", "TX_CDC_DMA_TX_3", "TX_CDC_DMA_TX_3"},
{"LSM6 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"LSM6 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
{"LSM6_UL_HL", NULL, "LSM6 Mixer"},
{"LSM7 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
@@ -27061,6 +27391,7 @@
{"LSM7 Mixer", "VA_CDC_DMA_TX_2", "VA_CDC_DMA_TX_2"},
{"LSM7 Mixer", "TX_CDC_DMA_TX_3", "TX_CDC_DMA_TX_3"},
{"LSM7 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"LSM7 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
{"LSM7_UL_HL", NULL, "LSM7 Mixer"},
{"LSM8 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
@@ -27074,6 +27405,7 @@
{"LSM8 Mixer", "VA_CDC_DMA_TX_2", "VA_CDC_DMA_TX_2"},
{"LSM8 Mixer", "TX_CDC_DMA_TX_3", "TX_CDC_DMA_TX_3"},
{"LSM8 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"LSM8 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
{"LSM8_UL_HL", NULL, "LSM8 Mixer"},
@@ -27862,6 +28194,12 @@
{"RX_CDC_DMA_RX_0 Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"RX_CDC_DMA_RX_0", NULL, "RX_CDC_DMA_RX_0 Port Mixer"},
+ {"RX_CDC_DMA_RX_1 Port Mixer", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_0"},
+ {"RX_CDC_DMA_RX_1 Port Mixer", "TX_CDC_DMA_TX_3", "TX_CDC_DMA_TX_3"},
+ {"RX_CDC_DMA_RX_1 Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
+ {"RX_CDC_DMA_RX_1 Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"RX_CDC_DMA_RX_1", NULL, "RX_CDC_DMA_RX_1 Port Mixer"},
+
{"SLIMBUS_0_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"SLIMBUS_0_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"SLIMBUS_0_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
@@ -28870,6 +29208,11 @@
uint32_t be_idx = ucontrol->value.integer.value[0];
int i;
+ if (be_idx >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s: Invalid Backend index %d\n", __func__, be_idx);
+ return -EINVAL;
+ }
+
for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL_V8; i++) {
channel_map[i] = (char)(ucontrol->value.integer.value[i + 1]);
if (channel_map[i] > PCM_MAX_CHMAP_ID) {
diff --git a/asoc/msm-pcm-voice-v2.c b/asoc/msm-pcm-voice-v2.c
index f8acc30..5a25b3e 100644
--- a/asoc/msm-pcm-voice-v2.c
+++ b/asoc/msm-pcm-voice-v2.c
@@ -582,6 +582,20 @@
return 0;
}
+static int msm_voice_ecns_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint32_t enable = ucontrol->value.integer.value[0];
+ uint32_t session_id = ucontrol->value.integer.value[1];
+ uint32_t module_id = ucontrol->value.integer.value[2];
+
+ pr_debug("%s: ecns enable=%d session_id=%#x\n", __func__, enable,
+ session_id);
+ voc_set_ecns_enable(session_id, module_id, enable);
+
+ return 0;
+}
+
static int msm_voice_hd_voice_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -695,6 +709,8 @@
msm_voice_tty_mode_put),
SOC_SINGLE_MULTI_EXT("Slowtalk Enable", SND_SOC_NOPM, 0, VSID_MAX, 0, 2,
NULL, msm_voice_slowtalk_put),
+ SOC_SINGLE_MULTI_EXT("Voice ECNS Enable", SND_SOC_NOPM, 0, VSID_MAX, 0, 3,
+ NULL, msm_voice_ecns_put),
SOC_SINGLE_MULTI_EXT("Voice Topology Disable", SND_SOC_NOPM, 0,
VSID_MAX, 0, 2, NULL,
msm_voice_topology_disable_put),
diff --git a/config/bengalauto.conf b/config/bengalauto.conf
new file mode 100644
index 0000000..d6fdadd
--- /dev/null
+++ b/config/bengalauto.conf
@@ -0,0 +1,34 @@
+CONFIG_PINCTRL_LPI=m
+CONFIG_AUDIO_EXT_CLK=m
+CONFIG_SND_SOC_WCD9XXX_V2=m
+CONFIG_SND_SOC_WCD_MBHC=m
+CONFIG_SND_SOC_WSA881X_ANALOG=m
+CONFIG_WCD9XXX_CODEC_CORE_V2=m
+CONFIG_MSM_CDC_PINCTRL=m
+CONFIG_MSM_QDSP6V2_CODECS=m
+CONFIG_MSM_ULTRASOUND=m
+CONFIG_MSM_QDSP6_APRV2_RPMSG=m
+CONFIG_MSM_ADSP_LOADER=m
+CONFIG_REGMAP_SWR=m
+CONFIG_MSM_QDSP6_SSR=m
+CONFIG_MSM_QDSP6_PDR=m
+CONFIG_MSM_QDSP6_NOTIFIER=m
+CONFIG_SND_SOC_MSM_HOSTLESS_PCM=m
+CONFIG_SND_SOC_MSM_QDSP6V2_INTF=m
+CONFIG_SOUNDWIRE=m
+CONFIG_SOUNDWIRE_MSTR_CTRL=m
+CONFIG_SND_SOC_QDSP6V2=m
+CONFIG_SND_SOC_WCD_MBHC_ADC=m
+CONFIG_QTI_PP=m
+CONFIG_SND_HWDEP_ROUTING=m
+CONFIG_SND_SOC_MSM_STUB=m
+CONFIG_MSM_AVTIMER=m
+CONFIG_SND_SOC_BOLERO=m
+CONFIG_VA_MACRO=m
+CONFIG_RX_MACRO=m
+CONFIG_TX_MACRO=m
+CONFIG_SND_SOC_WCD_IRQ=m
+CONFIG_SND_SOC_WCD937X=m
+CONFIG_SND_SOC_WCD937X_SLAVE=m
+CONFIG_SND_SOC_BENGAL=m
+CONFIG_SND_EVENT=m
diff --git a/config/bengalautoconf.h b/config/bengalautoconf.h
new file mode 100644
index 0000000..90d3e3c
--- /dev/null
+++ b/config/bengalautoconf.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#define CONFIG_PINCTRL_LPI 1
+#define CONFIG_AUDIO_EXT_CLK 1
+#define CONFIG_SND_SOC_WCD9XXX_V2 1
+#define CONFIG_SND_SOC_WCD_MBHC 1
+#define CONFIG_SND_SOC_WSA881X_ANALOG 1
+#define CONFIG_WCD9XXX_CODEC_CORE_V2 1
+#define CONFIG_MSM_CDC_PINCTRL 1
+#define CONFIG_MSM_QDSP6V2_CODECS 1
+#define CONFIG_MSM_ULTRASOUND 1
+#define CONFIG_MSM_QDSP6_APRV2_RPMSG 1
+#define CONFIG_SND_SOC_MSM_QDSP6V2_INTF 1
+#define CONFIG_MSM_ADSP_LOADER 1
+#define CONFIG_REGMAP_SWR 1
+#define CONFIG_MSM_QDSP6_SSR 1
+#define CONFIG_MSM_QDSP6_PDR 1
+#define CONFIG_MSM_QDSP6_NOTIFIER 1
+#define CONFIG_SND_SOC_MSM_HOSTLESS_PCM 1
+#define CONFIG_SOUNDWIRE 1
+#define CONFIG_SOUNDWIRE_MSTR_CTRL 1
+#define CONFIG_SND_SOC_WCD_MBHC_ADC 1
+#define CONFIG_SND_SOC_QDSP6V2 1
+#define CONFIG_QTI_PP 1
+#define CONFIG_SND_HWDEP_ROUTING 1
+#define CONFIG_SND_SOC_MSM_STUB 1
+#define CONFIG_MSM_AVTIMER 1
+#define CONFIG_SND_SOC_BOLERO 1
+#define CONFIG_VA_MACRO 1
+#define CONFIG_RX_MACRO 1
+#define CONFIG_TX_MACRO 1
+#define CONFIG_SND_SOC_WCD_IRQ 1
+#define CONFIG_SND_SOC_WCD937X 1
+#define CONFIG_SND_SOC_WCD937X_SLAVE 1
+#define CONFIG_SND_SOC_BENGAL 1
+#define CONFIG_SND_EVENT 1
diff --git a/dsp/Android.mk b/dsp/Android.mk
index df13d3d..c5ab3ff 100644
--- a/dsp/Android.mk
+++ b/dsp/Android.mk
@@ -27,6 +27,10 @@
AUDIO_SELECT := CONFIG_SND_SOC_LITO=m
endif
+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,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike),true)
diff --git a/dsp/Kbuild b/dsp/Kbuild
index 81f8094..006de44 100644
--- a/dsp/Kbuild
+++ b/dsp/Kbuild
@@ -40,9 +40,9 @@
INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
endif
ifeq ($(CONFIG_ARCH_BENGAL), y)
- include $(AUDIO_ROOT)/config/litoauto.conf
+ include $(AUDIO_ROOT)/config/bengalauto.conf
export
- INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
+ INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
endif
ifeq ($(CONFIG_ARCH_SM8150), y)
ifdef CONFIG_SND_SOC_SA8155
diff --git a/dsp/avtimer.c b/dsp/avtimer.c
index ad5e13a..e1d032d 100644
--- a/dsp/avtimer.c
+++ b/dsp/avtimer.c
@@ -271,6 +271,7 @@
rc = avcs_core_disable_avtimer(
avtimer.timer_handle);
avtimer.timer_handle = 0;
+ atomic_set(&avtimer.adsp_ready, 0);
}
}
}
diff --git a/dsp/codecs/Android.mk b/dsp/codecs/Android.mk
index 3d122f6..59a1603 100644
--- a/dsp/codecs/Android.mk
+++ b/dsp/codecs/Android.mk
@@ -19,6 +19,10 @@
AUDIO_SELECT := CONFIG_SND_SOC_LITO=m
endif
+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,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike),true)
diff --git a/dsp/codecs/Kbuild b/dsp/codecs/Kbuild
index 3bdcd7d..8709901 100644
--- a/dsp/codecs/Kbuild
+++ b/dsp/codecs/Kbuild
@@ -34,9 +34,9 @@
INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
endif
ifeq ($(CONFIG_ARCH_BENGAL), y)
- include $(AUDIO_ROOT)/config/litoauto.conf
+ include $(AUDIO_ROOT)/config/bengalauto.conf
export
- INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
+ INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
endif
ifeq ($(CONFIG_ARCH_SM8150), y)
include $(AUDIO_ROOT)/config/sm8150auto.conf
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index c30415a..7297a1e 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -110,7 +110,7 @@
wait_queue_head_t wait_wakeup;
struct task_struct *task;
wait_queue_head_t lpass_core_hw_wait;
- uint32_t lpass_hw_core_client_hdl;
+ uint32_t lpass_hw_core_client_hdl[AFE_LPASS_CORE_HW_VOTE_MAX];
void (*tx_cb)(uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv);
void (*rx_cb)(uint32_t opcode,
@@ -571,6 +571,8 @@
static int32_t afe_callback(struct apr_client_data *data, void *priv)
{
+ uint16_t i = 0;
+
if (!data) {
pr_err("%s: Invalid param data\n", __func__);
return -EINVAL;
@@ -598,7 +600,8 @@
/* Reset the core client handle in SSR/PDR use cases */
mutex_lock(&this_afe.afe_cmd_lock);
- this_afe.lpass_hw_core_client_hdl = 0;
+ for (i = 0; i < AFE_LPASS_CORE_HW_VOTE_MAX; i++)
+ this_afe.lpass_hw_core_client_hdl[i] = 0;
mutex_unlock(&this_afe.afe_cmd_lock);
/*
@@ -673,7 +676,9 @@
pr_debug("%s: AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST handle %d\n",
__func__, payload[0]);
- this_afe.lpass_hw_core_client_hdl = payload[0];
+ 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);
wake_up(&this_afe.lpass_core_hw_wait);
@@ -2897,7 +2902,8 @@
if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX ||
port_id == AFE_PORT_ID_INT3_MI2S_TX ||
- port_id == AFE_PORT_ID_TX_CODEC_DMA_TX_3) {
+ port_id == AFE_PORT_ID_TX_CODEC_DMA_TX_3 ||
+ port_id == AFE_PORT_ID_TERTIARY_TDM_TX) {
mad_type = MAD_SW_AUDIO;
return 0;
}
@@ -2926,7 +2932,8 @@
if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX ||
port_id == AFE_PORT_ID_INT3_MI2S_TX ||
- port_id == AFE_PORT_ID_TX_CODEC_DMA_TX_3)
+ port_id == AFE_PORT_ID_TX_CODEC_DMA_TX_3 ||
+ port_id == AFE_PORT_ID_TERTIARY_TDM_TX)
return MAD_SW_AUDIO;
i = port_id - SLIMBUS_0_RX;
@@ -7912,6 +7919,7 @@
if (this_afe.vi_tx_port != -1)
port = this_afe.vi_tx_port;
+ mutex_lock(&this_afe.afe_cmd_lock);
memset(¶m_hdr, 0, sizeof(param_hdr));
param_hdr.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI;
@@ -7922,7 +7930,7 @@
ret = q6afe_get_params(port, NULL, ¶m_hdr);
if (ret) {
pr_err("%s: Failed to get TH VI V-Vali data\n", __func__);
- goto done;
+ goto get_params_fail;
}
th_vi_v_vali->pdata = param_hdr;
@@ -7934,6 +7942,8 @@
th_vi_v_vali->param.status[SP_V2_SPKR_1],
th_vi_v_vali->param.status[SP_V2_SPKR_2]);
ret = 0;
+get_params_fail:
+ mutex_unlock(&this_afe.afe_cmd_lock);
done:
return ret;
}
@@ -7951,6 +7961,7 @@
if (this_afe.vi_tx_port != -1)
port = this_afe.vi_tx_port;
+ mutex_lock(&this_afe.afe_cmd_lock);
memset(¶m_hdr, 0, sizeof(param_hdr));
param_hdr.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_TH_VI;
@@ -7961,7 +7972,7 @@
ret = q6afe_get_params(port, NULL, ¶m_hdr);
if (ret) {
pr_err("%s: Failed to get TH VI FTM data\n", __func__);
- goto done;
+ goto get_params_fail;
}
th_vi->pdata = param_hdr;
@@ -7975,6 +7986,8 @@
th_vi->param.status[SP_V2_SPKR_1],
th_vi->param.status[SP_V2_SPKR_2]);
ret = 0;
+get_params_fail:
+ mutex_unlock(&this_afe.afe_cmd_lock);
done:
return ret;
}
@@ -7992,6 +8005,7 @@
if (this_afe.vi_tx_port != -1)
port = this_afe.vi_tx_port;
+ mutex_lock(&this_afe.afe_cmd_lock);
memset(¶m_hdr, 0, sizeof(param_hdr));
param_hdr.module_id = AFE_MODULE_SPEAKER_PROTECTION_V2_EX_VI;
@@ -8003,7 +8017,7 @@
if (ret < 0) {
pr_err("%s: get param port 0x%x param id[0x%x]failed %d\n",
__func__, port, param_hdr.param_id, ret);
- goto done;
+ goto get_params_fail;
}
ex_vi->pdata = param_hdr;
@@ -8019,6 +8033,8 @@
ex_vi->param.status[SP_V2_SPKR_1],
ex_vi->param.status[SP_V2_SPKR_2]);
ret = 0;
+get_params_fail:
+ mutex_unlock(&this_afe.afe_cmd_lock);
done:
return ret;
}
@@ -8044,6 +8060,7 @@
goto done;
}
+ mutex_lock(&this_afe.afe_cmd_lock);
memset(¶m_hdr, 0, sizeof(param_hdr));
param_hdr.module_id = AFE_MODULE_FB_SPKR_PROT_V2_RX;
@@ -8055,7 +8072,7 @@
if (ret < 0) {
pr_err("%s: get param port 0x%x param id[0x%x]failed %d\n",
__func__, port_id, param_hdr.param_id, ret);
- goto done;
+ goto get_params_fail;
}
memcpy(xt_logging, &this_afe.xt_logging_resp.param,
@@ -8069,6 +8086,8 @@
xt_logging->max_temperature[SP_V2_SPKR_2],
xt_logging->count_exceeded_temperature[SP_V2_SPKR_1],
xt_logging->count_exceeded_temperature[SP_V2_SPKR_2]);
+get_params_fail:
+ mutex_unlock(&this_afe.afe_cmd_lock);
done:
return ret;
}
@@ -8094,6 +8113,7 @@
goto exit;
}
+ mutex_lock(&this_afe.afe_cmd_lock);
memset(¶m_hdr, 0, sizeof(param_hdr));
param_hdr.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
param_hdr.instance_id = INSTANCE_ID_0;
@@ -8104,12 +8124,14 @@
if (ret < 0) {
pr_err("%s: get param port 0x%x param id[0x%x] failed %d\n",
__func__, port, param_hdr.param_id, ret);
- goto exit;
+ goto get_params_fail;
}
memcpy(timing_stats, &this_afe.av_dev_drift_resp.timing_stats,
param_hdr.param_size);
ret = 0;
+get_params_fail:
+ mutex_unlock(&this_afe.afe_cmd_lock);
exit:
return ret;
}
@@ -8135,6 +8157,7 @@
goto exit;
}
+ mutex_lock(&this_afe.afe_cmd_lock);
memset(¶m_hdr, 0, sizeof(param_hdr));
param_hdr.module_id = AUDPROC_MODULE_ID_FFNS;
param_hdr.instance_id = INSTANCE_ID_0;
@@ -8145,7 +8168,7 @@
if (ret < 0) {
pr_err("%s: get param port 0x%x param id[0x%x] failed %d\n",
__func__, port, param_hdr.param_id, ret);
- goto exit;
+ goto get_params_fail;
}
memcpy(doa_tracking_data, &this_afe.doa_tracking_mon_resp.doa,
@@ -8157,6 +8180,8 @@
__func__, i, doa_tracking_data->interf_angle_L16[i]);
}
+get_params_fail:
+ mutex_unlock(&this_afe.afe_cmd_lock);
exit:
return ret;
}
@@ -8175,6 +8200,7 @@
if (this_afe.vi_tx_port != -1)
port = this_afe.vi_tx_port;
+ mutex_lock(&this_afe.afe_cmd_lock);
memset(¶m_hdr, 0, sizeof(param_hdr));
param_hdr.module_id = AFE_MODULE_FB_SPKR_PROT_VI_PROC_V2;
param_hdr.instance_id = INSTANCE_ID_0;
@@ -8185,7 +8211,7 @@
if (ret < 0) {
pr_err("%s: get param port 0x%x param id[0x%x]failed %d\n",
__func__, port, param_hdr.param_id, ret);
- goto fail_cmd;
+ goto get_params_fail;
}
memcpy(&calib_resp->res_cfg, &this_afe.calib_data.res_cfg,
sizeof(this_afe.calib_data.res_cfg));
@@ -8194,6 +8220,8 @@
calib_resp->res_cfg.r0_cali_q24[SP_V2_SPKR_1],
calib_resp->res_cfg.r0_cali_q24[SP_V2_SPKR_2]);
ret = 0;
+get_params_fail:
+ mutex_unlock(&this_afe.afe_cmd_lock);
fail_cmd:
return ret;
}
@@ -9063,7 +9091,8 @@
this_afe.mmap_handle = 0;
this_afe.vi_tx_port = -1;
this_afe.vi_rx_port = -1;
- this_afe.lpass_hw_core_client_hdl = 0;
+ for (i = 0; i < AFE_LPASS_CORE_HW_VOTE_MAX; i++)
+ this_afe.lpass_hw_core_client_hdl[i] = 0;
this_afe.prot_cfg.mode = MSM_SPKR_PROT_DISABLED;
this_afe.th_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
this_afe.ex_ftm_cfg.mode = MSM_SPKR_PROT_DISABLED;
@@ -9195,7 +9224,7 @@
cmd_ptr->hdr.pkt_size = sizeof(hw_vote_cfg);
cmd_ptr->hdr.src_port = 0;
cmd_ptr->hdr.dest_port = 0;
- cmd_ptr->hdr.token = 0;
+ cmd_ptr->hdr.token = hw_block_id;
cmd_ptr->hdr.opcode = AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST;
cmd_ptr->hw_block_id = hw_block_id;
strlcpy(cmd_ptr->client_name, client_name,
@@ -9236,9 +9265,9 @@
goto done;
}
- *client_handle = this_afe.lpass_hw_core_client_hdl;
+ *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);
+ this_afe.lpass_hw_core_client_hdl[hw_block_id]);
done:
mutex_unlock(&this_afe.afe_cmd_lock);
return ret;
@@ -9268,7 +9297,7 @@
mutex_lock(&this_afe.afe_cmd_lock);
- if (!this_afe.lpass_hw_core_client_hdl) {
+ if (!this_afe.lpass_hw_core_client_hdl[hw_block_id]) {
pr_debug("%s: SSR in progress, return\n", __func__);
goto done;
}
diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c
index 9c5bf3d..d5c8e7e 100644
--- a/dsp/q6lsm.c
+++ b/dsp/q6lsm.c
@@ -104,8 +104,7 @@
if (lsm_session[n] == client)
return n;
}
- pr_err("%s: cannot find matching lsm client. client = %pa\n",
- __func__, client);
+ pr_err("%s: cannot find matching lsm client.\n", __func__);
return LSM_INVALID_SESSION_ID;
}
@@ -376,10 +375,10 @@
return;
}
apr_deregister(client->apr);
+ q6lsm_mmap_apr_dereg();
client->mmap_apr = NULL;
mutex_lock(&session_lock);
q6lsm_session_free(client);
- q6lsm_mmap_apr_dereg();
mutex_destroy(&client->cmd_lock);
kfree(client);
client = NULL;
diff --git a/dsp/q6voice.c b/dsp/q6voice.c
index 6de6686..e0491f1 100644
--- a/dsp/q6voice.c
+++ b/dsp/q6voice.c
@@ -110,6 +110,10 @@
static int voice_send_set_pp_enable_cmd(
struct voice_data *v, struct module_instance_info mod_inst_info,
int enable);
+
+static int voice_send_cvp_ecns_enable_cmd(struct voice_data *v,
+ uint32_t module_id, int enable);
+
static int is_cal_memory_allocated(void);
static bool is_cvd_version_queried(void);
static int is_voip_memory_allocated(void);
@@ -1544,6 +1548,124 @@
return ret;
}
+static int voice_send_cvp_ecns_enable_cmd(struct voice_data *v,
+ uint32_t module_id, int enable)
+{
+ int ret;
+ struct cvp_set_channel_ecns_cmd_v2 cvp_set_ch_ecns_cmd;
+ void *apr_cvp;
+ u16 cvp_handle;
+ struct vss_icommon_param_data_ecns_t *cvp_config_param_data =
+ &cvp_set_ch_ecns_cmd.
+ cvp_set_ecns.param_data;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cvp_handle = voice_get_cvp_handle(v);
+ memset(&cvp_set_ch_ecns_cmd, 0,
+ sizeof(cvp_set_ch_ecns_cmd));
+
+ cvp_set_ch_ecns_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_set_ch_ecns_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_set_ch_ecns_cmd) - APR_HDR_SIZE);
+ cvp_set_ch_ecns_cmd.hdr.src_svc = 0;
+ cvp_set_ch_ecns_cmd.hdr.src_domain = APR_DOMAIN_APPS;
+ cvp_set_ch_ecns_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvp_set_ch_ecns_cmd.hdr.dest_svc = 0;
+ cvp_set_ch_ecns_cmd.hdr.dest_domain = APR_DOMAIN_ADSP;
+ cvp_set_ch_ecns_cmd.hdr.dest_port = cvp_handle;
+ cvp_set_ch_ecns_cmd.hdr.token = 0;
+ cvp_set_ch_ecns_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_PARAM_V2;
+ cvp_set_ch_ecns_cmd.cvp_set_ecns.mem_size =
+ sizeof(struct vss_icommon_param_data_ecns_t);
+
+ cvp_config_param_data->module_id = module_id;
+ cvp_config_param_data->param_id = VOICE_PARAM_MOD_ENABLE;
+ cvp_config_param_data->param_size = MOD_ENABLE_PARAM_LEN;
+ cvp_config_param_data->reserved = 0;
+ cvp_config_param_data->enable = enable;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ v->async_err = 0;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *)&cvp_set_ch_ecns_cmd);
+
+ if (ret < 0) {
+ pr_err("%s: Failed to send VSS_ICOMMON_CMD_SET_PARAM_V2 %d\n",
+ __func__, ret);
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -ETIMEDOUT;
+ goto done;
+ }
+
+ if (v->async_err > 0) {
+ pr_err("%s: DSP returned error[%s] handle = %d\n", __func__,
+ adsp_err_get_err_str(v->async_err), cvp_handle);
+ ret = adsp_err_get_lnx_err_code(v->async_err);
+ goto done;
+ }
+ ret = 0;
+done:
+ return ret;
+}
+
+/**
+ * voc_set_ecns_enable -
+ * Command to set ECNS for voice module
+ *
+ * @session_id: voice session ID to send this command
+ * @module_id: voice module id
+ * @enable: enable/disable flag
+ *
+ * Returns 0 on success or error on failure
+ */
+int voc_set_ecns_enable(uint32_t session_id, uint32_t module_id,
+ uint32_t enable)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+ return -EINVAL;
+ }
+ mutex_lock(&v->lock);
+ v->ecns_enable = enable;
+ v->ecns_module_id = module_id;
+
+ if (is_voc_state_active(v->voc_state))
+ ret = voice_send_cvp_ecns_enable_cmd(v,
+ v->ecns_module_id, v->ecns_enable);
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(voc_set_ecns_enable);
+
static int voice_send_set_pp_enable_cmd(
struct voice_data *v, struct module_instance_info mod_inst_info,
int enable)
@@ -3852,6 +3974,7 @@
&cal_block->cal_data.paddr,
cal_block->map_data.map_size);
+ common.rtac_mem_map_table.dma_buf = NULL;
goto done_unlock;
}
}
@@ -4174,6 +4297,7 @@
struct cvp_set_mfc_config_cmd_v2 cvp_set_mfc_config_cmd;
void *apr_cvp;
u16 cvp_handle;
+ uint8_t ch_idx;
struct vss_icommon_param_data_mfc_config_v2_t *cvp_config_param_data =
&cvp_set_mfc_config_cmd.cvp_set_mfc_param_v2.param_data;
struct vss_param_mfc_config_info_t *mfc_config_info =
@@ -4222,9 +4346,15 @@
mfc_config_info->num_channels = v->dev_rx.no_of_channels;
mfc_config_info->bits_per_sample = 16;
mfc_config_info->sample_rate = v->dev_rx.sample_rate;
- memcpy(&mfc_config_info->channel_type,
- v->dev_rx.channel_mapping,
- VSS_NUM_CHANNELS_MAX * sizeof(uint8_t));
+
+ /*
+ * Do not use memcpy here as channel_type in mfc_config structure is a
+ * uint16_t array while channel_mapping array of device is of uint8_t
+ */
+ for (ch_idx = 0; ch_idx < VSS_NUM_CHANNELS_MAX; ch_idx++) {
+ mfc_config_info->channel_type[ch_idx] =
+ v->dev_rx.channel_mapping[ch_idx];
+ }
v->cvp_state = CMD_STATUS_FAIL;
v->async_err = 0;
@@ -4419,6 +4549,10 @@
if (v->dtmf_rx_detect_en)
voice_send_dtmf_rx_detection_cmd(v, v->dtmf_rx_detect_en);
+ if (v->ecns_enable)
+ voice_send_cvp_ecns_enable_cmd(v, v->ecns_module_id,
+ v->ecns_enable);
+
if (v->hd_enable)
voice_send_hd_cmd(v, v->hd_enable);
@@ -5075,6 +5209,9 @@
if (v->dtmf_rx_detect_en)
voice_send_dtmf_rx_detection_cmd(v, 0);
+ if (v->ecns_enable)
+ voice_send_cvp_ecns_enable_cmd(v, v->ecns_module_id, 0);
+
/* detach VOCPROC and wait for response from mvm */
mvm_d_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
diff --git a/include/asoc/wcd-mbhc-v2.h b/include/asoc/wcd-mbhc-v2.h
index 1f9d64e..f3ee728 100644
--- a/include/asoc/wcd-mbhc-v2.h
+++ b/include/asoc/wcd-mbhc-v2.h
@@ -451,6 +451,8 @@
};
struct wcd_mbhc_cb {
+ void (*bcs_enable)
+ (struct wcd_mbhc *mbhc, bool bcs_enable);
int (*enable_mb_source)(struct wcd_mbhc *mbhc, bool turn_on);
void (*trim_btn_reg)(struct snd_soc_component *component);
void (*compute_impedance)(struct wcd_mbhc *mbhc,
diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h
index d1b4f3c..9e1a0b2 100644
--- a/include/dsp/q6afe-v2.h
+++ b/include/dsp/q6afe-v2.h
@@ -483,10 +483,14 @@
int afe_get_doa_tracking_mon(u16 port_id,
struct doa_tracking_mon_param *doa_tracking_data);
-#define AFE_LPASS_CORE_HW_BLOCK_ID_NONE 0
-#define AFE_LPASS_CORE_HW_BLOCK_ID_AVTIMER 2
-#define AFE_LPASS_CORE_HW_MACRO_BLOCK 3
-#define AFE_LPASS_CORE_HW_DCODEC_BLOCK 4
+enum {
+ AFE_LPASS_CORE_HW_BLOCK_ID_NONE,
+ AFE_LPASS_CORE_HW_RSVD,
+ AFE_LPASS_CORE_HW_BLOCK_ID_AVTIMER,
+ AFE_LPASS_CORE_HW_MACRO_BLOCK,
+ AFE_LPASS_CORE_HW_DCODEC_BLOCK,
+ AFE_LPASS_CORE_HW_VOTE_MAX
+};
/* Handles audio-video timer (avtimer) and BTSC vote requests from clients.
*/
diff --git a/include/dsp/q6voice.h b/include/dsp/q6voice.h
index 2edfbe2..35ace4e 100644
--- a/include/dsp/q6voice.h
+++ b/include/dsp/q6voice.h
@@ -312,6 +312,21 @@
struct vss_param_channel_mixer_info_t ch_mixer_info;
} __packed;
+struct vss_icommon_param_data_ecns_t {
+ /* Valid ID of the module. */
+ uint32_t module_id;
+ /* Valid ID of the parameter. */
+ uint32_t param_id;
+ /*
+ * Data size of the structure relating to the param_id/module_id
+ * combination in uint8_t bytes.
+ */
+ uint16_t param_size;
+ /* This field must be set to zero. */
+ uint16_t reserved;
+ uint32_t enable;
+} __packed;
+
struct vss_icommon_cmd_set_param_ch_mixer_v2_t {
/*
* Pointer to the unique identifier for an address (physical/virtual).
@@ -338,6 +353,33 @@
struct vss_icommon_param_data_ch_mixer_v2_t param_data;
} __packed;
+
+struct vss_icommon_cmd_set_ecns_enable_t {
+ /*
+ * Pointer to the unique identifier for an address (physical/virtual).
+ *
+ * If the parameter data payload is within the message payload
+ * (in-band), set this field to 0. The parameter data begins at the
+ * specified data payload address.
+ *
+ * If the parameter data is out-of-band, this field is the handle to
+ * the physical address in the shared memory that holds the parameter
+ * data.
+ */
+ uint32_t mem_handle;
+ /*
+ * Location of the parameter data payload.
+ *
+ * The payload is an array of vss_icommon_param_data_t. If the
+ * mem_handle is 0, this field is ignored.
+ */
+ uint64_t mem_address;
+ /* Size of the parameter data payload in bytes. */
+ uint32_t mem_size;
+
+ struct vss_icommon_param_data_ecns_t param_data;
+} __packed;
+
struct vss_icommon_param_data_mfc_config_v2_t {
/* Valid ID of the module. */
uint32_t module_id;
@@ -809,6 +851,7 @@
#define MODULE_ID_VOICE_MODULE_ST 0x00010EE3
#define VOICE_PARAM_MOD_ENABLE 0x00010E00
+#define MOD_ENABLE_PARAM_LEN 4
#define VSS_IPLAYBACK_CMD_START 0x000112BD
/* Start in-call music delivery on the Tx voice path. */
@@ -1679,6 +1722,11 @@
struct apr_hdr hdr;
} __packed;
+struct cvp_set_channel_ecns_cmd_v2 {
+ struct apr_hdr hdr;
+ struct vss_icommon_cmd_set_ecns_enable_t cvp_set_ecns;
+} __packed;
+
struct cvp_set_rx_volume_index_cmd {
struct apr_hdr hdr;
struct vss_ivocproc_cmd_set_volume_index_t cvp_set_vol_idx;
@@ -1894,6 +1942,10 @@
bool mic_break_status;
struct work_struct voice_mic_break_work;
+
+ uint32_t ecns_enable;
+ uint32_t ecns_module_id;
+
};
#define MAX_VOC_SESSIONS 8
@@ -2042,6 +2094,8 @@
int voc_set_route_flag(uint32_t session_id, uint8_t path_dir, uint8_t set);
uint8_t voc_get_route_flag(uint32_t session_id, uint8_t path_dir);
bool voc_get_mbd_enable(void);
+int voc_set_ecns_enable(uint32_t session_id, uint32_t module_id,
+ uint32_t enable);
uint8_t voc_set_mbd_enable(bool enable);
int voc_enable_dtmf_rx_detection(uint32_t session_id, uint32_t enable);
void voc_disable_dtmf_det_on_active_sessions(void);
diff --git a/ipc/Android.mk b/ipc/Android.mk
index 62d78d0..3238a79 100644
--- a/ipc/Android.mk
+++ b/ipc/Android.mk
@@ -27,6 +27,10 @@
AUDIO_SELECT := CONFIG_SND_SOC_LITO=m
endif
+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,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike),true)
diff --git a/ipc/Kbuild b/ipc/Kbuild
index bb63b6f..bbea673 100644
--- a/ipc/Kbuild
+++ b/ipc/Kbuild
@@ -41,9 +41,9 @@
INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
endif
ifeq ($(CONFIG_ARCH_BENGAL), y)
- include $(AUDIO_ROOT)/config/litoauto.conf
+ include $(AUDIO_ROOT)/config/bengalauto.conf
export
- INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
+ INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
endif
ifeq ($(CONFIG_ARCH_SM8150), y)
ifdef CONFIG_SND_SOC_SA8155
diff --git a/soc/Android.mk b/soc/Android.mk
index 21d3d0a..9ed83d4 100644
--- a/soc/Android.mk
+++ b/soc/Android.mk
@@ -27,6 +27,10 @@
AUDIO_SELECT := CONFIG_SND_SOC_LITO=m
endif
+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,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike),true)
@@ -56,7 +60,7 @@
KBUILD_OPTIONS += $(AUDIO_SELECT)
###########################################################
-ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) kona lito),true)
+ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) kona lito bengal),true)
ifneq ($(TARGET_BOARD_AUTO),true)
include $(CLEAR_VARS)
LOCAL_MODULE := $(AUDIO_CHIPSET)_pinctrl_lpi.ko
@@ -98,7 +102,7 @@
include $(DLKM_DIR)/AndroidKernelModule.mk
endif
###########################################################
-ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) kona lito sdmshrike),true)
+ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) kona lito bengal sdmshrike),true)
ifneq ($(TARGET_PRODUCT), $(filter $(TARGET_PRODUCT), msmnile))
include $(CLEAR_VARS)
LOCAL_MODULE := $(AUDIO_CHIPSET)_snd_event.ko
diff --git a/soc/Kbuild b/soc/Kbuild
index 83bb243..9e32c42 100644
--- a/soc/Kbuild
+++ b/soc/Kbuild
@@ -35,9 +35,9 @@
INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
endif
ifeq ($(CONFIG_ARCH_BENGAL), y)
- include $(AUDIO_ROOT)/config/litoauto.conf
+ include $(AUDIO_ROOT)/config/bengalauto.conf
export
- INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
+ INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
endif
ifeq ($(CONFIG_ARCH_SM6150), y)
ifdef CONFIG_SND_SOC_SA6155
diff --git a/soc/pinctrl-lpi.c b/soc/pinctrl-lpi.c
index ba39129..2b9e52e 100644
--- a/soc/pinctrl-lpi.c
+++ b/soc/pinctrl-lpi.c
@@ -112,6 +112,7 @@
struct gpio_chip chip;
char __iomem *base;
struct clk *lpass_core_hw_vote;
+ struct clk *lpass_audio_hw_vote;
struct mutex slew_access_lock;
bool core_hw_vote_status;
struct mutex core_hw_vote_lock;
@@ -626,6 +627,7 @@
char __iomem *slew_base;
u32 reg, slew_reg;
struct clk *lpass_core_hw_vote = NULL;
+ struct clk *lpass_audio_hw_vote = NULL;
ret = of_property_read_u32(dev->of_node, "reg", ®);
if (ret < 0) {
@@ -796,6 +798,17 @@
}
state->lpass_core_hw_vote = lpass_core_hw_vote;
+ /* Register LPASS audio hw vote */
+ lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote");
+ if (IS_ERR(lpass_audio_hw_vote)) {
+ ret = PTR_ERR(lpass_audio_hw_vote);
+ dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n",
+ __func__, "lpass_audio_hw_vote", ret);
+ lpass_audio_hw_vote = NULL;
+ ret = 0;
+ }
+ state->lpass_audio_hw_vote = lpass_audio_hw_vote;
+
state->core_hw_vote_status = false;
pm_runtime_set_autosuspend_delay(&pdev->dev, LPI_AUTO_SUSPEND_DELAY);
pm_runtime_use_autosuspend(&pdev->dev);
@@ -842,14 +855,19 @@
{
struct lpi_gpio_state *state = dev_get_drvdata(dev);
int ret = 0;
+ struct clk *hw_vote = state->lpass_core_hw_vote;
if (state->lpass_core_hw_vote == NULL) {
dev_dbg(dev, "%s: Invalid core hw node\n", __func__);
- return 0;
+ if (state->lpass_audio_hw_vote == NULL) {
+ dev_dbg(dev, "%s: Invalid audio hw node\n", __func__);
+ return 0;
+ }
+ hw_vote = state->lpass_audio_hw_vote;
}
mutex_lock(&state->core_hw_vote_lock);
- ret = clk_prepare_enable(state->lpass_core_hw_vote);
+ ret = clk_prepare_enable(hw_vote);
if (ret < 0) {
pm_runtime_set_autosuspend_delay(dev,
LPI_AUTO_SUSPEND_DELAY_ERROR);
@@ -870,15 +888,20 @@
int lpi_pinctrl_runtime_suspend(struct device *dev)
{
struct lpi_gpio_state *state = dev_get_drvdata(dev);
+ struct clk *hw_vote = state->lpass_core_hw_vote;
if (state->lpass_core_hw_vote == NULL) {
dev_dbg(dev, "%s: Invalid core hw node\n", __func__);
- return 0;
+ if (state->lpass_audio_hw_vote == NULL) {
+ dev_dbg(dev, "%s: Invalid audio hw node\n", __func__);
+ return 0;
+ }
+ hw_vote = state->lpass_audio_hw_vote;
}
mutex_lock(&state->core_hw_vote_lock);
if (state->core_hw_vote_status) {
- clk_disable_unprepare(state->lpass_core_hw_vote);
+ clk_disable_unprepare(hw_vote);
state->core_hw_vote_status = false;
}
mutex_unlock(&state->core_hw_vote_lock);
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index 44d245d..242a512 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -25,6 +25,7 @@
#include "swrm_registers.h"
#include "swr-mstr-ctrl.h"
+#define SWRM_FRAME_SYNC_SEL 4000 /* 4KHz */
#define SWRM_SYSTEM_RESUME_TIMEOUT_MS 700
#define SWRM_SYS_SUSPEND_WAIT 1
@@ -43,6 +44,14 @@
#define ERR_AUTO_SUSPEND_TIMER_VAL 0x1
#define SWRM_INTERRUPT_STATUS_MASK 0x1FDFD
+#define SWRM_LINK_STATUS_RETRY_CNT 0x5
+
+#define SWRM_ROW_48 48
+#define SWRM_ROW_50 50
+#define SWRM_ROW_64 64
+#define SWRM_COL_02 02
+#define SWRM_COL_16 16
+
/* pm runtime auto suspend timer in msecs */
static int auto_suspend_timer = SWR_AUTO_SUSPEND_DELAY * 1000;
module_param(auto_suspend_timer, int, 0664);
@@ -306,6 +315,11 @@
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)
{
@@ -341,6 +355,40 @@
return ret;
}
+static int swrm_get_ssp_period(struct swr_mstr_ctrl *swrm,
+ int row, int col,
+ int frame_sync)
+{
+ if (!swrm || !row || !col || !frame_sync)
+ return 1;
+
+ 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;
@@ -354,13 +402,15 @@
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++;
@@ -397,14 +447,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;
@@ -420,15 +477,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;
@@ -476,6 +539,34 @@
return 0;
}
+static bool swrm_check_link_status(struct swr_mstr_ctrl *swrm, bool active)
+{
+ 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 {
+ 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;
+ }
+ retry--;
+ usleep_range(500, 510);
+ } while (retry);
+
+ if (retry == 0)
+ dev_err(swrm->dev, "%s: link status not %s\n", __func__,
+ active ? "connected" : "disconnected");
+
+ return ret;
+}
+
static bool swrm_is_port_en(struct swr_master *mstr)
{
return !!(mstr->num_port);
@@ -591,6 +682,10 @@
if (retry_attempt < MAX_FIFO_RD_FAIL_RETRY) {
/* wait 500 us before retry on fifo read failure */
usleep_range(500, 505);
+ if (retry_attempt == (MAX_FIFO_RD_FAIL_RETRY - 1)) {
+ swr_master_write(swrm, SWRM_CMD_FIFO_CMD, 0x1);
+ swr_master_write(swrm, SWRM_CMD_FIFO_RD_CMD, val);
+ }
retry_attempt++;
goto retry_read;
} else {
@@ -1093,7 +1188,9 @@
{
u8 bank;
u32 value, n_row, n_col;
+ u32 row = 0, col = 0;
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 |
@@ -1162,30 +1259,39 @@
if (enable) {
/* set col = 16 */
n_col = SWR_MAX_COL;
+ col = SWRM_COL_16;
} else {
/*
* Do not change to col = 2 if there are still active ports
*/
- if (!master->num_port)
+ if (!master->num_port) {
n_col = SWR_MIN_COL;
- else
+ col = SWRM_COL_02;
+ } else {
n_col = SWR_MAX_COL;
+ col = SWRM_COL_16;
+ }
}
/* 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);
n_row = SWR_ROW_64;
+ row = SWRM_ROW_64;
} else {
dev_dbg(swrm->dev, "setting 50 x %d frameshape\n",
n_col ? 16 : 2);
n_row = SWR_ROW_50;
+ row = SWRM_ROW_50;
}
+ 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);
+
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) |
- (0 << SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_SHFT));
+ ((ssp_period - 1) << SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_SHFT));
swr_master_write(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank), value);
dev_dbg(swrm->dev, "%s: regaddr: 0x%x, value: 0x%x\n", __func__,
@@ -1607,12 +1713,6 @@
struct swr_device *swr_dev;
struct swr_master *mstr = &swrm->master;
- if (!swrm->dev_up || swrm->state == SWR_MSTR_SSR) {
- complete(&swrm->broadcast);
- dev_dbg(swrm->dev, "%s swrm is not up\n", __func__);
- return IRQ_NONE;
- }
-
if (unlikely(swrm_lock_sleep(swrm) == false)) {
dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
return IRQ_NONE;
@@ -1684,6 +1784,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",
@@ -1732,6 +1833,7 @@
case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW:
dev_dbg(swrm->dev, "%s: SWR write FIFO overflow\n",
__func__);
+ swr_master_write(swrm, SWRM_CMD_FIFO_CMD, 0x1);
break;
case SWRM_INTERRUPT_STATUS_CMD_ERROR:
value = swr_master_read(swrm, SWRM_CMD_FIFO_STATUS);
@@ -1767,6 +1869,7 @@
case SWRM_INTERRUPT_STATUS_AUTO_ENUM_TABLE_IS_FULL_V2:
break;
case SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2:
+ swrm_check_link_status(swrm, 0x1);
break;
case SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2:
break;
@@ -1828,10 +1931,21 @@
pr_err("%s: swrm or dev is null\n", __func__);
return IRQ_NONE;
}
+
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;
}
@@ -1840,8 +1954,17 @@
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);
@@ -2022,12 +2145,17 @@
u8 retry_cmd_num = 3;
u32 reg[SWRM_MAX_INIT_REG];
u32 value[SWRM_MAX_INIT_REG];
+ u32 temp = 0;
int len = 0;
+ ssp_period = swrm_get_ssp_period(swrm, SWRM_ROW_50,
+ SWRM_COL_02, SWRM_FRAME_SYNC_SEL);
+ dev_dbg(swrm->dev, "%s: ssp_period: %d\n", __func__, ssp_period);
+
/* Clear Rows and Cols */
val = ((row_ctrl << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT) |
(col_ctrl << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT) |
- (ssp_period << SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_SHFT));
+ ((ssp_period - 1) << SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_SHFT));
reg[len] = SWRM_MCP_FRAME_CTRL_BANK_ADDR(0);
value[len++] = val;
@@ -2071,15 +2199,30 @@
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.
*/
- if (swrm->version == SWRM_VERSION_1_5_1)
+ /* Execute it for versions >= 1.5.1 */
+ if (swrm->version >= SWRM_VERSION_1_5_1)
swr_master_write(swrm, SWRM_CMD_FIFO_CFG_ADDR,
(swr_master_read(swrm,
SWRM_CMD_FIFO_CFG_ADDR) | 0x80000000));
+ /* SW workaround to gate hw_ctl for SWR version >=1.6 */
+ if (swrm->version >= SWRM_VERSION_1_6) {
+ if (swrm->swrm_hctl_reg) {
+ temp = ioread32(swrm->swrm_hctl_reg);
+ temp &= 0xFFFFFFFD;
+ iowrite32(temp, swrm->swrm_hctl_reg);
+ }
+ }
return ret;
}
@@ -2129,7 +2272,7 @@
{
struct swr_mstr_ctrl *swrm;
struct swr_ctrl_platform_data *pdata;
- u32 i, num_ports, port_num, port_type, ch_mask;
+ u32 i, num_ports, port_num, port_type, ch_mask, swrm_hctl_reg = 0;
u32 *temp, map_size, map_length, ch_iter = 0, old_port_num = 0;
int ret = 0;
struct clk *lpass_core_hw_vote = NULL;
@@ -2198,6 +2341,10 @@
}
swrm->core_vote = pdata->core_vote;
+ if (!(of_property_read_u32(pdev->dev.of_node,
+ "qcom,swrm-hctl-reg", &swrm_hctl_reg)))
+ swrm->swrm_hctl_reg = devm_ioremap(&pdev->dev,
+ swrm_hctl_reg, 0x4);
swrm->clk = pdata->clk;
if (!swrm->clk) {
dev_err(&pdev->dev, "%s: swrm->clk is NULL\n",
@@ -2295,6 +2442,7 @@
swrm->clk_ref_count = 0;
swrm->swr_irq_wakeup_capable = 0;
swrm->mclk_freq = MCLK_FREQ;
+ swrm->bus_clk = MCLK_FREQ;
swrm->dev_up = true;
swrm->state = SWR_MSTR_UP;
swrm->ipc_wakeup = false;
@@ -2302,6 +2450,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);
@@ -2448,6 +2597,7 @@
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);
@@ -2480,6 +2630,7 @@
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);
@@ -2534,6 +2685,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);
@@ -2568,6 +2733,8 @@
swrm_master_init(swrm);
/* wait for hw enumeration to complete */
usleep_range(100, 105);
+ if (!swrm_check_link_status(swrm, 0x1))
+ goto exit;
swrm_cmd_fifo_wr_cmd(swrm, 0x4, 0xF, 0x0,
SWRS_SCP_INT_STATUS_MASK_1);
if (swrm->state == SWR_MSTR_SSR) {
@@ -2578,7 +2745,17 @@
} 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;
}
swrm->state = SWR_MSTR_UP;
}
@@ -2657,6 +2834,13 @@
}
}
} 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,
@@ -2664,6 +2848,8 @@
mutex_lock(&swrm->reslock);
usleep_range(100, 105);
}
+ if (!swrm_check_link_status(swrm, 0x0))
+ goto exit;
ret = swrm_clk_request(swrm, false);
if (ret) {
dev_err(dev, "%s: swrmn clk failed\n", __func__);
@@ -2866,8 +3052,15 @@
__func__, swrm->state);
else
swrm_device_suspend(&pdev->dev);
+ /*
+ * add delay to ensure clk release happen
+ * if interrupt triggered for clk stop,
+ * wait for it to exit
+ */
+ usleep_range(10000, 10500);
}
swrm->mclk_freq = *(int *)data;
+ swrm->bus_clk = swrm->mclk_freq;
mutex_unlock(&swrm->mlock);
}
break;
diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h
index 321e84f..654dd0e 100644
--- a/soc/swr-mstr-ctrl.h
+++ b/soc/swr-mstr-ctrl.h
@@ -38,6 +38,7 @@
#define SWRM_VERSION_1_3 0x01040000
#define SWRM_VERSION_1_5 0x01050000
#define SWRM_VERSION_1_5_1 0x01050001
+#define SWRM_VERSION_1_6 0x01060000
#define SWR_MAX_CH_PER_PORT 8
@@ -123,8 +124,10 @@
struct mutex mlock;
struct mutex reslock;
struct mutex pm_lock;
+ struct mutex irq_lock;
u32 swrm_base_reg;
char __iomem *swrm_dig_base;
+ char __iomem *swrm_hctl_reg;
u8 rcmd_id;
u8 wcmd_id;
u32 master_id;
@@ -140,6 +143,7 @@
int wake_irq;
int version;
int mclk_freq;
+ int bus_clk;
u32 num_dev;
int slave_status;
struct swrm_mports mport_cfg[SWR_MAX_MSTR_PORT_NUM];
diff --git a/soc/swrm_registers.h b/soc/swrm_registers.h
index 6f2544b..63fe4ca 100644
--- a/soc/swrm_registers.h
+++ b/soc/swrm_registers.h
@@ -17,6 +17,7 @@
#define SWRM_COMP_CFG_ENABLE_SHFT 0x0
#define SWRM_COMP_SW_RESET (SWRM_BASE_ADDRESS+0x00000008)
+#define SWRM_COMP_STATUS (SWRM_BASE_ADDRESS+0x00000014)
#define SWRM_COMP_PARAMS (SWRM_BASE_ADDRESS+0x100)
#define SWRM_COMP_PARAMS_DOUT_PORTS_MASK 0x0000001F