Browse Source

Merge "ASoC: wsa883x: Add support for wsa883x speaker amplifer"

qctecmdr 5 years ago
parent
commit
360a45bad1

+ 49 - 0
asoc/codecs/wsa883x/Android.mk

@@ -0,0 +1,49 @@
+# Android makefile for audio kernel modules
+
+# Assume no targets will be supported
+
+# Check if this driver needs be built for current target
+ifeq ($(call is-board-platform,lahaina),true)
+AUDIO_SELECT  := CONFIG_SND_SOC_LAHAINA=m
+endif
+
+AUDIO_CHIPSET := audio
+# Build/Package only in case of supported target
+ifeq ($(call is-board-platform-in-list,lahaina),true)
+
+LOCAL_PATH := $(call my-dir)
+
+# This makefile is only for DLKM
+ifneq ($(findstring vendor,$(LOCAL_PATH)),)
+
+ifneq ($(findstring opensource,$(LOCAL_PATH)),)
+	AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel
+endif # opensource
+
+DLKM_DIR := $(TOP)/device/qcom/common/dlkm
+
+# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko
+###########################################################
+# This is set once per LOCAL_PATH, not per (kernel) module
+KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR)
+
+# We are actually building audio.ko here, as per the
+# requirement we are specifying <chipset>_audio.ko as LOCAL_MODULE.
+# This means we need to rename the module to <chipset>_audio.ko
+# after audio.ko is built.
+KBUILD_OPTIONS += MODNAME=wsa883x_dlkm
+KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM)
+KBUILD_OPTIONS += $(AUDIO_SELECT)
+
+###########################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE              := $(AUDIO_CHIPSET)_wsa883x.ko
+LOCAL_MODULE_KBUILD_NAME  := wsa883x_dlkm.ko
+LOCAL_MODULE_TAGS         := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/AndroidKernelModule.mk
+###########################################################
+
+endif # DLKM check
+endif # supported target check

+ 103 - 0
asoc/codecs/wsa883x/Kbuild

@@ -0,0 +1,103 @@
+# We can build either as part of a standalone Kernel build or as
+# an external module.  Determine which mechanism is being used
+ifeq ($(MODNAME),)
+	KERNEL_BUILD := 1
+else
+	KERNEL_BUILD := 0
+endif
+
+ifeq ($(KERNEL_BUILD), 1)
+	# These are configurable via Kconfig for kernel-based builds
+	# Need to explicitly configure for Android-based builds
+	AUDIO_BLD_DIR := $(shell pwd)/kernel/msm-4.19
+	AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio
+endif
+
+ifeq ($(KERNEL_BUILD), 0)
+	ifeq ($(CONFIG_ARCH_LAHAINA), y)
+		include $(AUDIO_ROOT)/config/lahainaauto.conf
+		INCS    +=  -include $(AUDIO_ROOT)/config/lahainaautoconf.h
+	endif
+endif
+
+# As per target team, build is done as follows:
+# Defconfig : build with default flags
+# Slub      : defconfig  + CONFIG_SLUB_DEBUG := y +
+#	      CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y
+# Perf      : Using appropriate msmXXXX-perf_defconfig
+#
+# Shipment builds (user variants) should not have any debug feature
+# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds
+# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since
+# there is no other way to identify defconfig builds, QTI internal
+# representation of perf builds (identified using the string 'perf'),
+# is used to identify if the build is a slub or defconfig one. This
+# way no critical debug feature will be enabled for perf and shipment
+# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT
+# config.
+
+############ UAPI ############
+UAPI_DIR :=	uapi
+UAPI_INC :=	-I$(AUDIO_ROOT)/include/$(UAPI_DIR)
+
+############ COMMON ############
+COMMON_DIR :=	include
+COMMON_INC :=	-I$(AUDIO_ROOT)/$(COMMON_DIR)
+
+############ WSA883X ############
+
+# for WSA883X Codec
+ifdef CONFIG_SND_SOC_WSA883X
+	WSA883X_OBJS += wsa883x.o
+	WSA883X_OBJS += wsa883x-regmap.o
+	WSA883X_OBJS += wsa883x-tables.o
+	WSA883X_OBJS += wsa883x-temp-sensor.o
+endif
+
+LINUX_INC +=	-Iinclude/linux
+
+INCS +=		$(COMMON_INC) \
+		$(UAPI_INC)
+
+EXTRA_CFLAGS += $(INCS)
+
+
+CDEFINES +=	-DANI_LITTLE_BYTE_ENDIAN \
+		-DANI_LITTLE_BIT_ENDIAN \
+		-DDOT11F_LITTLE_ENDIAN_HOST \
+		-DANI_COMPILER_TYPE_GCC \
+		-DANI_OS_TYPE_ANDROID=6 \
+		-DPTT_SOCK_SVC_ENABLE \
+		-Wall\
+		-Werror\
+		-D__linux__
+
+KBUILD_CPPFLAGS += $(CDEFINES)
+
+# Currently, for versions of gcc which support it, the kernel Makefile
+# is disabling the maybe-uninitialized warning.  Re-enable it for the
+# AUDIO driver.  Note that we must use EXTRA_CFLAGS here so that it
+# will override the kernel settings.
+ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y)
+EXTRA_CFLAGS += -Wmaybe-uninitialized
+endif
+#EXTRA_CFLAGS += -Wmissing-prototypes
+
+ifeq ($(call cc-option-yn, -Wheader-guard),y)
+EXTRA_CFLAGS += -Wheader-guard
+endif
+
+ifeq ($(KERNEL_BUILD), 0)
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers
+KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers
+endif
+
+# Module information used by KBuild framework
+obj-$(CONFIG_SND_SOC_WSA883X) += wsa883x_dlkm.o
+wsa883x_dlkm-y := $(WSA883X_OBJS)
+
+# inject some build related information
+DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"

+ 113 - 0
asoc/codecs/wsa883x/internal.h

@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef WSA883X_INTERNAL_H
+#define WSA883X_INTERNAL_H
+
+#include "wsa883x.h"
+#include "wsa883x-registers.h"
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#define SWR_SLV_MAX_REG_ADDR	0x2009
+#define SWR_SLV_START_REG_ADDR	0x40
+#define SWR_SLV_MAX_BUF_LEN	20
+#define BYTES_PER_LINE		12
+#define SWR_SLV_RD_BUF_LEN	8
+#define SWR_SLV_WR_BUF_LEN	32
+#define SWR_SLV_MAX_DEVICES	2
+#endif /* CONFIG_DEBUG_FS */
+
+#define WSA883X_DRV_NAME "wsa883x-codec"
+#define WSA883X_NUM_RETRY	5
+
+#define WSA883X_VERSION_ENTRY_SIZE 27
+
+enum {
+	G_18DB = 0,
+	G_16P5DB,
+	G_15DB,
+	G_13P5DB,
+	G_12DB,
+	G_10P5DB,
+	G_9DB,
+	G_7P5DB,
+	G_6DB,
+	G_4P5DB,
+	G_3DB,
+	G_1P5DB,
+	G_0DB,
+};
+
+enum {
+	DISABLE = 0,
+	ENABLE,
+};
+
+enum {
+	SWR_DAC_PORT,
+	SWR_COMP_PORT,
+	SWR_BOOST_PORT,
+	SWR_VISENSE_PORT,
+};
+
+struct swr_port {
+	u8 port_id;
+	u8 ch_mask;
+	u32 ch_rate;
+	u8 num_ch;
+	u8 port_type;
+};
+
+enum {
+	WSA883X_DEV_DOWN,
+	WSA883X_DEV_UP,
+	WSA883X_DEV_READY,
+};
+
+extern struct regmap_config wsa883x_regmap_config;
+
+/*
+ * Private data Structure for wsa883x. All parameters related to
+ * WSA883X codec needs to be defined here.
+ */
+struct wsa883x_priv {
+	struct regmap *regmap;
+	struct device *dev;
+	struct swr_device *swr_slave;
+	struct snd_soc_component *component;
+	bool comp_enable;
+	bool boost_enable;
+	bool visense_enable;
+	u8 pa_gain;
+	struct swr_port port[WSA883X_MAX_SWR_PORTS];
+	int pd_gpio;
+	struct wsa883x_tz_priv tz_pdata;
+	int bg_cnt;
+	int clk_cnt;
+	int version;
+	struct mutex bg_lock;
+	struct mutex res_lock;
+	struct mutex temp_lock;
+	struct snd_info_entry *entry;
+	struct snd_info_entry *version_entry;
+	int state;
+	struct delayed_work ocp_ctl_work;
+	struct device_node *wsa_rst_np;
+	int pa_mute;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_dent;
+	struct dentry *debugfs_peek;
+	struct dentry *debugfs_poke;
+	struct dentry *debugfs_reg_dump;
+	unsigned int read_data;
+#endif
+};
+
+static int32_t wsa883x_resource_acquire(struct snd_soc_component *component,
+						bool enable);
+#endif /* WSA883X_INTERNAL_H */

+ 376 - 0
asoc/codecs/wsa883x/wsa883x-registers.h

