summaryrefslogtreecommitdiff
path: root/asoc
diff options
context:
space:
mode:
Diffstat (limited to 'asoc')
-rw-r--r--asoc/codecs/bolero/bolero-cdc.c14
-rw-r--r--asoc/codecs/bolero/bolero-cdc.h3
-rw-r--r--asoc/codecs/bolero/bolero-clk-rsc.c30
-rw-r--r--asoc/codecs/bolero/va-macro.c10
-rw-r--r--asoc/codecs/rouleur/Android.mk65
-rw-r--r--asoc/codecs/rouleur/Kbuild120
-rw-r--r--asoc/codecs/rouleur/internal.h172
-rw-r--r--asoc/codecs/rouleur/pm2250-spmi.h17
-rw-r--r--asoc/codecs/rouleur/pm2250_spmi.c94
-rw-r--r--asoc/codecs/rouleur/rouleur-mbhc.c1155
-rw-r--r--asoc/codecs/rouleur/rouleur-mbhc.h67
-rw-r--r--asoc/codecs/rouleur/rouleur-registers.h121
-rw-r--r--asoc/codecs/rouleur/rouleur-regmap.c160
-rw-r--r--asoc/codecs/rouleur/rouleur-tables.c105
-rw-r--r--asoc/codecs/rouleur/rouleur.c2492
-rw-r--r--asoc/codecs/rouleur/rouleur.h19
-rw-r--r--asoc/codecs/rouleur/rouleur_slave.c144
-rw-r--r--asoc/codecs/wcd-mbhc-v2.c2
-rw-r--r--asoc/codecs/wcd937x/Android.mk2
-rw-r--r--asoc/codecs/wcd937x/Kbuild5
-rw-r--r--asoc/msm-dai-fe.c66
-rw-r--r--asoc/msm-pcm-routing-v2.c490
-rw-r--r--asoc/msm-pcm-routing-v2.h2
-rw-r--r--asoc/sa8155.c88
24 files changed, 5397 insertions, 46 deletions
diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c
index 6d1887e0..2db0c5b3 100644
--- a/asoc/codecs/bolero/bolero-cdc.c
+++ b/asoc/codecs/bolero/bolero-cdc.c
@@ -101,8 +101,11 @@ static int __bolero_reg_read(struct bolero_priv *priv,
goto ssr_err;
}
- if (priv->macro_params[VA_MACRO].dev)
+ if (priv->macro_params[VA_MACRO].dev) {
pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
+ if (!bolero_check_core_votes(priv->macro_params[VA_MACRO].dev))
+ goto ssr_err;
+ }
if (priv->version < BOLERO_VERSION_2_0) {
/* Request Clk before register access */
@@ -149,8 +152,11 @@ static int __bolero_reg_write(struct bolero_priv *priv,
ret = -EINVAL;
goto ssr_err;
}
- if (priv->macro_params[VA_MACRO].dev)
+ if (priv->macro_params[VA_MACRO].dev) {
pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev);
+ if (!bolero_check_core_votes(priv->macro_params[VA_MACRO].dev))
+ goto ssr_err;
+ }
if (priv->version < BOLERO_VERSION_2_0) {
/* Request Clk before register access */
@@ -828,6 +834,10 @@ static int bolero_ssr_enable(struct device *dev, void *data)
priv->component,
BOLERO_MACRO_EVT_CLK_RESET, 0x0);
}
+
+ if (priv->rsc_clk_cb)
+ priv->rsc_clk_cb(priv->clk_dev, BOLERO_MACRO_EVT_SSR_GFMUX_UP);
+
trace_printk("%s: clk count reset\n", __func__);
regcache_cache_only(priv->regmap, false);
mutex_lock(&priv->clk_lock);
diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h
index 3144d88b..b37eeae6 100644
--- a/asoc/codecs/bolero/bolero-cdc.h
+++ b/asoc/codecs/bolero/bolero-cdc.h
@@ -52,7 +52,8 @@ enum {
BOLERO_MACRO_EVT_CLK_RESET,
BOLERO_MACRO_EVT_REG_WAKE_IRQ,
BOLERO_MACRO_EVT_RX_COMPANDER_SOFT_RST,
- BOLERO_MACRO_EVT_BCS_CLK_OFF
+ BOLERO_MACRO_EVT_BCS_CLK_OFF,
+ BOLERO_MACRO_EVT_SSR_GFMUX_UP,
};
enum {
diff --git a/asoc/codecs/bolero/bolero-clk-rsc.c b/asoc/codecs/bolero/bolero-clk-rsc.c
index daed7e65..9cc9b1ca 100644
--- a/asoc/codecs/bolero/bolero-clk-rsc.c
+++ b/asoc/codecs/bolero/bolero-clk-rsc.c
@@ -38,6 +38,7 @@ struct bolero_clk_rsc {
int reg_seq_en_cnt;
int va_tx_clk_cnt;
bool dev_up;
+ bool dev_up_gfmux;
u32 num_fs_reg;
u32 *fs_gen_seq;
int default_clk_id[MAX_CLK];
@@ -65,10 +66,14 @@ static int bolero_clk_rsc_cb(struct device *dev, u16 event)
}
mutex_lock(&priv->rsc_clk_lock);
- if (event == BOLERO_MACRO_EVT_SSR_UP)
+ if (event == BOLERO_MACRO_EVT_SSR_UP) {
priv->dev_up = true;
- else if (event == BOLERO_MACRO_EVT_SSR_DOWN)
+ } else if (event == BOLERO_MACRO_EVT_SSR_DOWN) {
priv->dev_up = false;
+ priv->dev_up_gfmux = false;
+ } else if (event == BOLERO_MACRO_EVT_SSR_GFMUX_UP) {
+ priv->dev_up_gfmux = true;
+ }
mutex_unlock(&priv->rsc_clk_lock);
return 0;
@@ -282,10 +287,12 @@ static int bolero_clk_rsc_mux1_clk_request(struct bolero_clk_rsc *priv,
* care in DSP itself
*/
if (clk_id != VA_CORE_CLK) {
- iowrite32(0x1, clk_muxsel);
- muxsel = ioread32(clk_muxsel);
- trace_printk("%s: muxsel value after enable: %d\n",
- __func__, muxsel);
+ if (priv->dev_up_gfmux) {
+ iowrite32(0x1, clk_muxsel);
+ muxsel = ioread32(clk_muxsel);
+ trace_printk("%s: muxsel value after enable: %d\n",
+ __func__, muxsel);
+ }
bolero_clk_rsc_mux0_clk_request(priv,
default_clk_id,
false);
@@ -313,10 +320,12 @@ static int bolero_clk_rsc_mux1_clk_request(struct bolero_clk_rsc *priv,
* This configuration would be taken
* care in DSP itself.
*/
- iowrite32(0x0, clk_muxsel);
- muxsel = ioread32(clk_muxsel);
- trace_printk("%s: muxsel value after disable: %d\n",
- __func__, muxsel);
+ if (priv->dev_up_gfmux) {
+ iowrite32(0x0, clk_muxsel);
+ muxsel = ioread32(clk_muxsel);
+ trace_printk("%s: muxsel value after disable: %d\n",
+ __func__, muxsel);
+ }
}
}
if (priv->clk[clk_id + NPL_CLK_OFFSET])
@@ -706,6 +715,7 @@ static int bolero_clk_rsc_probe(struct platform_device *pdev)
}
priv->dev = &pdev->dev;
priv->dev_up = true;
+ priv->dev_up_gfmux = true;
mutex_init(&priv->rsc_clk_lock);
mutex_init(&priv->fs_gen_lock);
dev_set_drvdata(&pdev->dev, priv);
diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c
index dff74bdf..85d4ae39 100644
--- a/asoc/codecs/bolero/va-macro.c
+++ b/asoc/codecs/bolero/va-macro.c
@@ -727,14 +727,20 @@ static int va_macro_swrm_clock(void *handle, bool enable)
if (va_priv->va_swr_clk_cnt && !va_priv->tx_swr_clk_cnt) {
ret = va_macro_tx_va_mclk_enable(va_priv, regmap,
VA_MCLK, enable);
- if (ret)
+ if (ret) {
+ pm_runtime_mark_last_busy(va_priv->dev);
+ pm_runtime_put_autosuspend(va_priv->dev);
goto done;
+ }
va_priv->va_clk_status++;
} else {
ret = va_macro_tx_va_mclk_enable(va_priv, regmap,
TX_MCLK, enable);
- if (ret)
+ if (ret) {
+ pm_runtime_mark_last_busy(va_priv->dev);
+ pm_runtime_put_autosuspend(va_priv->dev);
goto done;
+ }
va_priv->tx_clk_status++;
}
pm_runtime_mark_last_busy(va_priv->dev);
diff --git a/asoc/codecs/rouleur/Android.mk b/asoc/codecs/rouleur/Android.mk
new file mode 100644
index 00000000..4fb57936
--- /dev/null
+++ b/asoc/codecs/rouleur/Android.mk
@@ -0,0 +1,65 @@
+# Android makefile for audio kernel modules
+
+# Assume no targets will be supported
+
+# Check if this driver needs be built for current target
+ifeq ($(call is-board-platform,bengal),true)
+AUDIO_SELECT := CONFIG_SND_SOC_BENGAL=m
+endif
+
+AUDIO_CHIPSET := audio
+# Build/Package only in case of supported target
+ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) bengal),true)
+
+LOCAL_PATH := $(call my-dir)
+
+# This makefile is only for DLKM
+ifneq ($(findstring vendor,$(LOCAL_PATH)),)
+
+ifneq ($(findstring opensource,$(LOCAL_PATH)),)
+ AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel
+endif # opensource
+
+DLKM_DIR := $(TOP)/device/qcom/common/dlkm
+
+# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko
+###########################################################
+# This is set once per LOCAL_PATH, not per (kernel) module
+KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR)
+
+# We are actually building audio.ko here, as per the
+# requirement we are specifying <chipset>_audio.ko as LOCAL_MODULE.
+# This means we need to rename the module to <chipset>_audio.ko
+# after audio.ko is built.
+KBUILD_OPTIONS += MODNAME=rouleur_dlkm
+KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM)
+KBUILD_OPTIONS += $(AUDIO_SELECT)
+
+###########################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(AUDIO_CHIPSET)_rouleur.ko
+LOCAL_MODULE_KBUILD_NAME := rouleur_dlkm.ko
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/AndroidKernelModule.mk
+###########################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(AUDIO_CHIPSET)_rouleur_slave.ko
+LOCAL_MODULE_KBUILD_NAME := rouleur_slave_dlkm.ko
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/AndroidKernelModule.mk
+###########################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(AUDIO_CHIPSET)_pm2250_spmi.ko
+LOCAL_MODULE_KBUILD_NAME := pm2250_spmi_dlkm.ko
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/AndroidKernelModule.mk
+###########################################################
+
+endif # DLKM check
+endif # supported target check
diff --git a/asoc/codecs/rouleur/Kbuild b/asoc/codecs/rouleur/Kbuild
new file mode 100644
index 00000000..b59bcb11
--- /dev/null
+++ b/asoc/codecs/rouleur/Kbuild
@@ -0,0 +1,120 @@
+# We can build either as part of a standalone Kernel build or as
+# an external module. Determine which mechanism is being used
+ifeq ($(MODNAME),)
+ KERNEL_BUILD := 1
+else
+ KERNEL_BUILD := 0
+endif
+
+
+
+ifeq ($(KERNEL_BUILD), 1)
+ # These are configurable via Kconfig for kernel-based builds
+ # Need to explicitly configure for Android-based builds
+ AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/kernel/msm-4.19
+ AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio
+endif
+
+ifeq ($(KERNEL_BUILD), 0)
+ ifeq ($(CONFIG_ARCH_BENGAL), y)
+ include $(AUDIO_ROOT)/config/bengalauto.conf
+ export
+ INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
+ endif
+endif
+
+# As per target team, build is done as follows:
+# Defconfig : build with default flags
+# Slub : defconfig + CONFIG_SLUB_DEBUG := y +
+# CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y
+# Perf : Using appropriate msmXXXX-perf_defconfig
+#
+# Shipment builds (user variants) should not have any debug feature
+# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds
+# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since
+# there is no other way to identify defconfig builds, QTI internal
+# representation of perf builds (identified using the string 'perf'),
+# is used to identify if the build is a slub or defconfig one. This
+# way no critical debug feature will be enabled for perf and shipment
+# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT
+# config.
+
+############ UAPI ############
+UAPI_DIR := uapi
+UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR)
+
+############ COMMON ############
+COMMON_DIR := include
+COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR)
+
+############ ROULEUR ############
+
+# for ROULEUR Codec
+ifdef CONFIG_SND_SOC_ROULEUR
+ ROULEUR_OBJS += rouleur.o
+ ROULEUR_OBJS += rouleur-regmap.o
+ ROULEUR_OBJS += rouleur-tables.o
+ ROULEUR_OBJS += rouleur-mbhc.o
+endif
+
+ifdef CONFIG_PM2250_SPMI
+ PM2250_SPMI_OBJS += pm2250_spmi.o
+endif
+
+ifdef CONFIG_SND_SOC_ROULEUR_SLAVE
+ ROULEUR_SLAVE_OBJS += rouleur_slave.o
+endif
+
+LINUX_INC += -Iinclude/linux
+
+INCS += $(COMMON_INC) \
+ $(UAPI_INC)
+
+EXTRA_CFLAGS += $(INCS)
+
+
+CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \
+ -DANI_LITTLE_BIT_ENDIAN \
+ -DDOT11F_LITTLE_ENDIAN_HOST \
+ -DANI_COMPILER_TYPE_GCC \
+ -DANI_OS_TYPE_ANDROID=6 \
+ -DPTT_SOCK_SVC_ENABLE \
+ -Wall\
+ -Werror\
+ -D__linux__
+
+KBUILD_CPPFLAGS += $(CDEFINES)
+
+# Currently, for versions of gcc which support it, the kernel Makefile
+# is disabling the maybe-uninitialized warning. Re-enable it for the
+# AUDIO driver. Note that we must use EXTRA_CFLAGS here so that it
+# will override the kernel settings.
+ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y)
+EXTRA_CFLAGS += -Wmaybe-uninitialized
+endif
+#EXTRA_CFLAGS += -Wmissing-prototypes
+
+ifeq ($(call cc-option-yn, -Wheader-guard),y)
+EXTRA_CFLAGS += -Wheader-guard
+endif
+
+ifeq ($(KERNEL_BUILD), 0)
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers
+endif
+
+# Module information used by KBuild framework
+obj-$(CONFIG_SND_SOC_ROULEUR) += rouleur_dlkm.o
+rouleur_dlkm-y := $(ROULEUR_OBJS)
+
+obj-$(CONFIG_SND_SOC_ROULEUR_SLAVE) += rouleur_slave_dlkm.o
+rouleur_slave_dlkm-y := $(ROULEUR_SLAVE_OBJS)
+
+obj-$(CONFIG_PM2250_SPMI) += pm2250_spmi_dlkm.o
+pm2250_spmi_dlkm-y := $(PM2250_SPMI_OBJS)
+
+# inject some build related information
+DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"
diff --git a/asoc/codecs/rouleur/internal.h b/asoc/codecs/rouleur/internal.h
new file mode 100644
index 00000000..7104685d
--- /dev/null
+++ b/asoc/codecs/rouleur/internal.h
@@ -0,0 +1,172 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _ROULEUR_INTERNAL_H
+#define _ROULEUR_INTERNAL_H
+
+#include <asoc/wcd-clsh.h>
+#include <asoc/wcd-mbhc-v2.h>
+#include <asoc/wcd-irq.h>
+#include "rouleur-mbhc.h"
+
+#define ROULEUR_MAX_MICBIAS 3
+
+/* Convert from vout ctl to micbias voltage in mV */
+#define WCD_VOUT_CTL_TO_MICB(v) (1600 + v * 50)
+#define MAX_PORT 8
+#define MAX_CH_PER_PORT 8
+
+extern struct regmap_config rouleur_regmap_config;
+
+struct codec_port_info {
+ u32 slave_port_type;
+ u32 master_port_type;
+ u32 ch_mask;
+ u32 num_ch;
+ u32 ch_rate;
+};
+
+struct rouleur_priv {
+ struct device *dev;
+
+ int variant;
+ struct snd_soc_component *component;
+ struct device_node *spmi_np;
+ struct regmap *regmap;
+
+ struct swr_device *rx_swr_dev;
+ struct swr_device *tx_swr_dev;
+
+ s32 micb_ref[ROULEUR_MAX_MICBIAS];
+ s32 pullup_ref[ROULEUR_MAX_MICBIAS];
+
+ struct fw_info *fw_data;
+
+ struct mutex micb_lock;
+ s32 dmic_0_1_clk_cnt;
+ /* mbhc module */
+ struct rouleur_mbhc *mbhc;
+
+ bool comp1_enable;
+ bool comp2_enable;
+
+ struct irq_domain *virq;
+ struct wcd_irq_info irq_info;
+ u32 rx_clk_cnt;
+ int num_irq_regs;
+ /* to track the status */
+ unsigned long status_mask;
+
+ u8 num_tx_ports;
+ u8 num_rx_ports;
+ struct codec_port_info
+ tx_port_mapping[MAX_PORT][MAX_CH_PER_PORT];
+ struct codec_port_info
+ rx_port_mapping[MAX_PORT][MAX_CH_PER_PORT];
+ struct regulator_bulk_data *supplies;
+ struct notifier_block nblock;
+ /* wcd callback to bolero */
+ void *handle;
+ int (*update_wcd_event)(void *handle, u16 event, u32 data);
+ int (*register_notifier)(void *handle,
+ struct notifier_block *nblock,
+ bool enable);
+ int (*wakeup)(void *handle, bool enable);
+ u32 version;
+ /* Entry for version info */
+ struct snd_info_entry *entry;
+ struct snd_info_entry *version_entry;
+ struct device *spmi_dev;
+ int reset_reg;
+ int mbias_cnt;
+ struct mutex rx_clk_lock;
+ struct mutex main_bias_lock;
+};
+
+struct rouleur_micbias_setting {
+ u32 micb1_mv;
+ u32 micb2_mv;
+ u32 micb3_mv;
+};
+
+struct rouleur_pdata {
+ struct device_node *spmi_np;
+ struct device_node *rx_slave;
+ struct device_node *tx_slave;
+ struct rouleur_micbias_setting micbias;
+
+ struct cdc_regulator *regulator;
+ int num_supplies;
+ int reset_reg;
+};
+
+struct wcd_ctrl_platform_data {
+ void *handle;
+ int (*update_wcd_event)(void *handle, u16 event, u32 data);
+ int (*register_notifier)(void *handle,
+ struct notifier_block *nblock,
+ bool enable);
+};
+
+enum {
+ WCD_RX1,
+ WCD_RX2,
+ WCD_RX3
+};
+
+enum {
+ BOLERO_WCD_EVT_TX_CH_HOLD_CLEAR = 1,
+ BOLERO_WCD_EVT_PA_OFF_PRE_SSR,
+ BOLERO_WCD_EVT_SSR_DOWN,
+ BOLERO_WCD_EVT_SSR_UP,
+};
+
+enum {
+ WCD_BOLERO_EVT_RX_MUTE = 1, /* for RX mute/unmute */
+ WCD_BOLERO_EVT_IMPED_TRUE, /* for imped true */
+ WCD_BOLERO_EVT_IMPED_FALSE, /* for imped false */
+ WCD_BOLERO_EVT_RX_COMPANDER_SOFT_RST,
+ WCD_BOLERO_EVT_BCS_CLK_OFF,
+};
+
+enum {
+ /* INTR_CTRL_INT_MASK_0 */
+ ROULEUR_IRQ_MBHC_BUTTON_PRESS_DET = 0,
+ ROULEUR_IRQ_MBHC_BUTTON_RELEASE_DET,
+ ROULEUR_IRQ_MBHC_ELECT_INS_REM_DET,
+ ROULEUR_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+ ROULEUR_IRQ_MBHC_SW_DET,
+ ROULEUR_IRQ_HPHR_OCP_INT,
+ ROULEUR_IRQ_HPHR_CNP_INT,
+ ROULEUR_IRQ_HPHL_OCP_INT,
+
+ /* INTR_CTRL_INT_MASK_1 */
+ ROULEUR_IRQ_HPHL_CNP_INT,
+ ROULEUR_IRQ_EAR_CNP_INT,
+ ROULEUR_IRQ_EAR_OCP_INT,
+ ROULEUR_IRQ_LO_CNP_INT,
+ ROULEUR_IRQ_LO_OCP_INT,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT,
+ ROULEUR_IRQ_HPHR_PDM_WD_INT,
+ ROULEUR_IRQ_RESERVED_0,
+
+ /* INTR_CTRL_INT_MASK_2 */
+ ROULEUR_IRQ_RESERVED_1,
+ ROULEUR_IRQ_RESERVED_2,
+ ROULEUR_IRQ_HPHL_SURGE_DET_INT,
+ ROULEUR_IRQ_HPHR_SURGE_DET_INT,
+ ROULEUR_NUM_IRQS,
+};
+
+extern void rouleur_disable_bcs_before_slow_insert(
+ struct snd_soc_component *component,
+ bool bcs_disable);
+extern struct rouleur_mbhc *rouleur_soc_get_mbhc(
+ struct snd_soc_component *component);
+extern int rouleur_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
+ int volt, int micb_num);
+extern int rouleur_get_micb_vout_ctl_val(u32 micb_mv);
+extern int rouleur_micbias_control(struct snd_soc_component *component,
+ int micb_num, int req, bool is_dapm);
+#endif
diff --git a/asoc/codecs/rouleur/pm2250-spmi.h b/asoc/codecs/rouleur/pm2250-spmi.h
new file mode 100644
index 00000000..87c913d4
--- /dev/null
+++ b/asoc/codecs/rouleur/pm2250-spmi.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _PM2250_SPMI_H
+#define _PM2250_SPMI_H
+
+#ifdef CONFIG_PM2250_SPMI
+int pm2250_spmi_write(struct device *dev, int reg, int value);
+#else
+int pm2250_spmi_write(struct device *dev, int reg, int value)
+{
+ return 0;
+}
+#endif /* CONFIG_PM2250_SPMI */
+
+#endif
diff --git a/asoc/codecs/rouleur/pm2250_spmi.c b/asoc/codecs/rouleur/pm2250_spmi.c
new file mode 100644
index 00000000..1e5f70d1
--- /dev/null
+++ b/asoc/codecs/rouleur/pm2250_spmi.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/**
+ * @regmap: regmap used to access PMIC registers
+ */
+struct pm2250_spmi {
+ struct regmap *regmap;
+};
+
+static const struct of_device_id pm2250_id_table[] = {
+ { .compatible = "qcom,pm2250-spmi" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, pm2250_id_table);
+
+int pm2250_spmi_write(struct device *dev, int reg, int value)
+{
+ int rc;
+ struct pm2250_spmi *spmi_dd;
+
+ if (!of_device_is_compatible(dev->of_node, "qcom,pm2250-spmi")) {
+ pr_err("%s: Device node is invalid\n", __func__);
+ return -EINVAL;
+ }
+
+ spmi_dd = dev_get_drvdata(dev);
+ if (!spmi_dd)
+ return -EINVAL;
+
+ rc = regmap_write(spmi_dd->regmap, reg, value);
+ if (rc)
+ dev_err(dev, "%s: Write to PMIC register failed\n", __func__);
+
+ return rc;
+}
+EXPORT_SYMBOL(pm2250_spmi_write);
+
+static int pm2250_spmi_probe(struct platform_device *pdev)
+{
+ struct pm2250_spmi *spmi_dd;
+ const struct of_device_id *match;
+
+ match = of_match_node(pm2250_id_table, pdev->dev.of_node);
+ if (!match)
+ return -ENXIO;
+
+ spmi_dd = devm_kzalloc(&pdev->dev, sizeof(*spmi_dd), GFP_KERNEL);
+ if (spmi_dd == NULL)
+ return -ENOMEM;
+
+ spmi_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!spmi_dd->regmap) {
+ dev_err(&pdev->dev, "Parent regmap unavailable.\n");
+ return -ENXIO;
+ }
+
+ platform_set_drvdata(pdev, spmi_dd);
+
+ dev_dbg(&pdev->dev, "Probe success !!\n");
+
+ return 0;
+}
+
+static int pm2250_spmi_remove(struct platform_device *pdev)
+{
+ of_platform_depopulate(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver pm2250_spmi_driver = {
+ .probe = pm2250_spmi_probe,
+ .remove = pm2250_spmi_remove,
+ .driver = {
+ .name = "pm2250-spmi",
+ .of_match_table = pm2250_id_table,
+ },
+};
+module_platform_driver(pm2250_spmi_driver);
+
+MODULE_ALIAS("platform:pm2250-spmi");
+MODULE_DESCRIPTION("PMIC SPMI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/rouleur/rouleur-mbhc.c b/asoc/codecs/rouleur/rouleur-mbhc.c
new file mode 100644
index 00000000..3e3ef511
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur-mbhc.c
@@ -0,0 +1,1155 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include "rouleur-registers.h"
+#include <asoc/wcdcal-hwdep.h>
+#include <asoc/wcd-mbhc-v2-api.h>
+#include "internal.h"
+
+#define ROULEUR_ZDET_SUPPORTED true
+/* Z value defined in milliohm */
+#define ROULEUR_ZDET_VAL_32 32000
+#define ROULEUR_ZDET_VAL_400 400000
+#define ROULEUR_ZDET_VAL_1200 1200000
+#define ROULEUR_ZDET_VAL_100K 100000000
+/* Z floating defined in ohms */
+#define ROULEUR_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE
+
+#define ROULEUR_ZDET_NUM_MEASUREMENTS 900
+#define ROULEUR_MBHC_GET_C1(c) ((c & 0xC000) >> 14)
+#define ROULEUR_MBHC_GET_X1(x) (x & 0x3FFF)
+/* Z value compared in milliOhm */
+#define ROULEUR_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000))
+#define ROULEUR_MBHC_ZDET_CONST (86 * 16384)
+#define ROULEUR_MBHC_MOISTURE_RREF R_24_KOHM
+
+static struct wcd_mbhc_register
+ wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
+ WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN",
+ ROULEUR_ANA_MBHC_MECH, 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN",
+ ROULEUR_ANA_MBHC_MECH, 0x40, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE",
+ ROULEUR_ANA_MBHC_MECH, 0x20, 5, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL",
+ ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, 0x30, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE",
+ ROULEUR_ANA_MBHC_ELECT, 0x08, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL",
+ ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, 0xC0, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL",
+ ROULEUR_ANA_MBHC_MECH, 0x04, 2, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE",
+ ROULEUR_ANA_MBHC_MECH, 0x10, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE",
+ ROULEUR_ANA_MBHC_MECH, 0x08, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND",
+ ROULEUR_ANA_MBHC_MECH, 0x01, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC",
+ ROULEUR_ANA_MBHC_ELECT, 0x06, 1, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN",
+ ROULEUR_ANA_MBHC_ELECT, 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC",
+ ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, 0x0F, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC",
+ ROULEUR_ANA_MBHC_CTL_1, 0x03, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF",
+ ROULEUR_ANA_MBHC_CTL_2, 0x03, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x08, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_IN2P_CLAMP_STATE",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x10, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x20, 5, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x40, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN",
+ SND_SOC_NOPM, 0x00, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x07, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL",
+ ROULEUR_ANA_MBHC_ELECT, 0x70, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
+ ROULEUR_ANA_MBHC_RESULT_3, 0xFF, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
+ ROULEUR_ANA_MICBIAS_MICB_1_2_EN, 0x04, 2, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
+ SND_SOC_NOPM, 0x00, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
+ ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x40, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN",
+ ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN",
+ ROULEUR_ANA_HPHPA_CNP_CTL_2, 0xC0, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
+ ROULEUR_ANA_MBHC_RESULT_3, 0x10, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
+ 0, 0, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN",
+ SND_SOC_NOPM, 0x00, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS",
+ ROULEUR_ANA_MBHC_FSM_STATUS, 0x01, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL",
+ ROULEUR_ANA_MBHC_CTL_2, 0x70, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS",
+ ROULEUR_ANA_MBHC_FSM_STATUS, 0x20, 5, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND",
+ SND_SOC_NOPM, 0x00, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND",
+ SND_SOC_NOPM, 0x00, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN",
+ ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x02, 1, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN",
+ ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x01, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_STATUS",
+ ROULEUR_DIG_SWR_INTR_STATUS_0, 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_STATUS",
+ ROULEUR_DIG_SWR_INTR_STATUS_0, 0x20, 5, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ADC_EN",
+ ROULEUR_ANA_MBHC_CTL_1, 0x08, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ADC_COMPLETE", ROULEUR_ANA_MBHC_FSM_STATUS,
+ 0x40, 6, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ADC_TIMEOUT", ROULEUR_ANA_MBHC_FSM_STATUS,
+ 0x80, 7, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ADC_RESULT", ROULEUR_ANA_MBHC_ADC_RESULT,
+ 0xFF, 0, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_MICB2_VOUT",
+ ROULEUR_ANA_MICBIAS_LDO_1_SETTING, 0xF8, 3, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ADC_MODE",
+ ROULEUR_ANA_MBHC_CTL_1, 0x10, 4, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_DETECTION_DONE",
+ ROULEUR_ANA_MBHC_CTL_1, 0x04, 2, 0),
+ WCD_MBHC_REGISTER("WCD_MBHC_ELECT_ISRC_EN",
+ ROULEUR_ANA_MBHC_ZDET, 0x02, 1, 0),
+};
+
+static const struct wcd_mbhc_intr intr_ids = {
+ .mbhc_sw_intr = ROULEUR_IRQ_MBHC_SW_DET,
+ .mbhc_btn_press_intr = ROULEUR_IRQ_MBHC_BUTTON_PRESS_DET,
+ .mbhc_btn_release_intr = ROULEUR_IRQ_MBHC_BUTTON_RELEASE_DET,
+ .mbhc_hs_ins_intr = ROULEUR_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+ .mbhc_hs_rem_intr = ROULEUR_IRQ_MBHC_ELECT_INS_REM_DET,
+ .hph_left_ocp = ROULEUR_IRQ_HPHL_OCP_INT,
+ .hph_right_ocp = ROULEUR_IRQ_HPHR_OCP_INT,
+};
+
+struct rouleur_mbhc_zdet_param {
+ u16 ldo_ctl;
+ u16 noff;
+ u16 nshift;
+ u16 btn5;
+ u16 btn6;
+ u16 btn7;
+};
+
+static int rouleur_mbhc_request_irq(struct snd_soc_component *component,
+ int irq, irq_handler_t handler,
+ const char *name, void *data)
+{
+ struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
+
+ return wcd_request_irq(&rouleur->irq_info, irq, name, handler, data);
+}
+
+static void rouleur_mbhc_irq_control(struct snd_soc_component *component,
+ int irq, bool enable)
+{
+ struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
+
+ if (enable)
+ wcd_enable_irq(&rouleur->irq_info, irq);
+ else
+ wcd_disable_irq(&rouleur->irq_info, irq);
+}
+
+static int rouleur_mbhc_free_irq(struct snd_soc_component *component,
+ int irq, void *data)
+{
+ struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
+
+ wcd_free_irq(&rouleur->irq_info, irq, data);
+
+ return 0;
+}
+
+static void rouleur_mbhc_clk_setup(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable)
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_1,
+ 0x80, 0x80);
+ else
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_1,
+ 0x80, 0x00);
+}
+
+static int rouleur_mbhc_btn_to_num(struct snd_soc_component *component)
+{
+ return snd_soc_component_read32(component, ROULEUR_ANA_MBHC_RESULT_3) &
+ 0x7;
+}
+
+static void rouleur_mbhc_mbhc_bias_control(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable)
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ELECT,
+ 0x01, 0x01);
+ else
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ELECT,
+ 0x01, 0x00);
+}
+
+static void rouleur_mbhc_program_btn_thr(struct snd_soc_component *component,
+ s16 *btn_low, s16 *btn_high,
+ int num_btn, bool is_micbias)
+{
+ int i;
+ int vth;
+
+ if (num_btn > WCD_MBHC_DEF_BUTTONS) {
+ dev_err(component->dev, "%s: invalid number of buttons: %d\n",
+ __func__, num_btn);
+ return;
+ }
+
+ for (i = 0; i < num_btn; i++) {
+ vth = ((btn_high[i] * 2) / 25) & 0x3F;
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBHC_BTN0_ZDET_VREF1 + i,
+ 0xFC, vth << 2);
+ dev_dbg(component->dev, "%s: btn_high[%d]: %d, vth: %d\n",
+ __func__, i, btn_high[i], vth);
+ }
+}
+
+static bool rouleur_mbhc_lock_sleep(struct wcd_mbhc *mbhc, bool lock)
+{
+ struct snd_soc_component *component = mbhc->component;
+ struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
+
+ rouleur->wakeup((void *)rouleur, lock);
+ return true;
+}
+
+static int rouleur_mbhc_register_notifier(struct wcd_mbhc *mbhc,
+ struct notifier_block *nblock,
+ bool enable)
+{
+ struct rouleur_mbhc *rouleur_mbhc;
+
+ rouleur_mbhc = container_of(mbhc, struct rouleur_mbhc, wcd_mbhc);
+
+ if (enable)
+ return blocking_notifier_chain_register(&rouleur_mbhc->notifier,
+ nblock);
+ else
+ return blocking_notifier_chain_unregister(
+ &rouleur_mbhc->notifier, nblock);
+}
+
+static bool rouleur_mbhc_micb_en_status(struct wcd_mbhc *mbhc, int micb_num)
+{
+ u8 val = 0;
+
+ if (micb_num == MIC_BIAS_2) {
+ val = ((snd_soc_component_read32(mbhc->component,
+ ROULEUR_ANA_MICBIAS_MICB_1_2_EN) & 0x04)
+ >> 2);
+ if (val == 0x01)
+ return true;
+ }
+ return false;
+}
+
+static bool rouleur_mbhc_hph_pa_on_status(struct snd_soc_component *component)
+{
+ return (snd_soc_component_read32(component, ROULEUR_ANA_HPHPA_PA_STATUS)
+ & 0xFF) ? true : false;
+}
+
+static void rouleur_mbhc_hph_l_pull_up_control(
+ struct snd_soc_component *component,
+ int pull_up_cur)
+{
+ /* Default pull up current to 2uA */
+ if (pull_up_cur < I_OFF || pull_up_cur > I_3P0_UA ||
+ pull_up_cur == I_DEFAULT)
+ pull_up_cur = I_2P0_UA;
+
+ dev_dbg(component->dev, "%s: HS pull up current:%d\n",
+ __func__, pull_up_cur);
+
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBHC_PLUG_DETECT_CTL,
+ 0xC0, pull_up_cur);
+}
+
+static int rouleur_mbhc_request_micbias(struct snd_soc_component *component,
+ int micb_num, int req)
+{
+ int ret = 0;
+
+ ret = rouleur_micbias_control(component, micb_num, req, false);
+
+ return ret;
+}
+
+static void rouleur_mbhc_micb_ramp_control(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBHC_MICB2_RAMP,
+ 0x1C, 0x0C);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBHC_MICB2_RAMP,
+ 0x80, 0x80);
+ } else {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBHC_MICB2_RAMP,
+ 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBHC_MICB2_RAMP,
+ 0x1C, 0x00);
+ }
+}
+
+static struct firmware_cal *rouleur_get_hwdep_fw_cal(struct wcd_mbhc *mbhc,
+ enum wcd_cal_type type)
+{
+ struct rouleur_mbhc *rouleur_mbhc;
+ struct firmware_cal *hwdep_cal;
+ struct snd_soc_component *component = mbhc->component;
+
+ rouleur_mbhc = container_of(mbhc, struct rouleur_mbhc, wcd_mbhc);
+
+ if (!component) {
+ pr_err("%s: NULL component pointer\n", __func__);
+ return NULL;
+ }
+ hwdep_cal = wcdcal_get_fw_cal(rouleur_mbhc->fw_data, type);
+ if (!hwdep_cal)
+ dev_err(component->dev, "%s: cal not sent by %d\n",
+ __func__, type);
+
+ return hwdep_cal;
+}
+
+static int rouleur_mbhc_micb_ctrl_threshold_mic(
+ struct snd_soc_component *component,
+ int micb_num, bool req_en)
+{
+ struct rouleur_pdata *pdata = dev_get_platdata(component->dev);
+ int rc, micb_mv;
+
+ if (micb_num != MIC_BIAS_2)
+ return -EINVAL;
+ /*
+ * If device tree micbias level is already above the minimum
+ * voltage needed to detect threshold microphone, then do
+ * not change the micbias, just return.
+ */
+ if (pdata->micbias.micb2_mv >= WCD_MBHC_THR_HS_MICB_MV)
+ return 0;
+
+ micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : pdata->micbias.micb2_mv;
+
+ rc = rouleur_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2);
+
+ return rc;
+}
+
+static inline void rouleur_mbhc_get_result_params(struct rouleur_priv *rouleur,
+ s16 *d1_a, u16 noff,
+ int32_t *zdet)
+{
+ int i;
+ int val = 0, val1 = 0;
+ s16 c1 = 0;
+ s32 x1 = 0, d1 = 0;
+ int32_t denom;
+ int minCode_param[] = {
+ 3277, 1639, 820, 410, 205, 103, 52, 26
+ };
+
+ regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x20, 0x20);
+ for (i = 0; i < ROULEUR_ZDET_NUM_MEASUREMENTS; i++) {
+ regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &val);
+ if (val & 0x80)
+ break;
+ }
+ val = val << 0x8;
+ regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_1, &val1);
+ val |= val1;
+ regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x20, 0x00);
+ x1 = ROULEUR_MBHC_GET_X1(val);
+ c1 = ROULEUR_MBHC_GET_C1(val);
+ /* If ramp is not complete, give additional 5ms */
+ if ((c1 < 2) && x1)
+ usleep_range(5000, 5050);
+
+ if (!c1 || !x1) {
+ dev_dbg(rouleur->dev,
+ "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n",
+ __func__, c1, x1);
+ goto ramp_down;
+ }
+ d1 = d1_a[c1];
+ denom = (x1 * d1) - (1 << (14 - noff));
+ if (denom > 0)
+ *zdet = (ROULEUR_MBHC_ZDET_CONST * 1000) / denom;
+ else if (x1 < minCode_param[noff])
+ *zdet = ROULEUR_ZDET_FLOATING_IMPEDANCE;
+
+ dev_dbg(rouleur->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n",
+ __func__, d1, c1, x1, *zdet);
+ramp_down:
+ i = 0;
+ while (x1) {
+ regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_1, &val);
+ regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &val1);
+ val = val << 0x8;
+ val |= val1;
+ x1 = ROULEUR_MBHC_GET_X1(val);
+ i++;
+ if (i == ROULEUR_ZDET_NUM_MEASUREMENTS)
+ break;
+ }
+}
+
+#if 0
+static void rouleur_mbhc_zdet_ramp(struct snd_soc_component *component,
+ struct rouleur_mbhc_zdet_param *zdet_param,
+ int32_t *zl, int32_t *zr, s16 *d1_a)
+{
+ struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
+ int32_t zdet = 0;
+
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ZDET_ANA_CTL,
+ 0x70, zdet_param->ldo_ctl << 4);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_BTN5, 0xFC,
+ zdet_param->btn5);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_BTN6, 0xFC,
+ zdet_param->btn6);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_BTN7, 0xFC,
+ zdet_param->btn7);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ZDET_ANA_CTL,
+ 0x0F, zdet_param->noff);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ZDET_RAMP_CTL,
+ 0x0F, zdet_param->nshift);
+
+ if (!zl)
+ goto z_right;
+ /* Start impedance measurement for HPH_L */
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_ZDET, 0x80, 0x80);
+ dev_dbg(rouleur->dev, "%s: ramp for HPH_L, noff = %d\n",
+ __func__, zdet_param->noff);
+ rouleur_mbhc_get_result_params(rouleur, d1_a, zdet_param->noff, &zdet);
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_ZDET, 0x80, 0x00);
+
+ *zl = zdet;
+
+z_right:
+ if (!zr)
+ return;
+ /* Start impedance measurement for HPH_R */
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_ZDET, 0x40, 0x40);
+ dev_dbg(rouleur->dev, "%s: ramp for HPH_R, noff = %d\n",
+ __func__, zdet_param->noff);
+ rouleur_mbhc_get_result_params(rouleur, d1_a, zdet_param->noff, &zdet);
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_ZDET, 0x40, 0x00);
+
+ *zr = zdet;
+}
+
+static inline void rouleur_wcd_mbhc_qfuse_cal(
+ struct snd_soc_component *component,
+ int32_t *z_val, int flag_l_r)
+{
+ s16 q1;
+ int q1_cal;
+
+ if (*z_val < (ROULEUR_ZDET_VAL_400/1000))
+ q1 = snd_soc_component_read32(component,
+ ROULEUR_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r));
+ else
+ q1 = snd_soc_component_read32(component,
+ ROULEUR_DIGITAL_EFUSE_REG_24 + (2 * flag_l_r));
+ if (q1 & 0x80)
+ q1_cal = (10000 - ((q1 & 0x7F) * 25));
+ else
+ q1_cal = (10000 + (q1 * 25));
+ if (q1_cal > 0)
+ *z_val = ((*z_val) * 10000) / q1_cal;
+}
+
+static void rouleur_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
+ uint32_t *zr)
+{
+ struct snd_soc_component *component = mbhc->component;
+ struct rouleur_priv *rouleur = dev_get_drvdata(component->dev);
+ s16 reg0, reg1, reg2, reg3, reg4;
+ int32_t z1L, z1R, z1Ls;
+ int zMono, z_diff1, z_diff2;
+ bool is_fsm_disable = false;
+ struct rouleur_mbhc_zdet_param zdet_param[] = {
+ {4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */
+ {2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */
+ {1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */
+ {1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */
+ };
+ struct rouleur_mbhc_zdet_param *zdet_param_ptr = NULL;
+ s16 d1_a[][4] = {
+ {0, 30, 90, 30},
+ {0, 30, 30, 5},
+ {0, 30, 30, 5},
+ {0, 30, 30, 5},
+ };
+ s16 *d1 = NULL;
+
+ WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
+
+ reg0 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_BTN5);
+ reg1 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_BTN6);
+ reg2 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_BTN7);
+ reg3 = snd_soc_component_read32(component, ROULEUR_MBHC_CTL_CLK);
+ reg4 = snd_soc_component_read32(component,
+ ROULEUR_ANA_MBHC_ZDET_ANA_CTL);
+
+ if (snd_soc_component_read32(component, ROULEUR_ANA_MBHC_ELECT) &
+ 0x80) {
+ is_fsm_disable = true;
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_ELECT, 0x80, 0x00);
+ }
+
+ /* For NO-jack, disable L_DET_EN before Z-det measurements */
+ if (mbhc->hphl_swh)
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_MECH, 0x80, 0x00);
+
+ /* Turn off 100k pull down on HPHL */
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_MECH, 0x01, 0x00);
+
+ /* Disable surge protection before impedance detection.
+ * This is done to give correct value for high impedance.
+ */
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0x00);
+ /* 1ms delay needed after disable surge protection */
+ usleep_range(1000, 1010);
+
+ /* First get impedance on Left */
+ d1 = d1_a[1];
+ zdet_param_ptr = &zdet_param[1];
+ rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1);
+
+ if (!ROULEUR_MBHC_IS_SECOND_RAMP_REQUIRED(z1L))
+ goto left_ch_impedance;
+
+ /* Second ramp for left ch */
+ if (z1L < ROULEUR_ZDET_VAL_32) {
+ zdet_param_ptr = &zdet_param[0];
+ d1 = d1_a[0];
+ } else if ((z1L > ROULEUR_ZDET_VAL_400) &&
+ (z1L <= ROULEUR_ZDET_VAL_1200)) {
+ zdet_param_ptr = &zdet_param[2];
+ d1 = d1_a[2];
+ } else if (z1L > ROULEUR_ZDET_VAL_1200) {
+ zdet_param_ptr = &zdet_param[3];
+ d1 = d1_a[3];
+ }
+ rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1);
+
+left_ch_impedance:
+ if ((z1L == ROULEUR_ZDET_FLOATING_IMPEDANCE) ||
+ (z1L > ROULEUR_ZDET_VAL_100K)) {
+ *zl = ROULEUR_ZDET_FLOATING_IMPEDANCE;
+ zdet_param_ptr = &zdet_param[1];
+ d1 = d1_a[1];
+ } else {
+ *zl = z1L/1000;
+ rouleur_wcd_mbhc_qfuse_cal(component, zl, 0);
+ }
+ dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n",
+ __func__, *zl);
+
+ /* Start of right impedance ramp and calculation */
+ rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1);
+ if (ROULEUR_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) {
+ if (((z1R > ROULEUR_ZDET_VAL_1200) &&
+ (zdet_param_ptr->noff == 0x6)) ||
+ ((*zl) != ROULEUR_ZDET_FLOATING_IMPEDANCE))
+ goto right_ch_impedance;
+ /* Second ramp for right ch */
+ if (z1R < ROULEUR_ZDET_VAL_32) {
+ zdet_param_ptr = &zdet_param[0];
+ d1 = d1_a[0];
+ } else if ((z1R > ROULEUR_ZDET_VAL_400) &&
+ (z1R <= ROULEUR_ZDET_VAL_1200)) {
+ zdet_param_ptr = &zdet_param[2];
+ d1 = d1_a[2];
+ } else if (z1R > ROULEUR_ZDET_VAL_1200) {
+ zdet_param_ptr = &zdet_param[3];
+ d1 = d1_a[3];
+ }
+ rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, NULL,
+ &z1R, d1);
+ }
+right_ch_impedance:
+ if ((z1R == ROULEUR_ZDET_FLOATING_IMPEDANCE) ||
+ (z1R > ROULEUR_ZDET_VAL_100K)) {
+ *zr = ROULEUR_ZDET_FLOATING_IMPEDANCE;
+ } else {
+ *zr = z1R/1000;
+ rouleur_wcd_mbhc_qfuse_cal(component, zr, 1);
+ }
+ dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n",
+ __func__, *zr);
+
+ /* Mono/stereo detection */
+ if ((*zl == ROULEUR_ZDET_FLOATING_IMPEDANCE) &&
+ (*zr == ROULEUR_ZDET_FLOATING_IMPEDANCE)) {
+ dev_dbg(component->dev,
+ "%s: plug type is invalid or extension cable\n",
+ __func__);
+ goto zdet_complete;
+ }
+ if ((*zl == ROULEUR_ZDET_FLOATING_IMPEDANCE) ||
+ (*zr == ROULEUR_ZDET_FLOATING_IMPEDANCE) ||
+ ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) ||
+ ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) {
+ dev_dbg(component->dev,
+ "%s: Mono plug type with one ch floating or shorted to GND\n",
+ __func__);
+ mbhc->hph_type = WCD_MBHC_HPH_MONO;
+ goto zdet_complete;
+ }
+ snd_soc_component_update_bits(component, ROULEUR_HPH_R_ATEST,
+ 0x02, 0x02);
+ snd_soc_component_update_bits(component, ROULEUR_HPH_PA_CTL2,
+ 0x40, 0x01);
+ if (*zl < (ROULEUR_ZDET_VAL_32/1000))
+ rouleur_mbhc_zdet_ramp(component, &zdet_param[0], &z1Ls,
+ NULL, d1);
+ else
+ rouleur_mbhc_zdet_ramp(component, &zdet_param[1], &z1Ls,
+ NULL, d1);
+ snd_soc_component_update_bits(component, ROULEUR_HPH_PA_CTL2,
+ 0x40, 0x00);
+ snd_soc_component_update_bits(component, ROULEUR_HPH_R_ATEST,
+ 0x02, 0x00);
+ z1Ls /= 1000;
+ rouleur_wcd_mbhc_qfuse_cal(component, &z1Ls, 0);
+ /* Parallel of left Z and 9 ohm pull down resistor */
+ zMono = ((*zl) * 9) / ((*zl) + 9);
+ z_diff1 = (z1Ls > zMono) ? (z1Ls - zMono) : (zMono - z1Ls);
+ z_diff2 = ((*zl) > z1Ls) ? ((*zl) - z1Ls) : (z1Ls - (*zl));
+ if ((z_diff1 * (*zl + z1Ls)) > (z_diff2 * (z1Ls + zMono))) {
+ dev_dbg(component->dev, "%s: stereo plug type detected\n",
+ __func__);
+ mbhc->hph_type = WCD_MBHC_HPH_STEREO;
+ } else {
+ dev_dbg(component->dev, "%s: MONO plug type detected\n",
+ __func__);
+ mbhc->hph_type = WCD_MBHC_HPH_MONO;
+ }
+
+ /* Enable surge protection again after impedance detection */
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0);
+zdet_complete:
+ snd_soc_component_write(component, ROULEUR_ANA_MBHC_BTN5, reg0);
+ snd_soc_component_write(component, ROULEUR_ANA_MBHC_BTN6, reg1);
+ snd_soc_component_write(component, ROULEUR_ANA_MBHC_BTN7, reg2);
+ /* Turn on 100k pull down on HPHL */
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_MECH, 0x01, 0x01);
+
+ /* For NO-jack, re-enable L_DET_EN after Z-det measurements */
+ if (mbhc->hphl_swh)
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_MECH, 0x80, 0x80);
+
+ snd_soc_component_write(component, ROULEUR_ANA_MBHC_ZDET_ANA_CTL, reg4);
+ snd_soc_component_write(component, ROULEUR_MBHC_CTL_CLK, reg3);
+ if (is_fsm_disable)
+ regmap_update_bits(rouleur->regmap,
+ ROULEUR_ANA_MBHC_ELECT, 0x80, 0x80);
+}
+#endif
+
+static void rouleur_mbhc_gnd_det_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH,
+ 0x02, 0x02);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH,
+ 0x40, 0x40);
+ } else {
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH,
+ 0x40, 0x00);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH,
+ 0x02, 0x00);
+ }
+}
+
+static void rouleur_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x30, 0x10);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x0C, 0x04);
+ } else {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x30, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x0C, 0x00);
+ }
+}
+
+static void rouleur_mbhc_moisture_config(struct wcd_mbhc *mbhc)
+{
+ struct snd_soc_component *component = mbhc->component;
+
+ if ((mbhc->moist_rref == R_OFF) ||
+ (mbhc->mbhc_cfg->enable_usbc_analog)) {
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, R_OFF << 2);
+ return;
+ }
+
+ /* Do not enable moisture detection if jack type is NC */
+ if (!mbhc->hphl_swh) {
+ dev_dbg(component->dev, "%s: disable moisture detection for NC\n",
+ __func__);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, R_OFF << 2);
+ return;
+ }
+
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, mbhc->moist_rref << 2);
+}
+
+static void rouleur_mbhc_moisture_detect_en(struct wcd_mbhc *mbhc, bool enable)
+{
+ struct snd_soc_component *component = mbhc->component;
+
+ if (enable)
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, mbhc->moist_rref << 2);
+ else
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, R_OFF << 2);
+}
+
+static bool rouleur_mbhc_get_moisture_status(struct wcd_mbhc *mbhc)
+{
+ struct snd_soc_component *component = mbhc->component;
+ bool ret = false;
+
+ if ((mbhc->moist_rref == R_OFF) ||
+ (mbhc->mbhc_cfg->enable_usbc_analog)) {
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, R_OFF << 2);
+ goto done;
+ }
+
+ /* Do not enable moisture detection if jack type is NC */
+ if (!mbhc->hphl_swh) {
+ dev_dbg(component->dev, "%s: disable moisture detection for NC\n",
+ __func__);
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_2,
+ 0x0C, R_OFF << 2);
+ goto done;
+ }
+
+ /* If moisture_en is already enabled, then skip to plug type
+ * detection.
+ */
+ if ((snd_soc_component_read32(component, ROULEUR_ANA_MBHC_CTL_2) &
+ 0x0C))
+ goto done;
+
+ rouleur_mbhc_moisture_detect_en(mbhc, true);
+ /* Read moisture comparator status */
+ ret = ((snd_soc_component_read32(component, ROULEUR_ANA_MBHC_FSM_STATUS)
+ & 0x20) ? 0 : 1);
+
+done:
+ return ret;
+
+}
+
+static void rouleur_mbhc_bcs_enable(struct wcd_mbhc *mbhc,
+ bool bcs_enable)
+{
+ if (bcs_enable)
+ rouleur_disable_bcs_before_slow_insert(mbhc->component, false);
+ else
+ rouleur_disable_bcs_before_slow_insert(mbhc->component, true);
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+ .request_irq = rouleur_mbhc_request_irq,
+ .irq_control = rouleur_mbhc_irq_control,
+ .free_irq = rouleur_mbhc_free_irq,
+ .clk_setup = rouleur_mbhc_clk_setup,
+ .map_btn_code_to_num = rouleur_mbhc_btn_to_num,
+ .mbhc_bias = rouleur_mbhc_mbhc_bias_control,
+ .set_btn_thr = rouleur_mbhc_program_btn_thr,
+ .lock_sleep = rouleur_mbhc_lock_sleep,
+ .register_notifier = rouleur_mbhc_register_notifier,
+ .micbias_enable_status = rouleur_mbhc_micb_en_status,
+ .hph_pa_on_status = rouleur_mbhc_hph_pa_on_status,
+ .hph_pull_up_control = rouleur_mbhc_hph_l_pull_up_control,
+ .mbhc_micbias_control = rouleur_mbhc_request_micbias,
+ .mbhc_micb_ramp_control = rouleur_mbhc_micb_ramp_control,
+ .get_hwdep_fw_cal = rouleur_get_hwdep_fw_cal,
+ .mbhc_micb_ctrl_thr_mic = rouleur_mbhc_micb_ctrl_threshold_mic,
+ //.compute_impedance = rouleur_wcd_mbhc_calc_impedance,
+ .mbhc_gnd_det_ctrl = rouleur_mbhc_gnd_det_ctrl,
+ .hph_pull_down_ctrl = rouleur_mbhc_hph_pull_down_ctrl,
+ .mbhc_moisture_config = rouleur_mbhc_moisture_config,
+ .mbhc_get_moisture_status = rouleur_mbhc_get_moisture_status,
+ .mbhc_moisture_detect_en = rouleur_mbhc_moisture_detect_en,
+ .bcs_enable = rouleur_mbhc_bcs_enable,
+};
+
+static int rouleur_get_hph_type(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct rouleur_mbhc *rouleur_mbhc = rouleur_soc_get_mbhc(component);
+ struct wcd_mbhc *mbhc;
+
+ if (!rouleur_mbhc) {
+ dev_err(component->dev, "%s: mbhc not initialized!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mbhc = &rouleur_mbhc->wcd_mbhc;
+
+ ucontrol->value.integer.value[0] = (u32) mbhc->hph_type;
+ dev_dbg(component->dev, "%s: hph_type = %u\n", __func__,
+ mbhc->hph_type);
+
+ return 0;
+}
+
+static int rouleur_hph_impedance_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint32_t zl = 0, zr = 0;
+ bool hphr;
+ struct soc_multi_mixer_control *mc;
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct rouleur_mbhc *rouleur_mbhc = rouleur_soc_get_mbhc(component);
+
+ if (!rouleur_mbhc) {
+ dev_err(component->dev, "%s: mbhc not initialized!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+ wcd_mbhc_get_impedance(&rouleur_mbhc->wcd_mbhc, &zl, &zr);
+ dev_dbg(component->dev, "%s: zl=%u(ohms), zr=%u(ohms)\n", __func__,
+ zl, zr);
+ ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new hph_type_detect_controls[] = {
+ SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
+ rouleur_get_hph_type, NULL),
+};
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+ SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
+ rouleur_hph_impedance_get, NULL),
+ SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
+ rouleur_hph_impedance_get, NULL),
+};
+
+/*
+ * rouleur_mbhc_get_impedance: get impedance of headphone
+ * left and right channels
+ * @rouleur_mbhc: handle to struct rouleur_mbhc *
+ * @zl: handle to left-ch impedance
+ * @zr: handle to right-ch impedance
+ * return 0 for success or error code in case of failure
+ */
+int rouleur_mbhc_get_impedance(struct rouleur_mbhc *rouleur_mbhc,
+ uint32_t *zl, uint32_t *zr)
+{
+ if (!rouleur_mbhc) {
+ pr_err("%s: mbhc not initialized!\n", __func__);
+ return -EINVAL;
+ }
+ if (!zl || !zr) {
+ pr_err("%s: zl or zr null!\n", __func__);
+ return -EINVAL;
+ }
+
+ return wcd_mbhc_get_impedance(&rouleur_mbhc->wcd_mbhc, zl, zr);
+}
+EXPORT_SYMBOL(rouleur_mbhc_get_impedance);
+
+/*
+ * rouleur_mbhc_hs_detect: starts mbhc insertion/removal functionality
+ * @component: handle to snd_soc_component *
+ * @mbhc_cfg: handle to mbhc configuration structure
+ * return 0 if mbhc_start is success or error code in case of failure
+ */
+int rouleur_mbhc_hs_detect(struct snd_soc_component *component,
+ struct wcd_mbhc_config *mbhc_cfg)
+{
+ struct rouleur_priv *rouleur = NULL;
+ struct rouleur_mbhc *rouleur_mbhc = NULL;
+
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ rouleur = snd_soc_component_get_drvdata(component);
+ if (!rouleur) {
+ pr_err("%s: rouleur is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ rouleur_mbhc = rouleur->mbhc;
+ if (!rouleur_mbhc) {
+ dev_err(component->dev, "%s: mbhc not initialized!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ return wcd_mbhc_start(&rouleur_mbhc->wcd_mbhc, mbhc_cfg);
+}
+EXPORT_SYMBOL(rouleur_mbhc_hs_detect);
+
+/*
+ * rouleur_mbhc_hs_detect_exit: stop mbhc insertion/removal functionality
+ * @component: handle to snd_soc_component *
+ */
+void rouleur_mbhc_hs_detect_exit(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = NULL;
+ struct rouleur_mbhc *rouleur_mbhc = NULL;
+
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return;
+ }
+
+ rouleur = snd_soc_component_get_drvdata(component);
+ if (!rouleur) {
+ pr_err("%s: rouleur is NULL\n", __func__);
+ return;
+ }
+
+ rouleur_mbhc = rouleur->mbhc;
+ if (!rouleur_mbhc) {
+ dev_err(component->dev, "%s: mbhc not initialized!\n",
+ __func__);
+ return;
+ }
+ wcd_mbhc_stop(&rouleur_mbhc->wcd_mbhc);
+}
+EXPORT_SYMBOL(rouleur_mbhc_hs_detect_exit);
+
+/*
+ * rouleur_mbhc_ssr_down: stop mbhc during
+ * rouleur subsystem restart
+ * @mbhc: pointer to rouleur_mbhc structure
+ * @component: handle to snd_soc_component *
+ */
+void rouleur_mbhc_ssr_down(struct rouleur_mbhc *mbhc,
+ struct snd_soc_component *component)
+{
+ struct wcd_mbhc *wcd_mbhc = NULL;
+
+ if (!mbhc || !component)
+ return;
+
+ wcd_mbhc = &mbhc->wcd_mbhc;
+ if (wcd_mbhc == NULL) {
+ dev_err(component->dev, "%s: wcd_mbhc is NULL\n", __func__);
+ return;
+ }
+
+ rouleur_mbhc_hs_detect_exit(component);
+ wcd_mbhc_deinit(wcd_mbhc);
+}
+EXPORT_SYMBOL(rouleur_mbhc_ssr_down);
+
+/*
+ * rouleur_mbhc_post_ssr_init: initialize mbhc for
+ * rouleur post subsystem restart
+ * @mbhc: poniter to rouleur_mbhc structure
+ * @component: handle to snd_soc_component *
+ *
+ * return 0 if mbhc_init is success or error code in case of failure
+ */
+int rouleur_mbhc_post_ssr_init(struct rouleur_mbhc *mbhc,
+ struct snd_soc_component *component)
+{
+ int ret = 0;
+ struct wcd_mbhc *wcd_mbhc = NULL;
+
+ if (!mbhc || !component)
+ return -EINVAL;
+
+ wcd_mbhc = &mbhc->wcd_mbhc;
+ if (wcd_mbhc == NULL) {
+ pr_err("%s: wcd_mbhc is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MECH,
+ 0x20, 0x20);
+ ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, &intr_ids,
+ wcd_mbhc_registers, ROULEUR_ZDET_SUPPORTED);
+ if (ret)
+ dev_err(component->dev, "%s: mbhc initialization failed\n",
+ __func__);
+
+ return ret;
+}
+EXPORT_SYMBOL(rouleur_mbhc_post_ssr_init);
+
+/*
+ * rouleur_mbhc_init: initialize mbhc for rouleur
+ * @mbhc: poniter to rouleur_mbhc struct pointer to store the configs
+ * @component: handle to snd_soc_component *
+ * @fw_data: handle to firmware data
+ *
+ * return 0 if mbhc_init is success or error code in case of failure
+ */
+int rouleur_mbhc_init(struct rouleur_mbhc **mbhc,
+ struct snd_soc_component *component,
+ struct fw_info *fw_data)
+{
+ struct rouleur_mbhc *rouleur_mbhc = NULL;
+ struct wcd_mbhc *wcd_mbhc = NULL;
+ struct rouleur_pdata *pdata;
+ int ret = 0;
+
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ rouleur_mbhc = devm_kzalloc(component->dev, sizeof(struct rouleur_mbhc),
+ GFP_KERNEL);
+ if (!rouleur_mbhc)
+ return -ENOMEM;
+
+ rouleur_mbhc->fw_data = fw_data;
+ BLOCKING_INIT_NOTIFIER_HEAD(&rouleur_mbhc->notifier);
+ wcd_mbhc = &rouleur_mbhc->wcd_mbhc;
+ if (wcd_mbhc == NULL) {
+ pr_err("%s: wcd_mbhc is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+
+ /* Setting default mbhc detection logic to ADC */
+ wcd_mbhc->mbhc_detection_logic = WCD_DETECTION_ADC;
+
+ pdata = dev_get_platdata(component->dev);
+ if (!pdata) {
+ dev_err(component->dev, "%s: pdata pointer is NULL\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ wcd_mbhc->micb_mv = pdata->micbias.micb2_mv;
+
+ ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb,
+ &intr_ids, wcd_mbhc_registers,
+ ROULEUR_ZDET_SUPPORTED);
+ if (ret) {
+ dev_err(component->dev, "%s: mbhc initialization failed\n",
+ __func__);
+ goto err;
+ }
+
+ (*mbhc) = rouleur_mbhc;
+ snd_soc_add_component_controls(component, impedance_detect_controls,
+ ARRAY_SIZE(impedance_detect_controls));
+ snd_soc_add_component_controls(component, hph_type_detect_controls,
+ ARRAY_SIZE(hph_type_detect_controls));
+
+ return 0;
+err:
+ devm_kfree(component->dev, rouleur_mbhc);
+ return ret;
+}
+EXPORT_SYMBOL(rouleur_mbhc_init);
+
+/*
+ * rouleur_mbhc_deinit: deinitialize mbhc for rouleur
+ * @component: handle to snd_soc_component *
+ */
+void rouleur_mbhc_deinit(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur;
+ struct rouleur_mbhc *rouleur_mbhc;
+
+ if (!component) {
+ pr_err("%s: component is NULL\n", __func__);
+ return;
+ }
+
+ rouleur = snd_soc_component_get_drvdata(component);
+ if (!rouleur) {
+ pr_err("%s: rouleur is NULL\n", __func__);
+ return;
+ }
+
+ rouleur_mbhc = rouleur->mbhc;
+ if (rouleur_mbhc) {
+ wcd_mbhc_deinit(&rouleur_mbhc->wcd_mbhc);
+ devm_kfree(component->dev, rouleur_mbhc);
+ }
+}
+EXPORT_SYMBOL(rouleur_mbhc_deinit);
diff --git a/asoc/codecs/rouleur/rouleur-mbhc.h b/asoc/codecs/rouleur/rouleur-mbhc.h
new file mode 100644
index 00000000..40bef376
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur-mbhc.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+#ifndef __ROULEUR_MBHC_H__
+#define __ROULEUR_MBHC_H__
+#include <asoc/wcd-mbhc-v2.h>
+
+struct rouleur_mbhc {
+ struct wcd_mbhc wcd_mbhc;
+ struct blocking_notifier_head notifier;
+ struct fw_info *fw_data;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_ROULEUR)
+extern int rouleur_mbhc_init(struct rouleur_mbhc **mbhc,
+ struct snd_soc_component *component,
+ struct fw_info *fw_data);
+extern void rouleur_mbhc_hs_detect_exit(struct snd_soc_component *component);
+extern int rouleur_mbhc_hs_detect(struct snd_soc_component *component,
+ struct wcd_mbhc_config *mbhc_cfg);
+extern void rouleur_mbhc_deinit(struct snd_soc_component *component);
+extern int rouleur_mbhc_post_ssr_init(struct rouleur_mbhc *mbhc,
+ struct snd_soc_component *component);
+extern void rouleur_mbhc_ssr_down(struct rouleur_mbhc *mbhc,
+ struct snd_soc_component *component);
+extern int rouleur_mbhc_get_impedance(struct rouleur_mbhc *rouleur_mbhc,
+ uint32_t *zl, uint32_t *zr);
+#else
+static inline int rouleur_mbhc_init(struct rouleur_mbhc **mbhc,
+ struct snd_soc_component *component,
+ struct fw_info *fw_data)
+{
+ return 0;
+}
+static inline void rouleur_mbhc_hs_detect_exit(
+ struct snd_soc_component *component)
+{
+}
+static inline int rouleur_mbhc_hs_detect(struct snd_soc_component *component,
+ struct wcd_mbhc_config *mbhc_cfg)
+{
+ return 0;
+}
+static inline void rouleur_mbhc_deinit(struct snd_soc_component *component)
+{
+}
+static inline int rouleur_mbhc_post_ssr_init(struct rouleur_mbhc *mbhc,
+ struct snd_soc_component *component)
+{
+ return 0;
+}
+static inline void rouleur_mbhc_ssr_down(struct rouleur_mbhc *mbhc,
+ struct snd_soc_component *component)
+{
+}
+static inline int rouleur_mbhc_get_impedance(struct rouleur_mbhc *rouleur_mbhc,
+ uint32_t *zl, uint32_t *zr)
+{
+ if (zl)
+ *zl = 0;
+ if (zr)
+ *zr = 0;
+ return -EINVAL;
+}
+#endif
+
+#endif /* __ROULEUR_MBHC_H__ */
diff --git a/asoc/codecs/rouleur/rouleur-registers.h b/asoc/codecs/rouleur/rouleur-registers.h
new file mode 100644
index 00000000..ff3934bb
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur-registers.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _ROULEUR_REGISTERS_H
+#define _ROULEUR_REGISTERS_H
+
+#define ROULEUR_ANA_BASE_ADDR 0x3000
+#define ROULEUR_DIG_BASE_ADDR 0x3400
+
+#define ROULEUR_REG(reg) ((reg > ROULEUR_DIG_BASE_ADDR) ? \
+ (reg - ROULEUR_DIG_BASE_ADDR) : \
+ (reg - ROULEUR_ANA_BASE_ADDR))
+
+enum {
+ REG_NO_ACCESS,
+ RD_REG,
+ WR_REG,
+ RD_WR_REG
+};
+
+#define ROULEUR_ANA_MICBIAS_MICB_1_2_EN (ROULEUR_ANA_BASE_ADDR+0x040)
+#define ROULEUR_ANA_MICBIAS_MICB_3_EN (ROULEUR_ANA_BASE_ADDR+0x041)
+#define ROULEUR_ANA_MICBIAS_LDO_1_SETTING (ROULEUR_ANA_BASE_ADDR+0x042)
+#define ROULEUR_ANA_MICBIAS_LDO_1_CTRL (ROULEUR_ANA_BASE_ADDR+0x043)
+#define ROULEUR_ANA_TX_AMIC1 (ROULEUR_ANA_BASE_ADDR+0x047)
+#define ROULEUR_ANA_TX_AMIC2 (ROULEUR_ANA_BASE_ADDR+0x048)
+#define ROULEUR_ANA_MBHC_MECH (ROULEUR_ANA_BASE_ADDR+0x05A)
+#define ROULEUR_ANA_MBHC_ELECT (ROULEUR_ANA_BASE_ADDR+0x05B)
+#define ROULEUR_ANA_MBHC_ZDET (ROULEUR_ANA_BASE_ADDR+0x05C)
+#define ROULEUR_ANA_MBHC_RESULT_1 (ROULEUR_ANA_BASE_ADDR+0x05D)
+#define ROULEUR_ANA_MBHC_RESULT_2 (ROULEUR_ANA_BASE_ADDR+0x05E)
+#define ROULEUR_ANA_MBHC_RESULT_3 (ROULEUR_ANA_BASE_ADDR+0x05F)
+#define ROULEUR_ANA_MBHC_BTN0_ZDET_VREF1 (ROULEUR_ANA_BASE_ADDR+0x060)
+#define ROULEUR_ANA_MBHC_BTN1_ZDET_VREF2 (ROULEUR_ANA_BASE_ADDR+0x061)
+#define ROULEUR_ANA_MBHC_BTN2_ZDET_VREF3 (ROULEUR_ANA_BASE_ADDR+0x062)
+#define ROULEUR_ANA_MBHC_BTN3_ZDET_DBG_400 (ROULEUR_ANA_BASE_ADDR+0x063)
+#define ROULEUR_ANA_MBHC_BTN4_ZDET_DBG_1400 (ROULEUR_ANA_BASE_ADDR+0x064)
+#define ROULEUR_ANA_MBHC_MICB2_RAMP (ROULEUR_ANA_BASE_ADDR+0x065)
+#define ROULEUR_ANA_MBHC_CTL_1 (ROULEUR_ANA_BASE_ADDR+0x066)
+#define ROULEUR_ANA_MBHC_CTL_2 (ROULEUR_ANA_BASE_ADDR+0x067)
+#define ROULEUR_ANA_MBHC_PLUG_DETECT_CTL (ROULEUR_ANA_BASE_ADDR+0x068)
+#define ROULEUR_ANA_MBHC_ZDET_ANA_CTL (ROULEUR_ANA_BASE_ADDR+0x069)
+#define ROULEUR_ANA_MBHC_ZDET_RAMP_CTL (ROULEUR_ANA_BASE_ADDR+0x06A)
+#define ROULEUR_ANA_MBHC_FSM_STATUS (ROULEUR_ANA_BASE_ADDR+0x06B)
+#define ROULEUR_ANA_MBHC_ADC_RESULT (ROULEUR_ANA_BASE_ADDR+0x06C)
+#define ROULEUR_ANA_MBHC_MCLK (ROULEUR_ANA_BASE_ADDR+0x06D)
+#define ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT (ROULEUR_ANA_BASE_ADDR+0x072)
+#define ROULEUR_ANA_NCP_EN (ROULEUR_ANA_BASE_ADDR+0x077)
+#define ROULEUR_ANA_HPHPA_CNP_CTL_2 (ROULEUR_ANA_BASE_ADDR+0x084)
+#define ROULEUR_ANA_HPHPA_PA_STATUS (ROULEUR_ANA_BASE_ADDR+0x087)
+#define ROULEUR_ANA_HPHPA_FSM_CLK (ROULEUR_ANA_BASE_ADDR+0x088)
+#define ROULEUR_ANA_HPHPA_L_GAIN (ROULEUR_ANA_BASE_ADDR+0x08B)
+#define ROULEUR_ANA_HPHPA_R_GAIN (ROULEUR_ANA_BASE_ADDR+0x08C)
+#define ROULEUR_ANA_HPHPA_SPARE_CTL (ROULEUR_ANA_BASE_ADDR+0x08E)
+#define ROULEUR_ANA_SURGE_EN (ROULEUR_ANA_BASE_ADDR+0x097)
+#define ROULEUR_ANA_COMBOPA_CTL (ROULEUR_ANA_BASE_ADDR+0x09B)
+#define ROULEUR_ANA_RXLDO_CTL (ROULEUR_ANA_BASE_ADDR+0x0B2)
+#define ROULEUR_ANA_MBIAS_EN (ROULEUR_ANA_BASE_ADDR+0x0B4)
+
+#define ROULEUR_DIG_SWR_CHIP_ID0 (ROULEUR_DIG_BASE_ADDR+0x001)
+#define ROULEUR_DIG_SWR_CHIP_ID1 (ROULEUR_DIG_BASE_ADDR+0x002)
+#define ROULEUR_DIG_SWR_CHIP_ID2 (ROULEUR_DIG_BASE_ADDR+0x003)
+#define ROULEUR_DIG_SWR_CHIP_ID3 (ROULEUR_DIG_BASE_ADDR+0x004)
+#define ROULEUR_DIG_SWR_SWR_TX_CLK_RATE (ROULEUR_DIG_BASE_ADDR+0x040)
+#define ROULEUR_DIG_SWR_CDC_RST_CTL (ROULEUR_DIG_BASE_ADDR+0x041)
+#define ROULEUR_DIG_SWR_TOP_CLK_CFG (ROULEUR_DIG_BASE_ADDR+0x042)
+#define ROULEUR_DIG_SWR_CDC_RX_CLK_CTL (ROULEUR_DIG_BASE_ADDR+0x043)
+#define ROULEUR_DIG_SWR_CDC_TX_CLK_CTL (ROULEUR_DIG_BASE_ADDR+0x044)
+#define ROULEUR_DIG_SWR_SWR_RST_EN (ROULEUR_DIG_BASE_ADDR+0x045)
+#define ROULEUR_DIG_SWR_CDC_RX_RST (ROULEUR_DIG_BASE_ADDR+0x047)
+#define ROULEUR_DIG_SWR_CDC_RX0_CTL (ROULEUR_DIG_BASE_ADDR+0x048)
+#define ROULEUR_DIG_SWR_CDC_RX1_CTL (ROULEUR_DIG_BASE_ADDR+0x049)
+#define ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1 (ROULEUR_DIG_BASE_ADDR+0x04B)
+#define ROULEUR_DIG_SWR_CDC_COMP_CTL_0 (ROULEUR_DIG_BASE_ADDR+0x04F)
+#define ROULEUR_DIG_SWR_CDC_RX_DELAY_CTL (ROULEUR_DIG_BASE_ADDR+0x052)
+#define ROULEUR_DIG_SWR_CDC_RX_GAIN_0 (ROULEUR_DIG_BASE_ADDR+0x053)
+#define ROULEUR_DIG_SWR_CDC_RX_GAIN_1 (ROULEUR_DIG_BASE_ADDR+0x054)
+#define ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL (ROULEUR_DIG_BASE_ADDR+0x057)
+#define ROULEUR_DIG_SWR_CDC_TX0_CTL (ROULEUR_DIG_BASE_ADDR+0x060)
+#define ROULEUR_DIG_SWR_CDC_TX1_CTL (ROULEUR_DIG_BASE_ADDR+0x061)
+#define ROULEUR_DIG_SWR_CDC_TX_RST (ROULEUR_DIG_BASE_ADDR+0x063)
+#define ROULEUR_DIG_SWR_CDC_REQ0_CTL (ROULEUR_DIG_BASE_ADDR+0x064)
+#define ROULEUR_DIG_SWR_CDC_REQ1_CTL (ROULEUR_DIG_BASE_ADDR+0x065)
+#define ROULEUR_DIG_SWR_CDC_RST (ROULEUR_DIG_BASE_ADDR+0x067)
+#define ROULEUR_DIG_SWR_CDC_AMIC_CTL (ROULEUR_DIG_BASE_ADDR+0x06A)
+#define ROULEUR_DIG_SWR_CDC_DMIC_CTL (ROULEUR_DIG_BASE_ADDR+0x06B)
+#define ROULEUR_DIG_SWR_CDC_DMIC1_CTL (ROULEUR_DIG_BASE_ADDR+0x06C)
+#define ROULEUR_DIG_SWR_CDC_DMIC1_RATE (ROULEUR_DIG_BASE_ADDR+0x06D)
+#define ROULEUR_DIG_SWR_PDM_WD_CTL0 (ROULEUR_DIG_BASE_ADDR+0x070)
+#define ROULEUR_DIG_SWR_PDM_WD_CTL1 (ROULEUR_DIG_BASE_ADDR+0x071)
+#define ROULEUR_DIG_SWR_INTR_MODE (ROULEUR_DIG_BASE_ADDR+0x080)
+#define ROULEUR_DIG_SWR_INTR_MASK_0 (ROULEUR_DIG_BASE_ADDR+0x081)
+#define ROULEUR_DIG_SWR_INTR_MASK_1 (ROULEUR_DIG_BASE_ADDR+0x082)
+#define ROULEUR_DIG_SWR_INTR_MASK_2 (ROULEUR_DIG_BASE_ADDR+0x083)
+#define ROULEUR_DIG_SWR_INTR_STATUS_0 (ROULEUR_DIG_BASE_ADDR+0x084)
+#define ROULEUR_DIG_SWR_INTR_STATUS_1 (ROULEUR_DIG_BASE_ADDR+0x085)
+#define ROULEUR_DIG_SWR_INTR_STATUS_2 (ROULEUR_DIG_BASE_ADDR+0x086)
+#define ROULEUR_DIG_SWR_INTR_CLEAR_0 (ROULEUR_DIG_BASE_ADDR+0x087)
+#define ROULEUR_DIG_SWR_INTR_CLEAR_1 (ROULEUR_DIG_BASE_ADDR+0x088)
+#define ROULEUR_DIG_SWR_INTR_CLEAR_2 (ROULEUR_DIG_BASE_ADDR+0x089)
+#define ROULEUR_DIG_SWR_INTR_LEVEL_0 (ROULEUR_DIG_BASE_ADDR+0x08A)
+#define ROULEUR_DIG_SWR_INTR_LEVEL_1 (ROULEUR_DIG_BASE_ADDR+0x08B)
+#define ROULEUR_DIG_SWR_INTR_LEVEL_2 (ROULEUR_DIG_BASE_ADDR+0x08C)
+#define ROULEUR_DIG_SWR_CDC_CONN_RX0_CTL (ROULEUR_DIG_BASE_ADDR+0x093)
+#define ROULEUR_DIG_SWR_CDC_CONN_RX1_CTL (ROULEUR_DIG_BASE_ADDR+0x094)
+#define ROULEUR_DIG_SWR_LOOP_BACK_MODE (ROULEUR_DIG_BASE_ADDR+0x097)
+#define ROULEUR_DIG_SWR_DRIVE_STRENGTH_0 (ROULEUR_DIG_BASE_ADDR+0x0A0)
+#define ROULEUR_DIG_SWR_DIG_DEBUG_CTL (ROULEUR_DIG_BASE_ADDR+0x0AB)
+#define ROULEUR_DIG_SWR_DIG_DEBUG_EN (ROULEUR_DIG_BASE_ADDR+0x0AC)
+#define ROULEUR_DIG_SWR_DEM_BYPASS_DATA0 (ROULEUR_DIG_BASE_ADDR+0x0B0)
+#define ROULEUR_DIG_SWR_DEM_BYPASS_DATA1 (ROULEUR_DIG_BASE_ADDR+0x0B1)
+#define ROULEUR_DIG_SWR_DEM_BYPASS_DATA2 (ROULEUR_DIG_BASE_ADDR+0x0B2)
+#define ROULEUR_DIG_SWR_DEM_BYPASS_DATA3 (ROULEUR_DIG_BASE_ADDR+0x0B3)
+
+#define ROULEUR_ANALOG_REGISTERS_MAX_SIZE (ROULEUR_ANA_BASE_ADDR+0x0B5)
+#define ROULEUR_DIGITAL_REGISTERS_MAX_SIZE (ROULEUR_DIG_BASE_ADDR+0x0B4)
+#define ROULEUR_ANALOG_MAX_REGISTER (ROULEUR_ANALOG_REGISTERS_MAX_SIZE - 1)
+#define ROULEUR_DIGITAL_MAX_REGISTER (ROULEUR_DIGITAL_REGISTERS_MAX_SIZE - 1)
+#endif
diff --git a/asoc/codecs/rouleur/rouleur-regmap.c b/asoc/codecs/rouleur/rouleur-regmap.c
new file mode 100644
index 00000000..62502140
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur-regmap.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "rouleur-registers.h"
+
+extern const u8 rouleur_reg_access_analog[
+ ROULEUR_REG(ROULEUR_ANALOG_REGISTERS_MAX_SIZE)];
+extern const u8 rouleur_reg_access_digital[
+ ROULEUR_REG(ROULEUR_DIGITAL_REGISTERS_MAX_SIZE)];
+
+static const struct reg_default rouleur_defaults[] = {
+ { ROULEUR_ANA_MICBIAS_MICB_1_2_EN, 0x01 },
+ { ROULEUR_ANA_MICBIAS_MICB_3_EN, 0x00 },
+ { ROULEUR_ANA_MICBIAS_LDO_1_SETTING, 0x21 },
+ { ROULEUR_ANA_MICBIAS_LDO_1_CTRL, 0x01 },
+ { ROULEUR_ANA_TX_AMIC1, 0x00 },
+ { ROULEUR_ANA_TX_AMIC2, 0x00 },
+ { ROULEUR_ANA_MBHC_MECH, 0x39 },
+ { ROULEUR_ANA_MBHC_ELECT, 0x08 },
+ { ROULEUR_ANA_MBHC_ZDET, 0x10 },
+ { ROULEUR_ANA_MBHC_RESULT_1, 0x00 },
+ { ROULEUR_ANA_MBHC_RESULT_2, 0x00 },
+ { ROULEUR_ANA_MBHC_RESULT_3, 0x00 },
+ { ROULEUR_ANA_MBHC_BTN0_ZDET_VREF1, 0x00 },
+ { ROULEUR_ANA_MBHC_BTN1_ZDET_VREF2, 0x10 },
+ { ROULEUR_ANA_MBHC_BTN2_ZDET_VREF3, 0x20 },
+ { ROULEUR_ANA_MBHC_BTN3_ZDET_DBG_400, 0x30 },
+ { ROULEUR_ANA_MBHC_BTN4_ZDET_DBG_1400, 0x40 },
+ { ROULEUR_ANA_MBHC_MICB2_RAMP, 0x00 },
+ { ROULEUR_ANA_MBHC_CTL_1, 0x02 },
+ { ROULEUR_ANA_MBHC_CTL_2, 0x05 },
+ { ROULEUR_ANA_MBHC_PLUG_DETECT_CTL, 0xE9 },
+ { ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x0F },
+ { ROULEUR_ANA_MBHC_ZDET_RAMP_CTL, 0x00 },
+ { ROULEUR_ANA_MBHC_FSM_STATUS, 0x00 },
+ { ROULEUR_ANA_MBHC_ADC_RESULT, 0x00 },
+ { ROULEUR_ANA_MBHC_MCLK, 0x30 },
+ { ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT, 0x00 },
+ { ROULEUR_ANA_NCP_EN, 0x00 },
+ { ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x2B },
+ { ROULEUR_ANA_HPHPA_PA_STATUS, 0x00 },
+ { ROULEUR_ANA_HPHPA_FSM_CLK, 0x12 },
+ { ROULEUR_ANA_HPHPA_SPARE_CTL, 0x02 },
+ { ROULEUR_ANA_SURGE_EN, 0x38 },
+ { ROULEUR_ANA_COMBOPA_CTL, 0x35 },
+ { ROULEUR_ANA_RXLDO_CTL, 0x86 },
+ { ROULEUR_ANA_MBIAS_EN, 0x00 },
+ { ROULEUR_DIG_SWR_CHIP_ID0, 0x00 },
+ { ROULEUR_DIG_SWR_CHIP_ID1, 0x00 },
+ { ROULEUR_DIG_SWR_CHIP_ID2, 0x0C },
+ { ROULEUR_DIG_SWR_CHIP_ID3, 0x01 },
+ { ROULEUR_DIG_SWR_SWR_TX_CLK_RATE, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_RST_CTL, 0x03 },
+ { ROULEUR_DIG_SWR_TOP_CLK_CFG, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_TX_CLK_CTL, 0x33 },
+ { ROULEUR_DIG_SWR_SWR_RST_EN, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_RX_RST, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_RX0_CTL, 0xFC },
+ { ROULEUR_DIG_SWR_CDC_RX1_CTL, 0xFC },
+ { ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_COMP_CTL_0, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_RX_DELAY_CTL, 0x66 },
+ { ROULEUR_DIG_SWR_CDC_RX_GAIN_0, 0x55 },
+ { ROULEUR_DIG_SWR_CDC_RX_GAIN_1, 0xA9 },
+ { ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_TX0_CTL, 0x68 },
+ { ROULEUR_DIG_SWR_CDC_TX1_CTL, 0x68 },
+ { ROULEUR_DIG_SWR_CDC_TX_RST, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_REQ0_CTL, 0x01 },
+ { ROULEUR_DIG_SWR_CDC_REQ1_CTL, 0x01 },
+ { ROULEUR_DIG_SWR_CDC_RST, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_AMIC_CTL, 0x02 },
+ { ROULEUR_DIG_SWR_CDC_DMIC_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_DMIC1_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_DMIC1_RATE, 0x01 },
+ { ROULEUR_DIG_SWR_PDM_WD_CTL0, 0x00 },
+ { ROULEUR_DIG_SWR_PDM_WD_CTL1, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_MODE, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_MASK_0, 0xFF },
+ { ROULEUR_DIG_SWR_INTR_MASK_1, 0x7F },
+ { ROULEUR_DIG_SWR_INTR_MASK_2, 0x0C },
+ { ROULEUR_DIG_SWR_INTR_STATUS_0, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_STATUS_1, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_STATUS_2, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_CLEAR_0, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_CLEAR_1, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_CLEAR_2, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_LEVEL_0, 0x00 },
+ { ROULEUR_DIG_SWR_INTR_LEVEL_1, 0x2A },
+ { ROULEUR_DIG_SWR_INTR_LEVEL_2, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_CONN_RX0_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_CDC_CONN_RX1_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_LOOP_BACK_MODE, 0x00 },
+ { ROULEUR_DIG_SWR_DRIVE_STRENGTH_0, 0x00 },
+ { ROULEUR_DIG_SWR_DIG_DEBUG_CTL, 0x00 },
+ { ROULEUR_DIG_SWR_DIG_DEBUG_EN, 0x00 },
+ { ROULEUR_DIG_SWR_DEM_BYPASS_DATA0, 0x55 },
+ { ROULEUR_DIG_SWR_DEM_BYPASS_DATA1, 0x55 },
+ { ROULEUR_DIG_SWR_DEM_BYPASS_DATA2, 0x55 },
+ { ROULEUR_DIG_SWR_DEM_BYPASS_DATA3, 0x01 },
+};
+
+static bool rouleur_readable_register(struct device *dev, unsigned int reg)
+{
+ if (reg > ROULEUR_ANA_BASE_ADDR && reg <
+ ROULEUR_ANALOG_REGISTERS_MAX_SIZE)
+ return rouleur_reg_access_analog[ROULEUR_REG(reg)] & RD_REG;
+ if (reg > ROULEUR_DIG_BASE_ADDR && reg <
+ ROULEUR_DIGITAL_REGISTERS_MAX_SIZE)
+ return rouleur_reg_access_digital[ROULEUR_REG(reg)] & RD_REG;
+ return 0;
+}
+
+static bool rouleur_writeable_register(struct device *dev, unsigned int reg)
+{
+ if (reg > ROULEUR_ANA_BASE_ADDR && reg <
+ ROULEUR_ANALOG_REGISTERS_MAX_SIZE)
+ return rouleur_reg_access_analog[ROULEUR_REG(reg)] & WR_REG;
+ if (reg > ROULEUR_DIG_BASE_ADDR && reg <
+ ROULEUR_DIGITAL_REGISTERS_MAX_SIZE)
+ return rouleur_reg_access_digital[ROULEUR_REG(reg)] & WR_REG;
+ return 0;
+}
+
+static bool rouleur_volatile_register(struct device *dev, unsigned int reg)
+{
+ if (reg > ROULEUR_ANA_BASE_ADDR && reg <
+ ROULEUR_ANALOG_REGISTERS_MAX_SIZE)
+ if ((rouleur_reg_access_analog[ROULEUR_REG(reg)] & RD_REG)
+ && !(rouleur_reg_access_analog[ROULEUR_REG(reg)] & WR_REG))
+ return true;
+ return false;
+ if (reg > ROULEUR_DIG_BASE_ADDR && reg <
+ ROULEUR_DIGITAL_REGISTERS_MAX_SIZE)
+ if ((rouleur_reg_access_digital[ROULEUR_REG(reg)] & RD_REG)
+ && !(rouleur_reg_access_digital[ROULEUR_REG(reg)] & WR_REG))
+ return true;
+ return false;
+ return 0;
+}
+
+struct regmap_config rouleur_regmap_config = {
+ .name = "rouleur_csr",
+ .reg_bits = 16,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rouleur_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rouleur_defaults),
+ .max_register = ROULEUR_ANALOG_MAX_REGISTER +
+ ROULEUR_DIGITAL_MAX_REGISTER,
+ .readable_reg = rouleur_readable_register,
+ .writeable_reg = rouleur_writeable_register,
+ .volatile_reg = rouleur_volatile_register,
+ .can_multi_write = true,
+};
diff --git a/asoc/codecs/rouleur/rouleur-tables.c b/asoc/codecs/rouleur/rouleur-tables.c
new file mode 100644
index 00000000..ea710ebb
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur-tables.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include "rouleur-registers.h"
+
+const u8 rouleur_reg_access_analog[ROULEUR_REG(
+ ROULEUR_ANALOG_REGISTERS_MAX_SIZE)] = {
+ [ROULEUR_REG(ROULEUR_ANA_MICBIAS_MICB_1_2_EN)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MICBIAS_MICB_3_EN)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MICBIAS_LDO_1_SETTING)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MICBIAS_LDO_1_CTRL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_TX_AMIC1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_TX_AMIC2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_MECH)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_ELECT)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_RESULT_1)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_RESULT_2)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_RESULT_3)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN0_ZDET_VREF1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN1_ZDET_VREF2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN2_ZDET_VREF3)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN3_ZDET_DBG_400)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_BTN4_ZDET_DBG_1400)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_MICB2_RAMP)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_CTL_1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_CTL_2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_PLUG_DETECT_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_ANA_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_RAMP_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_FSM_STATUS)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_ADC_RESULT)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_MCLK)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_NCP_EN)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_HPHPA_CNP_CTL_2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_HPHPA_PA_STATUS)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_ANA_HPHPA_FSM_CLK)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_HPHPA_SPARE_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_SURGE_EN)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_COMBOPA_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_RXLDO_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_ANA_MBIAS_EN)] = RD_WR_REG,
+};
+
+const u8 rouleur_reg_access_digital[ROULEUR_REG(
+ ROULEUR_DIGITAL_REGISTERS_MAX_SIZE)] = {
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CHIP_ID0)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CHIP_ID1)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CHIP_ID2)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CHIP_ID3)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_SWR_TX_CLK_RATE)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RST_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_TOP_CLK_CFG)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_CLK_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX_CLK_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_SWR_RST_EN)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_RST)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX0_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX1_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_COMP_CTL_0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_DELAY_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_GAIN_0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_GAIN_1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX0_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX1_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_TX_RST)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_REQ0_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_REQ1_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_RST)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_AMIC_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_DMIC_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_DMIC1_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_DMIC1_RATE)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_PDM_WD_CTL0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_PDM_WD_CTL1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_MODE)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_MASK_0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_MASK_1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_MASK_2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_STATUS_0)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_STATUS_1)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_STATUS_2)] = RD_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_CLEAR_0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_CLEAR_1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_CLEAR_2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_LEVEL_0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_LEVEL_1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_INTR_LEVEL_2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_CONN_RX0_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_CDC_CONN_RX1_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_LOOP_BACK_MODE)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DRIVE_STRENGTH_0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DIG_DEBUG_CTL)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DIG_DEBUG_EN)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DEM_BYPASS_DATA0)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DEM_BYPASS_DATA1)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DEM_BYPASS_DATA2)] = RD_WR_REG,
+ [ROULEUR_REG(ROULEUR_DIG_SWR_DEM_BYPASS_DATA3)] = RD_WR_REG,
+};
diff --git a/asoc/codecs/rouleur/rouleur.c b/asoc/codecs/rouleur/rouleur.c
new file mode 100644
index 00000000..14dfd52f
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur.c
@@ -0,0 +1,2492 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/component.h>
+#include <linux/regmap.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_platform.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <soc/soundwire.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include "internal.h"
+#include "rouleur.h"
+#include <asoc/wcdcal-hwdep.h>
+#include "rouleur-registers.h"
+#include "pm2250-spmi.h"
+#include <asoc/msm-cdc-pinctrl.h>
+#include <dt-bindings/sound/audio-codec-port-types.h>
+#include <asoc/msm-cdc-supply.h>
+
+#define DRV_NAME "rouleur_codec"
+
+#define NUM_SWRS_DT_PARAMS 5
+
+#define ROULEUR_VERSION_1_0 1
+#define ROULEUR_VERSION_ENTRY_SIZE 32
+
+#define NUM_ATTEMPTS 5
+
+enum {
+ CODEC_TX = 0,
+ CODEC_RX,
+};
+
+enum {
+ ALLOW_VPOS_DISABLE,
+ HPH_COMP_DELAY,
+ HPH_PA_DELAY,
+ AMIC2_BCS_ENABLE,
+};
+
+/* TODO: Check on the step values */
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+
+static int rouleur_handle_post_irq(void *data);
+static int rouleur_reset(struct device *dev, int val);
+
+static const struct regmap_irq ROULEUR_IRQs[ROULEUR_NUM_IRQS] = {
+ REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_MBHC_SW_DET, 0, 0x10),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHR_OCP_INT, 0, 0x20),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHR_CNP_INT, 0, 0x40),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHL_OCP_INT, 0, 0x80),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHL_CNP_INT, 1, 0x01),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_EAR_CNP_INT, 1, 0x02),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_EAR_OCP_INT, 1, 0x04),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_LO_CNP_INT, 1, 0x08),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_LO_OCP_INT, 1, 0x10),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHL_PDM_WD_INT, 1, 0x20),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHR_PDM_WD_INT, 1, 0x40),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHL_SURGE_DET_INT, 2, 0x04),
+ REGMAP_IRQ_REG(ROULEUR_IRQ_HPHR_SURGE_DET_INT, 2, 0x08),
+};
+
+static struct regmap_irq_chip rouleur_regmap_irq_chip = {
+ .name = "rouleur",
+ .irqs = ROULEUR_IRQs,
+ .num_irqs = ARRAY_SIZE(ROULEUR_IRQs),
+ .num_regs = 3,
+ .status_base = ROULEUR_DIG_SWR_INTR_STATUS_0,
+ .mask_base = ROULEUR_DIG_SWR_INTR_MASK_0,
+ .ack_base = ROULEUR_DIG_SWR_INTR_CLEAR_0,
+ .use_ack = 1,
+ .type_base = ROULEUR_DIG_SWR_INTR_LEVEL_0,
+ .runtime_pm = false,
+ .handle_post_irq = rouleur_handle_post_irq,
+ .irq_drv_data = NULL,
+};
+
+static int rouleur_handle_post_irq(void *data)
+{
+ struct rouleur_priv *rouleur = data;
+ u32 status1 = 0, status2 = 0, status3 = 0;
+
+ regmap_read(rouleur->regmap, ROULEUR_DIG_SWR_INTR_STATUS_0, &status1);
+ regmap_read(rouleur->regmap, ROULEUR_DIG_SWR_INTR_STATUS_1, &status2);
+ regmap_read(rouleur->regmap, ROULEUR_DIG_SWR_INTR_STATUS_2, &status3);
+
+ rouleur->tx_swr_dev->slave_irq_pending =
+ ((status1 || status2 || status3) ? true : false);
+
+ return IRQ_HANDLED;
+}
+
+static int rouleur_init_reg(struct snd_soc_component *component)
+{
+ /* Enable surge protection */
+ snd_soc_component_update_bits(component, ROULEUR_ANA_SURGE_EN,
+ 0xC0, 0xC0);
+ return 0;
+}
+
+static int rouleur_set_port_params(struct snd_soc_component *component,
+ u8 slv_prt_type, u8 *port_id, u8 *num_ch,
+ u8 *ch_mask, u32 *ch_rate,
+ u8 *port_type, u8 path)
+{
+ int i, j;
+ u8 num_ports = 0;
+ struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT] = NULL;
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ switch (path) {
+ case CODEC_RX:
+ map = &rouleur->rx_port_mapping;
+ num_ports = rouleur->num_rx_ports;
+ break;
+ case CODEC_TX:
+ map = &rouleur->tx_port_mapping;
+ num_ports = rouleur->num_tx_ports;
+ break;
+ default:
+ dev_err(component->dev, "%s Invalid path: %d\n",
+ __func__, path);
+ return -EINVAL;
+ }
+
+ for (i = 0; i <= num_ports; i++) {
+ for (j = 0; j < MAX_CH_PER_PORT; j++) {
+ if ((*map)[i][j].slave_port_type == slv_prt_type)
+ goto found;
+ }
+ }
+
+ dev_err(component->dev, "%s Failed to find slave port for type %u\n",
+ __func__, slv_prt_type);
+ return -EINVAL;
+found:
+ *port_id = i;
+ *num_ch = (*map)[i][j].num_ch;
+ *ch_mask = (*map)[i][j].ch_mask;
+ *ch_rate = (*map)[i][j].ch_rate;
+ *port_type = (*map)[i][j].master_port_type;
+
+ return 0;
+}
+
+static int rouleur_parse_port_mapping(struct device *dev,
+ char *prop, u8 path)
+{
+ u32 *dt_array, map_size, map_length;
+ u32 port_num = 0, ch_mask, ch_rate, old_port_num = 0;
+ u32 slave_port_type, master_port_type;
+ u32 i, ch_iter = 0;
+ int ret = 0;
+ u8 *num_ports = NULL;
+ struct codec_port_info (*map)[MAX_PORT][MAX_CH_PER_PORT] = NULL;
+ struct rouleur_priv *rouleur = dev_get_drvdata(dev);
+
+ switch (path) {
+ case CODEC_RX:
+ map = &rouleur->rx_port_mapping;
+ num_ports = &rouleur->num_rx_ports;
+ break;
+ case CODEC_TX:
+ map = &rouleur->tx_port_mapping;
+ num_ports = &rouleur->num_tx_ports;
+ break;
+ default:
+ dev_err(dev, "%s Invalid path: %d\n",
+ __func__, path);
+ return -EINVAL;
+ }
+
+ if (!of_find_property(dev->of_node, prop,
+ &map_size)) {
+ dev_err(dev, "missing port mapping prop %s\n", prop);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ map_length = map_size / (NUM_SWRS_DT_PARAMS * sizeof(u32));
+
+ dt_array = kzalloc(map_size, GFP_KERNEL);
+
+ if (!dt_array) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ ret = of_property_read_u32_array(dev->of_node, prop, dt_array,
+ NUM_SWRS_DT_PARAMS * map_length);
+ if (ret) {
+ dev_err(dev, "%s: Failed to read port mapping from prop %s\n",
+ __func__, prop);
+ ret = -EINVAL;
+ goto err_pdata_fail;
+ }
+
+ for (i = 0; i < map_length; i++) {
+ port_num = dt_array[NUM_SWRS_DT_PARAMS * i];
+ slave_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 1];
+ ch_mask = dt_array[NUM_SWRS_DT_PARAMS * i + 2];
+ ch_rate = dt_array[NUM_SWRS_DT_PARAMS * i + 3];
+ master_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 4];
+
+ if (port_num != old_port_num)
+ ch_iter = 0;
+
+ (*map)[port_num][ch_iter].slave_port_type = slave_port_type;
+ (*map)[port_num][ch_iter].ch_mask = ch_mask;
+ (*map)[port_num][ch_iter].master_port_type = master_port_type;
+ (*map)[port_num][ch_iter].num_ch = __sw_hweight8(ch_mask);
+ (*map)[port_num][ch_iter++].ch_rate = ch_rate;
+ old_port_num = port_num;
+ }
+ *num_ports = port_num;
+
+err_pdata_fail:
+ kfree(dt_array);
+err:
+ return ret;
+}
+
+static int rouleur_tx_connect_port(struct snd_soc_component *component,
+ u8 slv_port_type, u8 enable)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ u8 port_id;
+ u8 num_ch;
+ u8 ch_mask;
+ u32 ch_rate;
+ u8 port_type;
+ u8 num_port = 1;
+ int ret = 0;
+
+ ret = rouleur_set_port_params(component, slv_port_type, &port_id,
+ &num_ch, &ch_mask, &ch_rate,
+ &port_type, CODEC_TX);
+
+ if (ret) {
+ dev_err(rouleur->dev, "%s:Failed to set port params: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (enable)
+ ret = swr_connect_port(rouleur->tx_swr_dev, &port_id,
+ num_port, &ch_mask, &ch_rate,
+ &num_ch, &port_type);
+ else
+ ret = swr_disconnect_port(rouleur->tx_swr_dev, &port_id,
+ num_port, &ch_mask, &port_type);
+ return ret;
+
+}
+static int rouleur_rx_connect_port(struct snd_soc_component *component,
+ u8 slv_port_type, u8 enable)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ u8 port_id;
+ u8 num_ch;
+ u8 ch_mask;
+ u32 ch_rate;
+ u8 port_type;
+ u8 num_port = 1;
+ int ret = 0;
+
+ ret = rouleur_set_port_params(component, slv_port_type, &port_id,
+ &num_ch, &ch_mask, &ch_rate,
+ &port_type, CODEC_RX);
+
+ if (ret) {
+ dev_err(rouleur->dev, "%s:Failed to set port params: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (enable)
+ ret = swr_connect_port(rouleur->rx_swr_dev, &port_id,
+ num_port, &ch_mask, &ch_rate,
+ &num_ch, &port_type);
+ else
+ ret = swr_disconnect_port(rouleur->rx_swr_dev, &port_id,
+ num_port, &ch_mask, &port_type);
+ return ret;
+}
+
+static int rouleur_global_mbias_enable(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&rouleur->main_bias_lock);
+ if (rouleur->mbias_cnt == 0) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBIAS_EN, 0x20, 0x20);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBIAS_EN, 0x10, 0x10);
+ usleep_range(1000, 1100);
+ }
+ rouleur->mbias_cnt++;
+ mutex_unlock(&rouleur->main_bias_lock);
+
+ return 0;
+}
+
+static int rouleur_global_mbias_disable(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&rouleur->main_bias_lock);
+ if (rouleur->mbias_cnt == 0) {
+ dev_dbg(rouleur->dev, "%s:mbias already disabled\n", __func__);
+ mutex_unlock(&rouleur->main_bias_lock);
+ return 0;
+ }
+ rouleur->mbias_cnt--;
+ if (rouleur->mbias_cnt == 0) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBIAS_EN, 0x10, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MBIAS_EN, 0x20, 0x00);
+ }
+ mutex_unlock(&rouleur->main_bias_lock);
+
+ return 0;
+}
+
+static int rouleur_rx_clk_enable(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&rouleur->rx_clk_lock);
+ if (rouleur->rx_clk_cnt == 0) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x10, 0x10);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x20, 0x20);
+ usleep_range(5000, 5100);
+ rouleur_global_mbias_enable(component);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_FSM_CLK, 0x11, 0x11);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_FSM_CLK, 0x80, 0x80);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_NCP_EN, 0x01, 0x01);
+ usleep_range(500, 510);
+ }
+ rouleur->rx_clk_cnt++;
+ mutex_unlock(&rouleur->rx_clk_lock);
+
+ return 0;
+}
+
+static int rouleur_rx_clk_disable(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&rouleur->rx_clk_lock);
+ if (rouleur->rx_clk_cnt == 0) {
+ dev_dbg(rouleur->dev, "%s:clk already disabled\n", __func__);
+ mutex_unlock(&rouleur->rx_clk_lock);
+ return 0;
+ }
+ rouleur->rx_clk_cnt--;
+ if (rouleur->rx_clk_cnt == 0) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_FSM_CLK, 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_FSM_CLK, 0x11, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_NCP_EN, 0x01, 0x00);
+ rouleur_global_mbias_disable(component);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x20, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x10, 0x00);
+
+ }
+ mutex_unlock(&rouleur->rx_clk_lock);
+ return 0;
+}
+
+/*
+ * rouleur_soc_get_mbhc: get rouleur_mbhc handle of corresponding component
+ * @component: handle to snd_soc_component *
+ *
+ * return rouleur_mbhc handle or error code in case of failure
+ */
+struct rouleur_mbhc *rouleur_soc_get_mbhc(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur;
+
+ if (!component) {
+ pr_err("%s: Invalid params, NULL component\n", __func__);
+ return NULL;
+ }
+ rouleur = snd_soc_component_get_drvdata(component);
+
+ if (!rouleur) {
+ pr_err("%s: Invalid params, NULL tavil\n", __func__);
+ return NULL;
+ }
+
+ return rouleur->mbhc;
+}
+EXPORT_SYMBOL(rouleur_soc_get_mbhc);
+
+static int rouleur_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ rouleur_rx_clk_enable(component);
+ set_bit(HPH_COMP_DELAY, &rouleur->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (rouleur->comp1_enable) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+ 0x02, 0x02);
+
+ if (rouleur->comp2_enable)
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+ 0x01, 0x01);
+ /*
+ * 5ms sleep is required after COMP is enabled as per
+ * HW requirement
+ */
+ if (test_bit(HPH_COMP_DELAY, &rouleur->status_mask)) {
+ usleep_range(5000, 5100);
+ clear_bit(HPH_COMP_DELAY,
+ &rouleur->status_mask);
+ }
+ } else {
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+ 0x02, 0x00);
+ }
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX0_CTL,
+ 0x7C, 0x7C);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL,
+ 0x04, 0x04);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x01, 0x01);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_PDM_WD_CTL0,
+ 0x03, 0x03);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_PDM_WD_CTL0,
+ 0x03, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL,
+ 0x01, 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int rouleur_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ rouleur_rx_clk_enable(component);
+ set_bit(HPH_COMP_DELAY, &rouleur->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (rouleur->comp2_enable) {
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+ 0x01, 0x01);
+
+ if (rouleur->comp1_enable)
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+ 0x02, 0x02);
+ /*
+ * 5ms sleep is required after COMP is enabled as per
+ * HW requirement
+ */
+ if (test_bit(HPH_COMP_DELAY, &rouleur->status_mask)) {
+ usleep_range(5000, 5100);
+ clear_bit(HPH_COMP_DELAY,
+ &rouleur->status_mask);
+ }
+ } else {
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_COMP_CTL_0,
+ 0x01, 0x00);
+ }
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX1_CTL,
+ 0x7C, 0x7C);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL,
+ 0x08, 0x08);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x02, 0x02);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_PDM_WD_CTL1,
+ 0x03, 0x03);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_PDM_WD_CTL1,
+ 0x03, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x02, 0x00);
+ break;
+
+ }
+
+ return 0;
+}
+
+static int rouleur_codec_ear_lo_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ rouleur_rx_clk_enable(component);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX0_CTL,
+ 0x7C, 0x7C);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL,
+ 0x01, 0x01);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_PDM_WD_CTL0,
+ 0x03, 0x03);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL,
+ 0x04, 0x04);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_PDM_WD_CTL0,
+ 0x03, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_RX_CLK_CTL,
+ 0x01, 0x00);
+
+ break;
+ };
+ return 0;
+
+}
+
+static int rouleur_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
+ rouleur->rx_swr_dev->dev_num,
+ true);
+
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x40, 0x40);
+ set_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ /* TODO: WHY SECOND TIME */
+ ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
+ rouleur->rx_swr_dev->dev_num,
+ true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /*
+ * 5ms sleep is required after PA is enabled as per
+ * HW requirement.
+ */
+ if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) {
+ usleep_range(5000, 5100);
+ clear_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ }
+
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX2 << 0x10));
+ wcd_enable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHR_PDM_WD_INT);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wcd_disable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHR_PDM_WD_INT);
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX2 << 0x10 | 0x1));
+ blocking_notifier_call_chain(&rouleur->mbhc->notifier,
+ WCD_EVENT_PRE_HPHR_PA_OFF,
+ &rouleur->mbhc->wcd_mbhc);
+ set_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /*
+ * 7ms sleep is required after PA is disabled as per
+ * HW requirement. If compander is disabled, then
+ * 20ms delay is required.
+ */
+ if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) {
+
+ usleep_range(5000, 5100);
+ clear_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ }
+
+ blocking_notifier_call_chain(&rouleur->mbhc->notifier,
+ WCD_EVENT_POST_HPHR_PA_OFF,
+ &rouleur->mbhc->wcd_mbhc);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x40, 0x00);
+ break;
+ };
+ return ret;
+}
+
+static int rouleur_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
+ rouleur->rx_swr_dev->dev_num,
+ true);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x80, 0x80);
+ set_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /*
+ * 5ms sleep is required after PA is enabled as per
+ * HW requirement.
+ */
+ if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) {
+ usleep_range(5000, 5100);
+ clear_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ }
+
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10));
+ wcd_enable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wcd_disable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT);
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10 | 0x1));
+ blocking_notifier_call_chain(&rouleur->mbhc->notifier,
+ WCD_EVENT_PRE_HPHL_PA_OFF,
+ &rouleur->mbhc->wcd_mbhc);
+ set_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /*
+ * 5ms sleep is required after PA is disabled as per
+ * HW requirement.
+ */
+ if (test_bit(HPH_PA_DELAY, &rouleur->status_mask)) {
+ usleep_range(5000, 5100);
+ clear_bit(HPH_PA_DELAY, &rouleur->status_mask);
+ }
+
+ blocking_notifier_call_chain(&rouleur->mbhc->notifier,
+ WCD_EVENT_POST_HPHL_PA_OFF,
+ &rouleur->mbhc->wcd_mbhc);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0x80, 0x00);
+
+ break;
+ };
+ return ret;
+}
+
+static int rouleur_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
+ rouleur->rx_swr_dev->dev_num,
+ true);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x80, 0x80);
+ usleep_range(5000, 5100);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10));
+ wcd_enable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wcd_disable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT);
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10 | 0x1));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x80, 0x00);
+ usleep_range(5000, 5100);
+ };
+ return ret;
+}
+
+static int rouleur_codec_enable_lo_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev,
+ rouleur->rx_swr_dev->dev_num,
+ true);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x40, 0x40);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x80, 0x80);
+ usleep_range(5000, 5100);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10));
+ wcd_enable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wcd_disable_irq(&rouleur->irq_info,
+ ROULEUR_IRQ_HPHL_PDM_WD_INT);
+ if (rouleur->update_wcd_event)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_RX_MUTE,
+ (WCD_RX1 << 0x10 | 0x1));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x40, 0x00);
+ usleep_range(5000, 5100);
+ };
+ return ret;
+}
+
+static int rouleur_enable_rx1(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ rouleur_rx_connect_port(component, HPH_L, true);
+ if (rouleur->comp1_enable)
+ rouleur_rx_connect_port(component, COMP_L, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ rouleur_rx_connect_port(component, HPH_L, false);
+ if (rouleur->comp1_enable)
+ rouleur_rx_connect_port(component, COMP_L, false);
+ rouleur_rx_clk_disable(component);
+ break;
+ };
+ return 0;
+}
+
+static int rouleur_enable_rx2(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ rouleur_rx_connect_port(component, HPH_R, true);
+ if (rouleur->comp2_enable)
+ rouleur_rx_connect_port(component, COMP_R, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ rouleur_rx_connect_port(component, HPH_R, false);
+ if (rouleur->comp2_enable)
+ rouleur_rx_connect_port(component, COMP_R, false);
+ rouleur_rx_clk_disable(component);
+ break;
+ };
+
+ return 0;
+}
+
+static int rouleur_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ u16 dmic_clk_reg;
+ s32 *dmic_clk_cnt;
+ unsigned int dmic;
+ char *wname;
+ int ret = 0;
+
+ wname = strpbrk(w->name, "01");
+
+ if (!wname) {
+ dev_err(component->dev, "%s: widget not found\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = kstrtouint(wname, 10, &dmic);
+ if (ret < 0) {
+ dev_err(component->dev, "%s: Invalid DMIC line on the codec\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (dmic) {
+ case 0:
+ case 1:
+ dmic_clk_cnt = &(rouleur->dmic_0_1_clk_cnt);
+ dmic_clk_reg = ROULEUR_DIG_SWR_CDC_DMIC1_CTL;
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid DMIC Selection\n",
+ __func__);
+ return -EINVAL;
+ };
+ dev_dbg(component->dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n",
+ __func__, event, dmic, *dmic_clk_cnt);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_AMIC_CTL, 0x02, 0x00);
+ snd_soc_component_update_bits(component,
+ dmic_clk_reg, 0x08, 0x08);
+ rouleur_tx_connect_port(component, DMIC0 + (w->shift), true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ rouleur_tx_connect_port(component, DMIC0 + (w->shift), false);
+ snd_soc_component_update_bits(component,
+ dmic_clk_reg, 0x08, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_AMIC_CTL, 0x02, 0x02);
+ break;
+
+ };
+ return 0;
+}
+
+static int rouleur_tx_swr_ctrl(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = swr_slvdev_datapath_control(rouleur->tx_swr_dev,
+ rouleur->tx_swr_dev->dev_num,
+ true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ ret = swr_slvdev_datapath_control(rouleur->tx_swr_dev,
+ rouleur->tx_swr_dev->dev_num,
+ false);
+ break;
+ };
+
+ return ret;
+}
+
+static int rouleur_codec_enable_adc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur =
+ snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable BCS for Headset mic */
+ if (w->shift == 1 && !(snd_soc_component_read32(component,
+ ROULEUR_ANA_TX_AMIC2) & 0x10)) {
+ rouleur_tx_connect_port(component, MBHC, true);
+ set_bit(AMIC2_BCS_ENABLE, &rouleur->status_mask);
+ }
+ rouleur_tx_connect_port(component, ADC1 + (w->shift), true);
+ rouleur_global_mbias_enable(component);
+ if (w->shift)
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1,
+ 0x30, 0x30);
+ else
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1,
+ 0x03, 0x03);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ rouleur_tx_connect_port(component, ADC1 + (w->shift), false);
+ if (w->shift == 1 &&
+ test_bit(AMIC2_BCS_ENABLE, &rouleur->status_mask)) {
+ rouleur_tx_connect_port(component, MBHC, false);
+ clear_bit(AMIC2_BCS_ENABLE, &rouleur->status_mask);
+ }
+ if (w->shift)
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1,
+ 0x30, 0x00);
+ else
+ snd_soc_component_update_bits(component,
+ ROULEUR_DIG_SWR_CDC_TX_ANA_MODE_0_1,
+ 0x03, 0x00);
+ rouleur_global_mbias_disable(component);
+ break;
+ };
+
+ return 0;
+}
+
+/*
+ * rouleur_get_micb_vout_ctl_val: converts micbias from volts to register value
+ * @micb_mv: micbias in mv
+ *
+ * return register value converted
+ */
+int rouleur_get_micb_vout_ctl_val(u32 micb_mv)
+{
+ /* min micbias voltage is 1.6V and maximum is 2.85V */
+ if (micb_mv < 1600 || micb_mv > 2850) {
+ pr_err("%s: unsupported micbias voltage\n", __func__);
+ return -EINVAL;
+ }
+
+ return (micb_mv - 1600) / 50;
+}
+EXPORT_SYMBOL(rouleur_get_micb_vout_ctl_val);
+
+/*
+ * rouleur_mbhc_micb_adjust_voltage: adjust specific micbias voltage
+ * @component: handle to snd_soc_component *
+ * @req_volt: micbias voltage to be set
+ * @micb_num: micbias to be set, e.g. micbias1 or micbias2
+ *
+ * return 0 if adjustment is success or error code in case of failure
+ */
+int rouleur_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
+ int req_volt, int micb_num)
+{
+ struct rouleur_priv *rouleur =
+ snd_soc_component_get_drvdata(component);
+ int cur_vout_ctl, req_vout_ctl;
+ int micb_reg, micb_val, micb_en;
+ int ret = 0;
+ int pullup_mask;
+
+ micb_reg = ROULEUR_ANA_MICBIAS_MICB_1_2_EN;
+ switch (micb_num) {
+ case MIC_BIAS_1:
+ micb_val = snd_soc_component_read32(component, micb_reg);
+ micb_en = (micb_val & 0x40) >> 6;
+ pullup_mask = 0x20;
+ break;
+ case MIC_BIAS_2:
+ micb_val = snd_soc_component_read32(component, micb_reg);
+ micb_en = (micb_val & 0x04) >> 2;
+ pullup_mask = 0x02;
+ break;
+ case MIC_BIAS_3:
+ default:
+ dev_err(component->dev, "%s: Invalid micbias number: %d\n",
+ __func__, micb_num);
+ return -EINVAL;
+ }
+ mutex_lock(&rouleur->micb_lock);
+
+ /*
+ * If requested micbias voltage is same as current micbias
+ * voltage, then just return. Otherwise, adjust voltage as
+ * per requested value. If micbias is already enabled, then
+ * to avoid slow micbias ramp-up or down enable pull-up
+ * momentarily, change the micbias value and then re-enable
+ * micbias.
+ */
+ cur_vout_ctl = (snd_soc_component_read32(component,
+ ROULEUR_ANA_MICBIAS_LDO_1_SETTING)) & 0xF8;
+
+ req_vout_ctl = rouleur_get_micb_vout_ctl_val(req_volt);
+ if (req_vout_ctl < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ if (cur_vout_ctl == req_vout_ctl) {
+ ret = 0;
+ goto exit;
+ }
+
+ dev_dbg(component->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n",
+ __func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl),
+ req_volt, micb_en);
+
+ if (micb_en == 0x1)
+ snd_soc_component_update_bits(component, micb_reg, pullup_mask,
+ pullup_mask);
+
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_MICBIAS_LDO_1_SETTING, 0xF8, req_vout_ctl);
+
+ if (micb_en == 0x1) {
+ snd_soc_component_update_bits(component, micb_reg,
+ pullup_mask, 0x00);
+ /*
+ * Add 2ms delay as per HW requirement after enabling
+ * micbias
+ */
+ usleep_range(2000, 2100);
+ }
+exit:
+ mutex_unlock(&rouleur->micb_lock);
+ return ret;
+}
+EXPORT_SYMBOL(rouleur_mbhc_micb_adjust_voltage);
+
+int rouleur_micbias_control(struct snd_soc_component *component,
+ int micb_num, int req, bool is_dapm)
+{
+
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int micb_index = micb_num - 1;
+ u16 micb_reg;
+ int pre_off_event = 0, post_off_event = 0;
+ int post_on_event = 0, post_dapm_off = 0;
+ int post_dapm_on = 0;
+ u8 pullup_mask = 0, enable_mask = 0;
+
+ if ((micb_index < 0) || (micb_index > ROULEUR_MAX_MICBIAS - 1)) {
+ dev_err(component->dev, "%s: Invalid micbias index, micb_ind:%d\n",
+ __func__, micb_index);
+ return -EINVAL;
+ }
+ switch (micb_num) {
+ case MIC_BIAS_1:
+ micb_reg = ROULEUR_ANA_MICBIAS_MICB_1_2_EN;
+ pullup_mask = 0x20;
+ enable_mask = 0x40;
+ break;
+ case MIC_BIAS_2:
+ micb_reg = ROULEUR_ANA_MICBIAS_MICB_1_2_EN;
+ pullup_mask = 0x02;
+ enable_mask = 0x04;
+ pre_off_event = WCD_EVENT_PRE_MICBIAS_2_OFF;
+ post_off_event = WCD_EVENT_POST_MICBIAS_2_OFF;
+ post_on_event = WCD_EVENT_POST_MICBIAS_2_ON;
+ post_dapm_on = WCD_EVENT_POST_DAPM_MICBIAS_2_ON;
+ post_dapm_off = WCD_EVENT_POST_DAPM_MICBIAS_2_OFF;
+ break;
+ case MIC_BIAS_3:
+ micb_reg = ROULEUR_ANA_MICBIAS_MICB_3_EN;
+ pullup_mask = 0x02;
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid micbias number: %d\n",
+ __func__, micb_num);
+ return -EINVAL;
+ };
+ mutex_lock(&rouleur->micb_lock);
+
+ switch (req) {
+ case MICB_PULLUP_ENABLE:
+ rouleur->pullup_ref[micb_index]++;
+ if ((rouleur->pullup_ref[micb_index] == 1) &&
+ (rouleur->micb_ref[micb_index] == 0))
+ snd_soc_component_update_bits(component, micb_reg,
+ pullup_mask, pullup_mask);
+ break;
+ case MICB_PULLUP_DISABLE:
+ if (rouleur->pullup_ref[micb_index] > 0)
+ rouleur->pullup_ref[micb_index]--;
+ if ((rouleur->pullup_ref[micb_index] == 0) &&
+ (rouleur->micb_ref[micb_index] == 0))
+ snd_soc_component_update_bits(component, micb_reg,
+ pullup_mask, 0x00);
+ break;
+ case MICB_ENABLE:
+ rouleur->micb_ref[micb_index]++;
+ if (rouleur->micb_ref[micb_index] == 1) {
+ rouleur_global_mbias_enable(component);
+ snd_soc_component_update_bits(component,
+ micb_reg, enable_mask, enable_mask);
+ if (post_on_event)
+ blocking_notifier_call_chain(
+ &rouleur->mbhc->notifier, post_on_event,
+ &rouleur->mbhc->wcd_mbhc);
+ }
+ if (is_dapm && post_dapm_on && rouleur->mbhc)
+ blocking_notifier_call_chain(
+ &rouleur->mbhc->notifier, post_dapm_on,
+ &rouleur->mbhc->wcd_mbhc);
+ break;
+ case MICB_DISABLE:
+ if (rouleur->micb_ref[micb_index] > 0)
+ rouleur->micb_ref[micb_index]--;
+ if ((rouleur->micb_ref[micb_index] == 0) &&
+ (rouleur->pullup_ref[micb_index] == 0)) {
+ if (pre_off_event && rouleur->mbhc)
+ blocking_notifier_call_chain(
+ &rouleur->mbhc->notifier, pre_off_event,
+ &rouleur->mbhc->wcd_mbhc);
+ snd_soc_component_update_bits(component, micb_reg,
+ enable_mask, 0x00);
+ rouleur_global_mbias_disable(component);
+ if (post_off_event && rouleur->mbhc)
+ blocking_notifier_call_chain(
+ &rouleur->mbhc->notifier,
+ post_off_event,
+ &rouleur->mbhc->wcd_mbhc);
+ }
+ if (is_dapm && post_dapm_off && rouleur->mbhc)
+ blocking_notifier_call_chain(
+ &rouleur->mbhc->notifier, post_dapm_off,
+ &rouleur->mbhc->wcd_mbhc);
+ break;
+ };
+
+ dev_dbg(component->dev, "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n",
+ __func__, micb_num, rouleur->micb_ref[micb_index],
+ rouleur->pullup_ref[micb_index]);
+ mutex_unlock(&rouleur->micb_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(rouleur_micbias_control);
+
+void rouleur_disable_bcs_before_slow_insert(struct snd_soc_component *component,
+ bool bcs_disable)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ if (rouleur->update_wcd_event) {
+ if (bcs_disable)
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_BCS_CLK_OFF, 0);
+ else
+ rouleur->update_wcd_event(rouleur->handle,
+ WCD_BOLERO_EVT_BCS_CLK_OFF, 1);
+ }
+}
+
+static int rouleur_get_logical_addr(struct swr_device *swr_dev)
+{
+ int ret = 0;
+ uint8_t devnum = 0;
+ int num_retry = NUM_ATTEMPTS;
+
+ do {
+ ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum);
+ if (ret) {
+ dev_err(&swr_dev->dev,
+ "%s get devnum %d for dev addr %lx failed\n",
+ __func__, devnum, swr_dev->addr);
+ /* retry after 1ms */
+ usleep_range(1000, 1010);
+ }
+ } while (ret && --num_retry);
+ swr_dev->dev_num = devnum;
+ return 0;
+}
+
+static int rouleur_event_notify(struct notifier_block *block,
+ unsigned long val,
+ void *data)
+{
+ u16 event = (val & 0xffff);
+ int ret = 0;
+ struct rouleur_priv *rouleur = dev_get_drvdata((struct device *)data);
+ struct snd_soc_component *component = rouleur->component;
+ struct wcd_mbhc *mbhc;
+
+ switch (event) {
+ case BOLERO_WCD_EVT_PA_OFF_PRE_SSR:
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_HPHPA_CNP_CTL_2,
+ 0xC0, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x40, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x80, 0x00);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x40, 0x40);
+ snd_soc_component_update_bits(component,
+ ROULEUR_ANA_COMBOPA_CTL,
+ 0x80, 0x00);
+ break;
+ case BOLERO_WCD_EVT_SSR_DOWN:
+ rouleur->mbhc->wcd_mbhc.deinit_in_progress = true;
+ mbhc = &rouleur->mbhc->wcd_mbhc;
+ rouleur_mbhc_ssr_down(rouleur->mbhc, component);
+ rouleur_reset(rouleur->dev, 0x01);
+ break;
+ case BOLERO_WCD_EVT_SSR_UP:
+ rouleur_reset(rouleur->dev, 0x00);
+ /* allow reset to take effect */
+ usleep_range(10000, 10010);
+ rouleur_get_logical_addr(rouleur->tx_swr_dev);
+ rouleur_get_logical_addr(rouleur->rx_swr_dev);
+
+ rouleur_init_reg(component);
+ regcache_mark_dirty(rouleur->regmap);
+ regcache_sync(rouleur->regmap);
+ /* Initialize MBHC module */
+ mbhc = &rouleur->mbhc->wcd_mbhc;
+ ret = rouleur_mbhc_post_ssr_init(rouleur->mbhc, component);
+ if (ret) {
+ dev_err(component->dev, "%s: mbhc initialization failed\n",
+ __func__);
+ } else {
+ rouleur_mbhc_hs_detect(component, mbhc->mbhc_cfg);
+ }
+ rouleur->mbhc->wcd_mbhc.deinit_in_progress = false;
+ break;
+ default:
+ dev_err(component->dev, "%s: invalid event %d\n", __func__,
+ event);
+ break;
+ }
+ return 0;
+}
+
+static int __rouleur_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ int micb_num;
+
+ dev_dbg(component->dev, "%s: wname: %s, event: %d\n",
+ __func__, w->name, event);
+
+ if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1")))
+ micb_num = MIC_BIAS_1;
+ else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2")))
+ micb_num = MIC_BIAS_2;
+ else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3")))
+ micb_num = MIC_BIAS_3;
+ else
+ return -EINVAL;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Micbias LD0 enable not supported for MicBias 3*/
+ if (micb_num == MIC_BIAS_3)
+ rouleur_micbias_control(component, micb_num,
+ MICB_PULLUP_ENABLE, true);
+ else
+ rouleur_micbias_control(component, micb_num,
+ MICB_ENABLE, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(1000, 1100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (micb_num == MIC_BIAS_3)
+ rouleur_micbias_control(component, micb_num,
+ MICB_PULLUP_DISABLE, true);
+ else
+ rouleur_micbias_control(component, micb_num,
+ MICB_DISABLE, true);
+ break;
+ };
+
+ return 0;
+
+}
+
+static int rouleur_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ return __rouleur_codec_enable_micbias(w, event);
+}
+
+static int __rouleur_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ int micb_num;
+
+ dev_dbg(component->dev, "%s: wname: %s, event: %d\n",
+ __func__, w->name, event);
+
+ if (strnstr(w->name, "VA MIC BIAS1", sizeof("VA MIC BIAS1")))
+ micb_num = MIC_BIAS_1;
+ else if (strnstr(w->name, "VA MIC BIAS2", sizeof("VA MIC BIAS2")))
+ micb_num = MIC_BIAS_2;
+ else if (strnstr(w->name, "VA MIC BIAS3", sizeof("VA MIC BIAS3")))
+ micb_num = MIC_BIAS_3;
+ else
+ return -EINVAL;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ rouleur_micbias_control(component, micb_num,
+ MICB_PULLUP_ENABLE, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* 1 msec delay as per HW requirement */
+ usleep_range(1000, 1100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ rouleur_micbias_control(component, micb_num,
+ MICB_PULLUP_DISABLE, true);
+ break;
+ };
+
+ return 0;
+
+}
+
+static int rouleur_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ return __rouleur_codec_enable_micbias_pullup(w, event);
+}
+
+static int rouleur_get_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ bool hphr;
+ struct soc_multi_mixer_control *mc;
+
+ mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+
+ ucontrol->value.integer.value[0] = hphr ? rouleur->comp2_enable :
+ rouleur->comp1_enable;
+ return 0;
+}
+
+static int rouleur_set_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ int value = ucontrol->value.integer.value[0];
+ bool hphr;
+ struct soc_multi_mixer_control *mc;
+
+ mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+ if (hphr)
+ rouleur->comp2_enable = value;
+ else
+ rouleur->comp1_enable = value;
+
+ return 0;
+}
+
+static int rouleur_codec_enable_pa_vpos(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ struct rouleur_pdata *pdata = NULL;
+ int ret = 0;
+
+ pdata = dev_get_platdata(rouleur->dev);
+
+ if (!pdata) {
+ dev_err(component->dev, "%s: pdata is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (test_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask)) {
+ dev_dbg(component->dev,
+ "%s: vpos already in enabled state\n",
+ __func__);
+ clear_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask);
+ return 0;
+ }
+ ret = msm_cdc_enable_ondemand_supply(rouleur->dev,
+ rouleur->supplies,
+ pdata->regulator,
+ pdata->num_supplies,
+ "cdc-pa-vpos");
+ if (ret == -EINVAL) {
+ dev_err(component->dev, "%s: pa vpos is not enabled\n",
+ __func__);
+ return ret;
+ }
+ clear_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask);
+ /*
+ * 200us sleep is required after LDO15 is enabled as per
+ * HW requirement
+ */
+ usleep_range(200, 250);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ set_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_kcontrol_new rouleur_snd_controls[] = {
+ SOC_SINGLE_EXT("HPHL_COMP Switch", SND_SOC_NOPM, 0, 1, 0,
+ rouleur_get_compander, rouleur_set_compander),
+ SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0,
+ rouleur_get_compander, rouleur_set_compander),
+
+ SOC_SINGLE_TLV("HPHL Volume", ROULEUR_ANA_HPHPA_L_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", ROULEUR_ANA_HPHPA_R_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("ADC1 Volume", ROULEUR_ANA_TX_AMIC1, 0, 8, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", ROULEUR_ANA_TX_AMIC2, 0, 8, 0,
+ analog_gain),
+};
+
+static const struct snd_kcontrol_new adc1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new ear_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new lo_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphl_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphr_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const char * const adc2_mux_text[] = {
+ "INP2", "INP3"
+};
+
+static const struct soc_enum adc2_enum =
+ SOC_ENUM_SINGLE(ROULEUR_ANA_TX_AMIC2, 4,
+ ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+
+static const struct snd_kcontrol_new tx_adc2_mux =
+ SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
+
+static const struct snd_soc_dapm_widget rouleur_dapm_widgets[] = {
+
+ /*input widgets*/
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_INPUT("AMIC3"),
+ SND_SOC_DAPM_INPUT("IN1_HPHL"),
+ SND_SOC_DAPM_INPUT("IN2_HPHR"),
+
+ /*tx widgets*/
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0,
+ rouleur_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
+ &tx_adc2_mux),
+
+ /*tx mixers*/
+ SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0,
+ adc1_switch, ARRAY_SIZE(adc1_switch),
+ rouleur_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 0, 0,
+ adc2_switch, ARRAY_SIZE(adc2_switch),
+ rouleur_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* micbias widgets*/
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY("PA_VPOS", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_pa_vpos,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /*rx widgets*/
+ SND_SOC_DAPM_PGA_E("EAR PGA", ROULEUR_ANA_COMBOPA_CTL, 7, 0, NULL, 0,
+ rouleur_codec_enable_ear_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LO PGA", ROULEUR_ANA_COMBOPA_CTL, 7, 0, NULL, 0,
+ rouleur_codec_enable_lo_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHL PGA", ROULEUR_ANA_HPHPA_CNP_CTL_2, 7, 0, NULL,
+ 0, rouleur_codec_enable_hphl_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHR PGA", ROULEUR_ANA_HPHPA_CNP_CTL_2, 6, 0, NULL,
+ 0, rouleur_codec_enable_hphr_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0,
+ rouleur_codec_hphl_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0,
+ rouleur_codec_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0,
+ rouleur_codec_ear_lo_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rouleur_enable_rx1, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rouleur_enable_rx2, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* rx mixer widgets*/
+
+ SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0,
+ ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)),
+ SND_SOC_DAPM_MIXER("LO_RDAC", SND_SOC_NOPM, 0, 0,
+ lo_rdac_switch, ARRAY_SIZE(lo_rdac_switch)),
+ SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0,
+ hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)),
+ SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0,
+ hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)),
+
+ /*output widgets tx*/
+
+ SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"),
+
+ /*output widgets rx*/
+ SND_SOC_DAPM_OUTPUT("EAR"),
+ SND_SOC_DAPM_OUTPUT("LO"),
+ SND_SOC_DAPM_OUTPUT("HPHL"),
+ SND_SOC_DAPM_OUTPUT("HPHR"),
+
+ /* micbias pull up widgets*/
+ SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS1", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS2", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("VA MIC BIAS3", SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+ rouleur_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0,
+ rouleur_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /*tx mixer widgets*/
+ SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0,
+ 0, dmic1_switch, ARRAY_SIZE(dmic1_switch),
+ rouleur_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 0,
+ 0, dmic2_switch, ARRAY_SIZE(dmic2_switch),
+ rouleur_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /*output widgets*/
+ SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"),
+};
+
+static const struct snd_soc_dapm_route rouleur_audio_map[] = {
+ {"ADC1_OUTPUT", NULL, "ADC1_MIXER"},
+ {"ADC1_MIXER", "Switch", "ADC1"},
+ {"ADC1", NULL, "AMIC1"},
+
+ {"ADC2_OUTPUT", NULL, "ADC2_MIXER"},
+ {"ADC2_MIXER", "Switch", "ADC2"},
+ {"ADC2", NULL, "ADC2 MUX"},
+ {"ADC2 MUX", "INP3", "AMIC3"},
+ {"ADC2 MUX", "INP2", "AMIC2"},
+
+ {"IN1_HPHL", NULL, "PA_VPOS"},
+ {"RX1", NULL, "IN1_HPHL"},
+ {"RDAC1", NULL, "RX1"},
+ {"HPHL_RDAC", "Switch", "RDAC1"},
+ {"HPHL PGA", NULL, "HPHL_RDAC"},
+ {"HPHL", NULL, "HPHL PGA"},
+
+ {"IN2_HPHR", NULL, "PA_VPOS"},
+ {"RX2", NULL, "IN2_HPHR"},
+ {"RDAC2", NULL, "RX2"},
+ {"HPHR_RDAC", "Switch", "RDAC2"},
+ {"HPHR PGA", NULL, "HPHR_RDAC"},
+ {"HPHR", NULL, "HPHR PGA"},
+
+ {"RDAC3", NULL, "RX1"},
+ {"EAR_RDAC", "Switch", "RDAC3"},
+ {"EAR PGA", NULL, "EAR_RDAC"},
+ {"EAR", NULL, "EAR PGA"},
+
+ {"RDAC3", NULL, "RX1"},
+ {"LO_RDAC", "Switch", "RDAC3"},
+ {"LO PGA", NULL, "LO_RDAC"},
+ {"LO", NULL, "LO PGA"},
+
+ {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"},
+ {"DMIC1_MIXER", "Switch", "DMIC1"},
+
+ {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"},
+ {"DMIC2_MIXER", "Switch", "DMIC2"},
+};
+
+static ssize_t rouleur_version_read(struct snd_info_entry *entry,
+ void *file_private_data,
+ struct file *file,
+ char __user *buf, size_t count,
+ loff_t pos)
+{
+ struct rouleur_priv *priv;
+ char buffer[ROULEUR_VERSION_ENTRY_SIZE];
+ int len = 0;
+
+ priv = (struct rouleur_priv *) entry->private_data;
+ if (!priv) {
+ pr_err("%s: rouleur priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (priv->version) {
+ case ROULEUR_VERSION_1_0:
+ len = snprintf(buffer, sizeof(buffer), "rouleur_1_0\n");
+ break;
+ default:
+ len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+ }
+
+ return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops rouleur_info_ops = {
+ .read = rouleur_version_read,
+};
+
+/*
+ * rouleur_info_create_codec_entry - creates rouleur module
+ * @codec_root: The parent directory
+ * @component: component instance
+ *
+ * Creates rouleur module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int rouleur_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_component *component)
+{
+ struct snd_info_entry *version_entry;
+ struct rouleur_priv *priv;
+ struct snd_soc_card *card;
+
+ if (!codec_root || !component)
+ return -EINVAL;
+
+ priv = snd_soc_component_get_drvdata(component);
+ if (priv->entry) {
+ dev_dbg(priv->dev,
+ "%s:rouleur module already created\n", __func__);
+ return 0;
+ }
+ card = component->card;
+ priv->entry = snd_info_create_subdir(codec_root->module,
+ "rouleur", codec_root);
+ if (!priv->entry) {
+ dev_dbg(component->dev, "%s: failed to create rouleur entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+ version_entry = snd_info_create_card_entry(card->snd_card,
+ "version",
+ priv->entry);
+ if (!version_entry) {
+ dev_dbg(component->dev, "%s: failed to create rouleur version entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ version_entry->private_data = priv;
+ version_entry->size = ROULEUR_VERSION_ENTRY_SIZE;
+ version_entry->content = SNDRV_INFO_CONTENT_DATA;
+ version_entry->c.ops = &rouleur_info_ops;
+
+ if (snd_info_register(version_entry) < 0) {
+ snd_info_free_entry(version_entry);
+ return -ENOMEM;
+ }
+ priv->version_entry = version_entry;
+
+ return 0;
+}
+EXPORT_SYMBOL(rouleur_info_create_codec_entry);
+
+static int rouleur_set_micbias_data(struct rouleur_priv *rouleur,
+ struct rouleur_pdata *pdata)
+{
+ int vout_ctl = 0;
+ int rc = 0;
+
+ if (!pdata) {
+ dev_err(rouleur->dev, "%s: NULL pdata\n", __func__);
+ return -ENODEV;
+ }
+
+ /* set micbias voltage */
+ vout_ctl = rouleur_get_micb_vout_ctl_val(pdata->micbias.micb1_mv);
+ if (vout_ctl < 0) {
+ rc = -EINVAL;
+ goto done;
+ }
+ regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MICBIAS_LDO_1_SETTING,
+ 0xF8, vout_ctl);
+done:
+ return rc;
+}
+
+static int rouleur_soc_codec_probe(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ int ret = -EINVAL;
+
+ dev_info(component->dev, "%s()\n", __func__);
+ rouleur = snd_soc_component_get_drvdata(component);
+
+ if (!rouleur)
+ return -EINVAL;
+
+ rouleur->component = component;
+ snd_soc_component_init_regmap(component, rouleur->regmap);
+
+ rouleur->fw_data = devm_kzalloc(component->dev,
+ sizeof(*(rouleur->fw_data)),
+ GFP_KERNEL);
+ if (!rouleur->fw_data) {
+ dev_err(component->dev, "Failed to allocate fw_data\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ set_bit(WCD9XXX_MBHC_CAL, rouleur->fw_data->cal_bit);
+ ret = wcd_cal_create_hwdep(rouleur->fw_data,
+ WCD9XXX_CODEC_HWDEP_NODE, component);
+
+ if (ret < 0) {
+ dev_err(component->dev, "%s hwdep failed %d\n", __func__, ret);
+ goto done;
+ }
+
+ ret = rouleur_mbhc_init(&rouleur->mbhc, component, rouleur->fw_data);
+ if (ret) {
+ pr_err("%s: mbhc initialization failed\n", __func__);
+ goto done;
+ }
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
+ snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
+ snd_soc_dapm_ignore_suspend(dapm, "IN1_HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "IN2_HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "ADC1_OUTPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "ADC2_OUTPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "EAR");
+ snd_soc_dapm_ignore_suspend(dapm, "LO");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHL");
+ snd_soc_dapm_ignore_suspend(dapm, "HPHR");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC1_OUTPUT");
+ snd_soc_dapm_ignore_suspend(dapm, "DMIC2_OUTPUT");
+ snd_soc_dapm_sync(dapm);
+
+ rouleur_init_reg(component);
+
+ rouleur->version = ROULEUR_VERSION_1_0;
+ /* Register event notifier */
+ rouleur->nblock.notifier_call = rouleur_event_notify;
+ if (rouleur->register_notifier) {
+ ret = rouleur->register_notifier(rouleur->handle,
+ &rouleur->nblock,
+ true);
+ if (ret) {
+ dev_err(component->dev,
+ "%s: Failed to register notifier %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+done:
+ return ret;
+}
+
+static void rouleur_soc_codec_remove(struct snd_soc_component *component)
+{
+ struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component);
+
+ if (!rouleur)
+ return;
+
+ if (rouleur->register_notifier)
+ rouleur->register_notifier(rouleur->handle,
+ &rouleur->nblock,
+ false);
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_rouleur = {
+ .name = DRV_NAME,
+ .probe = rouleur_soc_codec_probe,
+ .remove = rouleur_soc_codec_remove,
+ .controls = rouleur_snd_controls,
+ .num_controls = ARRAY_SIZE(rouleur_snd_controls),
+ .dapm_widgets = rouleur_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rouleur_dapm_widgets),
+ .dapm_routes = rouleur_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rouleur_audio_map),
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int rouleur_suspend(struct device *dev)
+{
+ struct rouleur_priv *rouleur = NULL;
+ int ret = 0;
+ struct rouleur_pdata *pdata = NULL;
+
+ if (!dev)
+ return -ENODEV;
+
+ rouleur = dev_get_drvdata(dev);
+ if (!rouleur)
+ return -EINVAL;
+
+ pdata = dev_get_platdata(rouleur->dev);
+
+ if (!pdata) {
+ dev_err(dev, "%s: pdata is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (test_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask)) {
+ ret = msm_cdc_disable_ondemand_supply(rouleur->dev,
+ rouleur->supplies,
+ pdata->regulator,
+ pdata->num_supplies,
+ "cdc-pa-vpos");
+ if (ret == -EINVAL) {
+ dev_err(dev, "%s: pa vpos is not disabled\n",
+ __func__);
+ return 0;
+ }
+ clear_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask);
+ }
+ return 0;
+}
+
+static int rouleur_resume(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+static int rouleur_reset(struct device *dev, int reset_val)
+{
+ struct rouleur_priv *rouleur = NULL;
+
+ if (!dev)
+ return -ENODEV;
+
+ rouleur = dev_get_drvdata(dev);
+ if (!rouleur)
+ return -EINVAL;
+
+ pm2250_spmi_write(rouleur->spmi_dev, rouleur->reset_reg, reset_val);
+
+ return 0;
+}
+
+static int rouleur_read_of_property_u32(struct device *dev, const char *name,
+ u32 *val)
+{
+ int rc = 0;
+
+ rc = of_property_read_u32(dev->of_node, name, val);
+ if (rc)
+ dev_err(dev, "%s: Looking up %s property in node %s failed\n",
+ __func__, name, dev->of_node->full_name);
+
+ return rc;
+}
+
+static void rouleur_dt_parse_micbias_info(struct device *dev,
+ struct rouleur_micbias_setting *mb)
+{
+ u32 prop_val = 0;
+ int rc = 0;
+
+ /* MB1 */
+ if (of_find_property(dev->of_node, "qcom,cdc-micbias1-mv",
+ NULL)) {
+ rc = rouleur_read_of_property_u32(dev,
+ "qcom,cdc-micbias1-mv",
+ &prop_val);
+ if (!rc)
+ mb->micb1_mv = prop_val;
+ } else {
+ dev_info(dev, "%s: Micbias1 DT property not found\n",
+ __func__);
+ }
+
+ /* MB2 */
+ if (of_find_property(dev->of_node, "qcom,cdc-micbias2-mv",
+ NULL)) {
+ rc = rouleur_read_of_property_u32(dev,
+ "qcom,cdc-micbias2-mv",
+ &prop_val);
+ if (!rc)
+ mb->micb2_mv = prop_val;
+ } else {
+ dev_info(dev, "%s: Micbias2 DT property not found\n",
+ __func__);
+ }
+
+ /* MB3 */
+ if (of_find_property(dev->of_node, "qcom,cdc-micbias3-mv",
+ NULL)) {
+ rc = rouleur_read_of_property_u32(dev,
+ "qcom,cdc-micbias3-mv",
+ &prop_val);
+ if (!rc)
+ mb->micb3_mv = prop_val;
+ } else {
+ dev_info(dev, "%s: Micbias3 DT property not found\n",
+ __func__);
+ }
+}
+
+struct rouleur_pdata *rouleur_populate_dt_data(struct device *dev)
+{
+ struct rouleur_pdata *pdata = NULL;
+ u32 reg;
+ int ret = 0;
+
+ pdata = kzalloc(sizeof(struct rouleur_pdata),
+ GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ pdata->spmi_np = of_parse_phandle(dev->of_node,
+ "qcom,pmic-spmi-node", 0);
+ if (!pdata->spmi_np) {
+ dev_err(dev, "%s: Looking up %s property in node %s failed\n",
+ __func__, "qcom,pmic-spmi-node",
+ dev->of_node->full_name);
+ kfree(pdata);
+ return NULL;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "qcom,wcd-reset-reg", &reg);
+ if (ret) {
+ dev_err(dev, "%s: Failed to obtain reset reg value %d\n",
+ __func__, ret);
+ kfree(pdata);
+ return NULL;
+ }
+ pdata->reset_reg = reg;
+
+ /* Parse power supplies */
+ msm_cdc_get_power_supplies(dev, &pdata->regulator,
+ &pdata->num_supplies);
+ if (!pdata->regulator || (pdata->num_supplies <= 0)) {
+ dev_err(dev, "%s: no power supplies defined for codec\n",
+ __func__);
+ kfree(pdata);
+ return NULL;
+ }
+
+ pdata->rx_slave = of_parse_phandle(dev->of_node, "qcom,rx-slave", 0);
+ pdata->tx_slave = of_parse_phandle(dev->of_node, "qcom,tx-slave", 0);
+ rouleur_dt_parse_micbias_info(dev, &pdata->micbias);
+
+ return pdata;
+}
+
+static int rouleur_wakeup(void *handle, bool enable)
+{
+ struct rouleur_priv *priv;
+
+ if (!handle) {
+ pr_err("%s: NULL handle\n", __func__);
+ return -EINVAL;
+ }
+ priv = (struct rouleur_priv *)handle;
+ if (!priv->tx_swr_dev) {
+ pr_err("%s: tx swr dev is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (enable)
+ return swr_device_wakeup_vote(priv->tx_swr_dev);
+ else
+ return swr_device_wakeup_unvote(priv->tx_swr_dev);
+}
+
+static irqreturn_t rouleur_wd_handle_irq(int irq, void *data)
+{
+ pr_err_ratelimited("%s: Watchdog interrupt for irq =%d triggered\n",
+ __func__, irq);
+ return IRQ_HANDLED;
+}
+
+static int rouleur_bind(struct device *dev)
+{
+ int ret = 0, i = 0;
+ struct rouleur_priv *rouleur = NULL;
+ struct rouleur_pdata *pdata = NULL;
+ struct wcd_ctrl_platform_data *plat_data = NULL;
+ struct platform_device *pdev = NULL;
+
+ rouleur = kzalloc(sizeof(struct rouleur_priv), GFP_KERNEL);
+ if (!rouleur)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rouleur);
+
+ pdata = rouleur_populate_dt_data(dev);
+ if (!pdata) {
+ dev_err(dev, "%s: Fail to obtain platform data\n", __func__);
+ kfree(rouleur);
+ return -EINVAL;
+ }
+ rouleur->dev = dev;
+ rouleur->dev->platform_data = pdata;
+ pdev = of_find_device_by_node(pdata->spmi_np);
+ if (!pdev) {
+ dev_err(dev, "%s: platform device from SPMI node is NULL\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_bind_all;
+ }
+
+ rouleur->spmi_dev = &pdev->dev;
+ rouleur->reset_reg = pdata->reset_reg;
+ ret = msm_cdc_init_supplies(dev, &rouleur->supplies,
+ pdata->regulator, pdata->num_supplies);
+ if (!rouleur->supplies) {
+ dev_err(dev, "%s: Cannot init wcd supplies\n",
+ __func__);
+ goto err_bind_all;
+ }
+
+ plat_data = dev_get_platdata(dev->parent);
+ if (!plat_data) {
+ dev_err(dev, "%s: platform data from parent is NULL\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_bind_all;
+ }
+ rouleur->handle = (void *)plat_data->handle;
+ if (!rouleur->handle) {
+ dev_err(dev, "%s: handle is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err_bind_all;
+ }
+ rouleur->update_wcd_event = plat_data->update_wcd_event;
+ if (!rouleur->update_wcd_event) {
+ dev_err(dev, "%s: update_wcd_event api is null!\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_bind_all;
+ }
+ rouleur->register_notifier = plat_data->register_notifier;
+ if (!rouleur->register_notifier) {
+ dev_err(dev, "%s: register_notifier api is null!\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_bind_all;
+ }
+
+ ret = msm_cdc_enable_static_supplies(dev, rouleur->supplies,
+ pdata->regulator,
+ pdata->num_supplies);
+ if (ret) {
+ dev_err(dev, "%s: wcd static supply enable failed!\n",
+ __func__);
+ goto err_bind_all;
+ }
+
+ rouleur_reset(dev, 0x01);
+ usleep_range(20, 30);
+ rouleur_reset(dev, 0x00);
+ /*
+ * Add 5msec delay to provide sufficient time for
+ * soundwire auto enumeration of slave devices as
+ * as per HW requirement.
+ */
+ usleep_range(5000, 5010);
+ rouleur->wakeup = rouleur_wakeup;
+
+ ret = component_bind_all(dev, rouleur);
+ if (ret) {
+ dev_err(dev, "%s: Slave bind failed, ret = %d\n",
+ __func__, ret);
+ goto err_bind_all;
+ }
+
+ ret = rouleur_parse_port_mapping(dev, "qcom,rx_swr_ch_map", CODEC_RX);
+ ret |= rouleur_parse_port_mapping(dev, "qcom,tx_swr_ch_map", CODEC_TX);
+
+ if (ret) {
+ dev_err(dev, "Failed to read port mapping\n");
+ goto err;
+ }
+
+ rouleur->rx_swr_dev = get_matching_swr_slave_device(pdata->rx_slave);
+ if (!rouleur->rx_swr_dev) {
+ dev_err(dev, "%s: Could not find RX swr slave device\n",
+ __func__);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ rouleur->tx_swr_dev = get_matching_swr_slave_device(pdata->tx_slave);
+ if (!rouleur->tx_swr_dev) {
+ dev_err(dev, "%s: Could not find TX swr slave device\n",
+ __func__);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ rouleur->regmap = devm_regmap_init_swr(rouleur->tx_swr_dev,
+ &rouleur_regmap_config);
+ if (!rouleur->regmap) {
+ dev_err(dev, "%s: Regmap init failed\n",
+ __func__);
+ goto err;
+ }
+
+ /* Set all interupts as edge triggered */
+ for (i = 0; i < rouleur_regmap_irq_chip.num_regs; i++)
+ regmap_write(rouleur->regmap,
+ (ROULEUR_DIG_SWR_INTR_LEVEL_0 + i), 0);
+
+ rouleur_regmap_irq_chip.irq_drv_data = rouleur;
+ rouleur->irq_info.wcd_regmap_irq_chip = &rouleur_regmap_irq_chip;
+ rouleur->irq_info.codec_name = "rouleur";
+ rouleur->irq_info.regmap = rouleur->regmap;
+ rouleur->irq_info.dev = dev;
+ ret = wcd_irq_init(&rouleur->irq_info, &rouleur->virq);
+
+ if (ret) {
+ dev_err(dev, "%s: IRQ init failed: %d\n",
+ __func__, ret);
+ goto err;
+ }
+ rouleur->tx_swr_dev->slave_irq = rouleur->virq;
+
+ mutex_init(&rouleur->micb_lock);
+ mutex_init(&rouleur->main_bias_lock);
+ mutex_init(&rouleur->rx_clk_lock);
+
+ ret = rouleur_set_micbias_data(rouleur, pdata);
+ if (ret < 0) {
+ dev_err(dev, "%s: bad micbias pdata\n", __func__);
+ goto err_irq;
+ }
+
+ /* Request for watchdog interrupt */
+ wcd_request_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHR_PDM_WD_INT,
+ "HPHR PDM WD INT", rouleur_wd_handle_irq, NULL);
+ wcd_request_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHL_PDM_WD_INT,
+ "HPHL PDM WD INT", rouleur_wd_handle_irq, NULL);
+ /* Disable watchdog interrupt for HPH */
+ wcd_disable_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHR_PDM_WD_INT);
+ wcd_disable_irq(&rouleur->irq_info, ROULEUR_IRQ_HPHL_PDM_WD_INT);
+
+ ret = snd_soc_register_component(dev, &soc_codec_dev_rouleur,
+ NULL, 0);
+ if (ret) {
+ dev_err(dev, "%s: Codec registration failed\n",
+ __func__);
+ goto err_irq;
+ }
+
+ return ret;
+err_irq:
+ wcd_irq_exit(&rouleur->irq_info, rouleur->virq);
+ mutex_destroy(&rouleur->micb_lock);
+ mutex_destroy(&rouleur->main_bias_lock);
+ mutex_destroy(&rouleur->rx_clk_lock);
+err:
+ component_unbind_all(dev, rouleur);
+err_bind_all:
+ dev_set_drvdata(dev, NULL);
+ kfree(pdata);
+ kfree(rouleur);
+ return ret;
+}
+
+static void rouleur_unbind(struct device *dev)
+{
+ struct rouleur_priv *rouleur = dev_get_drvdata(dev);
+ struct rouleur_pdata *pdata = dev_get_platdata(rouleur->dev);
+
+ wcd_irq_exit(&rouleur->irq_info, rouleur->virq);
+ snd_soc_unregister_component(dev);
+ component_unbind_all(dev, rouleur);
+ mutex_destroy(&rouleur->micb_lock);
+ mutex_destroy(&rouleur->main_bias_lock);
+ mutex_destroy(&rouleur->rx_clk_lock);
+ dev_set_drvdata(dev, NULL);
+ kfree(pdata);
+ kfree(rouleur);
+}
+
+static const struct of_device_id rouleur_dt_match[] = {
+ { .compatible = "qcom,rouleur-codec" },
+ {}
+};
+
+static const struct component_master_ops rouleur_comp_ops = {
+ .bind = rouleur_bind,
+ .unbind = rouleur_unbind,
+};
+
+static int rouleur_compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static void rouleur_release_of(struct device *dev, void *data)
+{
+ of_node_put(data);
+}
+
+static int rouleur_add_slave_components(struct device *dev,
+ struct component_match **matchptr)
+{
+ struct device_node *np, *rx_node, *tx_node;
+
+ np = dev->of_node;
+
+ rx_node = of_parse_phandle(np, "qcom,rx-slave", 0);
+ if (!rx_node) {
+ dev_err(dev, "%s: Rx-slave node not defined\n", __func__);
+ return -ENODEV;
+ }
+ of_node_get(rx_node);
+ component_match_add_release(dev, matchptr,
+ rouleur_release_of,
+ rouleur_compare_of,
+ rx_node);
+
+ tx_node = of_parse_phandle(np, "qcom,tx-slave", 0);
+ if (!tx_node) {
+ dev_err(dev, "%s: Tx-slave node not defined\n", __func__);
+ return -ENODEV;
+ }
+ of_node_get(tx_node);
+ component_match_add_release(dev, matchptr,
+ rouleur_release_of,
+ rouleur_compare_of,
+ tx_node);
+ return 0;
+}
+
+static int rouleur_probe(struct platform_device *pdev)
+{
+ struct component_match *match = NULL;
+ int ret;
+
+ ret = rouleur_add_slave_components(&pdev->dev, &match);
+ if (ret)
+ return ret;
+
+ return component_master_add_with_match(&pdev->dev,
+ &rouleur_comp_ops, match);
+}
+
+static int rouleur_remove(struct platform_device *pdev)
+{
+ component_master_del(&pdev->dev, &rouleur_comp_ops);
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static const struct dev_pm_ops rouleur_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(
+ rouleur_suspend,
+ rouleur_resume
+ )
+};
+#endif
+
+static struct platform_driver rouleur_codec_driver = {
+ .probe = rouleur_probe,
+ .remove = rouleur_remove,
+ .driver = {
+ .name = "rouleur_codec",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rouleur_dt_match),
+#ifdef CONFIG_PM_SLEEP
+ .pm = &rouleur_dev_pm_ops,
+#endif
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(rouleur_codec_driver);
+MODULE_DESCRIPTION("Rouleur Codec driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/asoc/codecs/rouleur/rouleur.h b/asoc/codecs/rouleur/rouleur.h
new file mode 100644
index 00000000..51abff3a
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _ROULEUR_H
+#define _ROULEUR_H
+
+#ifdef CONFIG_SND_SOC_ROULEUR
+extern int rouleur_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_component *component);
+#else
+extern int rouleur_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_component *component)
+{
+ return 0;
+}
+#endif /* CONFIG_SND_SOC_ROULEUR */
+
+#endif
diff --git a/asoc/codecs/rouleur/rouleur_slave.c b/asoc/codecs/rouleur/rouleur_slave.c
new file mode 100644
index 00000000..8fac8a6f
--- /dev/null
+++ b/asoc/codecs/rouleur/rouleur_slave.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/component.h>
+#include <soc/soundwire.h>
+
+struct rouleur_slave_priv {
+ struct swr_device *swr_slave;
+};
+
+static int rouleur_slave_bind(struct device *dev,
+ struct device *master, void *data)
+{
+ int ret = 0;
+ struct rouleur_slave_priv *rouleur_slave = NULL;
+ uint8_t devnum = 0;
+ struct swr_device *pdev = to_swr_device(dev);
+
+ if (pdev == NULL) {
+ dev_err(dev, "%s: pdev is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ rouleur_slave = devm_kzalloc(&pdev->dev,
+ sizeof(struct rouleur_slave_priv), GFP_KERNEL);
+ if (!rouleur_slave)
+ return -ENOMEM;
+
+ swr_set_dev_data(pdev, rouleur_slave);
+
+ rouleur_slave->swr_slave = pdev;
+
+ ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
+ if (ret) {
+ dev_dbg(&pdev->dev,
+ "%s get devnum %d for dev addr %lx failed\n",
+ __func__, devnum, pdev->addr);
+ swr_remove_device(pdev);
+ return ret;
+ }
+ pdev->dev_num = devnum;
+
+ return ret;
+}
+
+static void rouleur_slave_unbind(struct device *dev,
+ struct device *master, void *data)
+{
+ struct rouleur_slave_priv *rouleur_slave = NULL;
+ struct swr_device *pdev = to_swr_device(dev);
+
+ if (pdev == NULL) {
+ dev_err(dev, "%s: pdev is NULL\n", __func__);
+ return;
+ }
+
+ rouleur_slave = swr_get_dev_data(pdev);
+ if (!rouleur_slave) {
+ dev_err(&pdev->dev, "%s: rouleur_slave is NULL\n", __func__);
+ return;
+ }
+
+ swr_set_dev_data(pdev, NULL);
+}
+
+static const struct swr_device_id rouleur_swr_id[] = {
+ {"rouleur-slave", 0},
+ {}
+};
+
+static const struct of_device_id rouleur_swr_dt_match[] = {
+ {
+ .compatible = "qcom,rouleur-slave",
+ },
+ {}
+};
+
+static const struct component_ops rouleur_slave_comp_ops = {
+ .bind = rouleur_slave_bind,
+ .unbind = rouleur_slave_unbind,
+};
+
+static int rouleur_swr_up(struct swr_device *pdev)
+{
+ return 0;
+}
+
+static int rouleur_swr_down(struct swr_device *pdev)
+{
+ return 0;
+}
+
+static int rouleur_swr_reset(struct swr_device *pdev)
+{
+ return 0;
+}
+
+static int rouleur_swr_probe(struct swr_device *pdev)
+{
+ return component_add(&pdev->dev, &rouleur_slave_comp_ops);
+}
+
+static int rouleur_swr_remove(struct swr_device *pdev)
+{
+ component_del(&pdev->dev, &rouleur_slave_comp_ops);
+ return 0;
+}
+
+static struct swr_driver rouleur_slave_driver = {
+ .driver = {
+ .name = "rouleur-slave",
+ .owner = THIS_MODULE,
+ .of_match_table = rouleur_swr_dt_match,
+ },
+ .probe = rouleur_swr_probe,
+ .remove = rouleur_swr_remove,
+ .id_table = rouleur_swr_id,
+ .device_up = rouleur_swr_up,
+ .device_down = rouleur_swr_down,
+ .reset_device = rouleur_swr_reset,
+};
+
+static int __init rouleur_slave_init(void)
+{
+ return swr_driver_register(&rouleur_slave_driver);
+}
+
+static void __exit rouleur_slave_exit(void)
+{
+ swr_driver_unregister(&rouleur_slave_driver);
+}
+
+module_init(rouleur_slave_init);
+module_exit(rouleur_slave_exit);
+
+MODULE_DESCRIPTION("WCD937X Swr Slave driver");
+MODULE_LICENSE("GPL v2");
diff --git a/asoc/codecs/wcd-mbhc-v2.c b/asoc/codecs/wcd-mbhc-v2.c
index 46a3850a..f3e71af1 100644
--- a/asoc/codecs/wcd-mbhc-v2.c
+++ b/asoc/codecs/wcd-mbhc-v2.c
@@ -415,7 +415,6 @@ static void wcd_mbhc_clr_and_turnon_hph_padac(struct wcd_mbhc *mbhc)
&mbhc->hph_pa_dac_state)) {
pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_PA_EN, 1);
- WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_OCP_DET_EN, 1);
pa_turned_on = true;
}
mutex_unlock(&mbhc->hphr_pa_lock);
@@ -424,7 +423,6 @@ static void wcd_mbhc_clr_and_turnon_hph_padac(struct wcd_mbhc *mbhc)
&mbhc->hph_pa_dac_state)) {
pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PA_EN, 1);
- WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_OCP_DET_EN, 1);
pa_turned_on = true;
}
mutex_unlock(&mbhc->hphl_pa_lock);
diff --git a/asoc/codecs/wcd937x/Android.mk b/asoc/codecs/wcd937x/Android.mk
index 4168dd1b..643339a1 100644
--- a/asoc/codecs/wcd937x/Android.mk
+++ b/asoc/codecs/wcd937x/Android.mk
@@ -13,7 +13,7 @@ endif
AUDIO_CHIPSET := audio
# Build/Package only in case of supported target
-ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) bengal),true)
+ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) bengal lito),true)
LOCAL_PATH := $(call my-dir)
diff --git a/asoc/codecs/wcd937x/Kbuild b/asoc/codecs/wcd937x/Kbuild
index e353e8a3..5bbbad7c 100644
--- a/asoc/codecs/wcd937x/Kbuild
+++ b/asoc/codecs/wcd937x/Kbuild
@@ -31,6 +31,11 @@ ifeq ($(KERNEL_BUILD), 0)
export
INCS += -include $(AUDIO_ROOT)/config/bengalautoconf.h
endif
+ ifeq ($(CONFIG_ARCH_LITO), y)
+ include $(AUDIO_ROOT)/config/litoauto.conf
+ export
+ INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h
+ endif
endif
# As per target team, build is done as follows:
diff --git a/asoc/msm-dai-fe.c b/asoc/msm-dai-fe.c
index 2025be91..29e15dda 100644
--- a/asoc/msm-dai-fe.c
+++ b/asoc/msm-dai-fe.c
@@ -2759,6 +2759,72 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
},
{
.playback = {
+ .stream_name = "MultiMedia24 Playback",
+ .aif_name = "MM_DL24",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "MultiMedia24 Capture",
+ .aif_name = "MM_UL24",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia24",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia25 Playback",
+ .aif_name = "MM_DL25",
+ .rates = (SNDRV_PCM_RATE_8000_384000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ },
+ .capture = {
+ .stream_name = "MultiMedia25 Capture",
+ .aif_name = "MM_UL25",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia25",
+ .probe = fe_dai_probe,
+ },
+ {
+ .playback = {
.stream_name = "MultiMedia26 Playback",
.aif_name = "MM_DL26",
.rates = (SNDRV_PCM_RATE_8000_384000|
diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c
index 24f39a60..e4e6e6f1 100644
--- a/asoc/msm-pcm-routing-v2.c
+++ b/asoc/msm-pcm-routing-v2.c
@@ -775,6 +775,12 @@ static struct msm_pcm_routing_fdai_data
/* MULTIMEDIA23 */
{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM},
{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM} },
+ /* MULTIMEDIA24 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM},
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM} },
+ /* MULTIMEDIA25 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM},
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM} },
/* MULTIMEDIA26 */
{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM},
{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL}, LEGACY_PCM} },
@@ -9655,6 +9661,14 @@ static const struct snd_kcontrol_new pri_tdm_rx_0_mixer_controls[] = {
MSM_BACKEND_DAI_PRI_TDM_RX_0,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = {
@@ -9734,6 +9748,14 @@ static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = {
MSM_BACKEND_DAI_PRI_TDM_RX_1,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_tdm_rx_2_mixer_controls[] = {
@@ -9813,6 +9835,14 @@ static const struct snd_kcontrol_new pri_tdm_rx_2_mixer_controls[] = {
MSM_BACKEND_DAI_PRI_TDM_RX_2,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_tdm_rx_3_mixer_controls[] = {
@@ -9892,6 +9922,14 @@ static const struct snd_kcontrol_new pri_tdm_rx_3_mixer_controls[] = {
MSM_BACKEND_DAI_PRI_TDM_RX_3,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_tdm_tx_0_mixer_controls[] = {
@@ -9963,6 +10001,14 @@ static const struct snd_kcontrol_new pri_tdm_tx_0_mixer_controls[] = {
MSM_BACKEND_DAI_PRI_TDM_TX_0,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_tdm_rx_0_mixer_controls[] = {
@@ -10042,6 +10088,14 @@ static const struct snd_kcontrol_new sec_tdm_rx_0_mixer_controls[] = {
MSM_BACKEND_DAI_SEC_TDM_RX_0,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = {
@@ -10121,6 +10175,14 @@ static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = {
MSM_BACKEND_DAI_SEC_TDM_RX_1,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_tdm_rx_2_mixer_controls[] = {
@@ -10200,6 +10262,14 @@ static const struct snd_kcontrol_new sec_tdm_rx_2_mixer_controls[] = {
MSM_BACKEND_DAI_SEC_TDM_RX_2,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_tdm_rx_3_mixer_controls[] = {
@@ -10279,6 +10349,14 @@ static const struct snd_kcontrol_new sec_tdm_rx_3_mixer_controls[] = {
MSM_BACKEND_DAI_SEC_TDM_RX_3,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_tdm_tx_0_mixer_controls[] = {
@@ -10350,6 +10428,14 @@ static const struct snd_kcontrol_new sec_tdm_tx_0_mixer_controls[] = {
MSM_BACKEND_DAI_SEC_TDM_TX_0,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_tdm_rx_0_mixer_controls[] = {
@@ -10429,6 +10515,14 @@ static const struct snd_kcontrol_new tert_tdm_rx_0_mixer_controls[] = {
MSM_BACKEND_DAI_TERT_TDM_RX_0,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_tdm_tx_0_mixer_controls[] = {
@@ -10500,6 +10594,14 @@ static const struct snd_kcontrol_new tert_tdm_tx_0_mixer_controls[] = {
MSM_BACKEND_DAI_TERT_TDM_TX_0,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_tdm_rx_1_mixer_controls[] = {
@@ -10579,6 +10681,14 @@ static const struct snd_kcontrol_new tert_tdm_rx_1_mixer_controls[] = {
MSM_BACKEND_DAI_TERT_TDM_RX_1,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_tdm_rx_2_mixer_controls[] = {
@@ -10658,6 +10768,14 @@ static const struct snd_kcontrol_new tert_tdm_rx_2_mixer_controls[] = {
MSM_BACKEND_DAI_TERT_TDM_RX_2,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = {
@@ -10737,6 +10855,14 @@ static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = {
MSM_BACKEND_DAI_TERT_TDM_RX_3,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = {
@@ -10816,6 +10942,14 @@ static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = {
MSM_BACKEND_DAI_TERT_TDM_RX_4,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = {
@@ -10899,6 +11033,14 @@ static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = {
MSM_BACKEND_DAI_QUAT_TDM_RX_0,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quat_tdm_tx_0_mixer_controls[] = {
@@ -10970,6 +11112,14 @@ static const struct snd_kcontrol_new quat_tdm_tx_0_mixer_controls[] = {
MSM_BACKEND_DAI_QUAT_TDM_TX_0,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quat_tdm_rx_1_mixer_controls[] = {
@@ -11053,6 +11203,14 @@ static const struct snd_kcontrol_new quat_tdm_rx_1_mixer_controls[] = {
MSM_BACKEND_DAI_QUAT_TDM_RX_1,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = {
@@ -11136,6 +11294,14 @@ static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = {
MSM_BACKEND_DAI_QUAT_TDM_RX_2,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = {
@@ -11219,6 +11385,14 @@ static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = {
MSM_BACKEND_DAI_QUAT_TDM_RX_3,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quin_tdm_rx_0_mixer_controls[] = {
@@ -11302,6 +11476,14 @@ static const struct snd_kcontrol_new quin_tdm_rx_0_mixer_controls[] = {
MSM_BACKEND_DAI_QUIN_TDM_RX_0,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quin_tdm_tx_0_mixer_controls[] = {
@@ -11373,6 +11555,14 @@ static const struct snd_kcontrol_new quin_tdm_tx_0_mixer_controls[] = {
MSM_BACKEND_DAI_QUIN_TDM_TX_0,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quin_tdm_tx_1_mixer_controls[] = {
@@ -11590,6 +11780,14 @@ static const struct snd_kcontrol_new quin_tdm_tx_2_mixer_controls[] = {
MSM_BACKEND_DAI_QUIN_TDM_RX_1,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quin_tdm_rx_2_mixer_controls[] = {
@@ -11673,6 +11871,14 @@ static const struct snd_kcontrol_new quin_tdm_rx_2_mixer_controls[] = {
MSM_BACKEND_DAI_QUIN_TDM_RX_2,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quin_tdm_tx_3_mixer_controls[] = {
@@ -11823,6 +12029,14 @@ static const struct snd_kcontrol_new quin_tdm_rx_3_mixer_controls[] = {
MSM_BACKEND_DAI_QUIN_TDM_RX_3,
MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_RX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sen_tdm_rx_0_mixer_controls[] = {
@@ -15268,6 +15482,172 @@ static const struct snd_kcontrol_new mmul23_mixer_controls[] = {
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul24_mixer_controls[] = {
+ SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul25_mixer_controls[] = {
+ SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_PRI_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_SEC_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_TERT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_0", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_0,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_1", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_1,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_2", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_2,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_DOUBLE_EXT("QUIN_TDM_TX_3", SND_SOC_NOPM,
+ MSM_BACKEND_DAI_QUIN_TDM_TX_3,
+ MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new mmul27_mixer_controls[] = {
SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM,
MSM_BACKEND_DAI_SLIMBUS_0_TX,
@@ -22272,6 +22652,7 @@ static int msm_routing_get_lsm_app_type_cfg_control(
kcontrol->private_value)->shift;
int i = 0, j = 0;
+ mutex_lock(&routing_lock);
ucontrol->value.integer.value[i] = num_app_cfg_types;
for (j = 0; j < num_app_cfg_types; ++j) {
@@ -22285,6 +22666,7 @@ static int msm_routing_get_lsm_app_type_cfg_control(
ucontrol->value.integer.value[++i] =
lsm_app_type_cfg[j].num_out_channels;
}
+ mutex_unlock(&routing_lock);
return 0;
}
@@ -22296,9 +22678,11 @@ static int msm_routing_put_lsm_app_type_cfg_control(
kcontrol->private_value)->shift;
int i = 0, j;
+ mutex_lock(&routing_lock);
if (ucontrol->value.integer.value[0] > MAX_APP_TYPES) {
pr_err("%s: number of app types exceed the max supported\n",
__func__);
+ mutex_unlock(&routing_lock);
return -EINVAL;
}
@@ -22318,7 +22702,7 @@ static int msm_routing_put_lsm_app_type_cfg_control(
lsm_app_type_cfg[j].num_out_channels =
ucontrol->value.integer.value[i++];
}
-
+ mutex_unlock(&routing_lock);
return 0;
}
@@ -23292,6 +23676,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_AIF_IN("MM_DL21", "MultiMedia21 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL22", "MultiMedia22 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL23", "MultiMedia23 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL24", "MultiMedia24 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL25", "MultiMedia25 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL26", "MultiMedia26 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
@@ -23311,6 +23697,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_AIF_OUT("MM_UL21", "MultiMedia21 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL22", "MultiMedia22 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL23", "MultiMedia23 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL24", "MultiMedia24 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL25", "MultiMedia25 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL27", "MultiMedia27 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL28", "MultiMedia28 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL29", "MultiMedia29 Capture", 0, 0, 0, 0),
@@ -24418,6 +24806,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
mmul22_mixer_controls, ARRAY_SIZE(mmul22_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia23 Mixer", SND_SOC_NOPM, 0, 0,
mmul23_mixer_controls, ARRAY_SIZE(mmul23_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia24 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul24_mixer_controls, ARRAY_SIZE(mmul24_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia25 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul25_mixer_controls, ARRAY_SIZE(mmul25_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia27 Mixer", SND_SOC_NOPM, 0, 0,
mmul27_mixer_controls, ARRAY_SIZE(mmul27_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia28 Mixer", SND_SOC_NOPM, 0, 0,
@@ -25658,6 +26050,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"},
{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25679,6 +26073,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"PRI_TDM_RX_1 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"PRI_TDM_RX_1 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"PRI_TDM_RX_1", NULL, "PRI_TDM_RX_1 Audio Mixer"},
{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25700,6 +26096,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"PRI_TDM_RX_2 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"PRI_TDM_RX_2 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"PRI_TDM_RX_2", NULL, "PRI_TDM_RX_2 Audio Mixer"},
{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25721,6 +26119,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"PRI_TDM_RX_3 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"PRI_TDM_RX_3 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"PRI_TDM_RX_3", NULL, "PRI_TDM_RX_3 Audio Mixer"},
{"PRI_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25740,6 +26140,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"PRI_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
{"PRI_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"PRI_TDM_TX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"PRI_TDM_TX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"PRI_TDM_TX_0", NULL, "PRI_TDM_TX_0 Audio Mixer"},
{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25761,6 +26163,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"SEC_TDM_RX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"},
{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25782,6 +26186,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"SEC_TDM_RX_1 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"SEC_TDM_RX_1 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"SEC_TDM_RX_1", NULL, "SEC_TDM_RX_1 Audio Mixer"},
{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25803,6 +26209,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"SEC_TDM_RX_2 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"SEC_TDM_RX_2 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"SEC_TDM_RX_2", NULL, "SEC_TDM_RX_2 Audio Mixer"},
{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25824,6 +26232,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"SEC_TDM_RX_3 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"SEC_TDM_RX_3 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"SEC_TDM_RX_3", NULL, "SEC_TDM_RX_3 Audio Mixer"},
{"SEC_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25843,6 +26253,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"SEC_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
{"SEC_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"SEC_TDM_TX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"SEC_TDM_TX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"SEC_TDM_TX_0", NULL, "SEC_TDM_TX_0 Audio Mixer"},
{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25864,6 +26276,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"TERT_TDM_RX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"TERT_TDM_RX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"TERT_TDM_RX_0", NULL, "TERT_TDM_RX_0 Audio Mixer"},
{"TERT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25883,6 +26297,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"TERT_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
{"TERT_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"TERT_TDM_TX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"TERT_TDM_TX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"TERT_TDM_TX_0", NULL, "TERT_TDM_TX_0 Audio Mixer"},
{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25904,6 +26320,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"TERT_TDM_RX_1 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"TERT_TDM_RX_1 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"TERT_TDM_RX_1", NULL, "TERT_TDM_RX_1 Audio Mixer"},
{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25925,6 +26343,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"TERT_TDM_RX_2 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"TERT_TDM_RX_2 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"TERT_TDM_RX_2", NULL, "TERT_TDM_RX_2 Audio Mixer"},
{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25946,6 +26366,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"TERT_TDM_RX_3 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_3 Audio Mixer"},
{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25967,6 +26389,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"TERT_TDM_RX_4", NULL, "TERT_TDM_RX_4 Audio Mixer"},
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -25989,6 +26413,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0 Audio Mixer"},
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -26008,6 +26434,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUAT_TDM_TX_0", NULL, "QUAT_TDM_TX_0 Audio Mixer"},
{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -26030,6 +26458,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUAT_TDM_RX_1", NULL, "QUAT_TDM_RX_1 Audio Mixer"},
{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -26052,6 +26482,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2 Audio Mixer"},
{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -26074,6 +26506,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3 Audio Mixer"},
{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -26096,6 +26530,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUIN_TDM_RX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUIN_TDM_RX_0", NULL, "QUIN_TDM_RX_0 Audio Mixer"},
{"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -26115,6 +26551,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
{"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUIN_TDM_TX_0 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUIN_TDM_TX_0", NULL, "QUIN_TDM_TX_0 Audio Mixer"},
{"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -26137,6 +26575,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUIN_TDM_RX_1 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUIN_TDM_RX_1", NULL, "QUIN_TDM_RX_1 Audio Mixer"},
{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -26159,6 +26599,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUIN_TDM_RX_2 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUIN_TDM_RX_2", NULL, "QUIN_TDM_RX_2 Audio Mixer"},
{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -26181,6 +26623,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia21", "MM_DL21"},
{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia22", "MM_DL22"},
{"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia23", "MM_DL23"},
+ {"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia24", "MM_DL24"},
+ {"QUIN_TDM_RX_3 Audio Mixer", "MultiMedia25", "MM_DL25"},
{"QUIN_TDM_RX_3", NULL, "QUIN_TDM_RX_3 Audio Mixer"},
{"SEN_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -26827,6 +27271,48 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia23 Mixer", "QUIN_TDM_TX_2", "QUIN_TDM_TX_2"},
{"MultiMedia23 Mixer", "QUIN_TDM_TX_3", "QUIN_TDM_TX_3"},
+ {"MultiMedia24 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia24 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia24 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia24 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia24 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia24 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia24 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia24 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+ {"MultiMedia24 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia24 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia24 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia24 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia24 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia24 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia24 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia24 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia24 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"MultiMedia24 Mixer", "QUIN_TDM_TX_1", "QUIN_TDM_TX_1"},
+ {"MultiMedia24 Mixer", "QUIN_TDM_TX_2", "QUIN_TDM_TX_2"},
+ {"MultiMedia24 Mixer", "QUIN_TDM_TX_3", "QUIN_TDM_TX_3"},
+
+ {"MultiMedia25 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+ {"MultiMedia25 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+ {"MultiMedia25 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+ {"MultiMedia25 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+ {"MultiMedia25 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+ {"MultiMedia25 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+ {"MultiMedia25 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+ {"MultiMedia25 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+ {"MultiMedia25 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+ {"MultiMedia25 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+ {"MultiMedia25 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+ {"MultiMedia25 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+ {"MultiMedia25 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+ {"MultiMedia25 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+ {"MultiMedia25 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+ {"MultiMedia25 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+ {"MultiMedia25 Mixer", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"},
+ {"MultiMedia25 Mixer", "QUIN_TDM_TX_1", "QUIN_TDM_TX_1"},
+ {"MultiMedia25 Mixer", "QUIN_TDM_TX_2", "QUIN_TDM_TX_2"},
+ {"MultiMedia25 Mixer", "QUIN_TDM_TX_3", "QUIN_TDM_TX_3"},
+
{"MultiMedia27 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia27 Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"MultiMedia27 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"},
@@ -27072,6 +27558,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MM_UL21", NULL, "MultiMedia21 Mixer"},
{"MM_UL22", NULL, "MultiMedia22 Mixer"},
{"MM_UL23", NULL, "MultiMedia23 Mixer"},
+ {"MM_UL24", NULL, "MultiMedia24 Mixer"},
+ {"MM_UL25", NULL, "MultiMedia25 Mixer"},
{"MM_UL27", NULL, "MultiMedia27 Mixer"},
{"MM_UL28", NULL, "MultiMedia28 Mixer"},
{"MM_UL29", NULL, "MultiMedia29 Mixer"},
diff --git a/asoc/msm-pcm-routing-v2.h b/asoc/msm-pcm-routing-v2.h
index ee9c63ad..6b96bdeb 100644
--- a/asoc/msm-pcm-routing-v2.h
+++ b/asoc/msm-pcm-routing-v2.h
@@ -263,6 +263,8 @@ enum {
MSM_FRONTEND_DAI_MULTIMEDIA21,
MSM_FRONTEND_DAI_MULTIMEDIA22,
MSM_FRONTEND_DAI_MULTIMEDIA23,
+ MSM_FRONTEND_DAI_MULTIMEDIA24,
+ MSM_FRONTEND_DAI_MULTIMEDIA25,
MSM_FRONTEND_DAI_MULTIMEDIA26,
MSM_FRONTEND_DAI_MULTIMEDIA27,
MSM_FRONTEND_DAI_MULTIMEDIA28,
diff --git a/asoc/sa8155.c b/asoc/sa8155.c
index 2e544470..47300605 100644
--- a/asoc/sa8155.c
+++ b/asoc/sa8155.c
@@ -174,14 +174,14 @@ struct tdm_conf {
/* TDM default config */
static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
{ /* PRI TDM */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_0 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_1 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_2 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_3 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_2 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_3 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */
},
{ /* SEC TDM */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* RX_0 */
@@ -228,14 +228,14 @@ static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
/* TDM default config */
static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
{ /* PRI TDM */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_0 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_1 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_2 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_3 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
- {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_2 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, /* TX_3 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */
+ {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */
},
{ /* SEC TDM */
{SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 6}, /* TX_0 */
@@ -343,7 +343,7 @@ struct tdm_slot_cfg {
static struct tdm_slot_cfg tdm_slot[TDM_INTERFACE_MAX] = {
/* PRI TDM */
- {32, 8},
+ {16, 16},
/* SEC TDM */
{32, 8},
/* TERT TDM */
@@ -377,11 +377,11 @@ static struct tdm_slot_cfg tdm_slot_custom[TDM_INTERFACE_MAX] = {
static unsigned int tdm_rx_slot_offset
[TDM_INTERFACE_MAX][TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = {
{/* PRI TDM */
- {0, 4, 0xFFFF},
- {8, 12, 0xFFFF},
- {16, 20, 0xFFFF},
- {24, 28, 0xFFFF},
- {0xFFFF}, /* not used */
+ {0, 0xFFFF},
+ {2, 0xFFFF},
+ {4, 6, 0xFFFF},
+ {8, 10, 0xFFFF},
+ {12, 14, 0xFFFF},
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
@@ -432,11 +432,11 @@ static unsigned int tdm_rx_slot_offset
static unsigned int tdm_tx_slot_offset
[TDM_INTERFACE_MAX][TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = {
{/* PRI TDM */
- {0, 4, 0xFFFF},
- {8, 12, 0xFFFF},
- {16, 20, 0xFFFF},
- {24, 28, 0xFFFF},
- {0xFFFF}, /* not used */
+ {0, 0xFFFF},
+ {2, 0xFFFF},
+ {4, 6, 0xFFFF},
+ {8, 10, 0xFFFF},
+ {12, 14, 0xFFFF},
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
@@ -5896,6 +5896,40 @@ static struct snd_soc_dai_link msm_auto_fe_dai_links[] = {
.ignore_pmdown_time = 1,
.id = MSM_FRONTEND_DAI_MULTIMEDIA23
},
+ {
+ .name = MSM_DAILINK_NAME(Media24),
+ .stream_name = "MultiMedia24",
+ .cpu_dai_name = "MultiMedia24",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA24
+ },
+ {
+ .name = MSM_DAILINK_NAME(Media25),
+ .stream_name = "MultiMedia25",
+ .cpu_dai_name = "MultiMedia25",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA25
+ },
};
static struct snd_soc_dai_link msm_custom_fe_dai_links[] = {