Browse Source

ASoC: wsa883x: Add support for wsa883x speaker amplifer

WSA883x is a speaker amplifier with soundwire interface and
enumerates as soundwire slave. WSA883x supports audio playback
on speakers and has temperature sensors for better speaker
protection and enhanced boost control support. Add software
driver support to enable WSA883x speaker amplifier.

Change-Id: Ib9cf2eebdda5ce331154bc786f059c5757f34fa2
Signed-off-by: Sudheer Papothi <[email protected]>
Sudheer Papothi 5 years ago
parent
commit
af0a66b78a

+ 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 */