@@ -0,0 +1,376 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef WSA883X_REGISTERS_H
+#define WSA883X_REGISTERS_H
+
+#define WSA883X_BASE                    0x3000
+#define WSA883X_REG(reg)    (reg - WSA883X_BASE)
+
+enum {
+	REG_NO_ACCESS,
+	RD_REG,
+	WR_REG,
+	RD_WR_REG,
+};
+
+#define WSA883X_ANA_BG_TSADC_BASE       (WSA883X_BASE+0x00000000)
+#define WSA883X_REF_CTRL                (WSA883X_ANA_BG_TSADC_BASE+0x0000)
+#define WSA883X_TEST_CTL_0              (WSA883X_ANA_BG_TSADC_BASE+0x0001)
+#define WSA883X_BIAS_0                  (WSA883X_ANA_BG_TSADC_BASE+0x0002)
+#define WSA883X_OP_CTL                  (WSA883X_ANA_BG_TSADC_BASE+0x0003)
+#define WSA883X_IREF_CTL                (WSA883X_ANA_BG_TSADC_BASE+0x0004)
+#define WSA883X_ISENS_CTL               (WSA883X_ANA_BG_TSADC_BASE+0x0005)
+#define WSA883X_CLK_CTL                 (WSA883X_ANA_BG_TSADC_BASE+0x0006)
+#define WSA883X_TEST_CTL_1              (WSA883X_ANA_BG_TSADC_BASE+0x0007)
+#define WSA883X_BIAS_1                  (WSA883X_ANA_BG_TSADC_BASE+0x0008)
+#define WSA883X_ADC_CTL                 (WSA883X_ANA_BG_TSADC_BASE+0x0009)
+#define WSA883X_DOUT_MSB                (WSA883X_ANA_BG_TSADC_BASE+0x000A)
+#define WSA883X_DOUT_LSB                (WSA883X_ANA_BG_TSADC_BASE+0x000B)
+#define WSA883X_VBAT_SNS                (WSA883X_ANA_BG_TSADC_BASE+0x000C)
+#define WSA883X_ITRIM_CODE              (WSA883X_ANA_BG_TSADC_BASE+0x000D)
+
+#define WSA883X_ANA_IVSENSE_BASE        (WSA883X_BASE+0x0000000F)
+#define WSA883X_EN                      (WSA883X_ANA_IVSENSE_BASE+0x0000)
+#define WSA883X_OVERRIDE1               (WSA883X_ANA_IVSENSE_BASE+0x0001)
+#define WSA883X_OVERRIDE2               (WSA883X_ANA_IVSENSE_BASE+0x0002)
+#define WSA883X_VSENSE1                 (WSA883X_ANA_IVSENSE_BASE+0x0003)
+#define WSA883X_ISENSE1                 (WSA883X_ANA_IVSENSE_BASE+0x0004)
+#define WSA883X_ISENSE2                 (WSA883X_ANA_IVSENSE_BASE+0x0005)
+#define WSA883X_ISENSE_CAL              (WSA883X_ANA_IVSENSE_BASE+0x0006)
+#define WSA883X_MISC                    (WSA883X_ANA_IVSENSE_BASE+0x0007)
+#define WSA883X_ADC_0                   (WSA883X_ANA_IVSENSE_BASE+0x0008)
+#define WSA883X_ADC_1                   (WSA883X_ANA_IVSENSE_BASE+0x0009)
+#define WSA883X_ADC_2                   (WSA883X_ANA_IVSENSE_BASE+0x000A)
+#define WSA883X_ADC_3                   (WSA883X_ANA_IVSENSE_BASE+0x000B)
+#define WSA883X_ADC_4                   (WSA883X_ANA_IVSENSE_BASE+0x000C)
+#define WSA883X_ADC_5                   (WSA883X_ANA_IVSENSE_BASE+0x000D)
+#define WSA883X_ADC_6                   (WSA883X_ANA_IVSENSE_BASE+0x000E)
+#define WSA883X_ADC_7                   (WSA883X_ANA_IVSENSE_BASE+0x000F)
+#define WSA883X_STATUS                  (WSA883X_ANA_IVSENSE_BASE+0x0010)
+
+#define WSA883X_ANA_SPK_TOP_BASE        (WSA883X_BASE+0x00000025)
+#define WSA883X_DAC_CTRL_REG            (WSA883X_ANA_SPK_TOP_BASE+0x0000)
+#define WSA883X_DAC_EN_DEBUG_REG        (WSA883X_ANA_SPK_TOP_BASE+0x0001)
+#define WSA883X_DAC_OPAMP_BIAS1_REG     (WSA883X_ANA_SPK_TOP_BASE+0x0002)
+#define WSA883X_DAC_OPAMP_BIAS2_REG     (WSA883X_ANA_SPK_TOP_BASE+0x0003)
+#define WSA883X_DAC_VCM_CTRL_REG        (WSA883X_ANA_SPK_TOP_BASE+0x0004)
+#define WSA883X_DAC_VOLTAGE_CTRL_REG    (WSA883X_ANA_SPK_TOP_BASE+0x0005)
+#define WSA883X_ATEST1_REG              (WSA883X_ANA_SPK_TOP_BASE+0x0006)
+#define WSA883X_ATEST2_REG              (WSA883X_ANA_SPK_TOP_BASE+0x0007)
+#define WSA883X_SPKR_TOP_BIAS_REG1      (WSA883X_ANA_SPK_TOP_BASE+0x0008)
+#define WSA883X_SPKR_TOP_BIAS_REG2      (WSA883X_ANA_SPK_TOP_BASE+0x0009)
+#define WSA883X_SPKR_TOP_BIAS_REG3      (WSA883X_ANA_SPK_TOP_BASE+0x000A)
+#define WSA883X_SPKR_TOP_BIAS_REG4      (WSA883X_ANA_SPK_TOP_BASE+0x000B)
+#define WSA883X_SPKR_CLIP_DET_REG       (WSA883X_ANA_SPK_TOP_BASE+0x000C)
+#define WSA883X_SPKR_DRV_LF_BLK_EN      (WSA883X_ANA_SPK_TOP_BASE+0x000D)
+#define WSA883X_SPKR_DRV_LF_EN          (WSA883X_ANA_SPK_TOP_BASE+0x000E)
+#define WSA883X_SPKR_DRV_LF_MASK_DCC_CTL (WSA883X_ANA_SPK_TOP_BASE+0x000F)
+#define WSA883X_SPKR_DRV_LF_MISC_CTL    (WSA883X_ANA_SPK_TOP_BASE+0x0010)
+#define WSA883X_SPKR_DRV_LF_REG_GAIN    (WSA883X_ANA_SPK_TOP_BASE+0x0011)
+#define WSA883X_SPKR_DRV_LF_OS_CAL_CTL1 (WSA883X_ANA_SPK_TOP_BASE+0x0012)
+#define WSA883X_SPKR_DRV_LF_OS_CAL_CTL  (WSA883X_ANA_SPK_TOP_BASE+0x0013)
+#define WSA883X_SPKR_PWM_CLK_CTL        (WSA883X_ANA_SPK_TOP_BASE+0x0014)
+#define WSA883X_SPKR_PDRV_HS_CTL        (WSA883X_ANA_SPK_TOP_BASE+0x0015)
+#define WSA883X_SPKR_PDRV_LS_CTL        (WSA883X_ANA_SPK_TOP_BASE+0x0016)
+#define WSA883X_SPKR_PWRSTG_DBG         (WSA883X_ANA_SPK_TOP_BASE+0x0017)
+#define WSA883X_SPKR_OCP_CTL            (WSA883X_ANA_SPK_TOP_BASE+0x0018)
+#define WSA883X_SPKR_BBM_CTL            (WSA883X_ANA_SPK_TOP_BASE+0x0019)
+#define WSA883X_PA_STATUS0              (WSA883X_ANA_SPK_TOP_BASE+0x001A)
+#define WSA883X_PA_STATUS1              (WSA883X_ANA_SPK_TOP_BASE+0x001B)
+#define WSA883X_PA_STATUS2              (WSA883X_ANA_SPK_TOP_BASE+0x001C)
+
+#define WSA883X_ANA_BOOST_BASE          (WSA883X_BASE+0x00000045)
+#define WSA883X_EN_CTRL                 (WSA883X_ANA_BOOST_BASE+0x0000)
+#define WSA883X_CURRENT_LIMIT           (WSA883X_ANA_BOOST_BASE+0x0001)
+#define WSA883X_IBIAS1                  (WSA883X_ANA_BOOST_BASE+0x0002)
+#define WSA883X_IBIAS2                  (WSA883X_ANA_BOOST_BASE+0x0003)
+#define WSA883X_IBIAS3                  (WSA883X_ANA_BOOST_BASE+0x0004)
+#define WSA883X_LDO_PROG                (WSA883X_ANA_BOOST_BASE+0x0005)
+#define WSA883X_STABILITY_CTRL1         (WSA883X_ANA_BOOST_BASE+0x0006)
+#define WSA883X_STABILITY_CTRL2         (WSA883X_ANA_BOOST_BASE+0x0007)
+#define WSA883X_PWRSTAGE_CTRL1          (WSA883X_ANA_BOOST_BASE+0x0008)
+#define WSA883X_PWRSTAGE_CTRL2          (WSA883X_ANA_BOOST_BASE+0x0009)
+#define WSA883X_UVLO                    (WSA883X_ANA_BOOST_BASE+0x000A)
+#define WSA883X_SEQUENCE_CTRL           (WSA883X_ANA_BOOST_BASE+0x000B)
+#define WSA883X_ZX_CTRL_1               (WSA883X_ANA_BOOST_BASE+0x000C)
+#define WSA883X_ZX_CTRL_2               (WSA883X_ANA_BOOST_BASE+0x000D)
+#define WSA883X_MISC1                   (WSA883X_ANA_BOOST_BASE+0x000E)
+#define WSA883X_MISC2                   (WSA883X_ANA_BOOST_BASE+0x000F)
+#define WSA883X_GMAMP_SUP1              (WSA883X_ANA_BOOST_BASE+0x0010)
+#define WSA883X_PWRSTAGE_CTRL3          (WSA883X_ANA_BOOST_BASE+0x0011)
+#define WSA883X_PRSTAGE_CTRL4           (WSA883X_ANA_BOOST_BASE+0x0012)
+#define WSA883X_SPARE1                  (WSA883X_ANA_BOOST_BASE+0x0013)
+
+#define WSA883X_ANA_PON_LDOL_BASE       (WSA883X_BASE+0x00000059)
+#define WSA883X_PON_CTL_0               (WSA883X_ANA_PON_LDOL_BASE+0x0000)
+#define WSA883X_PON_CLT_1               (WSA883X_ANA_PON_LDOL_BASE+0x0001)
+#define WSA883X_PON_CTL_2               (WSA883X_ANA_PON_LDOL_BASE+0x0002)
+#define WSA883X_PON_CTL_3               (WSA883X_ANA_PON_LDOL_BASE+0x0003)
+#define WSA883X_PON_CTL_4               (WSA883X_ANA_PON_LDOL_BASE+0x0004)
+#define WSA883X_CKWD_CTL_0              (WSA883X_ANA_PON_LDOL_BASE+0x0005)
+#define WSA883X_CKWD_CTL_1              (WSA883X_ANA_PON_LDOL_BASE+0x0006)
+#define WSA883X_CKWD_CTL_2              (WSA883X_ANA_PON_LDOL_BASE+0x0007)
+#define WSA883X_CKSK_CTL_0              (WSA883X_ANA_PON_LDOL_BASE+0x0008)
+#define WSA883X_TEST_0                  (WSA883X_ANA_PON_LDOL_BASE+0x0009)
+#define WSA883X_TEST_1                  (WSA883X_ANA_PON_LDOL_BASE+0x000A)
+#define WSA883X_STATUS_0                (WSA883X_ANA_PON_LDOL_BASE+0x000B)
+#define WSA883X_STATUS_1                (WSA883X_ANA_PON_LDOL_BASE+0x000C)
+
+#define WSA883X_DIG_CTRL_BASE           (WSA883X_BASE+0x00000400)
+#define WSA883X_PAGE_REGISTER           (WSA883X_DIG_CTRL_BASE+0x0000)
+#define WSA883X_CHIP_ID0                (WSA883X_DIG_CTRL_BASE+0x0001)
+#define WSA883X_CHIP_ID1                (WSA883X_DIG_CTRL_BASE+0x0002)
+#define WSA883X_CHIP_ID2                (WSA883X_DIG_CTRL_BASE+0x0003)
+#define WSA883X_CHIP_ID3                (WSA883X_DIG_CTRL_BASE+0x0004)
+#define WSA883X_BUS_ID                  (WSA883X_DIG_CTRL_BASE+0x0005)
+#define WSA883X_CDC_RST_CTL             (WSA883X_DIG_CTRL_BASE+0x0006)
+#define WSA883X_TOP_CLK_CFG             (WSA883X_DIG_CTRL_BASE+0x0007)
+#define WSA883X_CDC_PATH_MODE           (WSA883X_DIG_CTRL_BASE+0x0008)
+#define WSA883X_CDC_CLK_CTL             (WSA883X_DIG_CTRL_BASE+0x0009)
+#define WSA883X_SWR_RESET_EN            (WSA883X_DIG_CTRL_BASE+0x000A)
+#define WSA883X_PA_FSM_CTL              (WSA883X_DIG_CTRL_BASE+0x0010)
+#define WSA883X_PA_FSM_TIMER0           (WSA883X_DIG_CTRL_BASE+0x0011)
+#define WSA883X_PA_FSM_TIMER1           (WSA883X_DIG_CTRL_BASE+0x0012)
+#define WSA883X_PA_FSM_STA              (WSA883X_DIG_CTRL_BASE+0x0013)
+#define WSA883X_PA_FSM_ERR_COND         (WSA883X_DIG_CTRL_BASE+0x0014)
+#define WSA883X_PA_FSM_MSK              (WSA883X_DIG_CTRL_BASE+0x0015)
+#define WSA883X_PA_FSM_BYP              (WSA883X_DIG_CTRL_BASE+0x0016)
+#define WSA883X_TADC_VALUE_CTL          (WSA883X_DIG_CTRL_BASE+0x0020)
+#define WSA883X_TEMP_DETECT_CTL         (WSA883X_DIG_CTRL_BASE+0x0021)
+#define WSA883X_TEMP_MSB                (WSA883X_DIG_CTRL_BASE+0x0022)
+#define WSA883X_TEMP_LSB                (WSA883X_DIG_CTRL_BASE+0x0023)
+#define WSA883X_TEMP_CONFIG0            (WSA883X_DIG_CTRL_BASE+0x0024)
+#define WSA883X_TEMP_CONFIG1            (WSA883X_DIG_CTRL_BASE+0x0025)
+#define WSA883X_VBAT_ADC_FLT_CTL        (WSA883X_DIG_CTRL_BASE+0x0026)
+#define WSA883X_VBAT_DIN_MSB            (WSA883X_DIG_CTRL_BASE+0x0027)
+#define WSA883X_VBAT_DIN_LSB            (WSA883X_DIG_CTRL_BASE+0x0028)
+#define WSA883X_VBAT_DOUT               (WSA883X_DIG_CTRL_BASE+0x0029)
+#define WSA883X_SDM_PDM9_LSB            (WSA883X_DIG_CTRL_BASE+0x002A)
+#define WSA883X_SDM_PDM9_MSB            (WSA883X_DIG_CTRL_BASE+0x002B)
+#define WSA883X_CDC_RX_CTL              (WSA883X_DIG_CTRL_BASE+0x0030)
+#define WSA883X_CDC_SPK_DSM_A1_0        (WSA883X_DIG_CTRL_BASE+0x0031)
+#define WSA883X_CDC_SPK_DSM_A1_1        (WSA883X_DIG_CTRL_BASE+0x0032)
+#define WSA883X_CDC_SPK_DSM_A2_0        (WSA883X_DIG_CTRL_BASE+0x0033)
+#define WSA883X_CDC_SPK_DSM_A2_1        (WSA883X_DIG_CTRL_BASE+0x0034)
+#define WSA883X_CDC_SPK_DSM_A3_0        (WSA883X_DIG_CTRL_BASE+0x0035)
+#define WSA883X_CDC_SPK_DSM_A3_1        (WSA883X_DIG_CTRL_BASE+0x0036)
+#define WSA883X_CDC_SPK_DSM_A4_0        (WSA883X_DIG_CTRL_BASE+0x0037)
+#define WSA883X_CDC_SPK_DSM_A4_1        (WSA883X_DIG_CTRL_BASE+0x0038)
+#define WSA883X_CDC_SPK_DSM_A5_0        (WSA883X_DIG_CTRL_BASE+0x0039)
+#define WSA883X_CDC_SPK_DSM_A5_1        (WSA883X_DIG_CTRL_BASE+0x003A)
+#define WSA883X_CDC_SPK_DSM_A6_0        (WSA883X_DIG_CTRL_BASE+0x003B)
+#define WSA883X_CDC_SPK_DSM_A7_0        (WSA883X_DIG_CTRL_BASE+0x003C)
+#define WSA883X_CDC_SPK_DSM_C_0         (WSA883X_DIG_CTRL_BASE+0x003D)
+#define WSA883X_CDC_SPK_DSM_C_1         (WSA883X_DIG_CTRL_BASE+0x003E)
+#define WSA883X_CDC_SPK_DSM_C_2         (WSA883X_DIG_CTRL_BASE+0x003F)
+#define WSA883X_CDC_SPK_DSM_C_3         (WSA883X_DIG_CTRL_BASE+0x0040)
+#define WSA883X_CDC_SPK_DSM_R1          (WSA883X_DIG_CTRL_BASE+0x0041)
+#define WSA883X_CDC_SPK_DSM_R2          (WSA883X_DIG_CTRL_BASE+0x0042)
+#define WSA883X_CDC_SPK_DSM_R3          (WSA883X_DIG_CTRL_BASE+0x0043)
+#define WSA883X_CDC_SPK_DSM_R4          (WSA883X_DIG_CTRL_BASE+0x0044)
+#define WSA883X_CDC_SPK_DSM_R5          (WSA883X_DIG_CTRL_BASE+0x0045)
+#define WSA883X_CDC_SPK_DSM_R6          (WSA883X_DIG_CTRL_BASE+0x0046)
+#define WSA883X_CDC_SPK_DSM_R7          (WSA883X_DIG_CTRL_BASE+0x0047)
+#define WSA883X_CDC_SPK_GAIN_PDM_0      (WSA883X_DIG_CTRL_BASE+0x0048)
+#define WSA883X_CDC_SPK_GAIN_PDM_1      (WSA883X_DIG_CTRL_BASE+0x0049)
+#define WSA883X_CDC_SPK_GAIN_PDM_2      (WSA883X_DIG_CTRL_BASE+0x004A)
+#define WSA883X_PDM_WD_CTL              (WSA883X_DIG_CTRL_BASE+0x004B)
+#define WSA883X_DEM_BYPASS_DATA0        (WSA883X_DIG_CTRL_BASE+0x004C)
+#define WSA883X_DEM_BYPASS_DATA1        (WSA883X_DIG_CTRL_BASE+0x004D)
+#define WSA883X_DEM_BYPASS_DATA2        (WSA883X_DIG_CTRL_BASE+0x004E)
+#define WSA883X_DEM_BYPASS_DATA3        (WSA883X_DIG_CTRL_BASE+0x004F)
+#define WSA883X_WAVG_CTL                (WSA883X_DIG_CTRL_BASE+0x0050)
+#define WSA883X_WAVG_LRA_PER_0          (WSA883X_DIG_CTRL_BASE+0x0051)
+#define WSA883X_WAVG_LRA_PER_1          (WSA883X_DIG_CTRL_BASE+0x0052)
+#define WSA883X_WAVG_DELTA_THETA_0      (WSA883X_DIG_CTRL_BASE+0x0053)
+#define WSA883X_WAVG_DELTA_THETA_1      (WSA883X_DIG_CTRL_BASE+0x0054)
+#define WSA883X_WAVG_DIRECT_AMP_0       (WSA883X_DIG_CTRL_BASE+0x0055)
+#define WSA883X_WAVG_DIRECT_AMP_1       (WSA883X_DIG_CTRL_BASE+0x0056)
+#define WSA883X_WAVG_PTRN_AMP0_0        (WSA883X_DIG_CTRL_BASE+0x0057)
+#define WSA883X_WAVG_PTRN_AMP0_1        (WSA883X_DIG_CTRL_BASE+0x0058)
+#define WSA883X_WAVG_PTRN_AMP1_0        (WSA883X_DIG_CTRL_BASE+0x0059)
+#define WSA883X_WAVG_PTRN_AMP1_1        (WSA883X_DIG_CTRL_BASE+0x005A)
+#define WSA883X_WAVG_PTRN_AMP2_0        (WSA883X_DIG_CTRL_BASE+0x005B)
+#define WSA883X_WAVG_PTRN_AMP2_1        (WSA883X_DIG_CTRL_BASE+0x005C)
+#define WSA883X_WAVG_PTRN_AMP3_0        (WSA883X_DIG_CTRL_BASE+0x005D)
+#define WSA883X_WAVG_PTRN_AMP3_1        (WSA883X_DIG_CTRL_BASE+0x005E)
+#define WSA883X_WAVG_PTRN_AMP4_0        (WSA883X_DIG_CTRL_BASE+0x005F)
+#define WSA883X_WAVG_PTRN_AMP4_1        (WSA883X_DIG_CTRL_BASE+0x0060)
+#define WSA883X_WAVG_PTRN_AMP5_0        (WSA883X_DIG_CTRL_BASE+0x0061)
+#define WSA883X_WAVG_PTRN_AMP5_1        (WSA883X_DIG_CTRL_BASE+0x0062)
+#define WSA883X_WAVG_PTRN_AMP6_0        (WSA883X_DIG_CTRL_BASE+0x0063)
+#define WSA883X_WAVG_PTRN_AMP6_1        (WSA883X_DIG_CTRL_BASE+0x0064)
+#define WSA883X_WAVG_PTRN_AMP7_0        (WSA883X_DIG_CTRL_BASE+0x0065)
+#define WSA883X_WAVG_PTRN_AMP7_1        (WSA883X_DIG_CTRL_BASE+0x0066)
+#define WSA883X_WAVG_PER_0_1            (WSA883X_DIG_CTRL_BASE+0x0067)
+#define WSA883X_WAVG_PER_2_3            (WSA883X_DIG_CTRL_BASE+0x0068)
+#define WSA883X_WAVG_PER_4_5            (WSA883X_DIG_CTRL_BASE+0x0069)
+#define WSA883X_WAVG_PER_6_7            (WSA883X_DIG_CTRL_BASE+0x006A)
+#define WSA883X_DRE_CTL_0               (WSA883X_DIG_CTRL_BASE+0x006C)
+#define WSA883X_DRE_CTL_1               (WSA883X_DIG_CTRL_BASE+0x006D)
+#define WSA883X_CLSH_CTL_0              (WSA883X_DIG_CTRL_BASE+0x0070)
+#define WSA883X_CLSH_CTL_1              (WSA883X_DIG_CTRL_BASE+0x0071)
+#define WSA883X_CLSH_V_HD_PA            (WSA883X_DIG_CTRL_BASE+0x0072)
+#define WSA883X_CLSH_V_PA_MIN           (WSA883X_DIG_CTRL_BASE+0x0073)
+#define WSA883X_CLSH_OVRD_VAL           (WSA883X_DIG_CTRL_BASE+0x0074)
+#define WSA883X_CLSH_HARD_MAX           (WSA883X_DIG_CTRL_BASE+0x0075)
+#define WSA883X_CLSH_SOFT_MAX           (WSA883X_DIG_CTRL_BASE+0x0076)
+#define WSA883X_CLSH_SIG_DP             (WSA883X_DIG_CTRL_BASE+0x0077)
+#define WSA883X_TAGC_CTL                (WSA883X_DIG_CTRL_BASE+0x0078)
+#define WSA883X_TAGC_TIME               (WSA883X_DIG_CTRL_BASE+0x0079)
+#define WSA883X_TAGC_E2E_GAIN           (WSA883X_DIG_CTRL_BASE+0x007A)
+#define WSA883X_TAGC_FORCE_VAL          (WSA883X_DIG_CTRL_BASE+0x007B)
+#define WSA883X_VAGC_CTL                (WSA883X_DIG_CTRL_BASE+0x007C)
+#define WSA883X_VAGC_TIME               (WSA883X_DIG_CTRL_BASE+0x007D)
+#define WSA883X_VAGC_ATTN_LVL_1_2       (WSA883X_DIG_CTRL_BASE+0x007E)
+#define WSA883X_VAGC_ATTN_LVL_3         (WSA883X_DIG_CTRL_BASE+0x007F)
+#define WSA883X_INTR_MODE               (WSA883X_DIG_CTRL_BASE+0x0080)
+#define WSA883X_INTR_MASK0              (WSA883X_DIG_CTRL_BASE+0x0081)
+#define WSA883X_INTR_MASK1              (WSA883X_DIG_CTRL_BASE+0x0082)
+#define WSA883X_INTR_STATUS0            (WSA883X_DIG_CTRL_BASE+0x0083)
+#define WSA883X_INTR_STATUS1            (WSA883X_DIG_CTRL_BASE+0x0084)
+#define WSA883X_INTR_CLEAR0             (WSA883X_DIG_CTRL_BASE+0x0085)
+#define WSA883X_INTR_CLEAR1             (WSA883X_DIG_CTRL_BASE+0x0086)
+#define WSA883X_INTR_LEVEL0             (WSA883X_DIG_CTRL_BASE+0x0087)
+#define WSA883X_INTR_LEVEL1             (WSA883X_DIG_CTRL_BASE+0x0088)
+#define WSA883X_INTR_SET0               (WSA883X_DIG_CTRL_BASE+0x0089)
+#define WSA883X_INTR_SET1               (WSA883X_DIG_CTRL_BASE+0x008A)
+#define WSA883X_INTR_TEST0              (WSA883X_DIG_CTRL_BASE+0x008B)
+#define WSA883X_INTR_TEST1              (WSA883X_DIG_CTRL_BASE+0x008C)
+#define WSA883X_OTP_CTRL0               (WSA883X_DIG_CTRL_BASE+0x0090)
+#define WSA883X_OTP_CTRL1               (WSA883X_DIG_CTRL_BASE+0x0091)
+#define WSA883X_HDRIVE_CTL_GROUP1       (WSA883X_DIG_CTRL_BASE+0x0092)
+#define WSA883X_PIN_CTL                 (WSA883X_DIG_CTRL_BASE+0x0093)
+#define WSA883X_PIN_CTL_OE              (WSA883X_DIG_CTRL_BASE+0x0094)
+#define WSA883X_PIN_WDATA_IOPAD         (WSA883X_DIG_CTRL_BASE+0x0095)
+#define WSA883X_PIN_STATUS              (WSA883X_DIG_CTRL_BASE+0x0096)
+#define WSA883X_I2C_SLAVE_CTL           (WSA883X_DIG_CTRL_BASE+0x0097)
+#define WSA883X_PDM_TEST_MODE           (WSA883X_DIG_CTRL_BASE+0x00A0)
+#define WSA883X_ATE_TEST_MODE           (WSA883X_DIG_CTRL_BASE+0x00A1)
+#define WSA883X_DRE_TEST                (WSA883X_DIG_CTRL_BASE+0x00A2)
+#define WSA883X_DIG_DEBUG_MODE          (WSA883X_DIG_CTRL_BASE+0x00A3)
+#define WSA883X_DIG_DEBUG_SEL           (WSA883X_DIG_CTRL_BASE+0x00A4)
+#define WSA883X_DIG_DEBUG_EN            (WSA883X_DIG_CTRL_BASE+0x00A5)
+#define WSA883X_SWR_HM_TEST0            (WSA883X_DIG_CTRL_BASE+0x00A6)
+#define WSA883X_SWR_HM_TEST1            (WSA883X_DIG_CTRL_BASE+0x00A7)
+#define WSA883X_SWR_PAD_CTL             (WSA883X_DIG_CTRL_BASE+0x00A8)
+#define WSA883X_TEMP_DETECT_DBG_CTL     (WSA883X_DIG_CTRL_BASE+0x00A9)
+#define WSA883X_TEMP_DEBUG_MSB          (WSA883X_DIG_CTRL_BASE+0x00AA)
+#define WSA883X_TEMP_DEBUG_LSB          (WSA883X_DIG_CTRL_BASE+0x00AB)
+#define WSA883X_SAMPLE_EDGE_SEL         (WSA883X_DIG_CTRL_BASE+0x00AC)
+#define WSA883X_TEST_MODE_CTL           (WSA883X_DIG_CTRL_BASE+0x00AD)
+#define WSA883X_IOPAD_CTL               (WSA883X_DIG_CTRL_BASE+0x00AE)
+#define WSA883X_SPARE_0                 (WSA883X_DIG_CTRL_BASE+0x00B0)
+#define WSA883X_SPARE_1                 (WSA883X_DIG_CTRL_BASE+0x00B1)
+#define WSA883X_SPARE_2                 (WSA883X_DIG_CTRL_BASE+0x00B2)
+#define WSA883X_SCODE                   (WSA883X_DIG_CTRL_BASE+0x00C0)
+
+#define WSA883X_DIG_TRIM_BASE           (WSA883X_BASE+0x00000500)
+#define WSA883X_PAGE_REGISTER           (WSA883X_DIG_TRIM_BASE+0x0000)
+#define WSA883X_OTP_REG_0               (WSA883X_DIG_TRIM_BASE+0x0080)
+#define WSA883X_OTP_REG_1               (WSA883X_DIG_TRIM_BASE+0x0081)
+#define WSA883X_OTP_REG_2               (WSA883X_DIG_TRIM_BASE+0x0082)
+#define WSA883X_OTP_REG_3               (WSA883X_DIG_TRIM_BASE+0x0083)
+#define WSA883X_OTP_REG_4               (WSA883X_DIG_TRIM_BASE+0x0084)
+#define WSA883X_OTP_REG_5               (WSA883X_DIG_TRIM_BASE+0x0085)
+#define WSA883X_OTP_REG_6               (WSA883X_DIG_TRIM_BASE+0x0086)
+#define WSA883X_OTP_REG_7               (WSA883X_DIG_TRIM_BASE+0x0087)
+#define WSA883X_OTP_REG_8               (WSA883X_DIG_TRIM_BASE+0x0088)
+#define WSA883X_OTP_REG_9               (WSA883X_DIG_TRIM_BASE+0x0089)
+#define WSA883X_OTP_REG_10              (WSA883X_DIG_TRIM_BASE+0x008A)
+#define WSA883X_OTP_REG_11              (WSA883X_DIG_TRIM_BASE+0x008B)
+#define WSA883X_OTP_REG_12              (WSA883X_DIG_TRIM_BASE+0x008C)
+#define WSA883X_OTP_REG_13              (WSA883X_DIG_TRIM_BASE+0x008D)
+#define WSA883X_OTP_REG_14              (WSA883X_DIG_TRIM_BASE+0x008E)
+#define WSA883X_OTP_REG_15              (WSA883X_DIG_TRIM_BASE+0x008F)
+#define WSA883X_OTP_REG_16              (WSA883X_DIG_TRIM_BASE+0x0090)
+#define WSA883X_OTP_REG_17              (WSA883X_DIG_TRIM_BASE+0x0091)
+#define WSA883X_OTP_REG_18              (WSA883X_DIG_TRIM_BASE+0x0092)
+#define WSA883X_OTP_REG_19              (WSA883X_DIG_TRIM_BASE+0x0093)
+#define WSA883X_OTP_REG_20              (WSA883X_DIG_TRIM_BASE+0x0094)
+#define WSA883X_OTP_REG_21              (WSA883X_DIG_TRIM_BASE+0x0095)
+#define WSA883X_OTP_REG_22              (WSA883X_DIG_TRIM_BASE+0x0096)
+#define WSA883X_OTP_REG_23              (WSA883X_DIG_TRIM_BASE+0x0097)
+#define WSA883X_OTP_REG_24              (WSA883X_DIG_TRIM_BASE+0x0098)
+#define WSA883X_OTP_REG_25              (WSA883X_DIG_TRIM_BASE+0x0099)
+#define WSA883X_OTP_REG_26              (WSA883X_DIG_TRIM_BASE+0x009A)
+#define WSA883X_OTP_REG_27              (WSA883X_DIG_TRIM_BASE+0x009B)
+#define WSA883X_OTP_REG_28              (WSA883X_DIG_TRIM_BASE+0x009C)
+#define WSA883X_OTP_REG_29              (WSA883X_DIG_TRIM_BASE+0x009D)
+#define WSA883X_OTP_REG_30              (WSA883X_DIG_TRIM_BASE+0x009E)
+#define WSA883X_OTP_REG_31              (WSA883X_DIG_TRIM_BASE+0x009F)
+#define WSA883X_OTP_REG_SCODE           (WSA883X_DIG_TRIM_BASE+0x00A0)
+#define WSA883X_OTP_REG_63              (WSA883X_DIG_TRIM_BASE+0x00BF)
+
+#define WSA883X_DIG_EMEM_BASE           (WSA883X_BASE+0x000005C0)
+#define WSA883X_EMEM_0                  (WSA883X_DIG_EMEM_BASE+0x0000)
+#define WSA883X_EMEM_1                  (WSA883X_DIG_EMEM_BASE+0x0001)
+#define WSA883X_EMEM_2                  (WSA883X_DIG_EMEM_BASE+0x0002)
+#define WSA883X_EMEM_3                  (WSA883X_DIG_EMEM_BASE+0x0003)
+#define WSA883X_EMEM_4                  (WSA883X_DIG_EMEM_BASE+0x0004)
+#define WSA883X_EMEM_5                  (WSA883X_DIG_EMEM_BASE+0x0005)
+#define WSA883X_EMEM_6                  (WSA883X_DIG_EMEM_BASE+0x0006)
+#define WSA883X_EMEM_7                  (WSA883X_DIG_EMEM_BASE+0x0007)
+#define WSA883X_EMEM_8                  (WSA883X_DIG_EMEM_BASE+0x0008)
+#define WSA883X_EMEM_9                  (WSA883X_DIG_EMEM_BASE+0x0009)
+#define WSA883X_EMEM_10                 (WSA883X_DIG_EMEM_BASE+0x000A)
+#define WSA883X_EMEM_11                 (WSA883X_DIG_EMEM_BASE+0x000B)
+#define WSA883X_EMEM_12                 (WSA883X_DIG_EMEM_BASE+0x000C)
+#define WSA883X_EMEM_13                 (WSA883X_DIG_EMEM_BASE+0x000D)
+#define WSA883X_EMEM_14                 (WSA883X_DIG_EMEM_BASE+0x000E)
+#define WSA883X_EMEM_15                 (WSA883X_DIG_EMEM_BASE+0x000F)
+#define WSA883X_EMEM_16                 (WSA883X_DIG_EMEM_BASE+0x0010)
+#define WSA883X_EMEM_17                 (WSA883X_DIG_EMEM_BASE+0x0011)
+#define WSA883X_EMEM_18                 (WSA883X_DIG_EMEM_BASE+0x0012)
+#define WSA883X_EMEM_19                 (WSA883X_DIG_EMEM_BASE+0x0013)
+#define WSA883X_EMEM_20                 (WSA883X_DIG_EMEM_BASE+0x0014)
+#define WSA883X_EMEM_21                 (WSA883X_DIG_EMEM_BASE+0x0015)
+#define WSA883X_EMEM_22                 (WSA883X_DIG_EMEM_BASE+0x0016)
+#define WSA883X_EMEM_23                 (WSA883X_DIG_EMEM_BASE+0x0017)
+#define WSA883X_EMEM_24                 (WSA883X_DIG_EMEM_BASE+0x0018)
+#define WSA883X_EMEM_25                 (WSA883X_DIG_EMEM_BASE+0x0019)
+#define WSA883X_EMEM_26                 (WSA883X_DIG_EMEM_BASE+0x001A)
+#define WSA883X_EMEM_27                 (WSA883X_DIG_EMEM_BASE+0x001B)
+#define WSA883X_EMEM_28                 (WSA883X_DIG_EMEM_BASE+0x001C)
+#define WSA883X_EMEM_29                 (WSA883X_DIG_EMEM_BASE+0x001D)
+#define WSA883X_EMEM_30                 (WSA883X_DIG_EMEM_BASE+0x001E)
+#define WSA883X_EMEM_31                 (WSA883X_DIG_EMEM_BASE+0x001F)
+#define WSA883X_EMEM_32                 (WSA883X_DIG_EMEM_BASE+0x0020)
+#define WSA883X_EMEM_33                 (WSA883X_DIG_EMEM_BASE+0x0021)
+#define WSA883X_EMEM_34                 (WSA883X_DIG_EMEM_BASE+0x0022)
+#define WSA883X_EMEM_35                 (WSA883X_DIG_EMEM_BASE+0x0023)
+#define WSA883X_EMEM_36                 (WSA883X_DIG_EMEM_BASE+0x0024)
+#define WSA883X_EMEM_37                 (WSA883X_DIG_EMEM_BASE+0x0025)
+#define WSA883X_EMEM_38                 (WSA883X_DIG_EMEM_BASE+0x0026)
+#define WSA883X_EMEM_39                 (WSA883X_DIG_EMEM_BASE+0x0027)
+#define WSA883X_EMEM_40                 (WSA883X_DIG_EMEM_BASE+0x0028)
+#define WSA883X_EMEM_41                 (WSA883X_DIG_EMEM_BASE+0x0029)
+#define WSA883X_EMEM_42                 (WSA883X_DIG_EMEM_BASE+0x002A)
+#define WSA883X_EMEM_43                 (WSA883X_DIG_EMEM_BASE+0x002B)
+#define WSA883X_EMEM_44                 (WSA883X_DIG_EMEM_BASE+0x002C)
+#define WSA883X_EMEM_45                 (WSA883X_DIG_EMEM_BASE+0x002D)
+#define WSA883X_EMEM_46                 (WSA883X_DIG_EMEM_BASE+0x002E)
+#define WSA883X_EMEM_47                 (WSA883X_DIG_EMEM_BASE+0x002F)
+#define WSA883X_EMEM_48                 (WSA883X_DIG_EMEM_BASE+0x0030)
+#define WSA883X_EMEM_49                 (WSA883X_DIG_EMEM_BASE+0x0031)
+#define WSA883X_EMEM_50                 (WSA883X_DIG_EMEM_BASE+0x0032)
+#define WSA883X_EMEM_51                 (WSA883X_DIG_EMEM_BASE+0x0033)
+#define WSA883X_EMEM_52                 (WSA883X_DIG_EMEM_BASE+0x0034)
+#define WSA883X_EMEM_53                 (WSA883X_DIG_EMEM_BASE+0x0035)
+#define WSA883X_EMEM_54                 (WSA883X_DIG_EMEM_BASE+0x0036)
+#define WSA883X_EMEM_55                 (WSA883X_DIG_EMEM_BASE+0x0037)
+#define WSA883X_EMEM_56                 (WSA883X_DIG_EMEM_BASE+0x0038)
+#define WSA883X_EMEM_57                 (WSA883X_DIG_EMEM_BASE+0x0039)
+#define WSA883X_EMEM_58                 (WSA883X_DIG_EMEM_BASE+0x003A)
+#define WSA883X_EMEM_59                 (WSA883X_DIG_EMEM_BASE+0x003B)
+#define WSA883X_EMEM_60                 (WSA883X_DIG_EMEM_BASE+0x003C)
+#define WSA883X_EMEM_61                 (WSA883X_DIG_EMEM_BASE+0x003D)
+#define WSA883X_EMEM_62                 (WSA883X_DIG_EMEM_BASE+0x003E)
+#define WSA883X_EMEM_63                 (WSA883X_DIG_EMEM_BASE+0x003F)
+
+#define WSA883X_NUM_REGISTERS           (WSA883X_EMEM_63+1)
+#define WSA883X_MAX_REGISTER            (WSA883X_NUM_REGISTERS-1)
+
+#endif /* WSA883X_REGISTERS_H */

+ 393 - 0
asoc/codecs/wsa883x/wsa883x-regmap.c

@@ -0,0 +1,393 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015-2016, 2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "wsa883x-registers.h"
+#include "wsa883x.h"
+
+extern const u8 wsa883x_reg_access[WSA883X_NUM_REGISTERS];
+
+static struct reg_default wsa883x_defaults[] = {
+	{WSA883X_REF_CTRL,                   0x6C},
+	{WSA883X_TEST_CTL_0,                 0x06},
+	{WSA883X_BIAS_0,                     0xD2},
+	{WSA883X_OP_CTL,                     0xE0},
+	{WSA883X_IREF_CTL,                   0x58},
+	{WSA883X_ISENS_CTL,                  0x47},
+	{WSA883X_CLK_CTL,                    0x87},
+	{WSA883X_TEST_CTL_1,                 0x00},
+	{WSA883X_BIAS_1,                     0x51},
+	{WSA883X_ADC_CTL,                    0x03},
+	{WSA883X_DOUT_MSB,                   0x00},
+	{WSA883X_DOUT_LSB,                   0x00},
+	{WSA883X_VBAT_SNS,                   0x00},
+	{WSA883X_ITRIM_CODE,                 0x1F},
+	{WSA883X_EN,                         0x00},
+	{WSA883X_OVERRIDE1,                  0x00},
+	{WSA883X_OVERRIDE2,                  0x08},
+	{WSA883X_VSENSE1,                    0xD3},
+	{WSA883X_ISENSE1,                    0xD4},
+	{WSA883X_ISENSE2,                    0x20},
+	{WSA883X_ISENSE_CAL,                 0x00},
+	{WSA883X_MISC,                       0x00},
+	{WSA883X_ADC_0,                      0x00},
+	{WSA883X_ADC_1,                      0x00},
+	{WSA883X_ADC_2,                      0x00},
+	{WSA883X_ADC_3,                      0x00},
+	{WSA883X_ADC_4,                      0x45},
+	{WSA883X_ADC_5,                      0x20},
+	{WSA883X_ADC_6,                      0x10},
+	{WSA883X_ADC_7,                      0x00},
+	{WSA883X_STATUS,                     0x00},
+	{WSA883X_DAC_CTRL_REG,               0x41},
+	{WSA883X_DAC_EN_DEBUG_REG,           0x00},
+	{WSA883X_DAC_OPAMP_BIAS1_REG,        0x48},
+	{WSA883X_DAC_OPAMP_BIAS2_REG,        0x48},
+	{WSA883X_DAC_VCM_CTRL_REG,           0x0B},
+	{WSA883X_DAC_VOLTAGE_CTRL_REG,       0x05},
+	{WSA883X_ATEST1_REG,                 0x00},
+	{WSA883X_ATEST2_REG,                 0x00},
+	{WSA883X_SPKR_TOP_BIAS_REG1,         0x4A},
+	{WSA883X_SPKR_TOP_BIAS_REG2,         0x65},
+	{WSA883X_SPKR_TOP_BIAS_REG3,         0x55},
+	{WSA883X_SPKR_TOP_BIAS_REG4,         0xA9},
+	{WSA883X_SPKR_CLIP_DET_REG,          0x00},
+	{WSA883X_SPKR_DRV_LF_BLK_EN,         0x0F},
+	{WSA883X_SPKR_DRV_LF_EN,             0x0A},
+	{WSA883X_SPKR_DRV_LF_MASK_DCC_CTL,   0x00},
+	{WSA883X_SPKR_DRV_LF_MISC_CTL,       0x32},
+	{WSA883X_SPKR_DRV_LF_REG_GAIN,       0x00},
+	{WSA883X_SPKR_DRV_LF_OS_CAL_CTL1,    0x90},
+	{WSA883X_SPKR_DRV_LF_OS_CAL_CTL,     0x00},
+	{WSA883X_SPKR_PWM_CLK_CTL,           0x00},
+	{WSA883X_SPKR_PDRV_HS_CTL,           0x50},
+	{WSA883X_SPKR_PDRV_LS_CTL,           0x48},
+	{WSA883X_SPKR_PWRSTG_DBG,            0x00},
+	{WSA883X_SPKR_OCP_CTL,               0x00},
+	{WSA883X_SPKR_BBM_CTL,               0x90},
+	{WSA883X_PA_STATUS0,                 0x00},
+	{WSA883X_PA_STATUS1,                 0x00},
+	{WSA883X_PA_STATUS2,                 0x00},
+	{WSA883X_EN_CTRL,                    0x54},
+	{WSA883X_CURRENT_LIMIT,              0x90},
+	{WSA883X_IBIAS1,                     0x00},
+	{WSA883X_IBIAS2,                     0x00},
+	{WSA883X_IBIAS3,                     0x00},
+	{WSA883X_LDO_PROG,                   0x2A},
+	{WSA883X_STABILITY_CTRL1,            0x8E},
+	{WSA883X_STABILITY_CTRL2,            0x00},
+	{WSA883X_PWRSTAGE_CTRL1,             0x00},
+	{WSA883X_PWRSTAGE_CTRL2,             0x40},
+	{WSA883X_UVLO,                       0xE9},
+	{WSA883X_SEQUENCE_CTRL,              0x11},
+	{WSA883X_ZX_CTRL_1,                  0xF0},
+	{WSA883X_ZX_CTRL_2,                  0x06},
+	{WSA883X_MISC1,                      0x02},
+	{WSA883X_MISC2,                      0x81},
+	{WSA883X_GMAMP_SUP1,                 0x84},
+	{WSA883X_PWRSTAGE_CTRL3,             0x14},
+	{WSA883X_PRSTAGE_CTRL4,              0x5F},
+	{WSA883X_SPARE1,                     0x00},
+	{WSA883X_PON_CTL_0,                  0xE3},
+	{WSA883X_PON_CLT_1,                  0x70},
+	{WSA883X_PON_CTL_2,                  0x00},
+	{WSA883X_PON_CTL_3,                  0x00},
+	{WSA883X_PON_CTL_4,                  0x00},
+	{WSA883X_CKWD_CTL_0,                 0x34},
+	{WSA883X_CKWD_CTL_1,                 0x80},
+	{WSA883X_CKWD_CTL_2,                 0x00},
+	{WSA883X_CKSK_CTL_0,                 0x0A},
+	{WSA883X_TEST_0,                     0x00},
+	{WSA883X_TEST_1,                     0x00},
+	{WSA883X_STATUS_0,                   0x00},
+	{WSA883X_STATUS_1,                   0x00},
+	{WSA883X_PAGE_REGISTER,              0x00},
+	{WSA883X_CHIP_ID0,                   0x00},
+	{WSA883X_CHIP_ID1,                   0x00},
+	{WSA883X_CHIP_ID2,                   0x02},
+	{WSA883X_CHIP_ID3,                   0x02},
+	{WSA883X_BUS_ID,                     0x00},
+	{WSA883X_CDC_RST_CTL,                0x01},
+	{WSA883X_TOP_CLK_CFG,                0x00},
+	{WSA883X_CDC_PATH_MODE,              0x00},
+	{WSA883X_CDC_CLK_CTL,                0xFF},
+	{WSA883X_SWR_RESET_EN,               0x00},
+	{WSA883X_PA_FSM_CTL,                 0x00},
+	{WSA883X_PA_FSM_TIMER0,              0x80},
+	{WSA883X_PA_FSM_TIMER1,              0x80},
+	{WSA883X_PA_FSM_STA,                 0x00},
+	{WSA883X_PA_FSM_ERR_COND,            0x00},
+	{WSA883X_PA_FSM_MSK,                 0x00},
+	{WSA883X_PA_FSM_BYP,                 0x00},
+	{WSA883X_TADC_VALUE_CTL,             0x03},
+	{WSA883X_TEMP_DETECT_CTL,            0x01},
+	{WSA883X_TEMP_MSB,                   0x00},
+	{WSA883X_TEMP_LSB,                   0x00},
+	{WSA883X_TEMP_CONFIG0,               0x00},
+	{WSA883X_TEMP_CONFIG1,               0x00},
+	{WSA883X_VBAT_ADC_FLT_CTL,           0x00},
+	{WSA883X_VBAT_DIN_MSB,               0x00},
+	{WSA883X_VBAT_DIN_LSB,               0x00},
+	{WSA883X_VBAT_DOUT,                  0x00},
+	{WSA883X_SDM_PDM9_LSB,               0x00},
+	{WSA883X_SDM_PDM9_MSB,               0x00},
+	{WSA883X_CDC_RX_CTL,                 0xFE},
+	{WSA883X_CDC_SPK_DSM_A1_0,           0x00},
+	{WSA883X_CDC_SPK_DSM_A1_1,           0x01},
+	{WSA883X_CDC_SPK_DSM_A2_0,           0x96},
+	{WSA883X_CDC_SPK_DSM_A2_1,           0x09},
+	{WSA883X_CDC_SPK_DSM_A3_0,           0xAB},
+	{WSA883X_CDC_SPK_DSM_A3_1,           0x05},
+	{WSA883X_CDC_SPK_DSM_A4_0,           0x1C},
+	{WSA883X_CDC_SPK_DSM_A4_1,           0x02},
+	{WSA883X_CDC_SPK_DSM_A5_0,           0x17},
+	{WSA883X_CDC_SPK_DSM_A5_1,           0x02},
+	{WSA883X_CDC_SPK_DSM_A6_0,           0xAA},
+	{WSA883X_CDC_SPK_DSM_A7_0,           0xE3},
+	{WSA883X_CDC_SPK_DSM_C_0,            0x69},
+	{WSA883X_CDC_SPK_DSM_C_1,            0x54},
+	{WSA883X_CDC_SPK_DSM_C_2,            0x02},
+	{WSA883X_CDC_SPK_DSM_C_3,            0x15},
+	{WSA883X_CDC_SPK_DSM_R1,             0xA4},
+	{WSA883X_CDC_SPK_DSM_R2,             0xB5},
+	{WSA883X_CDC_SPK_DSM_R3,             0x86},
+	{WSA883X_CDC_SPK_DSM_R4,             0x85},
+	{WSA883X_CDC_SPK_DSM_R5,             0xAA},
+	{WSA883X_CDC_SPK_DSM_R6,             0xE2},
+	{WSA883X_CDC_SPK_DSM_R7,             0x62},
+	{WSA883X_CDC_SPK_GAIN_PDM_0,         0x00},
+	{WSA883X_CDC_SPK_GAIN_PDM_1,         0xFC},
+	{WSA883X_CDC_SPK_GAIN_PDM_2,         0x05},
+	{WSA883X_PDM_WD_CTL,                 0x00},
+	{WSA883X_DEM_BYPASS_DATA0,           0x00},
+	{WSA883X_DEM_BYPASS_DATA1,           0x00},
+	{WSA883X_DEM_BYPASS_DATA2,           0x00},
+	{WSA883X_DEM_BYPASS_DATA3,           0x00},
+	{WSA883X_WAVG_CTL,                   0x06},
+	{WSA883X_WAVG_LRA_PER_0,             0xD1},
+	{WSA883X_WAVG_LRA_PER_1,             0x00},
+	{WSA883X_WAVG_DELTA_THETA_0,         0xE6},
+	{WSA883X_WAVG_DELTA_THETA_1,         0x04},
+	{WSA883X_WAVG_DIRECT_AMP_0,          0x50},
+	{WSA883X_WAVG_DIRECT_AMP_1,          0x00},
+	{WSA883X_WAVG_PTRN_AMP0_0,           0x50},
+	{WSA883X_WAVG_PTRN_AMP0_1,           0x00},
+	{WSA883X_WAVG_PTRN_AMP1_0,           0x50},
+	{WSA883X_WAVG_PTRN_AMP1_1,           0x00},
+	{WSA883X_WAVG_PTRN_AMP2_0,           0x50},
+	{WSA883X_WAVG_PTRN_AMP2_1,           0x00},
+	{WSA883X_WAVG_PTRN_AMP3_0,           0x50},
+	{WSA883X_WAVG_PTRN_AMP3_1,           0x00},
+	{WSA883X_WAVG_PTRN_AMP4_0,           0x50},
+	{WSA883X_WAVG_PTRN_AMP4_1,           0x00},
+	{WSA883X_WAVG_PTRN_AMP5_0,           0x50},
+	{WSA883X_WAVG_PTRN_AMP5_1,           0x00},
+	{WSA883X_WAVG_PTRN_AMP6_0,           0x50},
+	{WSA883X_WAVG_PTRN_AMP6_1,           0x00},
+	{WSA883X_WAVG_PTRN_AMP7_0,           0x50},
+	{WSA883X_WAVG_PTRN_AMP7_1,           0x00},
+	{WSA883X_WAVG_PER_0_1,               0x88},
+	{WSA883X_WAVG_PER_2_3,               0x88},
+	{WSA883X_WAVG_PER_4_5,               0x88},
+	{WSA883X_WAVG_PER_6_7,               0x88},
+	{WSA883X_DRE_CTL_0,                  0x30},
+	{WSA883X_DRE_CTL_1,                  0x20},
+	{WSA883X_CLSH_CTL_0,                 0x37},
+	{WSA883X_CLSH_CTL_1,                 0x81},
+	{WSA883X_CLSH_V_HD_PA,               0x0F},
+	{WSA883X_CLSH_V_PA_MIN,              0x00},
+	{WSA883X_CLSH_OVRD_VAL,              0x00},
+	{WSA883X_CLSH_HARD_MAX,              0xFF},
+	{WSA883X_CLSH_SOFT_MAX,              0xFF},
+	{WSA883X_CLSH_SIG_DP,                0x00},
+	{WSA883X_TAGC_CTL,                   0x10},
+	{WSA883X_TAGC_TIME,                  0x20},
+	{WSA883X_TAGC_E2E_GAIN,              0x02},
+	{WSA883X_TAGC_FORCE_VAL,             0x00},
+	{WSA883X_VAGC_CTL,                   0x00},
+	{WSA883X_VAGC_TIME,                  0x08},
+	{WSA883X_VAGC_ATTN_LVL_1_2,          0x21},
+	{WSA883X_VAGC_ATTN_LVL_3,            0x03},
+	{WSA883X_INTR_MODE,                  0x00},
+	{WSA883X_INTR_MASK0,                 0x1B},
+	{WSA883X_INTR_MASK1,                 0x03},
+	{WSA883X_INTR_STATUS0,               0x00},
+	{WSA883X_INTR_STATUS1,               0x00},
+	{WSA883X_INTR_CLEAR0,                0x00},
+	{WSA883X_INTR_CLEAR1,                0x03},
+	{WSA883X_INTR_LEVEL0,                0x00},
+	{WSA883X_INTR_LEVEL1,                0x03},
+	{WSA883X_INTR_SET0,                  0x00},
+	{WSA883X_INTR_SET1,                  0x03},
+	{WSA883X_INTR_TEST0,                 0x00},
+	{WSA883X_INTR_TEST1,                 0x03},
+	{WSA883X_OTP_CTRL0,                  0x00},
+	{WSA883X_OTP_CTRL1,                  0x00},
+	{WSA883X_HDRIVE_CTL_GROUP1,          0x00},
+	{WSA883X_PIN_CTL,                    0x04},
+	{WSA883X_PIN_CTL_OE,                 0x00},
+	{WSA883X_PIN_WDATA_IOPAD,            0x00},
+	{WSA883X_PIN_STATUS,                 0x00},
+	{WSA883X_I2C_SLAVE_CTL,              0x00},
+	{WSA883X_PDM_TEST_MODE,              0x00},
+	{WSA883X_ATE_TEST_MODE,              0x00},
+	{WSA883X_DRE_TEST,                   0x00},
+	{WSA883X_DIG_DEBUG_MODE,             0x00},
+	{WSA883X_DIG_DEBUG_SEL,              0x00},
+	{WSA883X_DIG_DEBUG_EN,               0x00},
+	{WSA883X_SWR_HM_TEST0,               0x08},
+	{WSA883X_SWR_HM_TEST1,               0x00},
+	{WSA883X_SWR_PAD_CTL,                0x45},
+	{WSA883X_TEMP_DETECT_DBG_CTL,        0x00},
+	{WSA883X_TEMP_DEBUG_MSB,             0x00},
+	{WSA883X_TEMP_DEBUG_LSB,             0x00},
+	{WSA883X_SAMPLE_EDGE_SEL,            0x7F},
+	{WSA883X_TEST_MODE_CTL,              0x00},
+	{WSA883X_IOPAD_CTL,                  0x00},
+	{WSA883X_SPARE_0,                    0x00},
+	{WSA883X_SPARE_1,                    0x00},
+	{WSA883X_SPARE_2,                    0x00},
+	{WSA883X_SCODE,                      0x00},
+	{WSA883X_PAGE_REGISTER,              0x00},
+	{WSA883X_OTP_REG_0,                  0x01},
+	{WSA883X_OTP_REG_1,                  0xFF},
+	{WSA883X_OTP_REG_2,                  0xC0},
+	{WSA883X_OTP_REG_3,                  0xFF},
+	{WSA883X_OTP_REG_4,                  0xC0},
+	{WSA883X_OTP_REG_5,                  0xFF},
+	{WSA883X_OTP_REG_6,                  0xFF},
+	{WSA883X_OTP_REG_7,                  0xFF},
+	{WSA883X_OTP_REG_8,                  0xFF},
+	{WSA883X_OTP_REG_9,                  0xFF},
+	{WSA883X_OTP_REG_10,                 0xFF},
+	{WSA883X_OTP_REG_11,                 0xFF},
+	{WSA883X_OTP_REG_12,                 0xFF},
+	{WSA883X_OTP_REG_13,                 0xFF},
+	{WSA883X_OTP_REG_14,                 0xFF},
+	{WSA883X_OTP_REG_15,                 0xFF},
+	{WSA883X_OTP_REG_16,                 0xFF},
+	{WSA883X_OTP_REG_17,                 0xFF},
+	{WSA883X_OTP_REG_18,                 0xFF},
+	{WSA883X_OTP_REG_19,                 0xFF},
+	{WSA883X_OTP_REG_20,                 0xFF},
+	{WSA883X_OTP_REG_21,                 0xFF},
+	{WSA883X_OTP_REG_22,                 0xFF},
+	{WSA883X_OTP_REG_23,                 0xFF},
+	{WSA883X_OTP_REG_24,                 0x03},
+	{WSA883X_OTP_REG_25,                 0x01},
+	{WSA883X_OTP_REG_26,                 0x03},
+	{WSA883X_OTP_REG_27,                 0x11},
+	{WSA883X_OTP_REG_28,                 0x3F},
+	{WSA883X_OTP_REG_29,                 0x3F},
+	{WSA883X_OTP_REG_30,                 0x01},
+	{WSA883X_OTP_REG_31,                 0x01},
+	{WSA883X_OTP_REG_SCODE,              0x00},
+	{WSA883X_OTP_REG_63,                 0x40},
+	{WSA883X_EMEM_0,                     0x00},
+	{WSA883X_EMEM_1,                     0x00},
+	{WSA883X_EMEM_2,                     0x00},
+	{WSA883X_EMEM_3,                     0x00},
+	{WSA883X_EMEM_4,                     0x00},
+	{WSA883X_EMEM_5,                     0x00},
+	{WSA883X_EMEM_6,                     0x00},
+	{WSA883X_EMEM_7,                     0x00},
+	{WSA883X_EMEM_8,                     0x00},
+	{WSA883X_EMEM_9,                     0x00},
+	{WSA883X_EMEM_10,                    0x00},
+	{WSA883X_EMEM_11,                    0x00},
+	{WSA883X_EMEM_12,                    0x00},
+	{WSA883X_EMEM_13,                    0x00},
+	{WSA883X_EMEM_14,                    0x00},
+	{WSA883X_EMEM_15,                    0x00},
+	{WSA883X_EMEM_16,                    0x00},
+	{WSA883X_EMEM_17,                    0x00},
+	{WSA883X_EMEM_18,                    0x00},
+	{WSA883X_EMEM_19,                    0x00},
+	{WSA883X_EMEM_20,                    0x00},
+	{WSA883X_EMEM_21,                    0x00},
+	{WSA883X_EMEM_22,                    0x00},
+	{WSA883X_EMEM_23,                    0x00},
+	{WSA883X_EMEM_24,                    0x00},
+	{WSA883X_EMEM_25,                    0x00},
+	{WSA883X_EMEM_26,                    0x00},
+	{WSA883X_EMEM_27,                    0x00},
+	{WSA883X_EMEM_28,                    0x00},
+	{WSA883X_EMEM_29,                    0x00},
+	{WSA883X_EMEM_30,                    0x00},
+	{WSA883X_EMEM_31,                    0x00},
+	{WSA883X_EMEM_32,                    0x00},
+	{WSA883X_EMEM_33,                    0x00},
+	{WSA883X_EMEM_34,                    0x00},
+	{WSA883X_EMEM_35,                    0x00},
+	{WSA883X_EMEM_36,                    0x00},
+	{WSA883X_EMEM_37,                    0x00},
+	{WSA883X_EMEM_38,                    0x00},
+	{WSA883X_EMEM_39,                    0x00},
+	{WSA883X_EMEM_40,                    0x00},
+	{WSA883X_EMEM_41,                    0x00},
+	{WSA883X_EMEM_42,                    0x00},
+	{WSA883X_EMEM_43,                    0x00},
+	{WSA883X_EMEM_44,                    0x00},
+	{WSA883X_EMEM_45,                    0x00},
+	{WSA883X_EMEM_46,                    0x00},
+	{WSA883X_EMEM_47,                    0x00},
+	{WSA883X_EMEM_48,                    0x00},
+	{WSA883X_EMEM_49,                    0x00},
+	{WSA883X_EMEM_50,                    0x00},
+	{WSA883X_EMEM_51,                    0x00},
+	{WSA883X_EMEM_52,                    0x00},
+	{WSA883X_EMEM_53,                    0x00},
+	{WSA883X_EMEM_54,                    0x00},
+	{WSA883X_EMEM_55,                    0x00},
+	{WSA883X_EMEM_56,                    0x00},
+	{WSA883X_EMEM_57,                    0x00},
+	{WSA883X_EMEM_58,                    0x00},
+	{WSA883X_EMEM_59,                    0x00},
+	{WSA883X_EMEM_60,                    0x00},
+	{WSA883X_EMEM_61,                    0x00},
+	{WSA883X_EMEM_62,                    0x00},
+	{WSA883X_EMEM_63,                    0x00},
+};
+
+static bool wsa883x_readable_register(struct device *dev, unsigned int reg)
+{
+	if (reg <= WSA883X_BASE)
+		return 0;
+
+	return wsa883x_reg_access[WSA883X_REG(reg)] & RD_REG;
+}
+
+static bool wsa883x_writeable_register(struct device *dev, unsigned int reg)
+{
+	if (reg <= WSA883X_BASE)
+		return 0;
+
+	return wsa883x_reg_access[WSA883X_REG(reg)] & WR_REG;
+}
+
+static bool wsa883x_volatile_register(struct device *dev, unsigned int reg)
+{
+	if (reg <= WSA883X_BASE)
+		return 0;
+
+	return ((wsa883x_reg_access[WSA883X_REG(reg)] & RD_REG) &&
+		!(wsa883x_reg_access[WSA883X_REG(reg)] & WR_REG));
+}
+
+struct regmap_config wsa881x_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wsa883x_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wsa883x_defaults),
+	.max_register = WSA883X_MAX_REGISTER,
+	.volatile_reg = wsa883x_volatile_register,
+	.readable_reg = wsa883x_readable_register,
+	.writeable_reg = wsa883x_writeable_register,
+	.reg_format_endian = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian = REGMAP_ENDIAN_NATIVE,
+	.can_multi_write = true,
+};

+ 350 - 0
asoc/codecs/wsa883x/wsa883x-tables.c

@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include "wsa883x-registers.h"
+
+const u8 wsa883x_reg_readable[WSA883X_NUM_REGISTERS] = {
+	[WSA883X_REG(WSA883X_REF_CTRL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TEST_CTL_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_BIAS_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OP_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_IREF_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ISENS_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CLK_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TEST_CTL_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_BIAS_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ADC_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DOUT_MSB)] = RD_REG,
+	[WSA883X_REG(WSA883X_DOUT_LSB)] = RD_REG,
+	[WSA883X_REG(WSA883X_VBAT_SNS)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ITRIM_CODE)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EN)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OVERRIDE1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OVERRIDE2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_VSENSE1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ISENSE1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ISENSE2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ISENSE_CAL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_MISC)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ADC_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ADC_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ADC_2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ADC_3)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ADC_4)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ADC_5)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ADC_6)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ADC_7)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_STATUS)] = RD_REG,
+	[WSA883X_REG(WSA883X_DAC_CTRL_REG)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DAC_EN_DEBUG_REG)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DAC_OPAMP_BIAS1_REG)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DAC_OPAMP_BIAS2_REG)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DAC_VCM_CTRL_REG)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DAC_VOLTAGE_CTRL_REG)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ATEST1_REG)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ATEST2_REG)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_TOP_BIAS_REG1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_TOP_BIAS_REG2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_TOP_BIAS_REG3)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_TOP_BIAS_REG4)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_CLIP_DET_REG)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_DRV_LF_BLK_EN)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_DRV_LF_EN)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_DRV_LF_MASK_DCC_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_DRV_LF_MISC_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_DRV_LF_REG_GAIN)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_DRV_LF_OS_CAL_CTL1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_DRV_LF_OS_CAL_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_PWM_CLK_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_PDRV_HS_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_PDRV_LS_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_PWRSTG_DBG)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_OCP_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPKR_BBM_CTL)] = RD_REG,
+	[WSA883X_REG(WSA883X_PA_STATUS0)] = RD_REG,
+	[WSA883X_REG(WSA883X_PA_STATUS1)] = RD_REG,
+	[WSA883X_REG(WSA883X_PA_STATUS2)] = RD_REG,
+	[WSA883X_REG(WSA883X_EN_CTRL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CURRENT_LIMIT)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_IBIAS1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_IBIAS2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_IBIAS3)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_LDO_PROG)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_STABILITY_CTRL1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_STABILITY_CTRL2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PWRSTAGE_CTRL1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PWRSTAGE_CTRL2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_UVLO)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SEQUENCE_CTRL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ZX_CTRL_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ZX_CTRL_2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_MISC1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_MISC2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_GMAMP_SUP1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PWRSTAGE_CTRL3)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PRSTAGE_CTRL4)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPARE1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PON_CTL_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PON_CLT_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PON_CTL_2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PON_CTL_3)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PON_CTL_4)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CKWD_CTL_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CKWD_CTL_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CKWD_CTL_2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CKSK_CTL_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TEST_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TEST_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_STATUS_0)] = RD_REG,
+	[WSA883X_REG(WSA883X_STATUS_1)] = RD_REG,
+	[WSA883X_REG(WSA883X_PAGE_REGISTER)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CHIP_ID0)] = RD_REG,
+	[WSA883X_REG(WSA883X_CHIP_ID1)] = RD_REG,
+	[WSA883X_REG(WSA883X_CHIP_ID2)] = RD_REG,
+	[WSA883X_REG(WSA883X_CHIP_ID3)] = RD_REG,
+	[WSA883X_REG(WSA883X_BUS_ID)] = RD_REG,
+	[WSA883X_REG(WSA883X_CDC_RST_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TOP_CLK_CFG)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_PATH_MODE)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_CLK_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SWR_RESET_EN)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PA_FSM_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PA_FSM_TIMER0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PA_FSM_TIMER1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PA_FSM_STA)] = RD_REG,
+	[WSA883X_REG(WSA883X_PA_FSM_ERR_COND)] = RD_REG,
+	[WSA883X_REG(WSA883X_PA_FSM_MSK)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PA_FSM_BYP)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TADC_VALUE_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TEMP_DETECT_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TEMP_MSB)] = RD_REG,
+	[WSA883X_REG(WSA883X_TEMP_LSB)] = RD_REG,
+	[WSA883X_REG(WSA883X_TEMP_CONFIG0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TEMP_CONFIG1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_VBAT_ADC_FLT_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_VBAT_DIN_MSB)] = RD_REG,
+	[WSA883X_REG(WSA883X_VBAT_DIN_LSB)] = RD_REG,
+	[WSA883X_REG(WSA883X_VBAT_DOUT)] = RD_REG,
+	[WSA883X_REG(WSA883X_SDM_PDM9_LSB)] = RD_REG,
+	[WSA883X_REG(WSA883X_SDM_PDM9_MSB)] = RD_REG,
+	[WSA883X_REG(WSA883X_CDC_RX_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_A1_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_A1_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_A2_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_A2_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_A3_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_A3_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_A4_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_A4_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_A5_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_A5_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_A6_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_A7_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_C_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_C_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_C_2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_C_3)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_R1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_R2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_R3)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_R4)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_R5)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_R6)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_DSM_R7)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_GAIN_PDM_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_GAIN_PDM_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CDC_SPK_GAIN_PDM_2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PDM_WD_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DEM_BYPASS_DATA0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DEM_BYPASS_DATA1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DEM_BYPASS_DATA2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DEM_BYPASS_DATA3)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_LRA_PER_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_LRA_PER_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_DELTA_THETA_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_DELTA_THETA_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_DIRECT_AMP_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_DIRECT_AMP_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP0_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP0_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP1_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP1_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP2_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP2_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP3_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP3_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP4_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP4_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP5_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP5_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP6_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP6_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP7_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PTRN_AMP7_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PER_0_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PER_2_3)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PER_4_5)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_WAVG_PER_6_7)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DRE_CTL_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DRE_CTL_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CLSH_CTL_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CLSH_CTL_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CLSH_V_HD_PA)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CLSH_V_PA_MIN)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CLSH_OVRD_VAL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CLSH_HARD_MAX)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CLSH_SOFT_MAX)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_CLSH_SIG_DP)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TAGC_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TAGC_TIME)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TAGC_E2E_GAIN)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TAGC_FORCE_VAL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_VAGC_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_VAGC_TIME)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_VAGC_ATTN_LVL_1_2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_VAGC_ATTN_LVL_3)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_INTR_MODE)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_INTR_MASK0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_INTR_MASK1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_INTR_STATUS0)] = RD_REG,
+	[WSA883X_REG(WSA883X_INTR_STATUS1)] = RD_REG,
+	[WSA883X_REG(WSA883X_INTR_CLEAR0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_INTR_CLEAR1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_INTR_LEVEL0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_INTR_LEVEL1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_INTR_SET0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_INTR_SET1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_INTR_TEST0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_INTR_TEST1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_CTRL0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_CTRL1)] = RD_REG,
+	[WSA883X_REG(WSA883X_HDRIVE_CTL_GROUP1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PIN_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PIN_CTL_OE)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PIN_WDATA_IOPAD)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PIN_STATUS)] = RD_REG,
+	[WSA883X_REG(WSA883X_I2C_SLAVE_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PDM_TEST_MODE)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_ATE_TEST_MODE)] = RD_REG,
+	[WSA883X_REG(WSA883X_DRE_TEST)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DIG_DEBUG_MODE)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DIG_DEBUG_SEL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_DIG_DEBUG_EN)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SWR_HM_TEST0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SWR_HM_TEST1)] = RD_REG,
+	[WSA883X_REG(WSA883X_SWR_PAD_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TEMP_DETECT_DBG_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TEMP_DEBUG_MSB)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TEMP_DEBUG_LSB)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SAMPLE_EDGE_SEL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_TEST_MODE_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_IOPAD_CTL)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPARE_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPARE_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SPARE_2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_SCODE)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_PAGE_REGISTER)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_3)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_4)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_5)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_6)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_7)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_8)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_9)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_10)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_11)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_12)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_13)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_14)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_15)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_16)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_17)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_18)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_19)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_20)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_21)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_22)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_23)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_24)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_25)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_26)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_27)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_28)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_29)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_30)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_31)] = RD_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_SCODE)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_OTP_REG_63)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_0)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_1)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_2)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_3)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_4)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_5)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_6)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_7)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_8)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_9)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_10)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_11)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_12)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_13)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_14)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_15)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_16)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_17)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_18)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_19)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_20)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_21)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_22)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_23)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_24)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_25)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_26)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_27)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_28)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_29)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_30)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_31)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_32)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_33)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_34)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_35)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_36)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_37)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_38)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_39)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_40)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_41)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_42)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_43)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_44)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_45)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_46)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_47)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_48)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_49)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_50)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_51)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_52)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_53)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_54)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_55)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_56)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_57)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_58)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_59)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_60)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_61)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_62)] = RD_WR_REG,
+	[WSA883X_REG(WSA883X_EMEM_63)] = RD_WR_REG,
+};

+ 187 - 0
asoc/codecs/wsa883x/wsa883x-temp-sensor.c

@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2015, 2017-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/suspend.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/thermal.h>
+#include <sound/soc.h>
+#include "wsa883x-temp-sensor.h"
+
+#define T1_TEMP -10
+#define T2_TEMP 150
+#define LOW_TEMP_THRESHOLD 5
+#define HIGH_TEMP_THRESHOLD 45
+#define TEMP_INVALID	0xFFFF
+#define WSA883X_TEMP_RETRY 3
+/*
+ * wsa883x_get_temp - get wsa temperature
+ * @thermal: thermal zone device
+ * @temp: temperature value
+ *
+ * Get the temperature of wsa883x.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int wsa883x_get_temp(struct thermal_zone_device *thermal,
+		     int *temp)
+{
+	struct wsa883x_tz_priv *pdata;
+	struct snd_soc_component *component;
+	struct wsa_temp_register reg;
+	int dmeas, d1, d2;
+	int ret = 0;
+	int temp_val;
+	int t1 = T1_TEMP;
+	int t2 = T2_TEMP;
+	u8 retry = WSA883X_TEMP_RETRY;
+
+	if (!thermal)
+		return -EINVAL;
+
+	if (thermal->devdata) {
+		pdata = thermal->devdata;
+		if (pdata->component) {
+			component = pdata->component;
+		} else {
+			pr_err("%s: codec is NULL\n", __func__);
+			return -EINVAL;
+		}
+	} else {
+		pr_err("%s: pdata is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (atomic_cmpxchg(&pdata->is_suspend_spk, 1, 0)) {
+		/*
+		 * get_temp query happens as part of POST_PM_SUSPEND
+		 * from thermal core. To avoid calls to slimbus
+		 * as part of this thermal query, return default temp
+		 * and reset the suspend flag.
+		 */
+		if (!pdata->t0_init) {
+			if (temp)
+				*temp = pdata->curr_temp;
+			return 0;
+		}
+	}
+
+temp_retry:
+	if (pdata->wsa_temp_reg_read) {
+		ret = pdata->wsa_temp_reg_read(component, &reg);
+		if (ret) {
+			pr_err("%s: temp read failed: %d, current temp: %d\n",
+				__func__, ret, pdata->curr_temp);
+			if (temp)
+				*temp = pdata->curr_temp;
+			return 0;
+		}
+	} else {
+		pr_err("%s: wsa_temp_reg_read is NULL\n", __func__);
+		return -EINVAL;
+	}
+	/*
+	 * Temperature register values are expected to be in the
+	 * following range.
+	 * d1_msb  = 68 - 92 and d1_lsb  = 0, 64, 128, 192
+	 * d2_msb  = 185 -218 and  d2_lsb  = 0, 64, 128, 192
+	 */
+	if ((reg.d1_msb < 68 || reg.d1_msb > 92) ||
+	    (!(reg.d1_lsb == 0 || reg.d1_lsb == 64 || reg.d1_lsb == 128 ||
+		reg.d1_lsb == 192)) ||
+	    (reg.d2_msb < 185 || reg.d2_msb > 218) ||
+	    (!(reg.d2_lsb == 0 || reg.d2_lsb == 64 || reg.d2_lsb == 128 ||
+		reg.d2_lsb == 192))) {
+		printk_ratelimited("%s: Temperature registers[%d %d %d %d] are out of range\n",
+				   __func__, reg.d1_msb, reg.d1_lsb, reg.d2_msb,
+				   reg.d2_lsb);
+	}
+	dmeas = ((reg.dmeas_msb << 0x8) | reg.dmeas_lsb) >> 0x6;
+	d1 = ((reg.d1_msb << 0x8) | reg.d1_lsb) >> 0x6;
+	d2 = ((reg.d2_msb << 0x8) | reg.d2_lsb) >> 0x6;
+
+	if (d1 == d2)
+		temp_val = TEMP_INVALID;
+	else
+		temp_val = t1 + (((dmeas - d1) * (t2 - t1))/(d2 - d1));
+
+	if (temp_val <= LOW_TEMP_THRESHOLD ||
+		temp_val >= HIGH_TEMP_THRESHOLD) {
+		pr_debug("%s: T0: %d is out of range[%d, %d]\n", __func__,
+			 temp_val, LOW_TEMP_THRESHOLD, HIGH_TEMP_THRESHOLD);
+		if (retry--) {
+			msleep(20);
+			goto temp_retry;
+		}
+	}
+	pdata->curr_temp = temp_val;
+
+	if (temp)
+		*temp = temp_val;
+	pr_debug("%s: t0 measured: %d dmeas = %d, d1 = %d, d2 = %d\n",
+		  __func__, temp_val, dmeas, d1, d2);
+	return ret;
+}
+EXPORT_SYMBOL(wsa883x_get_temp);
+
+static struct thermal_zone_device_ops wsa883x_thermal_ops = {
+	.get_temp = wsa883x_get_temp,
+};
+
+
+static int wsa883x_pm_notify(struct notifier_block *nb,
+				unsigned long mode, void *_unused)
+{
+	struct wsa883x_tz_priv *pdata =
+			container_of(nb, struct wsa883x_tz_priv, pm_nb);
+
+	switch (mode) {
+	case PM_SUSPEND_PREPARE:
+		atomic_set(&pdata->is_suspend_spk, 1);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+int wsa883x_init_thermal(struct wsa883x_tz_priv *tz_pdata)
+{
+	struct thermal_zone_device *tz_dev;
+
+	if (tz_pdata == NULL) {
+		pr_err("%s: thermal pdata is NULL\n", __func__);
+		return -EINVAL;
+	}
+	/* Register with the thermal zone */
+	tz_dev = thermal_zone_device_register(tz_pdata->name,
+				0, 0, tz_pdata,
+				&wsa883x_thermal_ops, NULL, 0, 0);
+	if (IS_ERR(tz_dev)) {
+		pr_err("%s: thermal device register failed.\n", __func__);
+		return -EINVAL;
+	}
+	tz_pdata->tz_dev = tz_dev;
+	tz_pdata->pm_nb.notifier_call = wsa883x_pm_notify;
+	register_pm_notifier(&tz_pdata->pm_nb);
+	atomic_set(&tz_pdata->is_suspend_spk, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL(wsa883x_init_thermal);
+
+void wsa883x_deinit_thermal(struct thermal_zone_device *tz_dev)
+{
+	struct wsa883x_tz_priv *pdata;
+
+	if (tz_dev && tz_dev->devdata) {
+		pdata = tz_dev->devdata;
+		if (pdata)
+			unregister_pm_notifier(&pdata->pm_nb);
+	}
+	if (tz_dev)
+		thermal_zone_device_unregister(tz_dev);
+}
+EXPORT_SYMBOL(wsa883x_deinit_thermal);

+ 35 - 0
asoc/codecs/wsa883x/wsa883x-temp-sensor.h

@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2015, 2018-2019, The Linux Foundation. All rights reserved.
+ */
+#ifndef WSA883X_TEMP_SENSOR_H
+#define WSA883X_TEMP_SENSOR_H
+
+#include <linux/thermal.h>
+#include <sound/soc.h>
+
+struct wsa_temp_register {
+	u8 d1_msb;
+	u8 d1_lsb;
+	u8 d2_msb;
+	u8 d2_lsb;
+	u8 dmeas_msb;
+	u8 dmeas_lsb;
+};
+typedef int32_t (*wsa_temp_register_read)(struct snd_soc_component *component,
+					struct wsa_temp_register *wsa_temp_reg);
+struct wsa883x_tz_priv {
+	struct thermal_zone_device *tz_dev;
+	struct snd_soc_component *component;
+	struct wsa_temp_register *wsa_temp_reg;
+	char name[80];
+	wsa_temp_register_read wsa_temp_reg_read;
+	struct notifier_block pm_nb;
+	atomic_t is_suspend_spk;
+	int t0_init;
+	int curr_temp;
+};
+
+int wsa883x_get_temp(struct thermal_zone_device *tz_dev, int *temp);
+int wsa883x_init_thermal(struct wsa883x_tz_priv *tz_pdata);
+void wsa883x_deinit_thermal(struct thermal_zone_device *tz_dev);
+#endif

+ 1176 - 0
asoc/codecs/wsa883x/wsa883x.c

@@ -0,0 +1,1176 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/bitops.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/debugfs.h>
+#include <soc/soundwire.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <asoc/msm-cdc-pinctrl.h>
+#include "wsa883x.h"
+#include "wsa883x-temp-sensor.h"
+#include "internal.h"
+
+#ifdef CONFIG_DEBUG_FS
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int get_parameters(char *buf, u32 *param1, int num_of_par)
+{
+	char *token;
+	int base, cnt;
+
+	token = strsep(&buf, " ");
+	for (cnt = 0; cnt < num_of_par; cnt++) {
+		if (token) {
+			if ((token[1] == 'x') || (token[1] == 'X'))
+				base = 16;
+			else
+				base = 10;
+
+			if (kstrtou32(token, base, &param1[cnt]) != 0)
+				return -EINVAL;
+
+			token = strsep(&buf, " ");
+		} else {
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static bool is_swr_slave_reg_readable(int reg)
+{
+	int ret = true;
+
+	if (((reg > 0x46) && (reg < 0x4A)) ||
+	    ((reg > 0x4A) && (reg < 0x50)) ||
+	    ((reg > 0x55) && (reg < 0xD0)) ||
+	    ((reg > 0xD0) && (reg < 0xE0)) ||
+	    ((reg > 0xE0) && (reg < 0xF0)) ||
+	    ((reg > 0xF0) && (reg < 0x100)) ||
+	    ((reg > 0x105) && (reg < 0x120)) ||
+	    ((reg > 0x205) && (reg < 0x220)) ||
+	    ((reg > 0x305) && (reg < 0x320)) ||
+	    ((reg > 0x405) && (reg < 0x420)) ||
+	    ((reg > 0x128) && (reg < 0x130)) ||
+	    ((reg > 0x228) && (reg < 0x230)) ||
+	    ((reg > 0x328) && (reg < 0x330)) ||
+	    ((reg > 0x428) && (reg < 0x430)) ||
+	    ((reg > 0x138) && (reg < 0x205)) ||
+	    ((reg > 0x238) && (reg < 0x305)) ||
+	    ((reg > 0x338) && (reg < 0x405)) ||
+	    ((reg > 0x405) && (reg < 0xF00)) ||
+	    ((reg > 0xF05) && (reg < 0xF20)) ||
+	    ((reg > 0xF25) && (reg < 0xF30)) ||
+	    ((reg > 0xF35) && (reg < 0x2000)))
+		ret = false;
+
+	return ret;
+}
+
+static ssize_t swr_slave_reg_show(struct swr_device *pdev, char __user *ubuf,
+					size_t count, loff_t *ppos)
+{
+	int i, reg_val, len;
+	ssize_t total = 0;
+	char tmp_buf[SWR_SLV_MAX_BUF_LEN];
+
+	if (!ubuf || !ppos)
+		return 0;
+
+	for (i = (((int) *ppos/BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR);
+		i <= SWR_SLV_MAX_REG_ADDR; i++) {
+		if (!is_swr_slave_reg_readable(i))
+			continue;
+		swr_read(pdev, pdev->dev_num, i, &reg_val, 1);
+		len = snprintf(tmp_buf, 25, "0x%.3x: 0x%.2x\n", i,
+			       (reg_val & 0xFF));
+		if ((total + len) >= count - 1)
+			break;
+		if (copy_to_user((ubuf + total), tmp_buf, len)) {
+			pr_err("%s: fail to copy reg dump\n", __func__);
+			total = -EFAULT;
+			goto copy_err;
+		}
+		total += len;
+		*ppos += len;
+	}
+
+copy_err:
+	*ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE;
+	return total;
+}
+
+static ssize_t codec_debug_dump(struct file *file, char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	struct swr_device *pdev;
+
+	if (!count || !file || !ppos || !ubuf)
+		return -EINVAL;
+
+	pdev = file->private_data;
+	if (!pdev)
+		return -EINVAL;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	return swr_slave_reg_show(pdev, ubuf, count, ppos);
+}
+
+static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char lbuf[SWR_SLV_RD_BUF_LEN];
+	struct swr_device *pdev = NULL;
+	struct wsa883x_priv *wsa883x = NULL;
+
+	if (!count || !file || !ppos || !ubuf)
+		return -EINVAL;
+
+	pdev = file->private_data;
+	if (!pdev)
+		return -EINVAL;
+
+	wsa883x = swr_get_dev_data(pdev);
+	if (!wsa883x)
+		return -EINVAL;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	snprintf(lbuf, sizeof(lbuf), "0x%x\n",
+			(wsa883x->read_data & 0xFF));
+
+	return simple_read_from_buffer(ubuf, count, ppos, lbuf,
+					       strnlen(lbuf, 7));
+}
+
+static ssize_t codec_debug_peek_write(struct file *file,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char lbuf[SWR_SLV_WR_BUF_LEN];
+	int rc = 0;
+	u32 param[5];
+	struct swr_device *pdev = NULL;
+	struct wsa883x_priv *wsa883x = NULL;
+
+	if (!cnt || !file || !ppos || !ubuf)
+		return -EINVAL;
+
+	pdev = file->private_data;
+	if (!pdev)
+		return -EINVAL;
+
+	wsa883x = swr_get_dev_data(pdev);
+	if (!wsa883x)
+		return -EINVAL;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+	rc = get_parameters(lbuf, param, 1);
+	if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0)))
+		return -EINVAL;
+	swr_read(pdev, pdev->dev_num, param[0], &wsa883x->read_data, 1);
+	if (rc == 0)
+		rc = cnt;
+	else
+		pr_err("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static ssize_t codec_debug_write(struct file *file,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char lbuf[SWR_SLV_WR_BUF_LEN];
+	int rc = 0;
+	u32 param[5];
+	struct swr_device *pdev;
+
+	if (!file || !ppos || !ubuf)
+		return -EINVAL;
+
+	pdev = file->private_data;
+	if (!pdev)
+		return -EINVAL;
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+
+	rc = copy_from_user(lbuf, ubuf, cnt);
+	if (rc)
+		return -EFAULT;
+
+	lbuf[cnt] = '\0';
+	rc = get_parameters(lbuf, param, 2);
+	if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) &&
+		(param[1] <= 0xFF) && (rc == 0)))
+		return -EINVAL;
+	swr_write(pdev, pdev->dev_num, param[0], &param[1]);
+	if (rc == 0)
+		rc = cnt;
+	else
+		pr_err("%s: rc = %d\n", __func__, rc);
+
+	return rc;
+}
+
+static const struct file_operations codec_debug_write_ops = {
+	.open = codec_debug_open,
+	.write = codec_debug_write,
+};
+
+static const struct file_operations codec_debug_read_ops = {
+	.open = codec_debug_open,
+	.read = codec_debug_read,
+	.write = codec_debug_peek_write,
+};
+
+static const struct file_operations codec_debug_dump_ops = {
+	.open = codec_debug_open,
+	.read = codec_debug_dump,
+};
+#endif
+
+static const char * const wsa_pa_gain_text[] = {
+	"G_18_DB", "G_16P5_DB", "G_15_DB", "G_13P5_DB", "G_12_DB", "G_10P5_DB",
+	"G_9_DB", "G_7P5_DB", "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB",
+	"G_0_DB"
+};
+
+static const struct soc_enum wsa_pa_gain_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa_pa_gain_text), wsa_pa_gain_text);
+
+static int wsa_pa_gain_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wsa883x->pa_gain;
+
+	dev_dbg(component->dev, "%s: PA gain = 0x%x\n", __func__,
+			wsa883x->pa_gain);
+
+	return 0;
+}
+
+static int wsa_pa_gain_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0]  = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	wsa883x->pa_gain =  ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int wsa883x_get_mute(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wsa883x->pa_mute;
+
+	return 0;
+}
+
+static int wsa883x_set_mute(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(component->dev, "%s: mute current %d, new %d\n",
+		__func__, wsa883x->pa_mute, value);
+
+	wsa883x->pa_mute = value;
+
+	return 0;
+}
+
+static int wsa883x_get_t0_init(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+	struct wsa883x_tz_priv *pdata = &wsa883x->tz_pdata;
+
+	ucontrol->value.integer.value[0] = pdata->t0_init;
+	dev_dbg(component->dev, "%s: t0 init %d\n", __func__, pdata->t0_init);
+
+	return 0;
+}
+
+static int wsa883x_set_t0_init(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+			snd_soc_kcontrol_component(kcontrol);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+	struct wsa883x_tz_priv *pdata = &wsa883x->tz_pdata;
+
+	pdata->t0_init = ucontrol->value.integer.value[0];
+	dev_dbg(component->dev, "%s: t0 init %d\n", __func__, pdata->t0_init);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new wsa_snd_controls[] = {
+	SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum,
+		     wsa_pa_gain_get, wsa_pa_gain_put),
+	SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0,
+		wsa883x_get_mute, wsa883x_set_mute),
+	SOC_SINGLE_EXT("WSA T0 Init", SND_SOC_NOPM, 0, 1, 0,
+		wsa883x_get_t0_init, wsa883x_set_t0_init),
+};
+
+static ssize_t wsa883x_codec_version_read(struct snd_info_entry *entry,
+			       void *file_private_data, struct file *file,
+			       char __user *buf, size_t count, loff_t pos)
+{
+	struct wsa883x_priv *wsa883x;
+	char buffer[WSA883X_VERSION_ENTRY_SIZE];
+	int len = 0;
+
+	wsa883x = (struct wsa883x_priv *) entry->private_data;
+	if (!wsa883x) {
+		pr_err("%s: wsa883x priv is null\n", __func__);
+		return -EINVAL;
+	}
+
+	len = snprintf(buffer, sizeof(buffer), "WSA883X-SOUNDWIRE_1_0\n");
+
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops wsa883x_codec_info_ops = {
+	.read = wsa883x_codec_version_read,
+};
+
+/*
+ * wsa883x_codec_info_create_codec_entry - creates wsa883x module
+ * @codec_root: The parent directory
+ * @component: Codec instance
+ *
+ * Creates wsa883x module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int wsa883x_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+					  struct snd_soc_component *component)
+{
+	struct snd_info_entry *version_entry;
+	struct wsa883x_priv *wsa883x;
+	struct snd_soc_card *card;
+	char name[80];
+
+	if (!codec_root || !component)
+		return -EINVAL;
+
+	wsa883x = snd_soc_component_get_drvdata(component);
+	card = component->card;
+	snprintf(name, sizeof(name), "%s.%x", "wsa883x",
+		 (u32)wsa883x->swr_slave->addr);
+
+	wsa883x->entry = snd_info_create_subdir(codec_root->module,
+						(const char *)name,
+						codec_root);
+	if (!wsa883x->entry) {
+		dev_dbg(component->dev, "%s: failed to create wsa883x entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry = snd_info_create_card_entry(card->snd_card,
+						   "version",
+						   wsa883x->entry);
+	if (!version_entry) {
+		dev_dbg(component->dev, "%s: failed to create wsa883x version entry\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	version_entry->private_data = wsa883x;
+	version_entry->size = WSA883X_VERSION_ENTRY_SIZE;
+	version_entry->content = SNDRV_INFO_CONTENT_DATA;
+	version_entry->c.ops = &wsa883x_codec_info_ops;
+
+	if (snd_info_register(version_entry) < 0) {
+		snd_info_free_entry(version_entry);
+		return -ENOMEM;
+	}
+	wsa883x->version_entry = version_entry;
+
+	return 0;
+}
+EXPORT_SYMBOL(wsa883x_codec_info_create_codec_entry);
+
+static void wsa883x_regcache_sync(struct wsa883x_priv *wsa883x)
+{
+	mutex_lock(&wsa883x->res_lock);
+	if (wsa883x->state != WSA883X_DEV_READY) {
+		regcache_mark_dirty(wsa883x->regmap);
+		regcache_sync(wsa883x->regmap);
+		wsa883x->state = WSA883X_DEV_READY;
+	}
+	mutex_unlock(&wsa883x->res_lock);
+}
+
+static int wsa883x_visense_txfe_ctrl(struct snd_soc_component *component,
+				     bool enable, u8 isense1_gain,
+				     u8 isense2_gain, u8 vsense_gain)
+{
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev,
+		"%s: enable:%d, isense1 gain: %d, isense2 gain: %d, vsense_gain %d\n",
+		__func__, enable, isense1_gain, isense2_gain, vsense_gain);
+
+	return 0;
+}
+
+static int wsa883x_visense_adc_ctrl(struct snd_soc_component *component,
+				    bool enable)
+{
+
+	dev_dbg(component->dev, "%s: enable:%d\n", __func__, enable);
+
+	return 0;
+}
+
+static void wsa883x_bandgap_ctrl(struct snd_soc_component *component,
+				 bool enable)
+{
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s: enable:%d, bg_count:%d\n", __func__,
+		enable, wsa883x->bg_cnt);
+	mutex_lock(&wsa883x->bg_lock);
+	if (enable) {
+		++wsa883x->bg_cnt;
+		if (wsa883x->bg_cnt == 1) {
+			snd_soc_component_update_bits(component,
+					WSA883X_OP_CTL,
+					0x08, 0x08);
+		}
+	} else {
+		--wsa883x->bg_cnt;
+		if (wsa883x->bg_cnt <= 0) {
+			WARN_ON(wsa883x->bg_cnt < 0);
+			wsa883x->bg_cnt = 0;
+			snd_soc_component_update_bits(component,
+					WSA883X_OP_CTL, 0x08, 0x00);
+		}
+	}
+	mutex_unlock(&wsa883x->bg_lock);
+}
+
+static void wsa883x_clk_ctrl(struct snd_soc_component *component, bool enable)
+{
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s: enable:%d, clk_count:%d\n", __func__,
+		enable, wsa883x->clk_cnt);
+	mutex_lock(&wsa883x->res_lock);
+	if (enable) {
+		++wsa883x->clk_cnt;
+		if (wsa883x->clk_cnt == 1) {
+			snd_soc_component_write(component,
+					WSA883X_CDC_CLK_CTL, 0x01);
+			snd_soc_component_write(component,
+					WSA883X_CLK_CTL, 0x01);
+		}
+	} else {
+		--wsa883x->clk_cnt;
+		if (wsa883x->clk_cnt <= 0) {
+			WARN_ON(wsa883x->clk_cnt < 0);
+			wsa883x->clk_cnt = 0;
+			snd_soc_component_write(component,
+					WSA883X_CDC_CLK_CTL, 0x00);
+			snd_soc_component_write(component,
+					WSA883X_CLK_CTL, 0x00);
+		}
+	}
+	mutex_unlock(&wsa883x->res_lock);
+}
+
+static int wsa883x_get_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+				snd_soc_kcontrol_component(kcontrol);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wsa883x->comp_enable;
+	return 0;
+}
+
+static int wsa883x_set_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+				snd_soc_kcontrol_component(kcontrol);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(component->dev, "%s: Compander enable current %d, new %d\n",
+		 __func__, wsa883x->comp_enable, value);
+	wsa883x->comp_enable = value;
+	return 0;
+}
+
+static int wsa883x_get_visense(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+				snd_soc_kcontrol_component(kcontrol);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wsa883x->visense_enable;
+	return 0;
+}
+
+static int wsa883x_set_visense(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+				snd_soc_kcontrol_component(kcontrol);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(component->dev, "%s: VIsense enable current %d, new %d\n",
+		 __func__, wsa883x->visense_enable, value);
+	wsa883x->visense_enable = value;
+	return 0;
+}
+
+static const struct snd_kcontrol_new wsa883x_snd_controls[] = {
+	SOC_SINGLE_EXT("COMP Switch", SND_SOC_NOPM, 0, 1, 0,
+		wsa883x_get_compander, wsa883x_set_compander),
+
+	SOC_SINGLE_EXT("VISENSE Switch", SND_SOC_NOPM, 0, 1, 0,
+		wsa883x_get_visense, wsa883x_set_visense),
+};
+
+static const struct snd_kcontrol_new swr_dac_port[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static int wsa883x_set_port(struct snd_soc_component *component, int port_idx,
+			u8 *port_id, u8 *num_ch, u8 *ch_mask, u32 *ch_rate,
+			u8 *port_type)
+{
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	*port_id = wsa883x->port[port_idx].port_id;
+	*num_ch = wsa883x->port[port_idx].num_ch;
+	*ch_mask = wsa883x->port[port_idx].ch_mask;
+	*ch_rate = wsa883x->port[port_idx].ch_rate;
+	*port_type = wsa883x->port[port_idx].port_type;
+	return 0;
+}
+
+static int wsa883x_enable_swr_dac_port(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+			snd_soc_dapm_to_component(w->dapm);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+	u8 port_id[WSA883X_MAX_SWR_PORTS];
+	u8 num_ch[WSA883X_MAX_SWR_PORTS];
+	u8 ch_mask[WSA883X_MAX_SWR_PORTS];
+	u32 ch_rate[WSA883X_MAX_SWR_PORTS];
+	u8 port_type[WSA883X_MAX_SWR_PORTS];
+	u8 num_port = 0;
+
+	dev_dbg(component->dev, "%s: event %d name %s\n", __func__,
+		event, w->name);
+	if (wsa883x == NULL)
+		return -EINVAL;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wsa883x_set_port(component, SWR_DAC_PORT,
+				&port_id[num_port], &num_ch[num_port],
+				&ch_mask[num_port], &ch_rate[num_port],
+				&port_type[num_port]);
+		++num_port;
+
+		if (wsa883x->comp_enable) {
+			wsa883x_set_port(component, SWR_COMP_PORT,
+					&port_id[num_port], &num_ch[num_port],
+					&ch_mask[num_port], &ch_rate[num_port],
+					&port_type[num_port]);
+			++num_port;
+		}
+		if (wsa883x->visense_enable) {
+			wsa883x_set_port(component, SWR_VISENSE_PORT,
+					&port_id[num_port], &num_ch[num_port],
+					&ch_mask[num_port], &ch_rate[num_port],
+					&port_type[num_port]);
+			++num_port;
+		}
+		swr_connect_port(wsa883x->swr_slave, &port_id[0], num_port,
+				&ch_mask[0], &ch_rate[0], &num_ch[0],
+					&port_type[0]);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wsa883x_set_port(component, SWR_DAC_PORT,
+				&port_id[num_port], &num_ch[num_port],
+				&ch_mask[num_port], &ch_rate[num_port],
+				&port_type[num_port]);
+		++num_port;
+
+		if (wsa883x->comp_enable) {
+			wsa883x_set_port(component, SWR_COMP_PORT,
+					&port_id[num_port], &num_ch[num_port],
+					&ch_mask[num_port], &ch_rate[num_port],
+					&port_type[num_port]);
+			++num_port;
+		}
+		if (wsa883x->visense_enable) {
+			wsa883x_set_port(component, SWR_VISENSE_PORT,
+					&port_id[num_port], &num_ch[num_port],
+					&ch_mask[num_port], &ch_rate[num_port],
+					&port_type[num_port]);
+			++num_port;
+		}
+		swr_disconnect_port(wsa883x->swr_slave, &port_id[0], num_port,
+				&ch_mask[0], &port_type[0]);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int wsa883x_rdac_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+			snd_soc_dapm_to_component(w->dapm);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s: %s event: %d visense %d\n", __func__,
+		w->name, event, wsa883x->visense_enable);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mutex_lock(&wsa883x->temp_lock);
+		wsa883x_resource_acquire(component, ENABLE);
+		mutex_unlock(&wsa883x->temp_lock);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		swr_slvdev_datapath_control(wsa883x->swr_slave,
+					    wsa883x->swr_slave->dev_num,
+					    false);
+		mutex_lock(&wsa883x->temp_lock);
+		wsa883x_resource_acquire(component, DISABLE);
+		mutex_unlock(&wsa883x->temp_lock);
+		break;
+	}
+	return 0;
+}
+
+static int wsa883x_ramp_pa_gain(struct snd_soc_component *component,
+				int min_gain, int max_gain, int udelay)
+{
+	int val;
+
+	for (val = min_gain; max_gain <= val; val--) {
+		snd_soc_component_update_bits(component, WSA883X_SPKR_DRV_GAIN,
+				    0xF0, val << 4);
+		/*
+		 * 1ms delay is needed for every step change in gain as per
+		 * HW requirement.
+		 */
+		usleep_range(udelay, udelay + 10);
+	}
+	return 0;
+}
+
+static int wsa883x_spkr_pa_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+			snd_soc_dapm_to_component(w->dapm);
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+	int min_gain, max_gain;
+
+	dev_dbg(component->dev, "%s: %s %d\n", __func__, w->name, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		swr_slvdev_datapath_control(wsa883x->swr_slave,
+					    wsa883x->swr_slave->dev_num,
+					    true);
+		/* Set register mode if compander is not enabled */
+		if (!wsa883x->comp_enable)
+			snd_soc_component_update_bits(component,
+					WSA883X_SPKR_DRV_GAIN,
+					0x08, 0x08);
+		else
+			snd_soc_component_update_bits(component,
+					WSA883X_SPKR_DRV_GAIN,
+					0x08, 0x00);
+
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		if (!wsa883x->comp_enable) {
+			max_gain = wsa883x->pa_gain;
+			/*
+			 * Gain has to set incrementally in 4 steps
+			 * as per HW sequence
+			 */
+			if (max_gain > G_4P5DB)
+				min_gain = G_0DB;
+			else
+				min_gain = max_gain + 3;
+			/*
+			 * 1ms delay is needed before change in gain
+			 * as per HW requirement.
+			 */
+			usleep_range(1000, 1010);
+			wsa883x_ramp_pa_gain(component, min_gain, max_gain,
+					1000);
+		}
+		if (wsa883x->visense_enable) {
+			wsa883x_visense_txfe_ctrl(component, ENABLE,
+						0x00, 0x03, 0x01);
+			wsa883x_visense_adc_ctrl(component, ENABLE);
+		}
+		/* Force remove group */
+		swr_remove_from_group(wsa883x->swr_slave,
+				      wsa883x->swr_slave->dev_num);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (wsa883x->visense_enable) {
+			wsa883x_visense_adc_ctrl(component, DISABLE);
+			wsa883x_visense_txfe_ctrl(component, DISABLE,
+						0x00, 0x01, 0x01);
+		}
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget wsa883x_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("IN"),
+
+	SND_SOC_DAPM_MIXER_E("SWR DAC_Port", SND_SOC_NOPM, 0, 0, swr_dac_port,
+		ARRAY_SIZE(swr_dac_port), wsa883x_enable_swr_dac_port,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("RDAC", NULL, WSA883X_SPKR_DAC_CTL, 7, 0,
+		wsa883x_rdac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("SPKR PGA", WSA883X_SPKR_DRV_EN, 7, 0, NULL, 0,
+			wsa883x_spkr_pa_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_OUTPUT("SPKR"),
+};
+
+static const struct snd_soc_dapm_route wsa883x_audio_map[] = {
+	{"SWR DAC_Port", "Switch", "IN"},
+	{"RDAC", NULL, "SWR DAC_Port"},
+	{"SPKR PGA", NULL, "RDAC"},
+	{"SPKR", NULL, "SPKR PGA"},
+};
+
+int wsa883x_set_channel_map(struct snd_soc_component *component, u8 *port,
+			    u8 num_port, unsigned int *ch_mask,
+			    unsigned int *ch_rate, u8 *port_type)
+{
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+	int i;
+
+	if (!port || !ch_mask || !ch_rate ||
+		(num_port > WSA883X_MAX_SWR_PORTS)) {
+		dev_err(component->dev,
+			"%s: Invalid port=%pK, ch_mask=%pK, ch_rate=%pK\n",
+			__func__, port, ch_mask, ch_rate);
+		return -EINVAL;
+	}
+	for (i = 0; i < num_port; i++) {
+		wsa883x->port[i].port_id = port[i];
+		wsa883x->port[i].ch_mask = ch_mask[i];
+		wsa883x->port[i].ch_rate = ch_rate[i];
+		wsa883x->port[i].num_ch = __sw_hweight8(ch_mask[i]);
+		if (port_type)
+			wsa883x->port[i].port_type = port_type[i];
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(wsa883x_set_channel_map);
+
+static void wsa883x_init(struct snd_soc_component *component)
+{
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	if (!wsa883x)
+		return;
+
+}
+
+static int32_t wsa883x_resource_acquire(struct snd_soc_component *component,
+						bool enable)
+{
+	wsa883x_clk_ctrl(component, enable);
+	wsa883x_bandgap_ctrl(component, enable);
+	return 0;
+}
+
+static int32_t wsa883x_temp_reg_read(struct snd_soc_component *component,
+				     struct wsa_temp_register *wsa_temp_reg)
+{
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+	struct swr_device *dev;
+	u8 retry = WSA883X_NUM_RETRY;
+	u8 devnum = 0;
+
+	if (!wsa883x) {
+		dev_err(component->dev, "%s: wsa883x is NULL\n", __func__);
+		return -EINVAL;
+	}
+	dev = wsa883x->swr_slave;
+	if (dev && (wsa883x->state == WSA883X_DEV_DOWN)) {
+		while (swr_get_logical_dev_num(dev, dev->addr, &devnum) &&
+		       retry--) {
+			/* Retry after 1 msec delay */
+			usleep_range(1000, 1100);
+		}
+		if (retry == 0) {
+			dev_err(component->dev,
+				"%s get devnum %d for dev addr %lx failed\n",
+				__func__, devnum, dev->addr);
+			return -EINVAL;
+		}
+	}
+	wsa883x_regcache_sync(wsa883x);
+	mutex_lock(&wsa883x->temp_lock);
+	wsa883x_resource_acquire(component, ENABLE);
+
+	snd_soc_component_update_bits(component, WSA883X_TADC_VALUE_CTL,
+				0x01, 0x00);
+	wsa_temp_reg->dmeas_msb = snd_soc_component_read32(
+					component, WSA883X_TEMP_MSB);
+	wsa_temp_reg->dmeas_lsb = snd_soc_component_read32(
+					component, WSA883X_TEMP_LSB);
+	snd_soc_component_update_bits(component, WSA883X_TADC_VALUE_CTL,
+					0x01, 0x01);
+	wsa_temp_reg->d1_msb = snd_soc_component_read32(
+					component, WSA883X_OTP_REG_1);
+	wsa_temp_reg->d1_lsb = snd_soc_component_read32(
+					component, WSA883X_OTP_REG_2);
+	wsa_temp_reg->d2_msb = snd_soc_component_read32(
+					component, WSA883X_OTP_REG_3);
+	wsa_temp_reg->d2_lsb = snd_soc_component_read32(
+					component, WSA883X_OTP_REG_4);
+
+	wsa883x_resource_acquire(component, DISABLE);
+	mutex_unlock(&wsa883x->temp_lock);
+
+	return 0;
+}
+
+static int wsa883x_codec_probe(struct snd_soc_component *component)
+{
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+	struct swr_device *dev;
+
+	if (!wsa883x)
+		return -EINVAL;
+	snd_soc_component_init_regmap(component, wsa883x->regmap);
+
+	dev = wsa883x->swr_slave;
+	wsa883x->component = component;
+	mutex_init(&wsa883x->bg_lock);
+	wsa883x_init(component);
+	snprintf(wsa883x->tz_pdata.name, sizeof(wsa883x->tz_pdata.name),
+		"%s.%x", "wsatz", (u8)dev->addr);
+	wsa883x->bg_cnt = 0;
+	wsa883x->clk_cnt = 0;
+	wsa883x->tz_pdata.component = component;
+	wsa883x->tz_pdata.wsa_temp_reg_read = wsa883x_temp_reg_read;
+	wsa883x_init_thermal(&wsa883x->tz_pdata);
+	snd_soc_add_component_controls(component, wsa_snd_controls,
+				   ARRAY_SIZE(wsa_snd_controls));
+	return 0;
+}
+
+static void wsa883x_codec_remove(struct snd_soc_component *component)
+{
+	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+	if (wsa883x->tz_pdata.tz_dev)
+		wsa883x_deinit_thermal(wsa883x->tz_pdata.tz_dev);
+	mutex_destroy(&wsa883x->bg_lock);
+
+	return;
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_wsa883x = {
+	.name = DRV_NAME,
+	.probe = wsa883x_codec_probe,
+	.remove = wsa883x_codec_remove,
+	.controls = wsa883x_snd_controls,
+	.num_controls = ARRAY_SIZE(wsa883x_snd_controls),
+	.dapm_widgets = wsa883x_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wsa883x_dapm_widgets),
+	.dapm_routes = wsa883x_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(wsa883x_audio_map),
+};
+
+static int wsa883x_gpio_ctrl(struct wsa883x_priv *wsa883x, bool enable)
+{
+	int ret = 0;
+
+	if (enable)
+		ret = msm_cdc_pinctrl_select_active_state(
+						wsa883x->wsa_rst_np);
+	else
+		ret = msm_cdc_pinctrl_select_sleep_state(
+						wsa883x->wsa_rst_np);
+	if (ret != 0)
+		dev_err(wsa883x->dev,
+			"%s: Failed to turn state %d; ret=%d\n",
+			__func__, enable, ret);
+
+	return ret;
+}
+
+static int wsa883x_swr_probe(struct swr_device *pdev)
+{
+	int ret = 0;
+	struct wsa883x_priv *wsa883x;
+	u8 devnum = 0;
+	bool pin_state_current = false;
+
+	wsa883x = devm_kzalloc(&pdev->dev, sizeof(struct wsa883x_priv),
+			    GFP_KERNEL);
+	if (!wsa883x)
+		return -ENOMEM;
+
+	wsa883x->wsa_rst_np = of_parse_phandle(pdev->dev.of_node,
+					     "qcom,spkr-sd-n-node", 0);
+	if (!wsa883x->wsa_rst_np) {
+		dev_dbg(&pdev->dev, "%s: pinctrl not defined\n", __func__);
+		goto err;
+	}
+	swr_set_dev_data(pdev, wsa883x);
+	wsa883x->swr_slave = pdev;
+	pin_state_current = msm_cdc_pinctrl_get_state(wsa883x->wsa_rst_np);
+	wsa883x_gpio_ctrl(wsa883x, true);
+	/*
+	 * Add 5msec delay to provide sufficient time for
+	 * soundwire auto enumeration of slave devices as
+	 * as per HW requirement.
+	 */
+	usleep_range(5000, 5010);
+	ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
+	if (ret) {
+		dev_dbg(&pdev->dev,
+			"%s get devnum %d for dev addr %lx failed\n",
+			__func__, devnum, pdev->addr);
+		goto dev_err;
+	}
+	pdev->dev_num = devnum;
+
+	wsa883x->regmap = devm_regmap_init_swr(pdev,
+					       &wsa883x_regmap_config);
+	if (IS_ERR(wsa883x->regmap)) {
+		ret = PTR_ERR(wsa883x->regmap);
+		dev_err(&pdev->dev, "%s: regmap_init failed %d\n",
+			__func__, ret);
+		goto dev_err;
+	}
+
+	ret = snd_soc_register_component(&pdev->dev, &soc_codec_dev_wsa883x,
+				     NULL, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: Codec registration failed\n",
+			__func__);
+		goto dev_err;
+	}
+	mutex_init(&wsa883x->res_lock);
+	mutex_init(&wsa883x->temp_lock);
+	wsa883x->state = WSA883X_DEV_UP;
+
+#ifdef CONFIG_DEBUG_FS
+	if (!wcd938x->debugfs_dent) {
+		wcd938x->debugfs_dent = debugfs_create_dir(
+					dev_name(&pdev->dev), 0);
+		if (!IS_ERR(wcd938x->debugfs_dent)) {
+			wcd938x->debugfs_peek =
+				debugfs_create_file("swrslave_peek",
+				S_IFREG | 0444,
+				wcd938x->debugfs_dent,
+				(void *) pdev,
+				&codec_debug_read_ops);
+
+		wcd938x->debugfs_poke =
+				debugfs_create_file("swrslave_poke",
+				S_IFREG | 0444,
+				wcd938x->debugfs_dent,
+				(void *) pdev,
+				&codec_debug_write_ops);
+
+		wcd938x->debugfs_reg_dump =
+				debugfs_create_file(
+				"swrslave_reg_dump",
+				S_IFREG | 0444,
+				wcd938x->debugfs_dent,
+				(void *) pdev,
+				&codec_debug_dump_ops);
+	}
+}
+#endif
+
+	return 0;
+
+dev_err:
+	if (pin_state_current == false)
+		wsa883x_gpio_ctrl(wsa883x, false);
+	swr_remove_device(pdev);
+err:
+	return ret;
+}
+
+static int wsa883x_swr_remove(struct swr_device *pdev)
+{
+	struct wsa883x_priv *wsa883x;
+
+	wsa883x = swr_get_dev_data(pdev);
+	if (!wsa883x) {
+		dev_err(&pdev->dev, "%s: wsa883x is NULL\n", __func__);
+		return -EINVAL;
+	}
+#ifdef CONFIG_DEBUG_FS
+	debugfs_remove_recursive(wsa883x->debugfs_dent);
+	wsa883x->debugfs_dent = NULL;
+#endif
+	mutex_destroy(&wsa883x->res_lock);
+	mutex_destroy(&wsa883x->temp_lock);
+	snd_soc_unregister_component(&pdev->dev);
+	if (wsa883x->pd_gpio)
+		gpio_free(wsa883x->pd_gpio);
+	swr_set_dev_data(pdev, NULL);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int wsa883x_swr_suspend(struct device *dev)
+{
+	dev_dbg(dev, "%s: system suspend\n", __func__);
+	return 0;
+}
+
+static int wsa883x_swr_resume(struct device *dev)
+{
+	struct wsa883x_priv *wsa883x = swr_get_dev_data(to_swr_device(dev));
+
+	if (!wsa883x) {
+		dev_err(dev, "%s: wsa883x private data is NULL\n", __func__);
+		return -EINVAL;
+	}
+	dev_dbg(dev, "%s: system resume\n", __func__);
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops wsa883x_swr_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(wsa883x_swr_suspend, wsa883x_swr_resume)
+};
+
+static const struct swr_device_id wsa883x_swr_id[] = {
+	{"wsa883x", 0},
+	{}
+};
+
+static const struct of_device_id wsa883x_swr_dt_match[] = {
+	{
+		.compatible = "qcom,wsa883x",
+	},
+	{}
+};
+
+static struct swr_driver wsa883x_swr_driver = {
+	.driver = {
+		.name = "wsa883x",
+		.owner = THIS_MODULE,
+		.pm = &wsa883x_swr_pm_ops,
+		.of_match_table = wsa883x_swr_dt_match,
+	},
+	.probe = wsa883x_swr_probe,
+	.remove = wsa883x_swr_remove,
+	.id_table = wsa883x_swr_id,
+};
+
+static int __init wsa883x_swr_init(void)
+{
+	return swr_driver_register(&wsa883x_swr_driver);
+}
+
+static void __exit wsa883x_swr_exit(void)
+{
+	swr_driver_unregister(&wsa883x_swr_driver);
+}
+
+module_init(wsa883x_swr_init);
+module_exit(wsa883x_swr_exit);
+
+MODULE_DESCRIPTION("WSA883x codec driver");
+MODULE_LICENSE("GPL v2");

+ 41 - 0
asoc/codecs/wsa883x/wsa883x.h

@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _WSA883X_H
+#define _WSA883X_H
+
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/info.h>
+#include "wsa883x-registers.h"
+
+#define WSA883X_MAX_SWR_PORTS   4
+
+#if IS_ENABLED(CONFIG_SND_SOC_WSA883X)
+int wsa883x_set_channel_map(struct snd_soc_component *component,
+				   u8 *port, u8 num_port, unsigned int *ch_mask,
+				   unsigned int *ch_rate, u8 *port_type);
+
+
+int wsa883x_codec_info_create_codec_entry(
+					struct snd_info_entry *codec_root,
+					struct snd_soc_component *component);
+#else
+static int wsa883x_set_channel_map(struct snd_soc_component *component,
+				   u8 *port, u8 num_port, unsigned int *ch_mask,
+				   unsigned int *ch_rate, u8 *port_type)
+{
+	return 0;
+}
+
+static int wsa883x_codec_info_create_codec_entry(
+					struct snd_info_entry *codec_root,
+					struct snd_soc_component *component)
+{
+	return 0;
+}
+
+#endif
+
+#endif /* _WSA883X_H */