--- /dev/null
+From 787800e9ddc193ed15b603327bec947ae26b8746 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Jun 2022 10:06:42 +0100
+Subject: ASoC: codecs: add wsa883x amplifier support
+
+From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+[ Upstream commit 43b8c7dc85a14f36048a27bb6c627fd49144a8d1 ]
+
+This patch adds support to WSA8830/WSA8812/WSA8835 Class-D Smart
+Speaker Amplifier. This Amplifier is primarily interfaced with
+SoundWire.
+
+This patch is tested on SM8450 MTP Board.
+
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20220629090644.67982-3-srinivas.kandagatla@linaro.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: da29b94ed354 ("ASoC: codecs: wcd938x: fix resource leaks on bind errors")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/Kconfig | 10 +
+ sound/soc/codecs/Makefile | 2 +
+ sound/soc/codecs/wsa883x.c | 1301 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1313 insertions(+)
+ create mode 100644 sound/soc/codecs/wsa883x.c
+
+diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
+index b193db25c37fe..31896c8c2b0d6 100644
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -294,6 +294,7 @@ config SND_SOC_ALL_CODECS
+ imply SND_SOC_WM9712
+ imply SND_SOC_WM9713
+ imply SND_SOC_WSA881X
++ imply SND_SOC_WSA883X
+ imply SND_SOC_ZL38060
+ help
+ Normally ASoC codec drivers are only built if a machine driver which
+@@ -1838,6 +1839,15 @@ config SND_SOC_WSA881X
+ This enables support for Qualcomm WSA8810/WSA8815 Class-D
+ Smart Speaker Amplifier.
+
++config SND_SOC_WSA883X
++ tristate "WSA883X Codec"
++ depends on SOUNDWIRE
++ select REGMAP_SOUNDWIRE
++ tristate
++ help
++ This enables support for Qualcomm WSA8830/WSA8835 Class-D
++ Smart Speaker Amplifier.
++
+ config SND_SOC_ZL38060
+ tristate "Microsemi ZL38060 Connected Home Audio Processor"
+ depends on SPI_MASTER
+diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
+index 5ba164d41b300..4edc4775c7323 100644
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -317,6 +317,7 @@ snd-soc-wm9712-objs := wm9712.o
+ snd-soc-wm9713-objs := wm9713.o
+ snd-soc-wm-hubs-objs := wm_hubs.o
+ snd-soc-wsa881x-objs := wsa881x.o
++snd-soc-wsa883x-objs := wsa883x.o
+ snd-soc-zl38060-objs := zl38060.o
+ # Amp
+ snd-soc-max9877-objs := max9877.o
+@@ -649,6 +650,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
+ obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o
+ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
+ obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o
++obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o
+ obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o
+
+ # Amp
+diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
+new file mode 100644
+index 0000000000000..856709ec017e6
+--- /dev/null
++++ b/sound/soc/codecs/wsa883x.c
+@@ -0,0 +1,1301 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
++ */
++
++#include <linux/bitops.h>
++#include <linux/debugfs.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/gpio.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of_gpio.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/printk.h>
++#include <linux/regmap.h>
++#include <linux/regulator/consumer.h>
++#include <linux/slab.h>
++#include <linux/soundwire/sdw.h>
++#include <linux/soundwire/sdw_registers.h>
++#include <linux/soundwire/sdw_type.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc-dapm.h>
++#include <sound/soc.h>
++#include <sound/tlv.h>
++
++#define WSA883X_BASE 0x3000
++#define WSA883X_ANA_BG_TSADC_BASE (WSA883X_BASE + 0x00000001)
++#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_OS_CAL_CTL (WSA883X_ANA_SPK_TOP_BASE + 0x0012)
++#define WSA883X_SPKR_DRV_OS_CAL_CTL1 (WSA883X_ANA_SPK_TOP_BASE + 0x0013)
++#define WSA883X_SPKR_PWM_CLK_CTL (WSA883X_ANA_SPK_TOP_BASE + 0x0014)
++#define WSA883X_SPKR_PWM_FREQ_SEL_MASK BIT(3)
++#define WSA883X_SPKR_PWM_FREQ_F300KHZ 0
++#define WSA883X_SPKR_PWM_FREQ_F600KHZ 1
++#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 + 0x00000043)
++#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_BYPASS_1 (WSA883X_ANA_BOOST_BASE + 0x000A)
++#define WSA883X_BYPASS_2 (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_PWRSTAGE_CTRL4 (WSA883X_ANA_BOOST_BASE + 0x0012)
++#define WSA883X_TEST1 (WSA883X_ANA_BOOST_BASE + 0x0013)
++#define WSA883X_SPARE1 (WSA883X_ANA_BOOST_BASE + 0x0014)
++#define WSA883X_SPARE2 (WSA883X_ANA_BOOST_BASE + 0x0015)
++
++#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_CKWD_CTL_0 (WSA883X_ANA_PON_LDOL_BASE + 0x0004)
++#define WSA883X_CKWD_CTL_1 (WSA883X_ANA_PON_LDOL_BASE + 0x0005)
++#define WSA883X_CKWD_CTL_2 (WSA883X_ANA_PON_LDOL_BASE + 0x0006)
++#define WSA883X_CKSK_CTL_0 (WSA883X_ANA_PON_LDOL_BASE + 0x0007)
++#define WSA883X_PADSW_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_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_RXD_MODE_MASK BIT(1)
++#define WSA883X_RXD_MODE_NORMAL 0
++#define WSA883X_RXD_MODE_HIFI 1
++#define WSA883X_CDC_CLK_CTL (WSA883X_DIG_CTRL_BASE + 0x0009)
++#define WSA883X_SWR_RESET_EN (WSA883X_DIG_CTRL_BASE + 0x000A)
++#define WSA883X_RESET_CTL (WSA883X_DIG_CTRL_BASE + 0x000B)
++#define WSA883X_PA_FSM_CTL (WSA883X_DIG_CTRL_BASE + 0x0010)
++#define WSA883X_GLOBAL_PA_EN_MASK BIT(0)
++#define WSA883X_GLOBAL_PA_ENABLE 1
++#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_PA_FSM_DBG (WSA883X_DIG_CTRL_BASE + 0x0017)
++#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_ADC_FLT_EN_MASK BIT(0)
++#define WSA883X_VBAT_ADC_COEF_SEL_MASK GENMASK(3, 1)
++#define WSA883X_VBAT_ADC_COEF_F_1DIV2 0x0
++#define WSA883X_VBAT_ADC_COEF_F_1DIV16 0x3
++#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_PDM_EN_MASK BIT(0)
++#define WSA883X_PDM_ENABLE BIT(0)
++#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_WAVG_STA (WSA883X_DIG_CTRL_BASE + 0x006B)
++#define WSA883X_DRE_CTL_0 (WSA883X_DIG_CTRL_BASE + 0x006C)
++#define WSA883X_DRE_OFFSET_MASK GENMASK(2, 0)
++#define WSA883X_DRE_PROG_DELAY_MASK GENMASK(7, 4)
++#define WSA883X_DRE_CTL_1 (WSA883X_DIG_CTRL_BASE + 0x006D)
++#define WSA883X_DRE_GAIN_EN_MASK BIT(0)
++#define WSA883X_DRE_GAIN_FROM_CSR 1
++#define WSA883X_DRE_IDLE_DET_CTL (WSA883X_DIG_CTRL_BASE + 0x006E)
++#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_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_TADC_DETECT_DBG_CTL (WSA883X_DIG_CTRL_BASE + 0x00A9)
++#define WSA883X_TADC_DEBUG_MSB (WSA883X_DIG_CTRL_BASE + 0x00AA)
++#define WSA883X_TADC_DEBUG_LSB (WSA883X_DIG_CTRL_BASE + 0x00AB)
++#define WSA883X_SAMPLE_EDGE_SEL (WSA883X_DIG_CTRL_BASE + 0x00AC)
++#define WSA883X_SWR_EDGE_SEL (WSA883X_DIG_CTRL_BASE + 0x00AD)
++#define WSA883X_TEST_MODE_CTL (WSA883X_DIG_CTRL_BASE + 0x00AE)
++#define WSA883X_IOPAD_CTL (WSA883X_DIG_CTRL_BASE + 0x00AF)
++#define WSA883X_ANA_CSR_DBG_ADD (WSA883X_DIG_CTRL_BASE + 0x00B0)
++#define WSA883X_ANA_CSR_DBG_CTL (WSA883X_DIG_CTRL_BASE + 0x00B1)
++#define WSA883X_SPARE_R (WSA883X_DIG_CTRL_BASE + 0x00BC)
++#define WSA883X_SPARE_0 (WSA883X_DIG_CTRL_BASE + 0x00BD)
++#define WSA883X_SPARE_1 (WSA883X_DIG_CTRL_BASE + 0x00BE)
++#define WSA883X_SPARE_2 (WSA883X_DIG_CTRL_BASE + 0x00BF)
++#define WSA883X_SCODE (WSA883X_DIG_CTRL_BASE + 0x00C0)
++
++#define WSA883X_DIG_TRIM_BASE (WSA883X_BASE + 0x00000500)
++#define WSA883X_OTP_REG_0 (WSA883X_DIG_TRIM_BASE + 0x0080)
++#define WSA883X_ID_MASK GENMASK(3, 0)
++#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_32 (WSA883X_DIG_TRIM_BASE + 0x00A0)
++#define WSA883X_OTP_REG_33 (WSA883X_DIG_TRIM_BASE + 0x00A1)
++#define WSA883X_OTP_REG_34 (WSA883X_DIG_TRIM_BASE + 0x00A2)
++#define WSA883X_OTP_REG_35 (WSA883X_DIG_TRIM_BASE + 0x00A3)
++#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)
++#define WSA883X_PROBE_TIMEOUT 1000
++
++#define WSA883X_VERSION_1_0 0
++#define WSA883X_VERSION_1_1 1
++
++#define WSA883X_MAX_SWR_PORTS 4
++#define WSA883X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
++ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
++ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
++ SNDRV_PCM_RATE_384000)
++/* Fractional Rates */
++#define WSA883X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
++ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800)
++
++#define WSA883X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
++ SNDRV_PCM_FMTBIT_S24_LE |\
++ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
++
++struct wsa883x_priv {
++ struct regmap *regmap;
++ struct device *dev;
++ struct regulator *vdd;
++ struct sdw_slave *slave;
++ struct sdw_stream_config sconfig;
++ struct sdw_stream_runtime *sruntime;
++ struct sdw_port_config port_config[WSA883X_MAX_SWR_PORTS];
++ struct gpio_desc *sd_n;
++ bool port_prepared[WSA883X_MAX_SWR_PORTS];
++ bool port_enable[WSA883X_MAX_SWR_PORTS];
++ int version;
++ int variant;
++ int active_ports;
++ int dev_mode;
++ int comp_offset;
++};
++
++enum {
++ WSA8830 = 0,
++ WSA8835,
++ WSA8832,
++ WSA8835_V2 = 5,
++};
++
++enum {
++ COMP_OFFSET0,
++ COMP_OFFSET1,
++ COMP_OFFSET2,
++ COMP_OFFSET3,
++ COMP_OFFSET4,
++};
++
++enum wsa_port_ids {
++ WSA883X_PORT_DAC,
++ WSA883X_PORT_COMP,
++ WSA883X_PORT_BOOST,
++ WSA883X_PORT_VISENSE,
++};
++
++/* 4 ports */
++static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA883X_MAX_SWR_PORTS] = {
++ {
++ /* DAC */
++ .num = 1,
++ .type = SDW_DPN_SIMPLE,
++ .min_ch = 1,
++ .max_ch = 1,
++ .simple_ch_prep_sm = true,
++ .read_only_wordlength = true,
++ }, {
++ /* COMP */
++ .num = 2,
++ .type = SDW_DPN_SIMPLE,
++ .min_ch = 1,
++ .max_ch = 1,
++ .simple_ch_prep_sm = true,
++ .read_only_wordlength = true,
++ }, {
++ /* BOOST */
++ .num = 3,
++ .type = SDW_DPN_SIMPLE,
++ .min_ch = 1,
++ .max_ch = 1,
++ .simple_ch_prep_sm = true,
++ .read_only_wordlength = true,
++ }, {
++ /* VISENSE */
++ .num = 4,
++ .type = SDW_DPN_SIMPLE,
++ .min_ch = 1,
++ .max_ch = 1,
++ .simple_ch_prep_sm = true,
++ .read_only_wordlength = true,
++ }
++};
++
++static struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = {
++ {
++ .num = 1,
++ .ch_mask = 0x1,
++ }, {
++ .num = 2,
++ .ch_mask = 0xf,
++ }, {
++ .num = 3,
++ .ch_mask = 0x3,
++ }, { /* IV feedback */
++ .num = 4,
++ .ch_mask = 0x3,
++ },
++};
++
++static struct reg_default wsa883x_defaults[] = {
++ { WSA883X_REF_CTRL, 0xD5 },
++ { WSA883X_TEST_CTL_0, 0x06 },
++ { WSA883X_BIAS_0, 0xD2 },
++ { WSA883X_OP_CTL, 0xE0 },
++ { WSA883X_IREF_CTL, 0x57 },
++ { WSA883X_ISENS_CTL, 0x47 },
++ { WSA883X_CLK_CTL, 0x87 },
++ { WSA883X_TEST_CTL_1, 0x00 },
++ { WSA883X_BIAS_1, 0x51 },
++ { WSA883X_ADC_CTL, 0x01 },
++ { WSA883X_DOUT_MSB, 0x00 },
++ { WSA883X_DOUT_LSB, 0x00 },
++ { WSA883X_VBAT_SNS, 0x40 },
++ { WSA883X_ITRIM_CODE, 0x9F },
++ { WSA883X_EN, 0x20 },
++ { WSA883X_OVERRIDE1, 0x00 },
++ { WSA883X_OVERRIDE2, 0x08 },
++ { WSA883X_VSENSE1, 0xD3 },
++ { WSA883X_ISENSE1, 0xD4 },
++ { WSA883X_ISENSE2, 0x20 },
++ { WSA883X_ISENSE_CAL, 0x00 },
++ { WSA883X_MISC, 0x08 },
++ { WSA883X_ADC_0, 0x00 },
++ { WSA883X_ADC_1, 0x00 },
++ { WSA883X_ADC_2, 0x40 },
++ { WSA883X_ADC_3, 0x80 },
++ { WSA883X_ADC_4, 0x25 },
++ { WSA883X_ADC_5, 0x25 },
++ { WSA883X_ADC_6, 0x08 },
++ { WSA883X_ADC_7, 0x81 },
++ { WSA883X_STATUS, 0x00 },
++ { WSA883X_DAC_CTRL_REG, 0x53 },
++ { WSA883X_DAC_EN_DEBUG_REG, 0x00 },
++ { WSA883X_DAC_OPAMP_BIAS1_REG, 0x48 },
++ { WSA883X_DAC_OPAMP_BIAS2_REG, 0x48 },
++ { WSA883X_DAC_VCM_CTRL_REG, 0x88 },
++ { WSA883X_DAC_VOLTAGE_CTRL_REG, 0xA5 },
++ { WSA883X_ATEST1_REG, 0x00 },
++ { WSA883X_ATEST2_REG, 0x00 },
++ { WSA883X_SPKR_TOP_BIAS_REG1, 0x6A },
++ { WSA883X_SPKR_TOP_BIAS_REG2, 0x65 },
++ { WSA883X_SPKR_TOP_BIAS_REG3, 0x55 },
++ { WSA883X_SPKR_TOP_BIAS_REG4, 0xA9 },
++ { WSA883X_SPKR_CLIP_DET_REG, 0x9C },
++ { 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, 0x3A },
++ { WSA883X_SPKR_DRV_LF_REG_GAIN, 0x00 },
++ { WSA883X_SPKR_DRV_OS_CAL_CTL, 0x00 },
++ { WSA883X_SPKR_DRV_OS_CAL_CTL1, 0x90 },
++ { WSA883X_SPKR_PWM_CLK_CTL, 0x00 },
++ { WSA883X_SPKR_PDRV_HS_CTL, 0x52 },
++ { WSA883X_SPKR_PDRV_LS_CTL, 0x48 },
++ { WSA883X_SPKR_PWRSTG_DBG, 0x08 },
++ { WSA883X_SPKR_OCP_CTL, 0xE2 },
++ { WSA883X_SPKR_BBM_CTL, 0x92 },
++ { WSA883X_PA_STATUS0, 0x00 },
++ { WSA883X_PA_STATUS1, 0x00 },
++ { WSA883X_PA_STATUS2, 0x80 },
++ { WSA883X_EN_CTRL, 0x44 },
++ { WSA883X_CURRENT_LIMIT, 0xCC },
++ { WSA883X_IBIAS1, 0x00 },
++ { WSA883X_IBIAS2, 0x00 },
++ { WSA883X_IBIAS3, 0x00 },
++ { WSA883X_LDO_PROG, 0x02 },
++ { WSA883X_STABILITY_CTRL1, 0x8E },
++ { WSA883X_STABILITY_CTRL2, 0x10 },
++ { WSA883X_PWRSTAGE_CTRL1, 0x06 },
++ { WSA883X_PWRSTAGE_CTRL2, 0x00 },
++ { WSA883X_BYPASS_1, 0x19 },
++ { WSA883X_BYPASS_2, 0x13 },
++ { WSA883X_ZX_CTRL_1, 0xF0 },
++ { WSA883X_ZX_CTRL_2, 0x04 },
++ { WSA883X_MISC1, 0x06 },
++ { WSA883X_MISC2, 0xA0 },
++ { WSA883X_GMAMP_SUP1, 0x82 },
++ { WSA883X_PWRSTAGE_CTRL3, 0x39 },
++ { WSA883X_PWRSTAGE_CTRL4, 0x5F },
++ { WSA883X_TEST1, 0x00 },
++ { WSA883X_SPARE1, 0x00 },
++ { WSA883X_SPARE2, 0x00 },
++ { WSA883X_PON_CTL_0, 0x10 },
++ { WSA883X_PON_CLT_1, 0xE0 },
++ { WSA883X_PON_CTL_2, 0x90 },
++ { WSA883X_PON_CTL_3, 0x70 },
++ { WSA883X_CKWD_CTL_0, 0x34 },
++ { WSA883X_CKWD_CTL_1, 0x0F },
++ { WSA883X_CKWD_CTL_2, 0x00 },
++ { WSA883X_CKSK_CTL_0, 0x00 },
++ { WSA883X_PADSW_CTL_0, 0x00 },
++ { WSA883X_TEST_0, 0x00 },
++ { WSA883X_TEST_1, 0x00 },
++ { WSA883X_STATUS_0, 0x00 },
++ { WSA883X_STATUS_1, 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_RESET_CTL, 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, 0x01 },
++ { WSA883X_PA_FSM_DBG, 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_WAVG_STA, 0x00 },
++ { WSA883X_DRE_CTL_0, 0x70 },
++ { WSA883X_DRE_CTL_1, 0x08 },
++ { WSA883X_DRE_IDLE_DET_CTL, 0x1F },
++ { 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, 0xF5 },
++ { 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, 0x90 },
++ { WSA883X_INTR_MASK1, 0x00 },
++ { WSA883X_INTR_STATUS0, 0x00 },
++ { WSA883X_INTR_STATUS1, 0x00 },
++ { WSA883X_INTR_CLEAR0, 0x00 },
++ { WSA883X_INTR_CLEAR1, 0x00 },
++ { WSA883X_INTR_LEVEL0, 0x00 },
++ { WSA883X_INTR_LEVEL1, 0x00 },
++ { WSA883X_INTR_SET0, 0x00 },
++ { WSA883X_INTR_SET1, 0x00 },
++ { WSA883X_INTR_TEST0, 0x00 },
++ { WSA883X_INTR_TEST1, 0x00 },
++ { 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_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, 0x37 },
++ { WSA883X_TADC_DETECT_DBG_CTL, 0x00 },
++ { WSA883X_TADC_DEBUG_MSB, 0x00 },
++ { WSA883X_TADC_DEBUG_LSB, 0x00 },
++ { WSA883X_SAMPLE_EDGE_SEL, 0x7F },
++ { WSA883X_SWR_EDGE_SEL, 0x00 },
++ { WSA883X_TEST_MODE_CTL, 0x04 },
++ { WSA883X_IOPAD_CTL, 0x00 },
++ { WSA883X_ANA_CSR_DBG_ADD, 0x00 },
++ { WSA883X_ANA_CSR_DBG_CTL, 0x12 },
++ { WSA883X_SPARE_R, 0x00 },
++ { WSA883X_SPARE_0, 0x00 },
++ { WSA883X_SPARE_1, 0x00 },
++ { WSA883X_SPARE_2, 0x00 },
++ { WSA883X_SCODE, 0x00 },
++ { WSA883X_OTP_REG_0, 0x05 },
++ { 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, 0x37 },
++ { WSA883X_OTP_REG_25, 0x3F },
++ { WSA883X_OTP_REG_26, 0x03 },
++ { WSA883X_OTP_REG_27, 0x00 },
++ { WSA883X_OTP_REG_28, 0x00 },
++ { WSA883X_OTP_REG_29, 0x00 },
++ { WSA883X_OTP_REG_30, 0x00 },
++ { WSA883X_OTP_REG_31, 0x03 },
++ { WSA883X_OTP_REG_32, 0x00 },
++ { WSA883X_OTP_REG_33, 0xFF },
++ { WSA883X_OTP_REG_34, 0x00 },
++ { WSA883X_OTP_REG_35, 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_readonly_register(struct device *dev, unsigned int reg)
++{
++ switch (reg) {
++ case WSA883X_DOUT_MSB:
++ case WSA883X_DOUT_LSB:
++ case WSA883X_STATUS:
++ case WSA883X_PA_STATUS0:
++ case WSA883X_PA_STATUS1:
++ case WSA883X_PA_STATUS2:
++ case WSA883X_STATUS_0:
++ case WSA883X_STATUS_1:
++ case WSA883X_CHIP_ID0:
++ case WSA883X_CHIP_ID1:
++ case WSA883X_CHIP_ID2:
++ case WSA883X_CHIP_ID3:
++ case WSA883X_BUS_ID:
++ case WSA883X_PA_FSM_STA:
++ case WSA883X_PA_FSM_ERR_COND:
++ case WSA883X_TEMP_MSB:
++ case WSA883X_TEMP_LSB:
++ case WSA883X_VBAT_DIN_MSB:
++ case WSA883X_VBAT_DIN_LSB:
++ case WSA883X_VBAT_DOUT:
++ case WSA883X_SDM_PDM9_LSB:
++ case WSA883X_SDM_PDM9_MSB:
++ case WSA883X_WAVG_STA:
++ case WSA883X_INTR_STATUS0:
++ case WSA883X_INTR_STATUS1:
++ case WSA883X_OTP_CTRL1:
++ case WSA883X_PIN_STATUS:
++ case WSA883X_ATE_TEST_MODE:
++ case WSA883X_SWR_HM_TEST1:
++ case WSA883X_SPARE_R:
++ case WSA883X_OTP_REG_0:
++ return true;
++ }
++ return false;
++}
++
++static bool wsa883x_writeable_register(struct device *dev, unsigned int reg)
++{
++ return !wsa883x_readonly_register(dev, reg);
++}
++
++static bool wsa883x_volatile_register(struct device *dev, unsigned int reg)
++{
++ return wsa883x_readonly_register(dev, reg);
++}
++
++static struct regmap_config wsa883x_regmap_config = {
++ .reg_bits = 32,
++ .val_bits = 8,
++ .cache_type = REGCACHE_RBTREE,
++ .reg_defaults = wsa883x_defaults,
++ .max_register = WSA883X_MAX_REGISTER,
++ .num_reg_defaults = ARRAY_SIZE(wsa883x_defaults),
++ .volatile_reg = wsa883x_volatile_register,
++ .writeable_reg = wsa883x_writeable_register,
++ .reg_format_endian = REGMAP_ENDIAN_NATIVE,
++ .val_format_endian = REGMAP_ENDIAN_NATIVE,
++ .can_multi_write = true,
++ .use_single_read = true,
++};
++
++static const struct reg_sequence reg_init[] = {
++ {WSA883X_PA_FSM_BYP, 0x00},
++ {WSA883X_ADC_6, 0x02},
++ {WSA883X_CDC_SPK_DSM_A2_0, 0x0A},
++ {WSA883X_CDC_SPK_DSM_A2_1, 0x08},
++ {WSA883X_CDC_SPK_DSM_A3_0, 0xF3},
++ {WSA883X_CDC_SPK_DSM_A3_1, 0x07},
++ {WSA883X_CDC_SPK_DSM_A4_0, 0x79},
++ {WSA883X_CDC_SPK_DSM_A4_1, 0x02},
++ {WSA883X_CDC_SPK_DSM_A5_0, 0x0B},
++ {WSA883X_CDC_SPK_DSM_A5_1, 0x02},
++ {WSA883X_CDC_SPK_DSM_A6_0, 0x8A},
++ {WSA883X_CDC_SPK_DSM_A7_0, 0x9B},
++ {WSA883X_CDC_SPK_DSM_C_0, 0x68},
++ {WSA883X_CDC_SPK_DSM_C_1, 0x54},
++ {WSA883X_CDC_SPK_DSM_C_2, 0xF2},
++ {WSA883X_CDC_SPK_DSM_C_3, 0x20},
++ {WSA883X_CDC_SPK_DSM_R1, 0x83},
++ {WSA883X_CDC_SPK_DSM_R2, 0x7F},
++ {WSA883X_CDC_SPK_DSM_R3, 0x9D},
++ {WSA883X_CDC_SPK_DSM_R4, 0x82},
++ {WSA883X_CDC_SPK_DSM_R5, 0x8B},
++ {WSA883X_CDC_SPK_DSM_R6, 0x9B},
++ {WSA883X_CDC_SPK_DSM_R7, 0x3F},
++ {WSA883X_VBAT_SNS, 0x20},
++ {WSA883X_DRE_CTL_0, 0x92},
++ {WSA883X_DRE_IDLE_DET_CTL, 0x0F},
++ {WSA883X_CURRENT_LIMIT, 0xC4},
++ {WSA883X_VAGC_TIME, 0x0F},
++ {WSA883X_VAGC_ATTN_LVL_1_2, 0x00},
++ {WSA883X_VAGC_ATTN_LVL_3, 0x01},
++ {WSA883X_VAGC_CTL, 0x01},
++ {WSA883X_TAGC_CTL, 0x1A},
++ {WSA883X_TAGC_TIME, 0x2C},
++ {WSA883X_TEMP_CONFIG0, 0x02},
++ {WSA883X_TEMP_CONFIG1, 0x02},
++ {WSA883X_OTP_REG_1, 0x49},
++ {WSA883X_OTP_REG_2, 0x80},
++ {WSA883X_OTP_REG_3, 0xC9},
++ {WSA883X_OTP_REG_4, 0x40},
++ {WSA883X_TAGC_CTL, 0x1B},
++ {WSA883X_ADC_2, 0x00},
++ {WSA883X_ADC_7, 0x85},
++ {WSA883X_ADC_7, 0x87},
++ {WSA883X_CKWD_CTL_0, 0x14},
++ {WSA883X_CKWD_CTL_1, 0x1B},
++ {WSA883X_GMAMP_SUP1, 0xE2},
++};
++
++static void wsa883x_init(struct wsa883x_priv *wsa883x)
++{
++ struct regmap *regmap = wsa883x->regmap;
++ int variant, version;
++
++ regmap_read(regmap, WSA883X_OTP_REG_0, &variant);
++ wsa883x->variant = variant & WSA883X_ID_MASK;
++
++ regmap_read(regmap, WSA883X_CHIP_ID0, &version);
++ wsa883x->version = version;
++
++ switch (wsa883x->variant) {
++ case WSA8830:
++ dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8830\n",
++ wsa883x->version);
++ break;
++ case WSA8835:
++ dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835\n",
++ wsa883x->version);
++ break;
++ case WSA8832:
++ dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8832\n",
++ wsa883x->version);
++ break;
++ case WSA8835_V2:
++ dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835_V2\n",
++ wsa883x->version);
++ break;
++ default:
++ break;
++ }
++
++ wsa883x->comp_offset = COMP_OFFSET2;
++
++ /* Initial settings */
++ regmap_multi_reg_write(regmap, reg_init, ARRAY_SIZE(reg_init));
++
++ if (wsa883x->variant == WSA8830 || wsa883x->variant == WSA8832) {
++ wsa883x->comp_offset = COMP_OFFSET3;
++ regmap_update_bits(regmap, WSA883X_DRE_CTL_0,
++ WSA883X_DRE_OFFSET_MASK,
++ wsa883x->comp_offset);
++ }
++}
++
++static int wsa883x_update_status(struct sdw_slave *slave,
++ enum sdw_slave_status status)
++{
++ struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev);
++
++ if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0)
++ wsa883x_init(wsa883x);
++
++ return 0;
++}
++
++static int wsa883x_port_prep(struct sdw_slave *slave,
++ struct sdw_prepare_ch *prepare_ch,
++ enum sdw_port_prep_ops state)
++{
++ struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev);
++
++ if (state == SDW_OPS_PORT_POST_PREP)
++ wsa883x->port_prepared[prepare_ch->num - 1] = true;
++ else
++ wsa883x->port_prepared[prepare_ch->num - 1] = false;
++
++ return 0;
++}
++
++static struct sdw_slave_ops wsa883x_slave_ops = {
++ .update_status = wsa883x_update_status,
++ .port_prep = wsa883x_port_prep,
++};
++
++static int wsa883x_codec_probe(struct snd_soc_component *comp)
++{
++ struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(comp);
++
++ snd_soc_component_init_regmap(comp, wsa883x->regmap);
++
++ return 0;
++}
++
++static const struct snd_soc_component_driver wsa883x_component_drv = {
++ .name = "WSA883x",
++ .probe = wsa883x_codec_probe,
++};
++
++static int wsa883x_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params,
++ struct snd_soc_dai *dai)
++{
++ struct wsa883x_priv *wsa883x = dev_get_drvdata(dai->dev);
++ int i;
++
++ wsa883x->active_ports = 0;
++ for (i = 0; i < WSA883X_MAX_SWR_PORTS; i++) {
++ if (!wsa883x->port_enable[i])
++ continue;
++
++ wsa883x->port_config[wsa883x->active_ports] = wsa883x_pconfig[i];
++ wsa883x->active_ports++;
++ }
++
++ wsa883x->sconfig.frame_rate = params_rate(params);
++
++ return sdw_stream_add_slave(wsa883x->slave, &wsa883x->sconfig,
++ wsa883x->port_config, wsa883x->active_ports,
++ wsa883x->sruntime);
++}
++
++static int wsa883x_hw_free(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ struct wsa883x_priv *wsa883x = dev_get_drvdata(dai->dev);
++
++ sdw_stream_remove_slave(wsa883x->slave, wsa883x->sruntime);
++
++ return 0;
++}
++
++static int wsa883x_set_sdw_stream(struct snd_soc_dai *dai,
++ void *stream, int direction)
++{
++ struct wsa883x_priv *wsa883x = dev_get_drvdata(dai->dev);
++
++ wsa883x->sruntime = stream;
++
++ return 0;
++}
++
++static int wsa883x_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
++{
++ struct snd_soc_component *component = dai->component;
++
++ if (mute) {
++ snd_soc_component_write_field(component, WSA883X_DRE_CTL_1,
++ WSA883X_DRE_GAIN_EN_MASK, 0);
++ snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL,
++ WSA883X_GLOBAL_PA_EN_MASK, 0);
++
++ } else {
++ snd_soc_component_write_field(component, WSA883X_DRE_CTL_1,
++ WSA883X_DRE_GAIN_EN_MASK,
++ WSA883X_DRE_GAIN_FROM_CSR);
++ snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL,
++ WSA883X_GLOBAL_PA_EN_MASK, 1);
++
++ }
++
++ return 0;
++}
++
++static const struct snd_soc_dai_ops wsa883x_dai_ops = {
++ .hw_params = wsa883x_hw_params,
++ .hw_free = wsa883x_hw_free,
++ .mute_stream = wsa883x_digital_mute,
++ .set_stream = wsa883x_set_sdw_stream,
++};
++
++static struct snd_soc_dai_driver wsa883x_dais[] = {
++ {
++ .name = "SPKR",
++ .playback = {
++ .stream_name = "SPKR Playback",
++ .rates = WSA883X_RATES | WSA883X_FRAC_RATES,
++ .formats = WSA883X_FORMATS,
++ .rate_max = 8000,
++ .rate_min = 352800,
++ .channels_min = 1,
++ .channels_max = 1,
++ },
++ .ops = &wsa883x_dai_ops,
++ },
++};
++
++static int wsa883x_probe(struct sdw_slave *pdev,
++ const struct sdw_device_id *id)
++{
++ struct wsa883x_priv *wsa883x;
++ struct device *dev = &pdev->dev;
++ int ret;
++
++ wsa883x = devm_kzalloc(&pdev->dev, sizeof(*wsa883x), GFP_KERNEL);
++ if (!wsa883x)
++ return -ENOMEM;
++
++ wsa883x->vdd = devm_regulator_get(dev, "vdd");
++ if (IS_ERR(wsa883x->vdd)) {
++ dev_err(dev, "No vdd regulator found\n");
++ return PTR_ERR(wsa883x->vdd);
++ }
++
++ ret = regulator_enable(wsa883x->vdd);
++ if (ret) {
++ dev_err(dev, "Failed to enable vdd regulator (%d)\n", ret);
++ return ret;
++ }
++
++ wsa883x->sd_n = devm_gpiod_get_optional(&pdev->dev, "powerdown",
++ GPIOD_FLAGS_BIT_NONEXCLUSIVE);
++ if (IS_ERR(wsa883x->sd_n)) {
++ dev_err(&pdev->dev, "Shutdown Control GPIO not found\n");
++ ret = PTR_ERR(wsa883x->sd_n);
++ goto err;
++ }
++
++ dev_set_drvdata(&pdev->dev, wsa883x);
++ wsa883x->slave = pdev;
++ wsa883x->dev = &pdev->dev;
++ wsa883x->sconfig.ch_count = 1;
++ wsa883x->sconfig.bps = 1;
++ wsa883x->sconfig.direction = SDW_DATA_DIR_RX;
++ wsa883x->sconfig.type = SDW_STREAM_PDM;
++
++ pdev->prop.sink_ports = GENMASK(WSA883X_MAX_SWR_PORTS, 0);
++ pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
++ pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
++ gpiod_direction_output(wsa883x->sd_n, 1);
++
++ wsa883x->regmap = devm_regmap_init_sdw(pdev, &wsa883x_regmap_config);
++ if (IS_ERR(wsa883x->regmap)) {
++ dev_err(&pdev->dev, "regmap_init failed\n");
++ ret = PTR_ERR(wsa883x->regmap);
++ goto err;
++ }
++ pm_runtime_set_autosuspend_delay(dev, 3000);
++ pm_runtime_use_autosuspend(dev);
++ pm_runtime_mark_last_busy(dev);
++ pm_runtime_set_active(dev);
++ pm_runtime_enable(dev);
++
++ ret = devm_snd_soc_register_component(&pdev->dev,
++ &wsa883x_component_drv,
++ wsa883x_dais,
++ ARRAY_SIZE(wsa883x_dais));
++err:
++ if (ret)
++ regulator_disable(wsa883x->vdd);
++
++ return ret;
++
++}
++
++static int __maybe_unused wsa883x_runtime_suspend(struct device *dev)
++{
++ struct regmap *regmap = dev_get_regmap(dev, NULL);
++ struct wsa883x_priv *wsa883x = dev_get_drvdata(dev);
++
++ gpiod_direction_output(wsa883x->sd_n, 0);
++
++ regcache_cache_only(regmap, true);
++ regcache_mark_dirty(regmap);
++
++ regulator_disable(wsa883x->vdd);
++ return 0;
++}
++
++static int __maybe_unused wsa883x_runtime_resume(struct device *dev)
++{
++ struct sdw_slave *slave = dev_to_sdw_dev(dev);
++ struct regmap *regmap = dev_get_regmap(dev, NULL);
++ struct wsa883x_priv *wsa883x = dev_get_drvdata(dev);
++ int ret;
++
++ ret = regulator_enable(wsa883x->vdd);
++ if (ret) {
++ dev_err(dev, "Failed to enable vdd regulator (%d)\n", ret);
++ return ret;
++ }
++
++ gpiod_direction_output(wsa883x->sd_n, 1);
++
++ wait_for_completion_timeout(&slave->initialization_complete,
++ msecs_to_jiffies(WSA883X_PROBE_TIMEOUT));
++
++ usleep_range(20000, 20010);
++ regcache_cache_only(regmap, false);
++ regcache_sync(regmap);
++
++ return 0;
++}
++
++static const struct dev_pm_ops wsa883x_pm_ops = {
++ SET_RUNTIME_PM_OPS(wsa883x_runtime_suspend, wsa883x_runtime_resume, NULL)
++};
++
++static const struct sdw_device_id wsa883x_swr_id[] = {
++ SDW_SLAVE_ENTRY(0x0217, 0x0202, 0),
++ {},
++};
++
++static struct sdw_driver wsa883x_codec_driver = {
++ .driver = {
++ .name = "wsa883x-codec",
++ .pm = &wsa883x_pm_ops,
++ .suppress_bind_attrs = true,
++ },
++ .probe = wsa883x_probe,
++ .ops = &wsa883x_slave_ops,
++ .id_table = wsa883x_swr_id,
++};
++
++module_sdw_driver(wsa883x_codec_driver);
++
++MODULE_DESCRIPTION("WSA883x codec driver");
++MODULE_LICENSE("GPL");
+--
+2.42.0
+
--- /dev/null
+From 22c59dbef68cd57b47ba1970546156babadbdc11 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Jan 2023 17:39:51 +0100
+Subject: ASoC: codecs: constify static sdw_slave_ops struct
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 65b7b869da9bd3bd0b9fa60e6fe557bfbc0a75e8 ]
+
+The struct sdw_slave_ops is not modified and sdw_driver takes pointer to
+const, so make it a const for code safety.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/r/20230124163953.345949-1-krzysztof.kozlowski@linaro.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: da29b94ed354 ("ASoC: codecs: wcd938x: fix resource leaks on bind errors")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/rt1316-sdw.c | 2 +-
+ sound/soc/codecs/rt1318-sdw.c | 2 +-
+ sound/soc/codecs/rt711-sdca-sdw.c | 2 +-
+ sound/soc/codecs/rt715-sdca-sdw.c | 2 +-
+ sound/soc/codecs/wcd938x-sdw.c | 2 +-
+ sound/soc/codecs/wsa881x.c | 2 +-
+ sound/soc/codecs/wsa883x.c | 2 +-
+ 7 files changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
+index 1e04aa8ab1666..41f37ff421430 100644
+--- a/sound/soc/codecs/rt1316-sdw.c
++++ b/sound/soc/codecs/rt1316-sdw.c
+@@ -585,7 +585,7 @@ static int rt1316_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
+ * slave_ops: callbacks for get_clock_stop_mode, clock_stop and
+ * port_prep are not defined for now
+ */
+-static struct sdw_slave_ops rt1316_slave_ops = {
++static const struct sdw_slave_ops rt1316_slave_ops = {
+ .read_prop = rt1316_read_prop,
+ .update_status = rt1316_update_status,
+ };
+diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
+index f85f5ab2c6d04..c6ec86e97a6e7 100644
+--- a/sound/soc/codecs/rt1318-sdw.c
++++ b/sound/soc/codecs/rt1318-sdw.c
+@@ -697,7 +697,7 @@ static int rt1318_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
+ * slave_ops: callbacks for get_clock_stop_mode, clock_stop and
+ * port_prep are not defined for now
+ */
+-static struct sdw_slave_ops rt1318_slave_ops = {
++static const struct sdw_slave_ops rt1318_slave_ops = {
+ .read_prop = rt1318_read_prop,
+ .update_status = rt1318_update_status,
+ };
+diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
+index 4faf6b8544ddd..48ae52d2e01b9 100644
+--- a/sound/soc/codecs/rt711-sdca-sdw.c
++++ b/sound/soc/codecs/rt711-sdca-sdw.c
+@@ -338,7 +338,7 @@ static int rt711_sdca_interrupt_callback(struct sdw_slave *slave,
+ return ret;
+ }
+
+-static struct sdw_slave_ops rt711_sdca_slave_ops = {
++static const struct sdw_slave_ops rt711_sdca_slave_ops = {
+ .read_prop = rt711_sdca_read_prop,
+ .interrupt_callback = rt711_sdca_interrupt_callback,
+ .update_status = rt711_sdca_update_status,
+diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c
+index 85abf8073c278..2d72a943f982b 100644
+--- a/sound/soc/codecs/rt715-sdca-sdw.c
++++ b/sound/soc/codecs/rt715-sdca-sdw.c
+@@ -172,7 +172,7 @@ static int rt715_sdca_read_prop(struct sdw_slave *slave)
+ return 0;
+ }
+
+-static struct sdw_slave_ops rt715_sdca_slave_ops = {
++static const struct sdw_slave_ops rt715_sdca_slave_ops = {
+ .read_prop = rt715_sdca_read_prop,
+ .update_status = rt715_sdca_update_status,
+ };
+diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
+index 84a67bd98dc05..f3c9534ae9ef2 100644
+--- a/sound/soc/codecs/wcd938x-sdw.c
++++ b/sound/soc/codecs/wcd938x-sdw.c
+@@ -191,7 +191,7 @@ static int wcd9380_interrupt_callback(struct sdw_slave *slave,
+ return IRQ_HANDLED;
+ }
+
+-static struct sdw_slave_ops wcd9380_slave_ops = {
++static const struct sdw_slave_ops wcd9380_slave_ops = {
+ .update_status = wcd9380_update_status,
+ .interrupt_callback = wcd9380_interrupt_callback,
+ .bus_config = wcd9380_bus_config,
+diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
+index 8559047694873..67f43b5a34e56 100644
+--- a/sound/soc/codecs/wsa881x.c
++++ b/sound/soc/codecs/wsa881x.c
+@@ -1090,7 +1090,7 @@ static int wsa881x_bus_config(struct sdw_slave *slave,
+ return 0;
+ }
+
+-static struct sdw_slave_ops wsa881x_slave_ops = {
++static const struct sdw_slave_ops wsa881x_slave_ops = {
+ .update_status = wsa881x_update_status,
+ .bus_config = wsa881x_bus_config,
+ .port_prep = wsa881x_port_prep,
+diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
+index 856709ec017e6..9cc132c7ccf74 100644
+--- a/sound/soc/codecs/wsa883x.c
++++ b/sound/soc/codecs/wsa883x.c
+@@ -1061,7 +1061,7 @@ static int wsa883x_port_prep(struct sdw_slave *slave,
+ return 0;
+ }
+
+-static struct sdw_slave_ops wsa883x_slave_ops = {
++static const struct sdw_slave_ops wsa883x_slave_ops = {
+ .update_status = wsa883x_update_status,
+ .port_prep = wsa883x_port_prep,
+ };
+--
+2.42.0
+
--- /dev/null
+From 1c3a41eeacbfc67d9be1a73a59cb252c60b1ac64 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Mar 2023 16:05:48 +0100
+Subject: ASoC: codecs: wcd938x: Convert to platform remove callback returning
+ void
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 7cd686a59b36860511965882dad1f76df2c25766 ]
+
+The .remove() callback for a platform driver returns an int which makes
+many driver authors wrongly assume it's possible to do error handling by
+returning an error code. However the value returned is (mostly) ignored
+and this typically results in resource leaks. To improve here there is a
+quest to make the remove callback return void. In the first step of this
+quest all drivers are converted to .remove_new() which already returns
+void.
+
+Trivially convert this driver from always returning zero in the remove
+callback to the void returning variant.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Acked-by: Takashi Iwai <tiwai@suse.de>
+Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
+Link: https://lore.kernel.org/r/20230315150745.67084-57-u.kleine-koenig@pengutronix.de
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 69a026a2357e ("ASoC: codecs: wcd938x: fix regulator leaks on probe errors")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/wcd938x.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
+index e68992b704cfa..00538cf86b87f 100644
+--- a/sound/soc/codecs/wcd938x.c
++++ b/sound/soc/codecs/wcd938x.c
+@@ -3601,11 +3601,9 @@ static int wcd938x_probe(struct platform_device *pdev)
+ return 0;
+ }
+
+-static int wcd938x_remove(struct platform_device *pdev)
++static void wcd938x_remove(struct platform_device *pdev)
+ {
+ component_master_del(&pdev->dev, &wcd938x_comp_ops);
+-
+- return 0;
+ }
+
+ #if defined(CONFIG_OF)
+@@ -3619,7 +3617,7 @@ MODULE_DEVICE_TABLE(of, wcd938x_dt_match);
+
+ static struct platform_driver wcd938x_codec_driver = {
+ .probe = wcd938x_probe,
+- .remove = wcd938x_remove,
++ .remove_new = wcd938x_remove,
+ .driver = {
+ .name = "wcd938x_codec",
+ .of_match_table = of_match_ptr(wcd938x_dt_match),
+--
+2.42.0
+
--- /dev/null
+From 48b1f249eb428f77e6cc22daa0c9b10cfc7e4da8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 3 May 2023 16:41:02 +0200
+Subject: ASoC: codecs: wcd938x: fix accessing regmap on unattached devices
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 84822215acd15bd86a7759a835271e63bba83a7b ]
+
+The WCD938x comes with three devices on two Linux drivers:
+1. RX Soundwire device (wcd938x-sdw.c driver),
+2. TX Soundwire device, which is used to access devices via regmap (also
+ wcd938x-sdw.c driver),
+3. platform device (wcd938x.c driver) - glue and component master,
+ actually having most of the code using TX Soundwire device regmap.
+
+When RX and TX Soundwire devices probe, the component master (platform
+device) bind tries to write micbias configuration via TX Soundwire
+regmap. This might happen before TX Soundwire enumerates, so the regmap
+access fails. On Qualcomm SM8550 board with WCD9385:
+
+ qcom-soundwire 6d30000.soundwire-controller: Qualcomm Soundwire controller v2.0.0 Registered
+ wcd938x_codec audio-codec: bound sdw:0:0217:010d:00:4 (ops wcd938x_sdw_component_ops)
+ wcd938x_codec audio-codec: bound sdw:0:0217:010d:00:3 (ops wcd938x_sdw_component_ops)
+ qcom-soundwire 6ad0000.soundwire-controller: swrm_wait_for_wr_fifo_avail err write overflow
+
+Fix the issue by:
+1. Moving the regmap creation from platform device to TX Soundwire
+ device. The regmap settings are moved as-is with one difference:
+ making the wcd938x_regmap_config const.
+2. Using regmap in cache only mode till the actual TX Soundwire device
+ enumerates and then sync the regmap cache.
+
+Cc: <stable@vger.kernel.org> # v3.14+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+Message-Id: <20230503144102.242240-1-krzysztof.kozlowski@linaro.org>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: da29b94ed354 ("ASoC: codecs: wcd938x: fix resource leaks on bind errors")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/wcd938x-sdw.c | 1037 +++++++++++++++++++++++++++++++-
+ sound/soc/codecs/wcd938x.c | 1003 +-----------------------------
+ sound/soc/codecs/wcd938x.h | 1 +
+ 3 files changed, 1030 insertions(+), 1011 deletions(-)
+
+diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
+index f3c9534ae9ef2..f233d9d4a7717 100644
+--- a/sound/soc/codecs/wcd938x-sdw.c
++++ b/sound/soc/codecs/wcd938x-sdw.c
+@@ -161,6 +161,14 @@ EXPORT_SYMBOL_GPL(wcd938x_sdw_set_sdw_stream);
+ static int wcd9380_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+ {
++ struct wcd938x_sdw_priv *wcd = dev_get_drvdata(&slave->dev);
++
++ if (wcd->regmap && (status == SDW_SLAVE_ATTACHED)) {
++ /* Write out any cached changes that happened between probe and attach */
++ regcache_cache_only(wcd->regmap, false);
++ return regcache_sync(wcd->regmap);
++ }
++
+ return 0;
+ }
+
+@@ -177,20 +185,1014 @@ static int wcd9380_interrupt_callback(struct sdw_slave *slave,
+ {
+ struct wcd938x_sdw_priv *wcd = dev_get_drvdata(&slave->dev);
+ struct irq_domain *slave_irq = wcd->slave_irq;
+- struct regmap *regmap = dev_get_regmap(&slave->dev, NULL);
+ u32 sts1, sts2, sts3;
+
+ do {
+ handle_nested_irq(irq_find_mapping(slave_irq, 0));
+- regmap_read(regmap, WCD938X_DIGITAL_INTR_STATUS_0, &sts1);
+- regmap_read(regmap, WCD938X_DIGITAL_INTR_STATUS_1, &sts2);
+- regmap_read(regmap, WCD938X_DIGITAL_INTR_STATUS_2, &sts3);
++ regmap_read(wcd->regmap, WCD938X_DIGITAL_INTR_STATUS_0, &sts1);
++ regmap_read(wcd->regmap, WCD938X_DIGITAL_INTR_STATUS_1, &sts2);
++ regmap_read(wcd->regmap, WCD938X_DIGITAL_INTR_STATUS_2, &sts3);
+
+ } while (sts1 || sts2 || sts3);
+
+ return IRQ_HANDLED;
+ }
+
++static const struct reg_default wcd938x_defaults[] = {
++ {WCD938X_ANA_PAGE_REGISTER, 0x00},
++ {WCD938X_ANA_BIAS, 0x00},
++ {WCD938X_ANA_RX_SUPPLIES, 0x00},
++ {WCD938X_ANA_HPH, 0x0C},
++ {WCD938X_ANA_EAR, 0x00},
++ {WCD938X_ANA_EAR_COMPANDER_CTL, 0x02},
++ {WCD938X_ANA_TX_CH1, 0x20},
++ {WCD938X_ANA_TX_CH2, 0x00},
++ {WCD938X_ANA_TX_CH3, 0x20},
++ {WCD938X_ANA_TX_CH4, 0x00},
++ {WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC, 0x00},
++ {WCD938X_ANA_MICB3_DSP_EN_LOGIC, 0x00},
++ {WCD938X_ANA_MBHC_MECH, 0x39},
++ {WCD938X_ANA_MBHC_ELECT, 0x08},
++ {WCD938X_ANA_MBHC_ZDET, 0x00},
++ {WCD938X_ANA_MBHC_RESULT_1, 0x00},
++ {WCD938X_ANA_MBHC_RESULT_2, 0x00},
++ {WCD938X_ANA_MBHC_RESULT_3, 0x00},
++ {WCD938X_ANA_MBHC_BTN0, 0x00},
++ {WCD938X_ANA_MBHC_BTN1, 0x10},
++ {WCD938X_ANA_MBHC_BTN2, 0x20},
++ {WCD938X_ANA_MBHC_BTN3, 0x30},
++ {WCD938X_ANA_MBHC_BTN4, 0x40},
++ {WCD938X_ANA_MBHC_BTN5, 0x50},
++ {WCD938X_ANA_MBHC_BTN6, 0x60},
++ {WCD938X_ANA_MBHC_BTN7, 0x70},
++ {WCD938X_ANA_MICB1, 0x10},
++ {WCD938X_ANA_MICB2, 0x10},
++ {WCD938X_ANA_MICB2_RAMP, 0x00},
++ {WCD938X_ANA_MICB3, 0x10},
++ {WCD938X_ANA_MICB4, 0x10},
++ {WCD938X_BIAS_CTL, 0x2A},
++ {WCD938X_BIAS_VBG_FINE_ADJ, 0x55},
++ {WCD938X_LDOL_VDDCX_ADJUST, 0x01},
++ {WCD938X_LDOL_DISABLE_LDOL, 0x00},
++ {WCD938X_MBHC_CTL_CLK, 0x00},
++ {WCD938X_MBHC_CTL_ANA, 0x00},
++ {WCD938X_MBHC_CTL_SPARE_1, 0x00},
++ {WCD938X_MBHC_CTL_SPARE_2, 0x00},
++ {WCD938X_MBHC_CTL_BCS, 0x00},
++ {WCD938X_MBHC_MOISTURE_DET_FSM_STATUS, 0x00},
++ {WCD938X_MBHC_TEST_CTL, 0x00},
++ {WCD938X_LDOH_MODE, 0x2B},
++ {WCD938X_LDOH_BIAS, 0x68},
++ {WCD938X_LDOH_STB_LOADS, 0x00},
++ {WCD938X_LDOH_SLOWRAMP, 0x50},
++ {WCD938X_MICB1_TEST_CTL_1, 0x1A},
++ {WCD938X_MICB1_TEST_CTL_2, 0x00},
++ {WCD938X_MICB1_TEST_CTL_3, 0xA4},
++ {WCD938X_MICB2_TEST_CTL_1, 0x1A},
++ {WCD938X_MICB2_TEST_CTL_2, 0x00},
++ {WCD938X_MICB2_TEST_CTL_3, 0x24},
++ {WCD938X_MICB3_TEST_CTL_1, 0x1A},
++ {WCD938X_MICB3_TEST_CTL_2, 0x00},
++ {WCD938X_MICB3_TEST_CTL_3, 0xA4},
++ {WCD938X_MICB4_TEST_CTL_1, 0x1A},
++ {WCD938X_MICB4_TEST_CTL_2, 0x00},
++ {WCD938X_MICB4_TEST_CTL_3, 0xA4},
++ {WCD938X_TX_COM_ADC_VCM, 0x39},
++ {WCD938X_TX_COM_BIAS_ATEST, 0xE0},
++ {WCD938X_TX_COM_SPARE1, 0x00},
++ {WCD938X_TX_COM_SPARE2, 0x00},
++ {WCD938X_TX_COM_TXFE_DIV_CTL, 0x22},
++ {WCD938X_TX_COM_TXFE_DIV_START, 0x00},
++ {WCD938X_TX_COM_SPARE3, 0x00},
++ {WCD938X_TX_COM_SPARE4, 0x00},
++ {WCD938X_TX_1_2_TEST_EN, 0xCC},
++ {WCD938X_TX_1_2_ADC_IB, 0xE9},
++ {WCD938X_TX_1_2_ATEST_REFCTL, 0x0A},
++ {WCD938X_TX_1_2_TEST_CTL, 0x38},
++ {WCD938X_TX_1_2_TEST_BLK_EN1, 0xFF},
++ {WCD938X_TX_1_2_TXFE1_CLKDIV, 0x00},
++ {WCD938X_TX_1_2_SAR2_ERR, 0x00},
++ {WCD938X_TX_1_2_SAR1_ERR, 0x00},
++ {WCD938X_TX_3_4_TEST_EN, 0xCC},
++ {WCD938X_TX_3_4_ADC_IB, 0xE9},
++ {WCD938X_TX_3_4_ATEST_REFCTL, 0x0A},
++ {WCD938X_TX_3_4_TEST_CTL, 0x38},
++ {WCD938X_TX_3_4_TEST_BLK_EN3, 0xFF},
++ {WCD938X_TX_3_4_TXFE3_CLKDIV, 0x00},
++ {WCD938X_TX_3_4_SAR4_ERR, 0x00},
++ {WCD938X_TX_3_4_SAR3_ERR, 0x00},
++ {WCD938X_TX_3_4_TEST_BLK_EN2, 0xFB},
++ {WCD938X_TX_3_4_TXFE2_CLKDIV, 0x00},
++ {WCD938X_TX_3_4_SPARE1, 0x00},
++ {WCD938X_TX_3_4_TEST_BLK_EN4, 0xFB},
++ {WCD938X_TX_3_4_TXFE4_CLKDIV, 0x00},
++ {WCD938X_TX_3_4_SPARE2, 0x00},
++ {WCD938X_CLASSH_MODE_1, 0x40},
++ {WCD938X_CLASSH_MODE_2, 0x3A},
++ {WCD938X_CLASSH_MODE_3, 0x00},
++ {WCD938X_CLASSH_CTRL_VCL_1, 0x70},
++ {WCD938X_CLASSH_CTRL_VCL_2, 0x82},
++ {WCD938X_CLASSH_CTRL_CCL_1, 0x31},
++ {WCD938X_CLASSH_CTRL_CCL_2, 0x80},
++ {WCD938X_CLASSH_CTRL_CCL_3, 0x80},
++ {WCD938X_CLASSH_CTRL_CCL_4, 0x51},
++ {WCD938X_CLASSH_CTRL_CCL_5, 0x00},
++ {WCD938X_CLASSH_BUCK_TMUX_A_D, 0x00},
++ {WCD938X_CLASSH_BUCK_SW_DRV_CNTL, 0x77},
++ {WCD938X_CLASSH_SPARE, 0x00},
++ {WCD938X_FLYBACK_EN, 0x4E},
++ {WCD938X_FLYBACK_VNEG_CTRL_1, 0x0B},
++ {WCD938X_FLYBACK_VNEG_CTRL_2, 0x45},
++ {WCD938X_FLYBACK_VNEG_CTRL_3, 0x74},
++ {WCD938X_FLYBACK_VNEG_CTRL_4, 0x7F},
++ {WCD938X_FLYBACK_VNEG_CTRL_5, 0x83},
++ {WCD938X_FLYBACK_VNEG_CTRL_6, 0x98},
++ {WCD938X_FLYBACK_VNEG_CTRL_7, 0xA9},
++ {WCD938X_FLYBACK_VNEG_CTRL_8, 0x68},
++ {WCD938X_FLYBACK_VNEG_CTRL_9, 0x64},
++ {WCD938X_FLYBACK_VNEGDAC_CTRL_1, 0xED},
++ {WCD938X_FLYBACK_VNEGDAC_CTRL_2, 0xF0},
++ {WCD938X_FLYBACK_VNEGDAC_CTRL_3, 0xA6},
++ {WCD938X_FLYBACK_CTRL_1, 0x65},
++ {WCD938X_FLYBACK_TEST_CTL, 0x00},
++ {WCD938X_RX_AUX_SW_CTL, 0x00},
++ {WCD938X_RX_PA_AUX_IN_CONN, 0x01},
++ {WCD938X_RX_TIMER_DIV, 0x32},
++ {WCD938X_RX_OCP_CTL, 0x1F},
++ {WCD938X_RX_OCP_COUNT, 0x77},
++ {WCD938X_RX_BIAS_EAR_DAC, 0xA0},
++ {WCD938X_RX_BIAS_EAR_AMP, 0xAA},
++ {WCD938X_RX_BIAS_HPH_LDO, 0xA9},
++ {WCD938X_RX_BIAS_HPH_PA, 0xAA},
++ {WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8A},
++ {WCD938X_RX_BIAS_HPH_RDAC_LDO, 0x88},
++ {WCD938X_RX_BIAS_HPH_CNP1, 0x82},
++ {WCD938X_RX_BIAS_HPH_LOWPOWER, 0x82},
++ {WCD938X_RX_BIAS_AUX_DAC, 0xA0},
++ {WCD938X_RX_BIAS_AUX_AMP, 0xAA},
++ {WCD938X_RX_BIAS_VNEGDAC_BLEEDER, 0x50},
++ {WCD938X_RX_BIAS_MISC, 0x00},
++ {WCD938X_RX_BIAS_BUCK_RST, 0x08},
++ {WCD938X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44},
++ {WCD938X_RX_BIAS_FLYB_ERRAMP, 0x40},
++ {WCD938X_RX_BIAS_FLYB_BUFF, 0xAA},
++ {WCD938X_RX_BIAS_FLYB_MID_RST, 0x14},
++ {WCD938X_HPH_L_STATUS, 0x04},
++ {WCD938X_HPH_R_STATUS, 0x04},
++ {WCD938X_HPH_CNP_EN, 0x80},
++ {WCD938X_HPH_CNP_WG_CTL, 0x9A},
++ {WCD938X_HPH_CNP_WG_TIME, 0x14},
++ {WCD938X_HPH_OCP_CTL, 0x28},
++ {WCD938X_HPH_AUTO_CHOP, 0x16},
++ {WCD938X_HPH_CHOP_CTL, 0x83},
++ {WCD938X_HPH_PA_CTL1, 0x46},
++ {WCD938X_HPH_PA_CTL2, 0x50},
++ {WCD938X_HPH_L_EN, 0x80},
++ {WCD938X_HPH_L_TEST, 0xE0},
++ {WCD938X_HPH_L_ATEST, 0x50},
++ {WCD938X_HPH_R_EN, 0x80},
++ {WCD938X_HPH_R_TEST, 0xE0},
++ {WCD938X_HPH_R_ATEST, 0x54},
++ {WCD938X_HPH_RDAC_CLK_CTL1, 0x99},
++ {WCD938X_HPH_RDAC_CLK_CTL2, 0x9B},
++ {WCD938X_HPH_RDAC_LDO_CTL, 0x33},
++ {WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00},
++ {WCD938X_HPH_REFBUFF_UHQA_CTL, 0x68},
++ {WCD938X_HPH_REFBUFF_LP_CTL, 0x0E},
++ {WCD938X_HPH_L_DAC_CTL, 0x20},
++ {WCD938X_HPH_R_DAC_CTL, 0x20},
++ {WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL, 0x55},
++ {WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0x19},
++ {WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1, 0xA0},
++ {WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS, 0x00},
++ {WCD938X_EAR_EAR_EN_REG, 0x22},
++ {WCD938X_EAR_EAR_PA_CON, 0x44},
++ {WCD938X_EAR_EAR_SP_CON, 0xDB},
++ {WCD938X_EAR_EAR_DAC_CON, 0x80},
++ {WCD938X_EAR_EAR_CNP_FSM_CON, 0xB2},
++ {WCD938X_EAR_TEST_CTL, 0x00},
++ {WCD938X_EAR_STATUS_REG_1, 0x00},
++ {WCD938X_EAR_STATUS_REG_2, 0x08},
++ {WCD938X_ANA_NEW_PAGE_REGISTER, 0x00},
++ {WCD938X_HPH_NEW_ANA_HPH2, 0x00},
++ {WCD938X_HPH_NEW_ANA_HPH3, 0x00},
++ {WCD938X_SLEEP_CTL, 0x16},
++ {WCD938X_SLEEP_WATCHDOG_CTL, 0x00},
++ {WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00},
++ {WCD938X_MBHC_NEW_CTL_1, 0x02},
++ {WCD938X_MBHC_NEW_CTL_2, 0x05},
++ {WCD938X_MBHC_NEW_PLUG_DETECT_CTL, 0xE9},
++ {WCD938X_MBHC_NEW_ZDET_ANA_CTL, 0x0F},
++ {WCD938X_MBHC_NEW_ZDET_RAMP_CTL, 0x00},
++ {WCD938X_MBHC_NEW_FSM_STATUS, 0x00},
++ {WCD938X_MBHC_NEW_ADC_RESULT, 0x00},
++ {WCD938X_TX_NEW_AMIC_MUX_CFG, 0x00},
++ {WCD938X_AUX_AUXPA, 0x00},
++ {WCD938X_LDORXTX_MODE, 0x0C},
++ {WCD938X_LDORXTX_CONFIG, 0x10},
++ {WCD938X_DIE_CRACK_DIE_CRK_DET_EN, 0x00},
++ {WCD938X_DIE_CRACK_DIE_CRK_DET_OUT, 0x00},
++ {WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40},
++ {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x81},
++ {WCD938X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10},
++ {WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00},
++ {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x81},
++ {WCD938X_HPH_NEW_INT_PA_MISC1, 0x22},
++ {WCD938X_HPH_NEW_INT_PA_MISC2, 0x00},
++ {WCD938X_HPH_NEW_INT_PA_RDAC_MISC, 0x00},
++ {WCD938X_HPH_NEW_INT_HPH_TIMER1, 0xFE},
++ {WCD938X_HPH_NEW_INT_HPH_TIMER2, 0x02},
++ {WCD938X_HPH_NEW_INT_HPH_TIMER3, 0x4E},
++ {WCD938X_HPH_NEW_INT_HPH_TIMER4, 0x54},
++ {WCD938X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00},
++ {WCD938X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00},
++ {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW, 0x90},
++ {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW, 0x90},
++ {WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62},
++ {WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01},
++ {WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11},
++ {WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57},
++ {WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01},
++ {WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00},
++ {WCD938X_MBHC_NEW_INT_SPARE_2, 0x00},
++ {WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON, 0xA8},
++ {WCD938X_EAR_INT_NEW_CNP_VCM_CON1, 0x42},
++ {WCD938X_EAR_INT_NEW_CNP_VCM_CON2, 0x22},
++ {WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS, 0x00},
++ {WCD938X_AUX_INT_EN_REG, 0x00},
++ {WCD938X_AUX_INT_PA_CTRL, 0x06},
++ {WCD938X_AUX_INT_SP_CTRL, 0xD2},
++ {WCD938X_AUX_INT_DAC_CTRL, 0x80},
++ {WCD938X_AUX_INT_CLK_CTRL, 0x50},
++ {WCD938X_AUX_INT_TEST_CTRL, 0x00},
++ {WCD938X_AUX_INT_STATUS_REG, 0x00},
++ {WCD938X_AUX_INT_MISC, 0x00},
++ {WCD938X_LDORXTX_INT_BIAS, 0x6E},
++ {WCD938X_LDORXTX_INT_STB_LOADS_DTEST, 0x50},
++ {WCD938X_LDORXTX_INT_TEST0, 0x1C},
++ {WCD938X_LDORXTX_INT_STARTUP_TIMER, 0xFF},
++ {WCD938X_LDORXTX_INT_TEST1, 0x1F},
++ {WCD938X_LDORXTX_INT_STATUS, 0x00},
++ {WCD938X_SLEEP_INT_WATCHDOG_CTL_1, 0x0A},
++ {WCD938X_SLEEP_INT_WATCHDOG_CTL_2, 0x0A},
++ {WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1, 0x02},
++ {WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2, 0x60},
++ {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2, 0xFF},
++ {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1, 0x7F},
++ {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0, 0x3F},
++ {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M, 0x1F},
++ {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M, 0x0F},
++ {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1, 0xD7},
++ {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0, 0xC8},
++ {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP, 0xC6},
++ {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1, 0xD5},
++ {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0, 0xCA},
++ {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP, 0x05},
++ {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0, 0xA5},
++ {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP, 0x13},
++ {WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1, 0x88},
++ {WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP, 0x42},
++ {WCD938X_TX_COM_NEW_INT_TXADC_INT_L2, 0xFF},
++ {WCD938X_TX_COM_NEW_INT_TXADC_INT_L1, 0x64},
++ {WCD938X_TX_COM_NEW_INT_TXADC_INT_L0, 0x64},
++ {WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP, 0x77},
++ {WCD938X_DIGITAL_PAGE_REGISTER, 0x00},
++ {WCD938X_DIGITAL_CHIP_ID0, 0x00},
++ {WCD938X_DIGITAL_CHIP_ID1, 0x00},
++ {WCD938X_DIGITAL_CHIP_ID2, 0x0D},
++ {WCD938X_DIGITAL_CHIP_ID3, 0x01},
++ {WCD938X_DIGITAL_SWR_TX_CLK_RATE, 0x00},
++ {WCD938X_DIGITAL_CDC_RST_CTL, 0x03},
++ {WCD938X_DIGITAL_TOP_CLK_CFG, 0x00},
++ {WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x00},
++ {WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0xF0},
++ {WCD938X_DIGITAL_SWR_RST_EN, 0x00},
++ {WCD938X_DIGITAL_CDC_PATH_MODE, 0x55},
++ {WCD938X_DIGITAL_CDC_RX_RST, 0x00},
++ {WCD938X_DIGITAL_CDC_RX0_CTL, 0xFC},
++ {WCD938X_DIGITAL_CDC_RX1_CTL, 0xFC},
++ {WCD938X_DIGITAL_CDC_RX2_CTL, 0xFC},
++ {WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0x00},
++ {WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0x00},
++ {WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x00},
++ {WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL, 0x1E},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_A1_0, 0x00},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_A1_1, 0x01},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_A2_0, 0x63},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_A2_1, 0x04},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_A3_0, 0xAC},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_A3_1, 0x04},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_A4_0, 0x1A},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_A4_1, 0x03},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_A5_0, 0xBC},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_A5_1, 0x02},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_A6_0, 0xC7},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_A7_0, 0xF8},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_C_0, 0x47},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_C_1, 0x43},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_C_2, 0xB1},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_C_3, 0x17},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_R1, 0x4D},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_R2, 0x29},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_R3, 0x34},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_R4, 0x59},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_R5, 0x66},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_R6, 0x87},
++ {WCD938X_DIGITAL_CDC_HPH_DSM_R7, 0x64},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_A1_0, 0x00},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_A1_1, 0x01},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_A2_0, 0x96},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_A2_1, 0x09},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_A3_0, 0xAB},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_A3_1, 0x05},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_A4_0, 0x1C},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_A4_1, 0x02},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_A5_0, 0x17},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_A5_1, 0x02},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_A6_0, 0xAA},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_A7_0, 0xE3},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_C_0, 0x69},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_C_1, 0x54},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_C_2, 0x02},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_C_3, 0x15},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_R1, 0xA4},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_R2, 0xB5},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_R3, 0x86},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_R4, 0x85},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_R5, 0xAA},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_R6, 0xE2},
++ {WCD938X_DIGITAL_CDC_AUX_DSM_R7, 0x62},
++ {WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0, 0x55},
++ {WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1, 0xA9},
++ {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0, 0x3D},
++ {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1, 0x2E},
++ {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2, 0x01},
++ {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0, 0x00},
++ {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1, 0xFC},
++ {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2, 0x01},
++ {WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x00},
++ {WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x00},
++ {WCD938X_DIGITAL_CDC_EAR_PATH_CTL, 0x00},
++ {WCD938X_DIGITAL_CDC_SWR_CLH, 0x00},
++ {WCD938X_DIGITAL_SWR_CLH_BYP, 0x00},
++ {WCD938X_DIGITAL_CDC_TX0_CTL, 0x68},
++ {WCD938X_DIGITAL_CDC_TX1_CTL, 0x68},
++ {WCD938X_DIGITAL_CDC_TX2_CTL, 0x68},
++ {WCD938X_DIGITAL_CDC_TX_RST, 0x00},
++ {WCD938X_DIGITAL_CDC_REQ_CTL, 0x01},
++ {WCD938X_DIGITAL_CDC_RST, 0x00},
++ {WCD938X_DIGITAL_CDC_AMIC_CTL, 0x0F},
++ {WCD938X_DIGITAL_CDC_DMIC_CTL, 0x04},
++ {WCD938X_DIGITAL_CDC_DMIC1_CTL, 0x01},
++ {WCD938X_DIGITAL_CDC_DMIC2_CTL, 0x01},
++ {WCD938X_DIGITAL_CDC_DMIC3_CTL, 0x01},
++ {WCD938X_DIGITAL_CDC_DMIC4_CTL, 0x01},
++ {WCD938X_DIGITAL_EFUSE_PRG_CTL, 0x00},
++ {WCD938X_DIGITAL_EFUSE_CTL, 0x2B},
++ {WCD938X_DIGITAL_CDC_DMIC_RATE_1_2, 0x11},
++ {WCD938X_DIGITAL_CDC_DMIC_RATE_3_4, 0x11},
++ {WCD938X_DIGITAL_PDM_WD_CTL0, 0x00},
++ {WCD938X_DIGITAL_PDM_WD_CTL1, 0x00},
++ {WCD938X_DIGITAL_PDM_WD_CTL2, 0x00},
++ {WCD938X_DIGITAL_INTR_MODE, 0x00},
++ {WCD938X_DIGITAL_INTR_MASK_0, 0xFF},
++ {WCD938X_DIGITAL_INTR_MASK_1, 0xFF},
++ {WCD938X_DIGITAL_INTR_MASK_2, 0x3F},
++ {WCD938X_DIGITAL_INTR_STATUS_0, 0x00},
++ {WCD938X_DIGITAL_INTR_STATUS_1, 0x00},
++ {WCD938X_DIGITAL_INTR_STATUS_2, 0x00},
++ {WCD938X_DIGITAL_INTR_CLEAR_0, 0x00},
++ {WCD938X_DIGITAL_INTR_CLEAR_1, 0x00},
++ {WCD938X_DIGITAL_INTR_CLEAR_2, 0x00},
++ {WCD938X_DIGITAL_INTR_LEVEL_0, 0x00},
++ {WCD938X_DIGITAL_INTR_LEVEL_1, 0x00},
++ {WCD938X_DIGITAL_INTR_LEVEL_2, 0x00},
++ {WCD938X_DIGITAL_INTR_SET_0, 0x00},
++ {WCD938X_DIGITAL_INTR_SET_1, 0x00},
++ {WCD938X_DIGITAL_INTR_SET_2, 0x00},
++ {WCD938X_DIGITAL_INTR_TEST_0, 0x00},
++ {WCD938X_DIGITAL_INTR_TEST_1, 0x00},
++ {WCD938X_DIGITAL_INTR_TEST_2, 0x00},
++ {WCD938X_DIGITAL_TX_MODE_DBG_EN, 0x00},
++ {WCD938X_DIGITAL_TX_MODE_DBG_0_1, 0x00},
++ {WCD938X_DIGITAL_TX_MODE_DBG_2_3, 0x00},
++ {WCD938X_DIGITAL_LB_IN_SEL_CTL, 0x00},
++ {WCD938X_DIGITAL_LOOP_BACK_MODE, 0x00},
++ {WCD938X_DIGITAL_SWR_DAC_TEST, 0x00},
++ {WCD938X_DIGITAL_SWR_HM_TEST_RX_0, 0x40},
++ {WCD938X_DIGITAL_SWR_HM_TEST_TX_0, 0x40},
++ {WCD938X_DIGITAL_SWR_HM_TEST_RX_1, 0x00},
++ {WCD938X_DIGITAL_SWR_HM_TEST_TX_1, 0x00},
++ {WCD938X_DIGITAL_SWR_HM_TEST_TX_2, 0x00},
++ {WCD938X_DIGITAL_SWR_HM_TEST_0, 0x00},
++ {WCD938X_DIGITAL_SWR_HM_TEST_1, 0x00},
++ {WCD938X_DIGITAL_PAD_CTL_SWR_0, 0x8F},
++ {WCD938X_DIGITAL_PAD_CTL_SWR_1, 0x06},
++ {WCD938X_DIGITAL_I2C_CTL, 0x00},
++ {WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE, 0x00},
++ {WCD938X_DIGITAL_EFUSE_TEST_CTL_0, 0x00},
++ {WCD938X_DIGITAL_EFUSE_TEST_CTL_1, 0x00},
++ {WCD938X_DIGITAL_EFUSE_T_DATA_0, 0x00},
++ {WCD938X_DIGITAL_EFUSE_T_DATA_1, 0x00},
++ {WCD938X_DIGITAL_PAD_CTL_PDM_RX0, 0xF1},
++ {WCD938X_DIGITAL_PAD_CTL_PDM_RX1, 0xF1},
++ {WCD938X_DIGITAL_PAD_CTL_PDM_TX0, 0xF1},
++ {WCD938X_DIGITAL_PAD_CTL_PDM_TX1, 0xF1},
++ {WCD938X_DIGITAL_PAD_CTL_PDM_TX2, 0xF1},
++ {WCD938X_DIGITAL_PAD_INP_DIS_0, 0x00},
++ {WCD938X_DIGITAL_PAD_INP_DIS_1, 0x00},
++ {WCD938X_DIGITAL_DRIVE_STRENGTH_0, 0x00},
++ {WCD938X_DIGITAL_DRIVE_STRENGTH_1, 0x00},
++ {WCD938X_DIGITAL_DRIVE_STRENGTH_2, 0x00},
++ {WCD938X_DIGITAL_RX_DATA_EDGE_CTL, 0x1F},
++ {WCD938X_DIGITAL_TX_DATA_EDGE_CTL, 0x80},
++ {WCD938X_DIGITAL_GPIO_MODE, 0x00},
++ {WCD938X_DIGITAL_PIN_CTL_OE, 0x00},
++ {WCD938X_DIGITAL_PIN_CTL_DATA_0, 0x00},
++ {WCD938X_DIGITAL_PIN_CTL_DATA_1, 0x00},
++ {WCD938X_DIGITAL_PIN_STATUS_0, 0x00},
++ {WCD938X_DIGITAL_PIN_STATUS_1, 0x00},
++ {WCD938X_DIGITAL_DIG_DEBUG_CTL, 0x00},
++ {WCD938X_DIGITAL_DIG_DEBUG_EN, 0x00},
++ {WCD938X_DIGITAL_ANA_CSR_DBG_ADD, 0x00},
++ {WCD938X_DIGITAL_ANA_CSR_DBG_CTL, 0x48},
++ {WCD938X_DIGITAL_SSP_DBG, 0x00},
++ {WCD938X_DIGITAL_MODE_STATUS_0, 0x00},
++ {WCD938X_DIGITAL_MODE_STATUS_1, 0x00},
++ {WCD938X_DIGITAL_SPARE_0, 0x00},
++ {WCD938X_DIGITAL_SPARE_1, 0x00},
++ {WCD938X_DIGITAL_SPARE_2, 0x00},
++ {WCD938X_DIGITAL_EFUSE_REG_0, 0x00},
++ {WCD938X_DIGITAL_EFUSE_REG_1, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_2, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_3, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_4, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_5, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_6, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_7, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_8, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_9, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_10, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_11, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_12, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_13, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_14, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_15, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_16, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_17, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_18, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_19, 0xFF},
++ {WCD938X_DIGITAL_EFUSE_REG_20, 0x0E},
++ {WCD938X_DIGITAL_EFUSE_REG_21, 0x00},
++ {WCD938X_DIGITAL_EFUSE_REG_22, 0x00},
++ {WCD938X_DIGITAL_EFUSE_REG_23, 0xF8},
++ {WCD938X_DIGITAL_EFUSE_REG_24, 0x16},
++ {WCD938X_DIGITAL_EFUSE_REG_25, 0x00},
++ {WCD938X_DIGITAL_EFUSE_REG_26, 0x00},
++ {WCD938X_DIGITAL_EFUSE_REG_27, 0x00},
++ {WCD938X_DIGITAL_EFUSE_REG_28, 0x00},
++ {WCD938X_DIGITAL_EFUSE_REG_29, 0x00},
++ {WCD938X_DIGITAL_EFUSE_REG_30, 0x00},
++ {WCD938X_DIGITAL_EFUSE_REG_31, 0x00},
++ {WCD938X_DIGITAL_TX_REQ_FB_CTL_0, 0x88},
++ {WCD938X_DIGITAL_TX_REQ_FB_CTL_1, 0x88},
++ {WCD938X_DIGITAL_TX_REQ_FB_CTL_2, 0x88},
++ {WCD938X_DIGITAL_TX_REQ_FB_CTL_3, 0x88},
++ {WCD938X_DIGITAL_TX_REQ_FB_CTL_4, 0x88},
++ {WCD938X_DIGITAL_DEM_BYPASS_DATA0, 0x55},
++ {WCD938X_DIGITAL_DEM_BYPASS_DATA1, 0x55},
++ {WCD938X_DIGITAL_DEM_BYPASS_DATA2, 0x55},
++ {WCD938X_DIGITAL_DEM_BYPASS_DATA3, 0x01},
++};
++
++static bool wcd938x_rdwr_register(struct device *dev, unsigned int reg)
++{
++ switch (reg) {
++ case WCD938X_ANA_PAGE_REGISTER:
++ case WCD938X_ANA_BIAS:
++ case WCD938X_ANA_RX_SUPPLIES:
++ case WCD938X_ANA_HPH:
++ case WCD938X_ANA_EAR:
++ case WCD938X_ANA_EAR_COMPANDER_CTL:
++ case WCD938X_ANA_TX_CH1:
++ case WCD938X_ANA_TX_CH2:
++ case WCD938X_ANA_TX_CH3:
++ case WCD938X_ANA_TX_CH4:
++ case WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC:
++ case WCD938X_ANA_MICB3_DSP_EN_LOGIC:
++ case WCD938X_ANA_MBHC_MECH:
++ case WCD938X_ANA_MBHC_ELECT:
++ case WCD938X_ANA_MBHC_ZDET:
++ case WCD938X_ANA_MBHC_BTN0:
++ case WCD938X_ANA_MBHC_BTN1:
++ case WCD938X_ANA_MBHC_BTN2:
++ case WCD938X_ANA_MBHC_BTN3:
++ case WCD938X_ANA_MBHC_BTN4:
++ case WCD938X_ANA_MBHC_BTN5:
++ case WCD938X_ANA_MBHC_BTN6:
++ case WCD938X_ANA_MBHC_BTN7:
++ case WCD938X_ANA_MICB1:
++ case WCD938X_ANA_MICB2:
++ case WCD938X_ANA_MICB2_RAMP:
++ case WCD938X_ANA_MICB3:
++ case WCD938X_ANA_MICB4:
++ case WCD938X_BIAS_CTL:
++ case WCD938X_BIAS_VBG_FINE_ADJ:
++ case WCD938X_LDOL_VDDCX_ADJUST:
++ case WCD938X_LDOL_DISABLE_LDOL:
++ case WCD938X_MBHC_CTL_CLK:
++ case WCD938X_MBHC_CTL_ANA:
++ case WCD938X_MBHC_CTL_SPARE_1:
++ case WCD938X_MBHC_CTL_SPARE_2:
++ case WCD938X_MBHC_CTL_BCS:
++ case WCD938X_MBHC_TEST_CTL:
++ case WCD938X_LDOH_MODE:
++ case WCD938X_LDOH_BIAS:
++ case WCD938X_LDOH_STB_LOADS:
++ case WCD938X_LDOH_SLOWRAMP:
++ case WCD938X_MICB1_TEST_CTL_1:
++ case WCD938X_MICB1_TEST_CTL_2:
++ case WCD938X_MICB1_TEST_CTL_3:
++ case WCD938X_MICB2_TEST_CTL_1:
++ case WCD938X_MICB2_TEST_CTL_2:
++ case WCD938X_MICB2_TEST_CTL_3:
++ case WCD938X_MICB3_TEST_CTL_1:
++ case WCD938X_MICB3_TEST_CTL_2:
++ case WCD938X_MICB3_TEST_CTL_3:
++ case WCD938X_MICB4_TEST_CTL_1:
++ case WCD938X_MICB4_TEST_CTL_2:
++ case WCD938X_MICB4_TEST_CTL_3:
++ case WCD938X_TX_COM_ADC_VCM:
++ case WCD938X_TX_COM_BIAS_ATEST:
++ case WCD938X_TX_COM_SPARE1:
++ case WCD938X_TX_COM_SPARE2:
++ case WCD938X_TX_COM_TXFE_DIV_CTL:
++ case WCD938X_TX_COM_TXFE_DIV_START:
++ case WCD938X_TX_COM_SPARE3:
++ case WCD938X_TX_COM_SPARE4:
++ case WCD938X_TX_1_2_TEST_EN:
++ case WCD938X_TX_1_2_ADC_IB:
++ case WCD938X_TX_1_2_ATEST_REFCTL:
++ case WCD938X_TX_1_2_TEST_CTL:
++ case WCD938X_TX_1_2_TEST_BLK_EN1:
++ case WCD938X_TX_1_2_TXFE1_CLKDIV:
++ case WCD938X_TX_3_4_TEST_EN:
++ case WCD938X_TX_3_4_ADC_IB:
++ case WCD938X_TX_3_4_ATEST_REFCTL:
++ case WCD938X_TX_3_4_TEST_CTL:
++ case WCD938X_TX_3_4_TEST_BLK_EN3:
++ case WCD938X_TX_3_4_TXFE3_CLKDIV:
++ case WCD938X_TX_3_4_TEST_BLK_EN2:
++ case WCD938X_TX_3_4_TXFE2_CLKDIV:
++ case WCD938X_TX_3_4_SPARE1:
++ case WCD938X_TX_3_4_TEST_BLK_EN4:
++ case WCD938X_TX_3_4_TXFE4_CLKDIV:
++ case WCD938X_TX_3_4_SPARE2:
++ case WCD938X_CLASSH_MODE_1:
++ case WCD938X_CLASSH_MODE_2:
++ case WCD938X_CLASSH_MODE_3:
++ case WCD938X_CLASSH_CTRL_VCL_1:
++ case WCD938X_CLASSH_CTRL_VCL_2:
++ case WCD938X_CLASSH_CTRL_CCL_1:
++ case WCD938X_CLASSH_CTRL_CCL_2:
++ case WCD938X_CLASSH_CTRL_CCL_3:
++ case WCD938X_CLASSH_CTRL_CCL_4:
++ case WCD938X_CLASSH_CTRL_CCL_5:
++ case WCD938X_CLASSH_BUCK_TMUX_A_D:
++ case WCD938X_CLASSH_BUCK_SW_DRV_CNTL:
++ case WCD938X_CLASSH_SPARE:
++ case WCD938X_FLYBACK_EN:
++ case WCD938X_FLYBACK_VNEG_CTRL_1:
++ case WCD938X_FLYBACK_VNEG_CTRL_2:
++ case WCD938X_FLYBACK_VNEG_CTRL_3:
++ case WCD938X_FLYBACK_VNEG_CTRL_4:
++ case WCD938X_FLYBACK_VNEG_CTRL_5:
++ case WCD938X_FLYBACK_VNEG_CTRL_6:
++ case WCD938X_FLYBACK_VNEG_CTRL_7:
++ case WCD938X_FLYBACK_VNEG_CTRL_8:
++ case WCD938X_FLYBACK_VNEG_CTRL_9:
++ case WCD938X_FLYBACK_VNEGDAC_CTRL_1:
++ case WCD938X_FLYBACK_VNEGDAC_CTRL_2:
++ case WCD938X_FLYBACK_VNEGDAC_CTRL_3:
++ case WCD938X_FLYBACK_CTRL_1:
++ case WCD938X_FLYBACK_TEST_CTL:
++ case WCD938X_RX_AUX_SW_CTL:
++ case WCD938X_RX_PA_AUX_IN_CONN:
++ case WCD938X_RX_TIMER_DIV:
++ case WCD938X_RX_OCP_CTL:
++ case WCD938X_RX_OCP_COUNT:
++ case WCD938X_RX_BIAS_EAR_DAC:
++ case WCD938X_RX_BIAS_EAR_AMP:
++ case WCD938X_RX_BIAS_HPH_LDO:
++ case WCD938X_RX_BIAS_HPH_PA:
++ case WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2:
++ case WCD938X_RX_BIAS_HPH_RDAC_LDO:
++ case WCD938X_RX_BIAS_HPH_CNP1:
++ case WCD938X_RX_BIAS_HPH_LOWPOWER:
++ case WCD938X_RX_BIAS_AUX_DAC:
++ case WCD938X_RX_BIAS_AUX_AMP:
++ case WCD938X_RX_BIAS_VNEGDAC_BLEEDER:
++ case WCD938X_RX_BIAS_MISC:
++ case WCD938X_RX_BIAS_BUCK_RST:
++ case WCD938X_RX_BIAS_BUCK_VREF_ERRAMP:
++ case WCD938X_RX_BIAS_FLYB_ERRAMP:
++ case WCD938X_RX_BIAS_FLYB_BUFF:
++ case WCD938X_RX_BIAS_FLYB_MID_RST:
++ case WCD938X_HPH_CNP_EN:
++ case WCD938X_HPH_CNP_WG_CTL:
++ case WCD938X_HPH_CNP_WG_TIME:
++ case WCD938X_HPH_OCP_CTL:
++ case WCD938X_HPH_AUTO_CHOP:
++ case WCD938X_HPH_CHOP_CTL:
++ case WCD938X_HPH_PA_CTL1:
++ case WCD938X_HPH_PA_CTL2:
++ case WCD938X_HPH_L_EN:
++ case WCD938X_HPH_L_TEST:
++ case WCD938X_HPH_L_ATEST:
++ case WCD938X_HPH_R_EN:
++ case WCD938X_HPH_R_TEST:
++ case WCD938X_HPH_R_ATEST:
++ case WCD938X_HPH_RDAC_CLK_CTL1:
++ case WCD938X_HPH_RDAC_CLK_CTL2:
++ case WCD938X_HPH_RDAC_LDO_CTL:
++ case WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL:
++ case WCD938X_HPH_REFBUFF_UHQA_CTL:
++ case WCD938X_HPH_REFBUFF_LP_CTL:
++ case WCD938X_HPH_L_DAC_CTL:
++ case WCD938X_HPH_R_DAC_CTL:
++ case WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL:
++ case WCD938X_HPH_SURGE_HPHLR_SURGE_EN:
++ case WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1:
++ case WCD938X_EAR_EAR_EN_REG:
++ case WCD938X_EAR_EAR_PA_CON:
++ case WCD938X_EAR_EAR_SP_CON:
++ case WCD938X_EAR_EAR_DAC_CON:
++ case WCD938X_EAR_EAR_CNP_FSM_CON:
++ case WCD938X_EAR_TEST_CTL:
++ case WCD938X_ANA_NEW_PAGE_REGISTER:
++ case WCD938X_HPH_NEW_ANA_HPH2:
++ case WCD938X_HPH_NEW_ANA_HPH3:
++ case WCD938X_SLEEP_CTL:
++ case WCD938X_SLEEP_WATCHDOG_CTL:
++ case WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL:
++ case WCD938X_MBHC_NEW_CTL_1:
++ case WCD938X_MBHC_NEW_CTL_2:
++ case WCD938X_MBHC_NEW_PLUG_DETECT_CTL:
++ case WCD938X_MBHC_NEW_ZDET_ANA_CTL:
++ case WCD938X_MBHC_NEW_ZDET_RAMP_CTL:
++ case WCD938X_TX_NEW_AMIC_MUX_CFG:
++ case WCD938X_AUX_AUXPA:
++ case WCD938X_LDORXTX_MODE:
++ case WCD938X_LDORXTX_CONFIG:
++ case WCD938X_DIE_CRACK_DIE_CRK_DET_EN:
++ case WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL:
++ case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L:
++ case WCD938X_HPH_NEW_INT_RDAC_VREF_CTL:
++ case WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL:
++ case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R:
++ case WCD938X_HPH_NEW_INT_PA_MISC1:
++ case WCD938X_HPH_NEW_INT_PA_MISC2:
++ case WCD938X_HPH_NEW_INT_PA_RDAC_MISC:
++ case WCD938X_HPH_NEW_INT_HPH_TIMER1:
++ case WCD938X_HPH_NEW_INT_HPH_TIMER2:
++ case WCD938X_HPH_NEW_INT_HPH_TIMER3:
++ case WCD938X_HPH_NEW_INT_HPH_TIMER4:
++ case WCD938X_HPH_NEW_INT_PA_RDAC_MISC2:
++ case WCD938X_HPH_NEW_INT_PA_RDAC_MISC3:
++ case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW:
++ case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW:
++ case WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI:
++ case WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP:
++ case WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP:
++ case WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL:
++ case WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL:
++ case WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT:
++ case WCD938X_MBHC_NEW_INT_SPARE_2:
++ case WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON:
++ case WCD938X_EAR_INT_NEW_CNP_VCM_CON1:
++ case WCD938X_EAR_INT_NEW_CNP_VCM_CON2:
++ case WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS:
++ case WCD938X_AUX_INT_EN_REG:
++ case WCD938X_AUX_INT_PA_CTRL:
++ case WCD938X_AUX_INT_SP_CTRL:
++ case WCD938X_AUX_INT_DAC_CTRL:
++ case WCD938X_AUX_INT_CLK_CTRL:
++ case WCD938X_AUX_INT_TEST_CTRL:
++ case WCD938X_AUX_INT_MISC:
++ case WCD938X_LDORXTX_INT_BIAS:
++ case WCD938X_LDORXTX_INT_STB_LOADS_DTEST:
++ case WCD938X_LDORXTX_INT_TEST0:
++ case WCD938X_LDORXTX_INT_STARTUP_TIMER:
++ case WCD938X_LDORXTX_INT_TEST1:
++ case WCD938X_SLEEP_INT_WATCHDOG_CTL_1:
++ case WCD938X_SLEEP_INT_WATCHDOG_CTL_2:
++ case WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1:
++ case WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2:
++ case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2:
++ case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1:
++ case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0:
++ case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M:
++ case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M:
++ case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1:
++ case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0:
++ case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP:
++ case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1:
++ case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0:
++ case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP:
++ case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0:
++ case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP:
++ case WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1:
++ case WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP:
++ case WCD938X_TX_COM_NEW_INT_TXADC_INT_L2:
++ case WCD938X_TX_COM_NEW_INT_TXADC_INT_L1:
++ case WCD938X_TX_COM_NEW_INT_TXADC_INT_L0:
++ case WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP:
++ case WCD938X_DIGITAL_PAGE_REGISTER:
++ case WCD938X_DIGITAL_SWR_TX_CLK_RATE:
++ case WCD938X_DIGITAL_CDC_RST_CTL:
++ case WCD938X_DIGITAL_TOP_CLK_CFG:
++ case WCD938X_DIGITAL_CDC_ANA_CLK_CTL:
++ case WCD938X_DIGITAL_CDC_DIG_CLK_CTL:
++ case WCD938X_DIGITAL_SWR_RST_EN:
++ case WCD938X_DIGITAL_CDC_PATH_MODE:
++ case WCD938X_DIGITAL_CDC_RX_RST:
++ case WCD938X_DIGITAL_CDC_RX0_CTL:
++ case WCD938X_DIGITAL_CDC_RX1_CTL:
++ case WCD938X_DIGITAL_CDC_RX2_CTL:
++ case WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1:
++ case WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3:
++ case WCD938X_DIGITAL_CDC_COMP_CTL_0:
++ case WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_A1_0:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_A1_1:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_A2_0:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_A2_1:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_A3_0:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_A3_1:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_A4_0:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_A4_1:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_A5_0:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_A5_1:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_A6_0:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_A7_0:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_C_0:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_C_1:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_C_2:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_C_3:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_R1:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_R2:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_R3:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_R4:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_R5:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_R6:
++ case WCD938X_DIGITAL_CDC_HPH_DSM_R7:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_A1_0:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_A1_1:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_A2_0:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_A2_1:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_A3_0:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_A3_1:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_A4_0:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_A4_1:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_A5_0:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_A5_1:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_A6_0:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_A7_0:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_C_0:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_C_1:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_C_2:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_C_3:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_R1:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_R2:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_R3:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_R4:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_R5:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_R6:
++ case WCD938X_DIGITAL_CDC_AUX_DSM_R7:
++ case WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0:
++ case WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1:
++ case WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0:
++ case WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1:
++ case WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2:
++ case WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0:
++ case WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1:
++ case WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2:
++ case WCD938X_DIGITAL_CDC_HPH_GAIN_CTL:
++ case WCD938X_DIGITAL_CDC_AUX_GAIN_CTL:
++ case WCD938X_DIGITAL_CDC_EAR_PATH_CTL:
++ case WCD938X_DIGITAL_CDC_SWR_CLH:
++ case WCD938X_DIGITAL_SWR_CLH_BYP:
++ case WCD938X_DIGITAL_CDC_TX0_CTL:
++ case WCD938X_DIGITAL_CDC_TX1_CTL:
++ case WCD938X_DIGITAL_CDC_TX2_CTL:
++ case WCD938X_DIGITAL_CDC_TX_RST:
++ case WCD938X_DIGITAL_CDC_REQ_CTL:
++ case WCD938X_DIGITAL_CDC_RST:
++ case WCD938X_DIGITAL_CDC_AMIC_CTL:
++ case WCD938X_DIGITAL_CDC_DMIC_CTL:
++ case WCD938X_DIGITAL_CDC_DMIC1_CTL:
++ case WCD938X_DIGITAL_CDC_DMIC2_CTL:
++ case WCD938X_DIGITAL_CDC_DMIC3_CTL:
++ case WCD938X_DIGITAL_CDC_DMIC4_CTL:
++ case WCD938X_DIGITAL_EFUSE_PRG_CTL:
++ case WCD938X_DIGITAL_EFUSE_CTL:
++ case WCD938X_DIGITAL_CDC_DMIC_RATE_1_2:
++ case WCD938X_DIGITAL_CDC_DMIC_RATE_3_4:
++ case WCD938X_DIGITAL_PDM_WD_CTL0:
++ case WCD938X_DIGITAL_PDM_WD_CTL1:
++ case WCD938X_DIGITAL_PDM_WD_CTL2:
++ case WCD938X_DIGITAL_INTR_MODE:
++ case WCD938X_DIGITAL_INTR_MASK_0:
++ case WCD938X_DIGITAL_INTR_MASK_1:
++ case WCD938X_DIGITAL_INTR_MASK_2:
++ case WCD938X_DIGITAL_INTR_CLEAR_0:
++ case WCD938X_DIGITAL_INTR_CLEAR_1:
++ case WCD938X_DIGITAL_INTR_CLEAR_2:
++ case WCD938X_DIGITAL_INTR_LEVEL_0:
++ case WCD938X_DIGITAL_INTR_LEVEL_1:
++ case WCD938X_DIGITAL_INTR_LEVEL_2:
++ case WCD938X_DIGITAL_INTR_SET_0:
++ case WCD938X_DIGITAL_INTR_SET_1:
++ case WCD938X_DIGITAL_INTR_SET_2:
++ case WCD938X_DIGITAL_INTR_TEST_0:
++ case WCD938X_DIGITAL_INTR_TEST_1:
++ case WCD938X_DIGITAL_INTR_TEST_2:
++ case WCD938X_DIGITAL_TX_MODE_DBG_EN:
++ case WCD938X_DIGITAL_TX_MODE_DBG_0_1:
++ case WCD938X_DIGITAL_TX_MODE_DBG_2_3:
++ case WCD938X_DIGITAL_LB_IN_SEL_CTL:
++ case WCD938X_DIGITAL_LOOP_BACK_MODE:
++ case WCD938X_DIGITAL_SWR_DAC_TEST:
++ case WCD938X_DIGITAL_SWR_HM_TEST_RX_0:
++ case WCD938X_DIGITAL_SWR_HM_TEST_TX_0:
++ case WCD938X_DIGITAL_SWR_HM_TEST_RX_1:
++ case WCD938X_DIGITAL_SWR_HM_TEST_TX_1:
++ case WCD938X_DIGITAL_SWR_HM_TEST_TX_2:
++ case WCD938X_DIGITAL_PAD_CTL_SWR_0:
++ case WCD938X_DIGITAL_PAD_CTL_SWR_1:
++ case WCD938X_DIGITAL_I2C_CTL:
++ case WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE:
++ case WCD938X_DIGITAL_EFUSE_TEST_CTL_0:
++ case WCD938X_DIGITAL_EFUSE_TEST_CTL_1:
++ case WCD938X_DIGITAL_PAD_CTL_PDM_RX0:
++ case WCD938X_DIGITAL_PAD_CTL_PDM_RX1:
++ case WCD938X_DIGITAL_PAD_CTL_PDM_TX0:
++ case WCD938X_DIGITAL_PAD_CTL_PDM_TX1:
++ case WCD938X_DIGITAL_PAD_CTL_PDM_TX2:
++ case WCD938X_DIGITAL_PAD_INP_DIS_0:
++ case WCD938X_DIGITAL_PAD_INP_DIS_1:
++ case WCD938X_DIGITAL_DRIVE_STRENGTH_0:
++ case WCD938X_DIGITAL_DRIVE_STRENGTH_1:
++ case WCD938X_DIGITAL_DRIVE_STRENGTH_2:
++ case WCD938X_DIGITAL_RX_DATA_EDGE_CTL:
++ case WCD938X_DIGITAL_TX_DATA_EDGE_CTL:
++ case WCD938X_DIGITAL_GPIO_MODE:
++ case WCD938X_DIGITAL_PIN_CTL_OE:
++ case WCD938X_DIGITAL_PIN_CTL_DATA_0:
++ case WCD938X_DIGITAL_PIN_CTL_DATA_1:
++ case WCD938X_DIGITAL_DIG_DEBUG_CTL:
++ case WCD938X_DIGITAL_DIG_DEBUG_EN:
++ case WCD938X_DIGITAL_ANA_CSR_DBG_ADD:
++ case WCD938X_DIGITAL_ANA_CSR_DBG_CTL:
++ case WCD938X_DIGITAL_SSP_DBG:
++ case WCD938X_DIGITAL_SPARE_0:
++ case WCD938X_DIGITAL_SPARE_1:
++ case WCD938X_DIGITAL_SPARE_2:
++ case WCD938X_DIGITAL_TX_REQ_FB_CTL_0:
++ case WCD938X_DIGITAL_TX_REQ_FB_CTL_1:
++ case WCD938X_DIGITAL_TX_REQ_FB_CTL_2:
++ case WCD938X_DIGITAL_TX_REQ_FB_CTL_3:
++ case WCD938X_DIGITAL_TX_REQ_FB_CTL_4:
++ case WCD938X_DIGITAL_DEM_BYPASS_DATA0:
++ case WCD938X_DIGITAL_DEM_BYPASS_DATA1:
++ case WCD938X_DIGITAL_DEM_BYPASS_DATA2:
++ case WCD938X_DIGITAL_DEM_BYPASS_DATA3:
++ return true;
++ }
++
++ return false;
++}
++
++static bool wcd938x_readonly_register(struct device *dev, unsigned int reg)
++{
++ switch (reg) {
++ case WCD938X_ANA_MBHC_RESULT_1:
++ case WCD938X_ANA_MBHC_RESULT_2:
++ case WCD938X_ANA_MBHC_RESULT_3:
++ case WCD938X_MBHC_MOISTURE_DET_FSM_STATUS:
++ case WCD938X_TX_1_2_SAR2_ERR:
++ case WCD938X_TX_1_2_SAR1_ERR:
++ case WCD938X_TX_3_4_SAR4_ERR:
++ case WCD938X_TX_3_4_SAR3_ERR:
++ case WCD938X_HPH_L_STATUS:
++ case WCD938X_HPH_R_STATUS:
++ case WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS:
++ case WCD938X_EAR_STATUS_REG_1:
++ case WCD938X_EAR_STATUS_REG_2:
++ case WCD938X_MBHC_NEW_FSM_STATUS:
++ case WCD938X_MBHC_NEW_ADC_RESULT:
++ case WCD938X_DIE_CRACK_DIE_CRK_DET_OUT:
++ case WCD938X_AUX_INT_STATUS_REG:
++ case WCD938X_LDORXTX_INT_STATUS:
++ case WCD938X_DIGITAL_CHIP_ID0:
++ case WCD938X_DIGITAL_CHIP_ID1:
++ case WCD938X_DIGITAL_CHIP_ID2:
++ case WCD938X_DIGITAL_CHIP_ID3:
++ case WCD938X_DIGITAL_INTR_STATUS_0:
++ case WCD938X_DIGITAL_INTR_STATUS_1:
++ case WCD938X_DIGITAL_INTR_STATUS_2:
++ case WCD938X_DIGITAL_INTR_CLEAR_0:
++ case WCD938X_DIGITAL_INTR_CLEAR_1:
++ case WCD938X_DIGITAL_INTR_CLEAR_2:
++ case WCD938X_DIGITAL_SWR_HM_TEST_0:
++ case WCD938X_DIGITAL_SWR_HM_TEST_1:
++ case WCD938X_DIGITAL_EFUSE_T_DATA_0:
++ case WCD938X_DIGITAL_EFUSE_T_DATA_1:
++ case WCD938X_DIGITAL_PIN_STATUS_0:
++ case WCD938X_DIGITAL_PIN_STATUS_1:
++ case WCD938X_DIGITAL_MODE_STATUS_0:
++ case WCD938X_DIGITAL_MODE_STATUS_1:
++ case WCD938X_DIGITAL_EFUSE_REG_0:
++ case WCD938X_DIGITAL_EFUSE_REG_1:
++ case WCD938X_DIGITAL_EFUSE_REG_2:
++ case WCD938X_DIGITAL_EFUSE_REG_3:
++ case WCD938X_DIGITAL_EFUSE_REG_4:
++ case WCD938X_DIGITAL_EFUSE_REG_5:
++ case WCD938X_DIGITAL_EFUSE_REG_6:
++ case WCD938X_DIGITAL_EFUSE_REG_7:
++ case WCD938X_DIGITAL_EFUSE_REG_8:
++ case WCD938X_DIGITAL_EFUSE_REG_9:
++ case WCD938X_DIGITAL_EFUSE_REG_10:
++ case WCD938X_DIGITAL_EFUSE_REG_11:
++ case WCD938X_DIGITAL_EFUSE_REG_12:
++ case WCD938X_DIGITAL_EFUSE_REG_13:
++ case WCD938X_DIGITAL_EFUSE_REG_14:
++ case WCD938X_DIGITAL_EFUSE_REG_15:
++ case WCD938X_DIGITAL_EFUSE_REG_16:
++ case WCD938X_DIGITAL_EFUSE_REG_17:
++ case WCD938X_DIGITAL_EFUSE_REG_18:
++ case WCD938X_DIGITAL_EFUSE_REG_19:
++ case WCD938X_DIGITAL_EFUSE_REG_20:
++ case WCD938X_DIGITAL_EFUSE_REG_21:
++ case WCD938X_DIGITAL_EFUSE_REG_22:
++ case WCD938X_DIGITAL_EFUSE_REG_23:
++ case WCD938X_DIGITAL_EFUSE_REG_24:
++ case WCD938X_DIGITAL_EFUSE_REG_25:
++ case WCD938X_DIGITAL_EFUSE_REG_26:
++ case WCD938X_DIGITAL_EFUSE_REG_27:
++ case WCD938X_DIGITAL_EFUSE_REG_28:
++ case WCD938X_DIGITAL_EFUSE_REG_29:
++ case WCD938X_DIGITAL_EFUSE_REG_30:
++ case WCD938X_DIGITAL_EFUSE_REG_31:
++ return true;
++ }
++ return false;
++}
++
++static bool wcd938x_readable_register(struct device *dev, unsigned int reg)
++{
++ bool ret;
++
++ ret = wcd938x_readonly_register(dev, reg);
++ if (!ret)
++ return wcd938x_rdwr_register(dev, reg);
++
++ return ret;
++}
++
++static bool wcd938x_writeable_register(struct device *dev, unsigned int reg)
++{
++ return wcd938x_rdwr_register(dev, reg);
++}
++
++static bool wcd938x_volatile_register(struct device *dev, unsigned int reg)
++{
++ if (reg <= WCD938X_BASE_ADDRESS)
++ return false;
++
++ if (reg == WCD938X_DIGITAL_SWR_TX_CLK_RATE)
++ return true;
++
++ if (wcd938x_readonly_register(dev, reg))
++ return true;
++
++ return false;
++}
++
++static const struct regmap_config wcd938x_regmap_config = {
++ .name = "wcd938x_csr",
++ .reg_bits = 32,
++ .val_bits = 8,
++ .cache_type = REGCACHE_RBTREE,
++ .reg_defaults = wcd938x_defaults,
++ .num_reg_defaults = ARRAY_SIZE(wcd938x_defaults),
++ .max_register = WCD938X_MAX_REGISTER,
++ .readable_reg = wcd938x_readable_register,
++ .writeable_reg = wcd938x_writeable_register,
++ .volatile_reg = wcd938x_volatile_register,
++ .can_multi_write = true,
++};
++
+ static const struct sdw_slave_ops wcd9380_slave_ops = {
+ .update_status = wcd9380_update_status,
+ .interrupt_callback = wcd9380_interrupt_callback,
+@@ -260,6 +1262,16 @@ static int wcd9380_probe(struct sdw_slave *pdev,
+ wcd->ch_info = &wcd938x_sdw_rx_ch_info[0];
+ }
+
++ if (wcd->is_tx) {
++ wcd->regmap = devm_regmap_init_sdw(pdev, &wcd938x_regmap_config);
++ if (IS_ERR(wcd->regmap))
++ return dev_err_probe(dev, PTR_ERR(wcd->regmap),
++ "Regmap init failed\n");
++
++ /* Start in cache-only until device is enumerated */
++ regcache_cache_only(wcd->regmap, true);
++ };
++
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+@@ -301,22 +1313,23 @@ MODULE_DEVICE_TABLE(sdw, wcd9380_slave_id);
+
+ static int __maybe_unused wcd938x_sdw_runtime_suspend(struct device *dev)
+ {
+- struct regmap *regmap = dev_get_regmap(dev, NULL);
++ struct wcd938x_sdw_priv *wcd = dev_get_drvdata(dev);
+
+- if (regmap) {
+- regcache_cache_only(regmap, true);
+- regcache_mark_dirty(regmap);
++ if (wcd->regmap) {
++ regcache_cache_only(wcd->regmap, true);
++ regcache_mark_dirty(wcd->regmap);
+ }
++
+ return 0;
+ }
+
+ static int __maybe_unused wcd938x_sdw_runtime_resume(struct device *dev)
+ {
+- struct regmap *regmap = dev_get_regmap(dev, NULL);
++ struct wcd938x_sdw_priv *wcd = dev_get_drvdata(dev);
+
+- if (regmap) {
+- regcache_cache_only(regmap, false);
+- regcache_sync(regmap);
++ if (wcd->regmap) {
++ regcache_cache_only(wcd->regmap, false);
++ regcache_sync(wcd->regmap);
+ }
+
+ pm_runtime_mark_last_busy(dev);
+diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
+index 1fa58e2bff3d0..16e2e1c186846 100644
+--- a/sound/soc/codecs/wcd938x.c
++++ b/sound/soc/codecs/wcd938x.c
+@@ -271,1001 +271,6 @@ static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, WCD938X_ANA_MBHC_ZDET, 0x02),
+ };
+
+-static const struct reg_default wcd938x_defaults[] = {
+- {WCD938X_ANA_PAGE_REGISTER, 0x00},
+- {WCD938X_ANA_BIAS, 0x00},
+- {WCD938X_ANA_RX_SUPPLIES, 0x00},
+- {WCD938X_ANA_HPH, 0x0C},
+- {WCD938X_ANA_EAR, 0x00},
+- {WCD938X_ANA_EAR_COMPANDER_CTL, 0x02},
+- {WCD938X_ANA_TX_CH1, 0x20},
+- {WCD938X_ANA_TX_CH2, 0x00},
+- {WCD938X_ANA_TX_CH3, 0x20},
+- {WCD938X_ANA_TX_CH4, 0x00},
+- {WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC, 0x00},
+- {WCD938X_ANA_MICB3_DSP_EN_LOGIC, 0x00},
+- {WCD938X_ANA_MBHC_MECH, 0x39},
+- {WCD938X_ANA_MBHC_ELECT, 0x08},
+- {WCD938X_ANA_MBHC_ZDET, 0x00},
+- {WCD938X_ANA_MBHC_RESULT_1, 0x00},
+- {WCD938X_ANA_MBHC_RESULT_2, 0x00},
+- {WCD938X_ANA_MBHC_RESULT_3, 0x00},
+- {WCD938X_ANA_MBHC_BTN0, 0x00},
+- {WCD938X_ANA_MBHC_BTN1, 0x10},
+- {WCD938X_ANA_MBHC_BTN2, 0x20},
+- {WCD938X_ANA_MBHC_BTN3, 0x30},
+- {WCD938X_ANA_MBHC_BTN4, 0x40},
+- {WCD938X_ANA_MBHC_BTN5, 0x50},
+- {WCD938X_ANA_MBHC_BTN6, 0x60},
+- {WCD938X_ANA_MBHC_BTN7, 0x70},
+- {WCD938X_ANA_MICB1, 0x10},
+- {WCD938X_ANA_MICB2, 0x10},
+- {WCD938X_ANA_MICB2_RAMP, 0x00},
+- {WCD938X_ANA_MICB3, 0x10},
+- {WCD938X_ANA_MICB4, 0x10},
+- {WCD938X_BIAS_CTL, 0x2A},
+- {WCD938X_BIAS_VBG_FINE_ADJ, 0x55},
+- {WCD938X_LDOL_VDDCX_ADJUST, 0x01},
+- {WCD938X_LDOL_DISABLE_LDOL, 0x00},
+- {WCD938X_MBHC_CTL_CLK, 0x00},
+- {WCD938X_MBHC_CTL_ANA, 0x00},
+- {WCD938X_MBHC_CTL_SPARE_1, 0x00},
+- {WCD938X_MBHC_CTL_SPARE_2, 0x00},
+- {WCD938X_MBHC_CTL_BCS, 0x00},
+- {WCD938X_MBHC_MOISTURE_DET_FSM_STATUS, 0x00},
+- {WCD938X_MBHC_TEST_CTL, 0x00},
+- {WCD938X_LDOH_MODE, 0x2B},
+- {WCD938X_LDOH_BIAS, 0x68},
+- {WCD938X_LDOH_STB_LOADS, 0x00},
+- {WCD938X_LDOH_SLOWRAMP, 0x50},
+- {WCD938X_MICB1_TEST_CTL_1, 0x1A},
+- {WCD938X_MICB1_TEST_CTL_2, 0x00},
+- {WCD938X_MICB1_TEST_CTL_3, 0xA4},
+- {WCD938X_MICB2_TEST_CTL_1, 0x1A},
+- {WCD938X_MICB2_TEST_CTL_2, 0x00},
+- {WCD938X_MICB2_TEST_CTL_3, 0x24},
+- {WCD938X_MICB3_TEST_CTL_1, 0x1A},
+- {WCD938X_MICB3_TEST_CTL_2, 0x00},
+- {WCD938X_MICB3_TEST_CTL_3, 0xA4},
+- {WCD938X_MICB4_TEST_CTL_1, 0x1A},
+- {WCD938X_MICB4_TEST_CTL_2, 0x00},
+- {WCD938X_MICB4_TEST_CTL_3, 0xA4},
+- {WCD938X_TX_COM_ADC_VCM, 0x39},
+- {WCD938X_TX_COM_BIAS_ATEST, 0xE0},
+- {WCD938X_TX_COM_SPARE1, 0x00},
+- {WCD938X_TX_COM_SPARE2, 0x00},
+- {WCD938X_TX_COM_TXFE_DIV_CTL, 0x22},
+- {WCD938X_TX_COM_TXFE_DIV_START, 0x00},
+- {WCD938X_TX_COM_SPARE3, 0x00},
+- {WCD938X_TX_COM_SPARE4, 0x00},
+- {WCD938X_TX_1_2_TEST_EN, 0xCC},
+- {WCD938X_TX_1_2_ADC_IB, 0xE9},
+- {WCD938X_TX_1_2_ATEST_REFCTL, 0x0A},
+- {WCD938X_TX_1_2_TEST_CTL, 0x38},
+- {WCD938X_TX_1_2_TEST_BLK_EN1, 0xFF},
+- {WCD938X_TX_1_2_TXFE1_CLKDIV, 0x00},
+- {WCD938X_TX_1_2_SAR2_ERR, 0x00},
+- {WCD938X_TX_1_2_SAR1_ERR, 0x00},
+- {WCD938X_TX_3_4_TEST_EN, 0xCC},
+- {WCD938X_TX_3_4_ADC_IB, 0xE9},
+- {WCD938X_TX_3_4_ATEST_REFCTL, 0x0A},
+- {WCD938X_TX_3_4_TEST_CTL, 0x38},
+- {WCD938X_TX_3_4_TEST_BLK_EN3, 0xFF},
+- {WCD938X_TX_3_4_TXFE3_CLKDIV, 0x00},
+- {WCD938X_TX_3_4_SAR4_ERR, 0x00},
+- {WCD938X_TX_3_4_SAR3_ERR, 0x00},
+- {WCD938X_TX_3_4_TEST_BLK_EN2, 0xFB},
+- {WCD938X_TX_3_4_TXFE2_CLKDIV, 0x00},
+- {WCD938X_TX_3_4_SPARE1, 0x00},
+- {WCD938X_TX_3_4_TEST_BLK_EN4, 0xFB},
+- {WCD938X_TX_3_4_TXFE4_CLKDIV, 0x00},
+- {WCD938X_TX_3_4_SPARE2, 0x00},
+- {WCD938X_CLASSH_MODE_1, 0x40},
+- {WCD938X_CLASSH_MODE_2, 0x3A},
+- {WCD938X_CLASSH_MODE_3, 0x00},
+- {WCD938X_CLASSH_CTRL_VCL_1, 0x70},
+- {WCD938X_CLASSH_CTRL_VCL_2, 0x82},
+- {WCD938X_CLASSH_CTRL_CCL_1, 0x31},
+- {WCD938X_CLASSH_CTRL_CCL_2, 0x80},
+- {WCD938X_CLASSH_CTRL_CCL_3, 0x80},
+- {WCD938X_CLASSH_CTRL_CCL_4, 0x51},
+- {WCD938X_CLASSH_CTRL_CCL_5, 0x00},
+- {WCD938X_CLASSH_BUCK_TMUX_A_D, 0x00},
+- {WCD938X_CLASSH_BUCK_SW_DRV_CNTL, 0x77},
+- {WCD938X_CLASSH_SPARE, 0x00},
+- {WCD938X_FLYBACK_EN, 0x4E},
+- {WCD938X_FLYBACK_VNEG_CTRL_1, 0x0B},
+- {WCD938X_FLYBACK_VNEG_CTRL_2, 0x45},
+- {WCD938X_FLYBACK_VNEG_CTRL_3, 0x74},
+- {WCD938X_FLYBACK_VNEG_CTRL_4, 0x7F},
+- {WCD938X_FLYBACK_VNEG_CTRL_5, 0x83},
+- {WCD938X_FLYBACK_VNEG_CTRL_6, 0x98},
+- {WCD938X_FLYBACK_VNEG_CTRL_7, 0xA9},
+- {WCD938X_FLYBACK_VNEG_CTRL_8, 0x68},
+- {WCD938X_FLYBACK_VNEG_CTRL_9, 0x64},
+- {WCD938X_FLYBACK_VNEGDAC_CTRL_1, 0xED},
+- {WCD938X_FLYBACK_VNEGDAC_CTRL_2, 0xF0},
+- {WCD938X_FLYBACK_VNEGDAC_CTRL_3, 0xA6},
+- {WCD938X_FLYBACK_CTRL_1, 0x65},
+- {WCD938X_FLYBACK_TEST_CTL, 0x00},
+- {WCD938X_RX_AUX_SW_CTL, 0x00},
+- {WCD938X_RX_PA_AUX_IN_CONN, 0x01},
+- {WCD938X_RX_TIMER_DIV, 0x32},
+- {WCD938X_RX_OCP_CTL, 0x1F},
+- {WCD938X_RX_OCP_COUNT, 0x77},
+- {WCD938X_RX_BIAS_EAR_DAC, 0xA0},
+- {WCD938X_RX_BIAS_EAR_AMP, 0xAA},
+- {WCD938X_RX_BIAS_HPH_LDO, 0xA9},
+- {WCD938X_RX_BIAS_HPH_PA, 0xAA},
+- {WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8A},
+- {WCD938X_RX_BIAS_HPH_RDAC_LDO, 0x88},
+- {WCD938X_RX_BIAS_HPH_CNP1, 0x82},
+- {WCD938X_RX_BIAS_HPH_LOWPOWER, 0x82},
+- {WCD938X_RX_BIAS_AUX_DAC, 0xA0},
+- {WCD938X_RX_BIAS_AUX_AMP, 0xAA},
+- {WCD938X_RX_BIAS_VNEGDAC_BLEEDER, 0x50},
+- {WCD938X_RX_BIAS_MISC, 0x00},
+- {WCD938X_RX_BIAS_BUCK_RST, 0x08},
+- {WCD938X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44},
+- {WCD938X_RX_BIAS_FLYB_ERRAMP, 0x40},
+- {WCD938X_RX_BIAS_FLYB_BUFF, 0xAA},
+- {WCD938X_RX_BIAS_FLYB_MID_RST, 0x14},
+- {WCD938X_HPH_L_STATUS, 0x04},
+- {WCD938X_HPH_R_STATUS, 0x04},
+- {WCD938X_HPH_CNP_EN, 0x80},
+- {WCD938X_HPH_CNP_WG_CTL, 0x9A},
+- {WCD938X_HPH_CNP_WG_TIME, 0x14},
+- {WCD938X_HPH_OCP_CTL, 0x28},
+- {WCD938X_HPH_AUTO_CHOP, 0x16},
+- {WCD938X_HPH_CHOP_CTL, 0x83},
+- {WCD938X_HPH_PA_CTL1, 0x46},
+- {WCD938X_HPH_PA_CTL2, 0x50},
+- {WCD938X_HPH_L_EN, 0x80},
+- {WCD938X_HPH_L_TEST, 0xE0},
+- {WCD938X_HPH_L_ATEST, 0x50},
+- {WCD938X_HPH_R_EN, 0x80},
+- {WCD938X_HPH_R_TEST, 0xE0},
+- {WCD938X_HPH_R_ATEST, 0x54},
+- {WCD938X_HPH_RDAC_CLK_CTL1, 0x99},
+- {WCD938X_HPH_RDAC_CLK_CTL2, 0x9B},
+- {WCD938X_HPH_RDAC_LDO_CTL, 0x33},
+- {WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00},
+- {WCD938X_HPH_REFBUFF_UHQA_CTL, 0x68},
+- {WCD938X_HPH_REFBUFF_LP_CTL, 0x0E},
+- {WCD938X_HPH_L_DAC_CTL, 0x20},
+- {WCD938X_HPH_R_DAC_CTL, 0x20},
+- {WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL, 0x55},
+- {WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0x19},
+- {WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1, 0xA0},
+- {WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS, 0x00},
+- {WCD938X_EAR_EAR_EN_REG, 0x22},
+- {WCD938X_EAR_EAR_PA_CON, 0x44},
+- {WCD938X_EAR_EAR_SP_CON, 0xDB},
+- {WCD938X_EAR_EAR_DAC_CON, 0x80},
+- {WCD938X_EAR_EAR_CNP_FSM_CON, 0xB2},
+- {WCD938X_EAR_TEST_CTL, 0x00},
+- {WCD938X_EAR_STATUS_REG_1, 0x00},
+- {WCD938X_EAR_STATUS_REG_2, 0x08},
+- {WCD938X_ANA_NEW_PAGE_REGISTER, 0x00},
+- {WCD938X_HPH_NEW_ANA_HPH2, 0x00},
+- {WCD938X_HPH_NEW_ANA_HPH3, 0x00},
+- {WCD938X_SLEEP_CTL, 0x16},
+- {WCD938X_SLEEP_WATCHDOG_CTL, 0x00},
+- {WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00},
+- {WCD938X_MBHC_NEW_CTL_1, 0x02},
+- {WCD938X_MBHC_NEW_CTL_2, 0x05},
+- {WCD938X_MBHC_NEW_PLUG_DETECT_CTL, 0xE9},
+- {WCD938X_MBHC_NEW_ZDET_ANA_CTL, 0x0F},
+- {WCD938X_MBHC_NEW_ZDET_RAMP_CTL, 0x00},
+- {WCD938X_MBHC_NEW_FSM_STATUS, 0x00},
+- {WCD938X_MBHC_NEW_ADC_RESULT, 0x00},
+- {WCD938X_TX_NEW_AMIC_MUX_CFG, 0x00},
+- {WCD938X_AUX_AUXPA, 0x00},
+- {WCD938X_LDORXTX_MODE, 0x0C},
+- {WCD938X_LDORXTX_CONFIG, 0x10},
+- {WCD938X_DIE_CRACK_DIE_CRK_DET_EN, 0x00},
+- {WCD938X_DIE_CRACK_DIE_CRK_DET_OUT, 0x00},
+- {WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40},
+- {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x81},
+- {WCD938X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10},
+- {WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00},
+- {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x81},
+- {WCD938X_HPH_NEW_INT_PA_MISC1, 0x22},
+- {WCD938X_HPH_NEW_INT_PA_MISC2, 0x00},
+- {WCD938X_HPH_NEW_INT_PA_RDAC_MISC, 0x00},
+- {WCD938X_HPH_NEW_INT_HPH_TIMER1, 0xFE},
+- {WCD938X_HPH_NEW_INT_HPH_TIMER2, 0x02},
+- {WCD938X_HPH_NEW_INT_HPH_TIMER3, 0x4E},
+- {WCD938X_HPH_NEW_INT_HPH_TIMER4, 0x54},
+- {WCD938X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00},
+- {WCD938X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00},
+- {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW, 0x90},
+- {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW, 0x90},
+- {WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62},
+- {WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01},
+- {WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11},
+- {WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57},
+- {WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01},
+- {WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00},
+- {WCD938X_MBHC_NEW_INT_SPARE_2, 0x00},
+- {WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON, 0xA8},
+- {WCD938X_EAR_INT_NEW_CNP_VCM_CON1, 0x42},
+- {WCD938X_EAR_INT_NEW_CNP_VCM_CON2, 0x22},
+- {WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS, 0x00},
+- {WCD938X_AUX_INT_EN_REG, 0x00},
+- {WCD938X_AUX_INT_PA_CTRL, 0x06},
+- {WCD938X_AUX_INT_SP_CTRL, 0xD2},
+- {WCD938X_AUX_INT_DAC_CTRL, 0x80},
+- {WCD938X_AUX_INT_CLK_CTRL, 0x50},
+- {WCD938X_AUX_INT_TEST_CTRL, 0x00},
+- {WCD938X_AUX_INT_STATUS_REG, 0x00},
+- {WCD938X_AUX_INT_MISC, 0x00},
+- {WCD938X_LDORXTX_INT_BIAS, 0x6E},
+- {WCD938X_LDORXTX_INT_STB_LOADS_DTEST, 0x50},
+- {WCD938X_LDORXTX_INT_TEST0, 0x1C},
+- {WCD938X_LDORXTX_INT_STARTUP_TIMER, 0xFF},
+- {WCD938X_LDORXTX_INT_TEST1, 0x1F},
+- {WCD938X_LDORXTX_INT_STATUS, 0x00},
+- {WCD938X_SLEEP_INT_WATCHDOG_CTL_1, 0x0A},
+- {WCD938X_SLEEP_INT_WATCHDOG_CTL_2, 0x0A},
+- {WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1, 0x02},
+- {WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2, 0x60},
+- {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2, 0xFF},
+- {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1, 0x7F},
+- {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0, 0x3F},
+- {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M, 0x1F},
+- {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M, 0x0F},
+- {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1, 0xD7},
+- {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0, 0xC8},
+- {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP, 0xC6},
+- {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1, 0xD5},
+- {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0, 0xCA},
+- {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP, 0x05},
+- {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0, 0xA5},
+- {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP, 0x13},
+- {WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1, 0x88},
+- {WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP, 0x42},
+- {WCD938X_TX_COM_NEW_INT_TXADC_INT_L2, 0xFF},
+- {WCD938X_TX_COM_NEW_INT_TXADC_INT_L1, 0x64},
+- {WCD938X_TX_COM_NEW_INT_TXADC_INT_L0, 0x64},
+- {WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP, 0x77},
+- {WCD938X_DIGITAL_PAGE_REGISTER, 0x00},
+- {WCD938X_DIGITAL_CHIP_ID0, 0x00},
+- {WCD938X_DIGITAL_CHIP_ID1, 0x00},
+- {WCD938X_DIGITAL_CHIP_ID2, 0x0D},
+- {WCD938X_DIGITAL_CHIP_ID3, 0x01},
+- {WCD938X_DIGITAL_SWR_TX_CLK_RATE, 0x00},
+- {WCD938X_DIGITAL_CDC_RST_CTL, 0x03},
+- {WCD938X_DIGITAL_TOP_CLK_CFG, 0x00},
+- {WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x00},
+- {WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0xF0},
+- {WCD938X_DIGITAL_SWR_RST_EN, 0x00},
+- {WCD938X_DIGITAL_CDC_PATH_MODE, 0x55},
+- {WCD938X_DIGITAL_CDC_RX_RST, 0x00},
+- {WCD938X_DIGITAL_CDC_RX0_CTL, 0xFC},
+- {WCD938X_DIGITAL_CDC_RX1_CTL, 0xFC},
+- {WCD938X_DIGITAL_CDC_RX2_CTL, 0xFC},
+- {WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0x00},
+- {WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0x00},
+- {WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x00},
+- {WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL, 0x1E},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_A1_0, 0x00},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_A1_1, 0x01},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_A2_0, 0x63},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_A2_1, 0x04},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_A3_0, 0xAC},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_A3_1, 0x04},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_A4_0, 0x1A},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_A4_1, 0x03},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_A5_0, 0xBC},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_A5_1, 0x02},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_A6_0, 0xC7},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_A7_0, 0xF8},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_C_0, 0x47},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_C_1, 0x43},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_C_2, 0xB1},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_C_3, 0x17},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_R1, 0x4D},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_R2, 0x29},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_R3, 0x34},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_R4, 0x59},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_R5, 0x66},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_R6, 0x87},
+- {WCD938X_DIGITAL_CDC_HPH_DSM_R7, 0x64},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_A1_0, 0x00},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_A1_1, 0x01},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_A2_0, 0x96},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_A2_1, 0x09},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_A3_0, 0xAB},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_A3_1, 0x05},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_A4_0, 0x1C},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_A4_1, 0x02},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_A5_0, 0x17},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_A5_1, 0x02},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_A6_0, 0xAA},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_A7_0, 0xE3},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_C_0, 0x69},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_C_1, 0x54},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_C_2, 0x02},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_C_3, 0x15},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_R1, 0xA4},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_R2, 0xB5},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_R3, 0x86},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_R4, 0x85},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_R5, 0xAA},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_R6, 0xE2},
+- {WCD938X_DIGITAL_CDC_AUX_DSM_R7, 0x62},
+- {WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0, 0x55},
+- {WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1, 0xA9},
+- {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0, 0x3D},
+- {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1, 0x2E},
+- {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2, 0x01},
+- {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0, 0x00},
+- {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1, 0xFC},
+- {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2, 0x01},
+- {WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x00},
+- {WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x00},
+- {WCD938X_DIGITAL_CDC_EAR_PATH_CTL, 0x00},
+- {WCD938X_DIGITAL_CDC_SWR_CLH, 0x00},
+- {WCD938X_DIGITAL_SWR_CLH_BYP, 0x00},
+- {WCD938X_DIGITAL_CDC_TX0_CTL, 0x68},
+- {WCD938X_DIGITAL_CDC_TX1_CTL, 0x68},
+- {WCD938X_DIGITAL_CDC_TX2_CTL, 0x68},
+- {WCD938X_DIGITAL_CDC_TX_RST, 0x00},
+- {WCD938X_DIGITAL_CDC_REQ_CTL, 0x01},
+- {WCD938X_DIGITAL_CDC_RST, 0x00},
+- {WCD938X_DIGITAL_CDC_AMIC_CTL, 0x0F},
+- {WCD938X_DIGITAL_CDC_DMIC_CTL, 0x04},
+- {WCD938X_DIGITAL_CDC_DMIC1_CTL, 0x01},
+- {WCD938X_DIGITAL_CDC_DMIC2_CTL, 0x01},
+- {WCD938X_DIGITAL_CDC_DMIC3_CTL, 0x01},
+- {WCD938X_DIGITAL_CDC_DMIC4_CTL, 0x01},
+- {WCD938X_DIGITAL_EFUSE_PRG_CTL, 0x00},
+- {WCD938X_DIGITAL_EFUSE_CTL, 0x2B},
+- {WCD938X_DIGITAL_CDC_DMIC_RATE_1_2, 0x11},
+- {WCD938X_DIGITAL_CDC_DMIC_RATE_3_4, 0x11},
+- {WCD938X_DIGITAL_PDM_WD_CTL0, 0x00},
+- {WCD938X_DIGITAL_PDM_WD_CTL1, 0x00},
+- {WCD938X_DIGITAL_PDM_WD_CTL2, 0x00},
+- {WCD938X_DIGITAL_INTR_MODE, 0x00},
+- {WCD938X_DIGITAL_INTR_MASK_0, 0xFF},
+- {WCD938X_DIGITAL_INTR_MASK_1, 0xFF},
+- {WCD938X_DIGITAL_INTR_MASK_2, 0x3F},
+- {WCD938X_DIGITAL_INTR_STATUS_0, 0x00},
+- {WCD938X_DIGITAL_INTR_STATUS_1, 0x00},
+- {WCD938X_DIGITAL_INTR_STATUS_2, 0x00},
+- {WCD938X_DIGITAL_INTR_CLEAR_0, 0x00},
+- {WCD938X_DIGITAL_INTR_CLEAR_1, 0x00},
+- {WCD938X_DIGITAL_INTR_CLEAR_2, 0x00},
+- {WCD938X_DIGITAL_INTR_LEVEL_0, 0x00},
+- {WCD938X_DIGITAL_INTR_LEVEL_1, 0x00},
+- {WCD938X_DIGITAL_INTR_LEVEL_2, 0x00},
+- {WCD938X_DIGITAL_INTR_SET_0, 0x00},
+- {WCD938X_DIGITAL_INTR_SET_1, 0x00},
+- {WCD938X_DIGITAL_INTR_SET_2, 0x00},
+- {WCD938X_DIGITAL_INTR_TEST_0, 0x00},
+- {WCD938X_DIGITAL_INTR_TEST_1, 0x00},
+- {WCD938X_DIGITAL_INTR_TEST_2, 0x00},
+- {WCD938X_DIGITAL_TX_MODE_DBG_EN, 0x00},
+- {WCD938X_DIGITAL_TX_MODE_DBG_0_1, 0x00},
+- {WCD938X_DIGITAL_TX_MODE_DBG_2_3, 0x00},
+- {WCD938X_DIGITAL_LB_IN_SEL_CTL, 0x00},
+- {WCD938X_DIGITAL_LOOP_BACK_MODE, 0x00},
+- {WCD938X_DIGITAL_SWR_DAC_TEST, 0x00},
+- {WCD938X_DIGITAL_SWR_HM_TEST_RX_0, 0x40},
+- {WCD938X_DIGITAL_SWR_HM_TEST_TX_0, 0x40},
+- {WCD938X_DIGITAL_SWR_HM_TEST_RX_1, 0x00},
+- {WCD938X_DIGITAL_SWR_HM_TEST_TX_1, 0x00},
+- {WCD938X_DIGITAL_SWR_HM_TEST_TX_2, 0x00},
+- {WCD938X_DIGITAL_SWR_HM_TEST_0, 0x00},
+- {WCD938X_DIGITAL_SWR_HM_TEST_1, 0x00},
+- {WCD938X_DIGITAL_PAD_CTL_SWR_0, 0x8F},
+- {WCD938X_DIGITAL_PAD_CTL_SWR_1, 0x06},
+- {WCD938X_DIGITAL_I2C_CTL, 0x00},
+- {WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE, 0x00},
+- {WCD938X_DIGITAL_EFUSE_TEST_CTL_0, 0x00},
+- {WCD938X_DIGITAL_EFUSE_TEST_CTL_1, 0x00},
+- {WCD938X_DIGITAL_EFUSE_T_DATA_0, 0x00},
+- {WCD938X_DIGITAL_EFUSE_T_DATA_1, 0x00},
+- {WCD938X_DIGITAL_PAD_CTL_PDM_RX0, 0xF1},
+- {WCD938X_DIGITAL_PAD_CTL_PDM_RX1, 0xF1},
+- {WCD938X_DIGITAL_PAD_CTL_PDM_TX0, 0xF1},
+- {WCD938X_DIGITAL_PAD_CTL_PDM_TX1, 0xF1},
+- {WCD938X_DIGITAL_PAD_CTL_PDM_TX2, 0xF1},
+- {WCD938X_DIGITAL_PAD_INP_DIS_0, 0x00},
+- {WCD938X_DIGITAL_PAD_INP_DIS_1, 0x00},
+- {WCD938X_DIGITAL_DRIVE_STRENGTH_0, 0x00},
+- {WCD938X_DIGITAL_DRIVE_STRENGTH_1, 0x00},
+- {WCD938X_DIGITAL_DRIVE_STRENGTH_2, 0x00},
+- {WCD938X_DIGITAL_RX_DATA_EDGE_CTL, 0x1F},
+- {WCD938X_DIGITAL_TX_DATA_EDGE_CTL, 0x80},
+- {WCD938X_DIGITAL_GPIO_MODE, 0x00},
+- {WCD938X_DIGITAL_PIN_CTL_OE, 0x00},
+- {WCD938X_DIGITAL_PIN_CTL_DATA_0, 0x00},
+- {WCD938X_DIGITAL_PIN_CTL_DATA_1, 0x00},
+- {WCD938X_DIGITAL_PIN_STATUS_0, 0x00},
+- {WCD938X_DIGITAL_PIN_STATUS_1, 0x00},
+- {WCD938X_DIGITAL_DIG_DEBUG_CTL, 0x00},
+- {WCD938X_DIGITAL_DIG_DEBUG_EN, 0x00},
+- {WCD938X_DIGITAL_ANA_CSR_DBG_ADD, 0x00},
+- {WCD938X_DIGITAL_ANA_CSR_DBG_CTL, 0x48},
+- {WCD938X_DIGITAL_SSP_DBG, 0x00},
+- {WCD938X_DIGITAL_MODE_STATUS_0, 0x00},
+- {WCD938X_DIGITAL_MODE_STATUS_1, 0x00},
+- {WCD938X_DIGITAL_SPARE_0, 0x00},
+- {WCD938X_DIGITAL_SPARE_1, 0x00},
+- {WCD938X_DIGITAL_SPARE_2, 0x00},
+- {WCD938X_DIGITAL_EFUSE_REG_0, 0x00},
+- {WCD938X_DIGITAL_EFUSE_REG_1, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_2, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_3, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_4, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_5, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_6, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_7, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_8, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_9, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_10, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_11, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_12, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_13, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_14, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_15, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_16, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_17, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_18, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_19, 0xFF},
+- {WCD938X_DIGITAL_EFUSE_REG_20, 0x0E},
+- {WCD938X_DIGITAL_EFUSE_REG_21, 0x00},
+- {WCD938X_DIGITAL_EFUSE_REG_22, 0x00},
+- {WCD938X_DIGITAL_EFUSE_REG_23, 0xF8},
+- {WCD938X_DIGITAL_EFUSE_REG_24, 0x16},
+- {WCD938X_DIGITAL_EFUSE_REG_25, 0x00},
+- {WCD938X_DIGITAL_EFUSE_REG_26, 0x00},
+- {WCD938X_DIGITAL_EFUSE_REG_27, 0x00},
+- {WCD938X_DIGITAL_EFUSE_REG_28, 0x00},
+- {WCD938X_DIGITAL_EFUSE_REG_29, 0x00},
+- {WCD938X_DIGITAL_EFUSE_REG_30, 0x00},
+- {WCD938X_DIGITAL_EFUSE_REG_31, 0x00},
+- {WCD938X_DIGITAL_TX_REQ_FB_CTL_0, 0x88},
+- {WCD938X_DIGITAL_TX_REQ_FB_CTL_1, 0x88},
+- {WCD938X_DIGITAL_TX_REQ_FB_CTL_2, 0x88},
+- {WCD938X_DIGITAL_TX_REQ_FB_CTL_3, 0x88},
+- {WCD938X_DIGITAL_TX_REQ_FB_CTL_4, 0x88},
+- {WCD938X_DIGITAL_DEM_BYPASS_DATA0, 0x55},
+- {WCD938X_DIGITAL_DEM_BYPASS_DATA1, 0x55},
+- {WCD938X_DIGITAL_DEM_BYPASS_DATA2, 0x55},
+- {WCD938X_DIGITAL_DEM_BYPASS_DATA3, 0x01},
+-};
+-
+-static bool wcd938x_rdwr_register(struct device *dev, unsigned int reg)
+-{
+- switch (reg) {
+- case WCD938X_ANA_PAGE_REGISTER:
+- case WCD938X_ANA_BIAS:
+- case WCD938X_ANA_RX_SUPPLIES:
+- case WCD938X_ANA_HPH:
+- case WCD938X_ANA_EAR:
+- case WCD938X_ANA_EAR_COMPANDER_CTL:
+- case WCD938X_ANA_TX_CH1:
+- case WCD938X_ANA_TX_CH2:
+- case WCD938X_ANA_TX_CH3:
+- case WCD938X_ANA_TX_CH4:
+- case WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC:
+- case WCD938X_ANA_MICB3_DSP_EN_LOGIC:
+- case WCD938X_ANA_MBHC_MECH:
+- case WCD938X_ANA_MBHC_ELECT:
+- case WCD938X_ANA_MBHC_ZDET:
+- case WCD938X_ANA_MBHC_BTN0:
+- case WCD938X_ANA_MBHC_BTN1:
+- case WCD938X_ANA_MBHC_BTN2:
+- case WCD938X_ANA_MBHC_BTN3:
+- case WCD938X_ANA_MBHC_BTN4:
+- case WCD938X_ANA_MBHC_BTN5:
+- case WCD938X_ANA_MBHC_BTN6:
+- case WCD938X_ANA_MBHC_BTN7:
+- case WCD938X_ANA_MICB1:
+- case WCD938X_ANA_MICB2:
+- case WCD938X_ANA_MICB2_RAMP:
+- case WCD938X_ANA_MICB3:
+- case WCD938X_ANA_MICB4:
+- case WCD938X_BIAS_CTL:
+- case WCD938X_BIAS_VBG_FINE_ADJ:
+- case WCD938X_LDOL_VDDCX_ADJUST:
+- case WCD938X_LDOL_DISABLE_LDOL:
+- case WCD938X_MBHC_CTL_CLK:
+- case WCD938X_MBHC_CTL_ANA:
+- case WCD938X_MBHC_CTL_SPARE_1:
+- case WCD938X_MBHC_CTL_SPARE_2:
+- case WCD938X_MBHC_CTL_BCS:
+- case WCD938X_MBHC_TEST_CTL:
+- case WCD938X_LDOH_MODE:
+- case WCD938X_LDOH_BIAS:
+- case WCD938X_LDOH_STB_LOADS:
+- case WCD938X_LDOH_SLOWRAMP:
+- case WCD938X_MICB1_TEST_CTL_1:
+- case WCD938X_MICB1_TEST_CTL_2:
+- case WCD938X_MICB1_TEST_CTL_3:
+- case WCD938X_MICB2_TEST_CTL_1:
+- case WCD938X_MICB2_TEST_CTL_2:
+- case WCD938X_MICB2_TEST_CTL_3:
+- case WCD938X_MICB3_TEST_CTL_1:
+- case WCD938X_MICB3_TEST_CTL_2:
+- case WCD938X_MICB3_TEST_CTL_3:
+- case WCD938X_MICB4_TEST_CTL_1:
+- case WCD938X_MICB4_TEST_CTL_2:
+- case WCD938X_MICB4_TEST_CTL_3:
+- case WCD938X_TX_COM_ADC_VCM:
+- case WCD938X_TX_COM_BIAS_ATEST:
+- case WCD938X_TX_COM_SPARE1:
+- case WCD938X_TX_COM_SPARE2:
+- case WCD938X_TX_COM_TXFE_DIV_CTL:
+- case WCD938X_TX_COM_TXFE_DIV_START:
+- case WCD938X_TX_COM_SPARE3:
+- case WCD938X_TX_COM_SPARE4:
+- case WCD938X_TX_1_2_TEST_EN:
+- case WCD938X_TX_1_2_ADC_IB:
+- case WCD938X_TX_1_2_ATEST_REFCTL:
+- case WCD938X_TX_1_2_TEST_CTL:
+- case WCD938X_TX_1_2_TEST_BLK_EN1:
+- case WCD938X_TX_1_2_TXFE1_CLKDIV:
+- case WCD938X_TX_3_4_TEST_EN:
+- case WCD938X_TX_3_4_ADC_IB:
+- case WCD938X_TX_3_4_ATEST_REFCTL:
+- case WCD938X_TX_3_4_TEST_CTL:
+- case WCD938X_TX_3_4_TEST_BLK_EN3:
+- case WCD938X_TX_3_4_TXFE3_CLKDIV:
+- case WCD938X_TX_3_4_TEST_BLK_EN2:
+- case WCD938X_TX_3_4_TXFE2_CLKDIV:
+- case WCD938X_TX_3_4_SPARE1:
+- case WCD938X_TX_3_4_TEST_BLK_EN4:
+- case WCD938X_TX_3_4_TXFE4_CLKDIV:
+- case WCD938X_TX_3_4_SPARE2:
+- case WCD938X_CLASSH_MODE_1:
+- case WCD938X_CLASSH_MODE_2:
+- case WCD938X_CLASSH_MODE_3:
+- case WCD938X_CLASSH_CTRL_VCL_1:
+- case WCD938X_CLASSH_CTRL_VCL_2:
+- case WCD938X_CLASSH_CTRL_CCL_1:
+- case WCD938X_CLASSH_CTRL_CCL_2:
+- case WCD938X_CLASSH_CTRL_CCL_3:
+- case WCD938X_CLASSH_CTRL_CCL_4:
+- case WCD938X_CLASSH_CTRL_CCL_5:
+- case WCD938X_CLASSH_BUCK_TMUX_A_D:
+- case WCD938X_CLASSH_BUCK_SW_DRV_CNTL:
+- case WCD938X_CLASSH_SPARE:
+- case WCD938X_FLYBACK_EN:
+- case WCD938X_FLYBACK_VNEG_CTRL_1:
+- case WCD938X_FLYBACK_VNEG_CTRL_2:
+- case WCD938X_FLYBACK_VNEG_CTRL_3:
+- case WCD938X_FLYBACK_VNEG_CTRL_4:
+- case WCD938X_FLYBACK_VNEG_CTRL_5:
+- case WCD938X_FLYBACK_VNEG_CTRL_6:
+- case WCD938X_FLYBACK_VNEG_CTRL_7:
+- case WCD938X_FLYBACK_VNEG_CTRL_8:
+- case WCD938X_FLYBACK_VNEG_CTRL_9:
+- case WCD938X_FLYBACK_VNEGDAC_CTRL_1:
+- case WCD938X_FLYBACK_VNEGDAC_CTRL_2:
+- case WCD938X_FLYBACK_VNEGDAC_CTRL_3:
+- case WCD938X_FLYBACK_CTRL_1:
+- case WCD938X_FLYBACK_TEST_CTL:
+- case WCD938X_RX_AUX_SW_CTL:
+- case WCD938X_RX_PA_AUX_IN_CONN:
+- case WCD938X_RX_TIMER_DIV:
+- case WCD938X_RX_OCP_CTL:
+- case WCD938X_RX_OCP_COUNT:
+- case WCD938X_RX_BIAS_EAR_DAC:
+- case WCD938X_RX_BIAS_EAR_AMP:
+- case WCD938X_RX_BIAS_HPH_LDO:
+- case WCD938X_RX_BIAS_HPH_PA:
+- case WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2:
+- case WCD938X_RX_BIAS_HPH_RDAC_LDO:
+- case WCD938X_RX_BIAS_HPH_CNP1:
+- case WCD938X_RX_BIAS_HPH_LOWPOWER:
+- case WCD938X_RX_BIAS_AUX_DAC:
+- case WCD938X_RX_BIAS_AUX_AMP:
+- case WCD938X_RX_BIAS_VNEGDAC_BLEEDER:
+- case WCD938X_RX_BIAS_MISC:
+- case WCD938X_RX_BIAS_BUCK_RST:
+- case WCD938X_RX_BIAS_BUCK_VREF_ERRAMP:
+- case WCD938X_RX_BIAS_FLYB_ERRAMP:
+- case WCD938X_RX_BIAS_FLYB_BUFF:
+- case WCD938X_RX_BIAS_FLYB_MID_RST:
+- case WCD938X_HPH_CNP_EN:
+- case WCD938X_HPH_CNP_WG_CTL:
+- case WCD938X_HPH_CNP_WG_TIME:
+- case WCD938X_HPH_OCP_CTL:
+- case WCD938X_HPH_AUTO_CHOP:
+- case WCD938X_HPH_CHOP_CTL:
+- case WCD938X_HPH_PA_CTL1:
+- case WCD938X_HPH_PA_CTL2:
+- case WCD938X_HPH_L_EN:
+- case WCD938X_HPH_L_TEST:
+- case WCD938X_HPH_L_ATEST:
+- case WCD938X_HPH_R_EN:
+- case WCD938X_HPH_R_TEST:
+- case WCD938X_HPH_R_ATEST:
+- case WCD938X_HPH_RDAC_CLK_CTL1:
+- case WCD938X_HPH_RDAC_CLK_CTL2:
+- case WCD938X_HPH_RDAC_LDO_CTL:
+- case WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL:
+- case WCD938X_HPH_REFBUFF_UHQA_CTL:
+- case WCD938X_HPH_REFBUFF_LP_CTL:
+- case WCD938X_HPH_L_DAC_CTL:
+- case WCD938X_HPH_R_DAC_CTL:
+- case WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL:
+- case WCD938X_HPH_SURGE_HPHLR_SURGE_EN:
+- case WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1:
+- case WCD938X_EAR_EAR_EN_REG:
+- case WCD938X_EAR_EAR_PA_CON:
+- case WCD938X_EAR_EAR_SP_CON:
+- case WCD938X_EAR_EAR_DAC_CON:
+- case WCD938X_EAR_EAR_CNP_FSM_CON:
+- case WCD938X_EAR_TEST_CTL:
+- case WCD938X_ANA_NEW_PAGE_REGISTER:
+- case WCD938X_HPH_NEW_ANA_HPH2:
+- case WCD938X_HPH_NEW_ANA_HPH3:
+- case WCD938X_SLEEP_CTL:
+- case WCD938X_SLEEP_WATCHDOG_CTL:
+- case WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL:
+- case WCD938X_MBHC_NEW_CTL_1:
+- case WCD938X_MBHC_NEW_CTL_2:
+- case WCD938X_MBHC_NEW_PLUG_DETECT_CTL:
+- case WCD938X_MBHC_NEW_ZDET_ANA_CTL:
+- case WCD938X_MBHC_NEW_ZDET_RAMP_CTL:
+- case WCD938X_TX_NEW_AMIC_MUX_CFG:
+- case WCD938X_AUX_AUXPA:
+- case WCD938X_LDORXTX_MODE:
+- case WCD938X_LDORXTX_CONFIG:
+- case WCD938X_DIE_CRACK_DIE_CRK_DET_EN:
+- case WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL:
+- case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L:
+- case WCD938X_HPH_NEW_INT_RDAC_VREF_CTL:
+- case WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL:
+- case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R:
+- case WCD938X_HPH_NEW_INT_PA_MISC1:
+- case WCD938X_HPH_NEW_INT_PA_MISC2:
+- case WCD938X_HPH_NEW_INT_PA_RDAC_MISC:
+- case WCD938X_HPH_NEW_INT_HPH_TIMER1:
+- case WCD938X_HPH_NEW_INT_HPH_TIMER2:
+- case WCD938X_HPH_NEW_INT_HPH_TIMER3:
+- case WCD938X_HPH_NEW_INT_HPH_TIMER4:
+- case WCD938X_HPH_NEW_INT_PA_RDAC_MISC2:
+- case WCD938X_HPH_NEW_INT_PA_RDAC_MISC3:
+- case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW:
+- case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW:
+- case WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI:
+- case WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP:
+- case WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP:
+- case WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL:
+- case WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL:
+- case WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT:
+- case WCD938X_MBHC_NEW_INT_SPARE_2:
+- case WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON:
+- case WCD938X_EAR_INT_NEW_CNP_VCM_CON1:
+- case WCD938X_EAR_INT_NEW_CNP_VCM_CON2:
+- case WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS:
+- case WCD938X_AUX_INT_EN_REG:
+- case WCD938X_AUX_INT_PA_CTRL:
+- case WCD938X_AUX_INT_SP_CTRL:
+- case WCD938X_AUX_INT_DAC_CTRL:
+- case WCD938X_AUX_INT_CLK_CTRL:
+- case WCD938X_AUX_INT_TEST_CTRL:
+- case WCD938X_AUX_INT_MISC:
+- case WCD938X_LDORXTX_INT_BIAS:
+- case WCD938X_LDORXTX_INT_STB_LOADS_DTEST:
+- case WCD938X_LDORXTX_INT_TEST0:
+- case WCD938X_LDORXTX_INT_STARTUP_TIMER:
+- case WCD938X_LDORXTX_INT_TEST1:
+- case WCD938X_SLEEP_INT_WATCHDOG_CTL_1:
+- case WCD938X_SLEEP_INT_WATCHDOG_CTL_2:
+- case WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1:
+- case WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2:
+- case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2:
+- case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1:
+- case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0:
+- case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M:
+- case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M:
+- case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1:
+- case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0:
+- case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP:
+- case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1:
+- case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0:
+- case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP:
+- case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0:
+- case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP:
+- case WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1:
+- case WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP:
+- case WCD938X_TX_COM_NEW_INT_TXADC_INT_L2:
+- case WCD938X_TX_COM_NEW_INT_TXADC_INT_L1:
+- case WCD938X_TX_COM_NEW_INT_TXADC_INT_L0:
+- case WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP:
+- case WCD938X_DIGITAL_PAGE_REGISTER:
+- case WCD938X_DIGITAL_SWR_TX_CLK_RATE:
+- case WCD938X_DIGITAL_CDC_RST_CTL:
+- case WCD938X_DIGITAL_TOP_CLK_CFG:
+- case WCD938X_DIGITAL_CDC_ANA_CLK_CTL:
+- case WCD938X_DIGITAL_CDC_DIG_CLK_CTL:
+- case WCD938X_DIGITAL_SWR_RST_EN:
+- case WCD938X_DIGITAL_CDC_PATH_MODE:
+- case WCD938X_DIGITAL_CDC_RX_RST:
+- case WCD938X_DIGITAL_CDC_RX0_CTL:
+- case WCD938X_DIGITAL_CDC_RX1_CTL:
+- case WCD938X_DIGITAL_CDC_RX2_CTL:
+- case WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1:
+- case WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3:
+- case WCD938X_DIGITAL_CDC_COMP_CTL_0:
+- case WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_A1_0:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_A1_1:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_A2_0:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_A2_1:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_A3_0:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_A3_1:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_A4_0:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_A4_1:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_A5_0:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_A5_1:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_A6_0:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_A7_0:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_C_0:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_C_1:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_C_2:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_C_3:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_R1:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_R2:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_R3:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_R4:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_R5:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_R6:
+- case WCD938X_DIGITAL_CDC_HPH_DSM_R7:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_A1_0:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_A1_1:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_A2_0:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_A2_1:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_A3_0:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_A3_1:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_A4_0:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_A4_1:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_A5_0:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_A5_1:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_A6_0:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_A7_0:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_C_0:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_C_1:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_C_2:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_C_3:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_R1:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_R2:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_R3:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_R4:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_R5:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_R6:
+- case WCD938X_DIGITAL_CDC_AUX_DSM_R7:
+- case WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0:
+- case WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1:
+- case WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0:
+- case WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1:
+- case WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2:
+- case WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0:
+- case WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1:
+- case WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2:
+- case WCD938X_DIGITAL_CDC_HPH_GAIN_CTL:
+- case WCD938X_DIGITAL_CDC_AUX_GAIN_CTL:
+- case WCD938X_DIGITAL_CDC_EAR_PATH_CTL:
+- case WCD938X_DIGITAL_CDC_SWR_CLH:
+- case WCD938X_DIGITAL_SWR_CLH_BYP:
+- case WCD938X_DIGITAL_CDC_TX0_CTL:
+- case WCD938X_DIGITAL_CDC_TX1_CTL:
+- case WCD938X_DIGITAL_CDC_TX2_CTL:
+- case WCD938X_DIGITAL_CDC_TX_RST:
+- case WCD938X_DIGITAL_CDC_REQ_CTL:
+- case WCD938X_DIGITAL_CDC_RST:
+- case WCD938X_DIGITAL_CDC_AMIC_CTL:
+- case WCD938X_DIGITAL_CDC_DMIC_CTL:
+- case WCD938X_DIGITAL_CDC_DMIC1_CTL:
+- case WCD938X_DIGITAL_CDC_DMIC2_CTL:
+- case WCD938X_DIGITAL_CDC_DMIC3_CTL:
+- case WCD938X_DIGITAL_CDC_DMIC4_CTL:
+- case WCD938X_DIGITAL_EFUSE_PRG_CTL:
+- case WCD938X_DIGITAL_EFUSE_CTL:
+- case WCD938X_DIGITAL_CDC_DMIC_RATE_1_2:
+- case WCD938X_DIGITAL_CDC_DMIC_RATE_3_4:
+- case WCD938X_DIGITAL_PDM_WD_CTL0:
+- case WCD938X_DIGITAL_PDM_WD_CTL1:
+- case WCD938X_DIGITAL_PDM_WD_CTL2:
+- case WCD938X_DIGITAL_INTR_MODE:
+- case WCD938X_DIGITAL_INTR_MASK_0:
+- case WCD938X_DIGITAL_INTR_MASK_1:
+- case WCD938X_DIGITAL_INTR_MASK_2:
+- case WCD938X_DIGITAL_INTR_CLEAR_0:
+- case WCD938X_DIGITAL_INTR_CLEAR_1:
+- case WCD938X_DIGITAL_INTR_CLEAR_2:
+- case WCD938X_DIGITAL_INTR_LEVEL_0:
+- case WCD938X_DIGITAL_INTR_LEVEL_1:
+- case WCD938X_DIGITAL_INTR_LEVEL_2:
+- case WCD938X_DIGITAL_INTR_SET_0:
+- case WCD938X_DIGITAL_INTR_SET_1:
+- case WCD938X_DIGITAL_INTR_SET_2:
+- case WCD938X_DIGITAL_INTR_TEST_0:
+- case WCD938X_DIGITAL_INTR_TEST_1:
+- case WCD938X_DIGITAL_INTR_TEST_2:
+- case WCD938X_DIGITAL_TX_MODE_DBG_EN:
+- case WCD938X_DIGITAL_TX_MODE_DBG_0_1:
+- case WCD938X_DIGITAL_TX_MODE_DBG_2_3:
+- case WCD938X_DIGITAL_LB_IN_SEL_CTL:
+- case WCD938X_DIGITAL_LOOP_BACK_MODE:
+- case WCD938X_DIGITAL_SWR_DAC_TEST:
+- case WCD938X_DIGITAL_SWR_HM_TEST_RX_0:
+- case WCD938X_DIGITAL_SWR_HM_TEST_TX_0:
+- case WCD938X_DIGITAL_SWR_HM_TEST_RX_1:
+- case WCD938X_DIGITAL_SWR_HM_TEST_TX_1:
+- case WCD938X_DIGITAL_SWR_HM_TEST_TX_2:
+- case WCD938X_DIGITAL_PAD_CTL_SWR_0:
+- case WCD938X_DIGITAL_PAD_CTL_SWR_1:
+- case WCD938X_DIGITAL_I2C_CTL:
+- case WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE:
+- case WCD938X_DIGITAL_EFUSE_TEST_CTL_0:
+- case WCD938X_DIGITAL_EFUSE_TEST_CTL_1:
+- case WCD938X_DIGITAL_PAD_CTL_PDM_RX0:
+- case WCD938X_DIGITAL_PAD_CTL_PDM_RX1:
+- case WCD938X_DIGITAL_PAD_CTL_PDM_TX0:
+- case WCD938X_DIGITAL_PAD_CTL_PDM_TX1:
+- case WCD938X_DIGITAL_PAD_CTL_PDM_TX2:
+- case WCD938X_DIGITAL_PAD_INP_DIS_0:
+- case WCD938X_DIGITAL_PAD_INP_DIS_1:
+- case WCD938X_DIGITAL_DRIVE_STRENGTH_0:
+- case WCD938X_DIGITAL_DRIVE_STRENGTH_1:
+- case WCD938X_DIGITAL_DRIVE_STRENGTH_2:
+- case WCD938X_DIGITAL_RX_DATA_EDGE_CTL:
+- case WCD938X_DIGITAL_TX_DATA_EDGE_CTL:
+- case WCD938X_DIGITAL_GPIO_MODE:
+- case WCD938X_DIGITAL_PIN_CTL_OE:
+- case WCD938X_DIGITAL_PIN_CTL_DATA_0:
+- case WCD938X_DIGITAL_PIN_CTL_DATA_1:
+- case WCD938X_DIGITAL_DIG_DEBUG_CTL:
+- case WCD938X_DIGITAL_DIG_DEBUG_EN:
+- case WCD938X_DIGITAL_ANA_CSR_DBG_ADD:
+- case WCD938X_DIGITAL_ANA_CSR_DBG_CTL:
+- case WCD938X_DIGITAL_SSP_DBG:
+- case WCD938X_DIGITAL_SPARE_0:
+- case WCD938X_DIGITAL_SPARE_1:
+- case WCD938X_DIGITAL_SPARE_2:
+- case WCD938X_DIGITAL_TX_REQ_FB_CTL_0:
+- case WCD938X_DIGITAL_TX_REQ_FB_CTL_1:
+- case WCD938X_DIGITAL_TX_REQ_FB_CTL_2:
+- case WCD938X_DIGITAL_TX_REQ_FB_CTL_3:
+- case WCD938X_DIGITAL_TX_REQ_FB_CTL_4:
+- case WCD938X_DIGITAL_DEM_BYPASS_DATA0:
+- case WCD938X_DIGITAL_DEM_BYPASS_DATA1:
+- case WCD938X_DIGITAL_DEM_BYPASS_DATA2:
+- case WCD938X_DIGITAL_DEM_BYPASS_DATA3:
+- return true;
+- }
+-
+- return false;
+-}
+-
+-static bool wcd938x_readonly_register(struct device *dev, unsigned int reg)
+-{
+- switch (reg) {
+- case WCD938X_ANA_MBHC_RESULT_1:
+- case WCD938X_ANA_MBHC_RESULT_2:
+- case WCD938X_ANA_MBHC_RESULT_3:
+- case WCD938X_MBHC_MOISTURE_DET_FSM_STATUS:
+- case WCD938X_TX_1_2_SAR2_ERR:
+- case WCD938X_TX_1_2_SAR1_ERR:
+- case WCD938X_TX_3_4_SAR4_ERR:
+- case WCD938X_TX_3_4_SAR3_ERR:
+- case WCD938X_HPH_L_STATUS:
+- case WCD938X_HPH_R_STATUS:
+- case WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS:
+- case WCD938X_EAR_STATUS_REG_1:
+- case WCD938X_EAR_STATUS_REG_2:
+- case WCD938X_MBHC_NEW_FSM_STATUS:
+- case WCD938X_MBHC_NEW_ADC_RESULT:
+- case WCD938X_DIE_CRACK_DIE_CRK_DET_OUT:
+- case WCD938X_AUX_INT_STATUS_REG:
+- case WCD938X_LDORXTX_INT_STATUS:
+- case WCD938X_DIGITAL_CHIP_ID0:
+- case WCD938X_DIGITAL_CHIP_ID1:
+- case WCD938X_DIGITAL_CHIP_ID2:
+- case WCD938X_DIGITAL_CHIP_ID3:
+- case WCD938X_DIGITAL_INTR_STATUS_0:
+- case WCD938X_DIGITAL_INTR_STATUS_1:
+- case WCD938X_DIGITAL_INTR_STATUS_2:
+- case WCD938X_DIGITAL_INTR_CLEAR_0:
+- case WCD938X_DIGITAL_INTR_CLEAR_1:
+- case WCD938X_DIGITAL_INTR_CLEAR_2:
+- case WCD938X_DIGITAL_SWR_HM_TEST_0:
+- case WCD938X_DIGITAL_SWR_HM_TEST_1:
+- case WCD938X_DIGITAL_EFUSE_T_DATA_0:
+- case WCD938X_DIGITAL_EFUSE_T_DATA_1:
+- case WCD938X_DIGITAL_PIN_STATUS_0:
+- case WCD938X_DIGITAL_PIN_STATUS_1:
+- case WCD938X_DIGITAL_MODE_STATUS_0:
+- case WCD938X_DIGITAL_MODE_STATUS_1:
+- case WCD938X_DIGITAL_EFUSE_REG_0:
+- case WCD938X_DIGITAL_EFUSE_REG_1:
+- case WCD938X_DIGITAL_EFUSE_REG_2:
+- case WCD938X_DIGITAL_EFUSE_REG_3:
+- case WCD938X_DIGITAL_EFUSE_REG_4:
+- case WCD938X_DIGITAL_EFUSE_REG_5:
+- case WCD938X_DIGITAL_EFUSE_REG_6:
+- case WCD938X_DIGITAL_EFUSE_REG_7:
+- case WCD938X_DIGITAL_EFUSE_REG_8:
+- case WCD938X_DIGITAL_EFUSE_REG_9:
+- case WCD938X_DIGITAL_EFUSE_REG_10:
+- case WCD938X_DIGITAL_EFUSE_REG_11:
+- case WCD938X_DIGITAL_EFUSE_REG_12:
+- case WCD938X_DIGITAL_EFUSE_REG_13:
+- case WCD938X_DIGITAL_EFUSE_REG_14:
+- case WCD938X_DIGITAL_EFUSE_REG_15:
+- case WCD938X_DIGITAL_EFUSE_REG_16:
+- case WCD938X_DIGITAL_EFUSE_REG_17:
+- case WCD938X_DIGITAL_EFUSE_REG_18:
+- case WCD938X_DIGITAL_EFUSE_REG_19:
+- case WCD938X_DIGITAL_EFUSE_REG_20:
+- case WCD938X_DIGITAL_EFUSE_REG_21:
+- case WCD938X_DIGITAL_EFUSE_REG_22:
+- case WCD938X_DIGITAL_EFUSE_REG_23:
+- case WCD938X_DIGITAL_EFUSE_REG_24:
+- case WCD938X_DIGITAL_EFUSE_REG_25:
+- case WCD938X_DIGITAL_EFUSE_REG_26:
+- case WCD938X_DIGITAL_EFUSE_REG_27:
+- case WCD938X_DIGITAL_EFUSE_REG_28:
+- case WCD938X_DIGITAL_EFUSE_REG_29:
+- case WCD938X_DIGITAL_EFUSE_REG_30:
+- case WCD938X_DIGITAL_EFUSE_REG_31:
+- return true;
+- }
+- return false;
+-}
+-
+-static bool wcd938x_readable_register(struct device *dev, unsigned int reg)
+-{
+- bool ret;
+-
+- ret = wcd938x_readonly_register(dev, reg);
+- if (!ret)
+- return wcd938x_rdwr_register(dev, reg);
+-
+- return ret;
+-}
+-
+-static bool wcd938x_writeable_register(struct device *dev, unsigned int reg)
+-{
+- return wcd938x_rdwr_register(dev, reg);
+-}
+-
+-static bool wcd938x_volatile_register(struct device *dev, unsigned int reg)
+-{
+- if (reg <= WCD938X_BASE_ADDRESS)
+- return false;
+-
+- if (reg == WCD938X_DIGITAL_SWR_TX_CLK_RATE)
+- return true;
+-
+- if (wcd938x_readonly_register(dev, reg))
+- return true;
+-
+- return false;
+-}
+-
+-static struct regmap_config wcd938x_regmap_config = {
+- .name = "wcd938x_csr",
+- .reg_bits = 32,
+- .val_bits = 8,
+- .cache_type = REGCACHE_RBTREE,
+- .reg_defaults = wcd938x_defaults,
+- .num_reg_defaults = ARRAY_SIZE(wcd938x_defaults),
+- .max_register = WCD938X_MAX_REGISTER,
+- .readable_reg = wcd938x_readable_register,
+- .writeable_reg = wcd938x_writeable_register,
+- .volatile_reg = wcd938x_volatile_register,
+- .can_multi_write = true,
+-};
+-
+ static const struct regmap_irq wcd938x_irqs[WCD938X_NUM_IRQS] = {
+ REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01),
+ REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02),
+@@ -4445,10 +3450,10 @@ static int wcd938x_bind(struct device *dev)
+ return -EINVAL;
+ }
+
+- wcd938x->regmap = devm_regmap_init_sdw(wcd938x->tx_sdw_dev, &wcd938x_regmap_config);
+- if (IS_ERR(wcd938x->regmap)) {
+- dev_err(dev, "%s: tx csr regmap not found\n", __func__);
+- return PTR_ERR(wcd938x->regmap);
++ wcd938x->regmap = dev_get_regmap(&wcd938x->tx_sdw_dev->dev, NULL);
++ if (!wcd938x->regmap) {
++ dev_err(dev, "could not get TX device regmap\n");
++ return -EINVAL;
+ }
+
+ ret = wcd938x_irq_init(wcd938x, dev);
+diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h
+index ea82039e78435..74b1498fec38b 100644
+--- a/sound/soc/codecs/wcd938x.h
++++ b/sound/soc/codecs/wcd938x.h
+@@ -663,6 +663,7 @@ struct wcd938x_sdw_priv {
+ bool is_tx;
+ struct wcd938x_priv *wcd938x;
+ struct irq_domain *slave_irq;
++ struct regmap *regmap;
+ };
+
+ #if IS_ENABLED(CONFIG_SND_SOC_WCD938X_SDW)
+--
+2.42.0
+
--- /dev/null
+From 7e30e3c7254ed812e9835adf6b2f4bbec70d1d80 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Oct 2023 17:55:55 +0200
+Subject: ASoC: codecs: wcd938x: fix regulator leaks on probe errors
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ Upstream commit 69a026a2357ee69983690d07976de44ef26ee38a ]
+
+Make sure to disable and free the regulators on probe errors and on
+driver unbind.
+
+Fixes: 16572522aece ("ASoC: codecs: wcd938x-sdw: add SoundWire driver")
+Cc: stable@vger.kernel.org # 5.14
+Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20231003155558.27079-5-johan+linaro@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/wcd938x.c | 18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
+index ea86f04641b8a..5cf780dc333f6 100644
+--- a/sound/soc/codecs/wcd938x.c
++++ b/sound/soc/codecs/wcd938x.c
+@@ -3300,8 +3300,10 @@ static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device
+ return dev_err_probe(dev, ret, "Failed to get supplies\n");
+
+ ret = regulator_bulk_enable(WCD938X_MAX_SUPPLY, wcd938x->supplies);
+- if (ret)
++ if (ret) {
++ regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies);
+ return dev_err_probe(dev, ret, "Failed to enable supplies\n");
++ }
+
+ wcd938x_dt_parse_micbias_info(dev, wcd938x);
+
+@@ -3577,13 +3579,13 @@ static int wcd938x_probe(struct platform_device *pdev)
+
+ ret = wcd938x_add_slave_components(wcd938x, dev, &match);
+ if (ret)
+- return ret;
++ goto err_disable_regulators;
+
+ wcd938x_reset(wcd938x);
+
+ ret = component_master_add_with_match(dev, &wcd938x_comp_ops, match);
+ if (ret)
+- return ret;
++ goto err_disable_regulators;
+
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+@@ -3593,11 +3595,21 @@ static int wcd938x_probe(struct platform_device *pdev)
+ pm_runtime_idle(dev);
+
+ return 0;
++
++err_disable_regulators:
++ regulator_bulk_disable(WCD938X_MAX_SUPPLY, wcd938x->supplies);
++ regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies);
++
++ return ret;
+ }
+
+ static void wcd938x_remove(struct platform_device *pdev)
+ {
++ struct wcd938x_priv *wcd938x = dev_get_drvdata(&pdev->dev);
++
+ component_master_del(&pdev->dev, &wcd938x_comp_ops);
++ regulator_bulk_disable(WCD938X_MAX_SUPPLY, wcd938x->supplies);
++ regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies);
+ }
+
+ #if defined(CONFIG_OF)
+--
+2.42.0
+
--- /dev/null
+From 3313465836cea8838b025d092e711ebcd4926d85 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Oct 2023 17:55:54 +0200
+Subject: ASoC: codecs: wcd938x: fix resource leaks on bind errors
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ Upstream commit da29b94ed3547cee9d510d02eca4009f2de476cf ]
+
+Add the missing code to release resources on bind errors, including the
+references taken by wcd938x_sdw_device_get() which also need to be
+dropped on unbind().
+
+Fixes: 16572522aece ("ASoC: codecs: wcd938x-sdw: add SoundWire driver")
+Cc: stable@vger.kernel.org # 5.14
+Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20231003155558.27079-4-johan+linaro@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/wcd938x.c | 44 +++++++++++++++++++++++++++++---------
+ 1 file changed, 34 insertions(+), 10 deletions(-)
+
+diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
+index 16e2e1c186846..e68992b704cfa 100644
+--- a/sound/soc/codecs/wcd938x.c
++++ b/sound/soc/codecs/wcd938x.c
+@@ -3416,7 +3416,8 @@ static int wcd938x_bind(struct device *dev)
+ wcd938x->rxdev = wcd938x_sdw_device_get(wcd938x->rxnode);
+ if (!wcd938x->rxdev) {
+ dev_err(dev, "could not find slave with matching of node\n");
+- return -EINVAL;
++ ret = -EINVAL;
++ goto err_unbind;
+ }
+ wcd938x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd938x->rxdev);
+ wcd938x->sdw_priv[AIF1_PB]->wcd938x = wcd938x;
+@@ -3424,7 +3425,8 @@ static int wcd938x_bind(struct device *dev)
+ wcd938x->txdev = wcd938x_sdw_device_get(wcd938x->txnode);
+ if (!wcd938x->txdev) {
+ dev_err(dev, "could not find txslave with matching of node\n");
+- return -EINVAL;
++ ret = -EINVAL;
++ goto err_put_rxdev;
+ }
+ wcd938x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd938x->txdev);
+ wcd938x->sdw_priv[AIF1_CAP]->wcd938x = wcd938x;
+@@ -3435,31 +3437,35 @@ static int wcd938x_bind(struct device *dev)
+ if (!device_link_add(wcd938x->rxdev, wcd938x->txdev, DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME)) {
+ dev_err(dev, "could not devlink tx and rx\n");
+- return -EINVAL;
++ ret = -EINVAL;
++ goto err_put_txdev;
+ }
+
+ if (!device_link_add(dev, wcd938x->txdev, DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME)) {
+ dev_err(dev, "could not devlink wcd and tx\n");
+- return -EINVAL;
++ ret = -EINVAL;
++ goto err_remove_rxtx_link;
+ }
+
+ if (!device_link_add(dev, wcd938x->rxdev, DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME)) {
+ dev_err(dev, "could not devlink wcd and rx\n");
+- return -EINVAL;
++ ret = -EINVAL;
++ goto err_remove_tx_link;
+ }
+
+ wcd938x->regmap = dev_get_regmap(&wcd938x->tx_sdw_dev->dev, NULL);
+ if (!wcd938x->regmap) {
+ dev_err(dev, "could not get TX device regmap\n");
+- return -EINVAL;
++ ret = -EINVAL;
++ goto err_remove_rx_link;
+ }
+
+ ret = wcd938x_irq_init(wcd938x, dev);
+ if (ret) {
+ dev_err(dev, "%s: IRQ init failed: %d\n", __func__, ret);
+- return ret;
++ goto err_remove_rx_link;
+ }
+
+ wcd938x->sdw_priv[AIF1_PB]->slave_irq = wcd938x->virq;
+@@ -3468,17 +3474,33 @@ static int wcd938x_bind(struct device *dev)
+ ret = wcd938x_set_micbias_data(wcd938x);
+ if (ret < 0) {
+ dev_err(dev, "%s: bad micbias pdata\n", __func__);
+- return ret;
++ goto err_remove_rx_link;
+ }
+
+ ret = snd_soc_register_component(dev, &soc_codec_dev_wcd938x,
+ wcd938x_dais, ARRAY_SIZE(wcd938x_dais));
+- if (ret)
++ if (ret) {
+ dev_err(dev, "%s: Codec registration failed\n",
+ __func__);
++ goto err_remove_rx_link;
++ }
+
+- return ret;
++ return 0;
+
++err_remove_rx_link:
++ device_link_remove(dev, wcd938x->rxdev);
++err_remove_tx_link:
++ device_link_remove(dev, wcd938x->txdev);
++err_remove_rxtx_link:
++ device_link_remove(wcd938x->rxdev, wcd938x->txdev);
++err_put_txdev:
++ put_device(wcd938x->txdev);
++err_put_rxdev:
++ put_device(wcd938x->rxdev);
++err_unbind:
++ component_unbind_all(dev, wcd938x);
++
++ return ret;
+ }
+
+ static void wcd938x_unbind(struct device *dev)
+@@ -3489,6 +3511,8 @@ static void wcd938x_unbind(struct device *dev)
+ device_link_remove(dev, wcd938x->txdev);
+ device_link_remove(dev, wcd938x->rxdev);
+ device_link_remove(wcd938x->rxdev, wcd938x->txdev);
++ put_device(wcd938x->txdev);
++ put_device(wcd938x->rxdev);
+ component_unbind_all(dev, wcd938x);
+ }
+
+--
+2.42.0
+
--- /dev/null
+From 91a14cfc96c1f13e42be7645624f554b8382fde1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Oct 2023 17:55:56 +0200
+Subject: ASoC: codecs: wcd938x: fix runtime PM imbalance on remove
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ Upstream commit 3ebebb2c1eca92a15107b2d7aeff34196fd9e217 ]
+
+Make sure to balance the runtime PM operations, including the disable
+count, on driver unbind.
+
+Fixes: 16572522aece ("ASoC: codecs: wcd938x-sdw: add SoundWire driver")
+Cc: stable@vger.kernel.org # 5.14
+Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20231003155558.27079-6-johan+linaro@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/wcd938x.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
+index 5cf780dc333f6..ccfdb571fd3af 100644
+--- a/sound/soc/codecs/wcd938x.c
++++ b/sound/soc/codecs/wcd938x.c
+@@ -3605,9 +3605,15 @@ static int wcd938x_probe(struct platform_device *pdev)
+
+ static void wcd938x_remove(struct platform_device *pdev)
+ {
+- struct wcd938x_priv *wcd938x = dev_get_drvdata(&pdev->dev);
++ struct device *dev = &pdev->dev;
++ struct wcd938x_priv *wcd938x = dev_get_drvdata(dev);
++
++ component_master_del(dev, &wcd938x_comp_ops);
++
++ pm_runtime_disable(dev);
++ pm_runtime_set_suspended(dev);
++ pm_runtime_dont_use_autosuspend(dev);
+
+- component_master_del(&pdev->dev, &wcd938x_comp_ops);
+ regulator_bulk_disable(WCD938X_MAX_SUPPLY, wcd938x->supplies);
+ regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies);
+ }
+--
+2.42.0
+
--- /dev/null
+From 6ed2624f72fe0382dd3628c1e76add6cf246e480 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Apr 2023 09:46:30 +0200
+Subject: ASoC: codecs: wcd938x: Simplify with dev_err_probe
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 60ba2fda5280528e70fa26b44e36d1530f6d1d7e ]
+
+Replace dev_err() in probe() path with dev_err_probe() to:
+1. Make code a bit simpler and easier to read,
+2. Do not print messages on deferred probe.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/r/20230418074630.8681-4-krzysztof.kozlowski@linaro.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 69a026a2357e ("ASoC: codecs: wcd938x: fix regulator leaks on probe errors")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/wcd938x.c | 20 +++++++-------------
+ 1 file changed, 7 insertions(+), 13 deletions(-)
+
+diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
+index 00538cf86b87f..ea86f04641b8a 100644
+--- a/sound/soc/codecs/wcd938x.c
++++ b/sound/soc/codecs/wcd938x.c
+@@ -3286,11 +3286,9 @@ static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device
+ int ret;
+
+ wcd938x->reset_gpio = of_get_named_gpio(dev->of_node, "reset-gpios", 0);
+- if (wcd938x->reset_gpio < 0) {
+- dev_err(dev, "Failed to get reset gpio: err = %d\n",
+- wcd938x->reset_gpio);
+- return wcd938x->reset_gpio;
+- }
++ if (wcd938x->reset_gpio < 0)
++ return dev_err_probe(dev, wcd938x->reset_gpio,
++ "Failed to get reset gpio\n");
+
+ wcd938x->supplies[0].supply = "vdd-rxtx";
+ wcd938x->supplies[1].supply = "vdd-io";
+@@ -3298,16 +3296,12 @@ static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device
+ wcd938x->supplies[3].supply = "vdd-mic-bias";
+
+ ret = regulator_bulk_get(dev, WCD938X_MAX_SUPPLY, wcd938x->supplies);
+- if (ret) {
+- dev_err(dev, "Failed to get supplies: err = %d\n", ret);
+- return ret;
+- }
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to get supplies\n");
+
+ ret = regulator_bulk_enable(WCD938X_MAX_SUPPLY, wcd938x->supplies);
+- if (ret) {
+- dev_err(dev, "Failed to enable supplies: err = %d\n", ret);
+- return ret;
+- }
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to enable supplies\n");
+
+ wcd938x_dt_parse_micbias_info(dev, wcd938x);
+
+--
+2.42.0
+
--- /dev/null
+From 5916f2b7fe364af68f13896cbfbd0b9c3df8c2b0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 8 Nov 2022 17:27:27 +0800
+Subject: ASoC: rt1318: Add RT1318 SDCA vendor-specific driver
+
+From: Shuming Fan <shumingf@realtek.com>
+
+[ Upstream commit 6ad73a2b42ea6d43fc5bf32033e8f6b21df3109e ]
+
+This is the initial amplifier driver for rt1318 SDCA version.
+
+Signed-off-by: Shuming Fan <shumingf@realtek.com>
+Link: https://lore.kernel.org/r/20221108092727.13011-1-shumingf@realtek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: da29b94ed354 ("ASoC: codecs: wcd938x: fix resource leaks on bind errors")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/Kconfig | 6 +
+ sound/soc/codecs/Makefile | 2 +
+ sound/soc/codecs/rt1318-sdw.c | 884 ++++++++++++++++++++++++++++++++++
+ sound/soc/codecs/rt1318-sdw.h | 101 ++++
+ 4 files changed, 993 insertions(+)
+ create mode 100644 sound/soc/codecs/rt1318-sdw.c
+ create mode 100644 sound/soc/codecs/rt1318-sdw.h
+
+diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
+index 31896c8c2b0d6..4c7c01f0e77a2 100644
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -187,6 +187,7 @@ config SND_SOC_ALL_CODECS
+ imply SND_SOC_RT715_SDCA_SDW
+ imply SND_SOC_RT1308_SDW
+ imply SND_SOC_RT1316_SDW
++ imply SND_SOC_RT1318_SDW
+ imply SND_SOC_RT9120
+ imply SND_SOC_SDW_MOCKUP
+ imply SND_SOC_SGTL5000
+@@ -1173,6 +1174,11 @@ config SND_SOC_RT1316_SDW
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+
++config SND_SOC_RT1318_SDW
++ tristate "Realtek RT1318 Codec - SDW"
++ depends on SOUNDWIRE
++ select REGMAP_SOUNDWIRE
++
+ config SND_SOC_RT5514
+ tristate
+ depends on I2C
+diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
+index 4edc4775c7323..12adfbf048a2a 100644
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -177,6 +177,7 @@ snd-soc-rt1305-objs := rt1305.o
+ snd-soc-rt1308-objs := rt1308.o
+ snd-soc-rt1308-sdw-objs := rt1308-sdw.o
+ snd-soc-rt1316-sdw-objs := rt1316-sdw.o
++snd-soc-rt1318-sdw-objs := rt1318-sdw.o
+ snd-soc-rt274-objs := rt274.o
+ snd-soc-rt286-objs := rt286.o
+ snd-soc-rt298-objs := rt298.o
+@@ -506,6 +507,7 @@ obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o
+ obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o
+ obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o
+ obj-$(CONFIG_SND_SOC_RT1316_SDW) += snd-soc-rt1316-sdw.o
++obj-$(CONFIG_SND_SOC_RT1318_SDW) += snd-soc-rt1318-sdw.o
+ obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o
+ obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
+ obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
+diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
+new file mode 100644
+index 0000000000000..f85f5ab2c6d04
+--- /dev/null
++++ b/sound/soc/codecs/rt1318-sdw.c
+@@ -0,0 +1,884 @@
++// SPDX-License-Identifier: GPL-2.0-only
++//
++// rt1318-sdw.c -- rt1318 SDCA ALSA SoC amplifier audio driver
++//
++// Copyright(c) 2022 Realtek Semiconductor Corp.
++//
++//
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/pm_runtime.h>
++#include <linux/mod_devicetable.h>
++#include <linux/module.h>
++#include <linux/regmap.h>
++#include <linux/dmi.h>
++#include <linux/firmware.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc-dapm.h>
++#include <sound/initval.h>
++#include "rt1318-sdw.h"
++
++static const struct reg_sequence rt1318_blind_write[] = {
++ { 0xc001, 0x43 },
++ { 0xc003, 0xa2 },
++ { 0xc004, 0x44 },
++ { 0xc005, 0x44 },
++ { 0xc006, 0x33 },
++ { 0xc007, 0x64 },
++ { 0xc320, 0x20 },
++ { 0xf203, 0x18 },
++ { 0xf211, 0x00 },
++ { 0xf212, 0x26 },
++ { 0xf20d, 0x17 },
++ { 0xf214, 0x06 },
++ { 0xf20e, 0x00 },
++ { 0xf223, 0x7f },
++ { 0xf224, 0xdb },
++ { 0xf225, 0xee },
++ { 0xf226, 0x3f },
++ { 0xf227, 0x0f },
++ { 0xf21a, 0x78 },
++ { 0xf242, 0x3c },
++ { 0xc321, 0x0b },
++ { 0xc200, 0xd8 },
++ { 0xc201, 0x27 },
++ { 0xc202, 0x0f },
++ { 0xf800, 0x20 },
++ { 0xdf00, 0x10 },
++ { 0xdf5f, 0x01 },
++ { 0xdf60, 0xa7 },
++ { 0xc400, 0x0e },
++ { 0xc401, 0x43 },
++ { 0xc402, 0xe0 },
++ { 0xc403, 0x00 },
++ { 0xc404, 0x4c },
++ { 0xc407, 0x02 },
++ { 0xc408, 0x3f },
++ { 0xc300, 0x01 },
++ { 0xc206, 0x78 },
++ { 0xc203, 0x84 },
++ { 0xc120, 0xc0 },
++ { 0xc121, 0x03 },
++ { 0xe000, 0x88 },
++ { 0xc321, 0x09 },
++ { 0xc322, 0x01 },
++ { 0xe706, 0x0f },
++ { 0xe707, 0x30 },
++ { 0xe806, 0x0f },
++ { 0xe807, 0x30 },
++ { 0xed00, 0xb0 },
++ { 0xce04, 0x02 },
++ { 0xce05, 0x63 },
++ { 0xce06, 0x68 },
++ { 0xce07, 0x07 },
++ { 0xcf04, 0x02 },
++ { 0xcf05, 0x63 },
++ { 0xcf06, 0x68 },
++ { 0xcf07, 0x07 },
++ { 0xce60, 0xe3 },
++ { 0xc130, 0x51 },
++ { 0xf102, 0x00 },
++ { 0xf103, 0x00 },
++ { 0xf104, 0xf5 },
++ { 0xf105, 0x06 },
++ { 0xf109, 0x9b },
++ { 0xf10a, 0x0b },
++ { 0xf10b, 0x4c },
++ { 0xf10b, 0x5c },
++ { 0xf102, 0x00 },
++ { 0xf103, 0x00 },
++ { 0xf104, 0xf5 },
++ { 0xf105, 0x0b },
++ { 0xf109, 0x03 },
++ { 0xf10a, 0x0b },
++ { 0xf10b, 0x4c },
++ { 0xf10b, 0x5c },
++ { 0xf102, 0x00 },
++ { 0xf103, 0x00 },
++ { 0xf104, 0xf5 },
++ { 0xf105, 0x0c },
++ { 0xf109, 0x7f },
++ { 0xf10a, 0x0b },
++ { 0xf10b, 0x4c },
++ { 0xf10b, 0x5c },
++
++ { 0xe604, 0x00 },
++ { 0xdb00, 0x0c },
++ { 0xdd00, 0x0c },
++ { 0xdc19, 0x00 },
++ { 0xdc1a, 0xff },
++ { 0xdc1b, 0xff },
++ { 0xdc1c, 0xff },
++ { 0xdc1d, 0x00 },
++ { 0xdc1e, 0x00 },
++ { 0xdc1f, 0x00 },
++ { 0xdc20, 0xff },
++ { 0xde19, 0x00 },
++ { 0xde1a, 0xff },
++ { 0xde1b, 0xff },
++ { 0xde1c, 0xff },
++ { 0xde1d, 0x00 },
++ { 0xde1e, 0x00 },
++ { 0xde1f, 0x00 },
++ { 0xde20, 0xff },
++ { 0xdb32, 0x00 },
++ { 0xdd32, 0x00 },
++ { 0xdb33, 0x0a },
++ { 0xdd33, 0x0a },
++ { 0xdb34, 0x1a },
++ { 0xdd34, 0x1a },
++ { 0xdb17, 0xef },
++ { 0xdd17, 0xef },
++ { 0xdba7, 0x00 },
++ { 0xdba8, 0x64 },
++ { 0xdda7, 0x00 },
++ { 0xdda8, 0x64 },
++ { 0xdb19, 0x40 },
++ { 0xdd19, 0x40 },
++ { 0xdb00, 0x4c },
++ { 0xdb01, 0x79 },
++ { 0xdd01, 0x79 },
++ { 0xdb04, 0x05 },
++ { 0xdb05, 0x03 },
++ { 0xdd04, 0x05 },
++ { 0xdd05, 0x03 },
++ { 0xdbbb, 0x09 },
++ { 0xdbbc, 0x30 },
++ { 0xdbbd, 0xf0 },
++ { 0xdbbe, 0xf1 },
++ { 0xddbb, 0x09 },
++ { 0xddbc, 0x30 },
++ { 0xddbd, 0xf0 },
++ { 0xddbe, 0xf1 },
++ { 0xdb01, 0x79 },
++ { 0xdd01, 0x79 },
++ { 0xdc52, 0xef },
++ { 0xde52, 0xef },
++ { 0x2f55, 0x22 },
++};
++
++static const struct reg_default rt1318_reg_defaults[] = {
++ { 0x3000, 0x00 },
++ { 0x3004, 0x01 },
++ { 0x3005, 0x23 },
++ { 0x3202, 0x00 },
++ { 0x3203, 0x01 },
++ { 0x3206, 0x00 },
++ { 0xc000, 0x00 },
++ { 0xc001, 0x43 },
++ { 0xc003, 0x22 },
++ { 0xc004, 0x44 },
++ { 0xc005, 0x44 },
++ { 0xc006, 0x33 },
++ { 0xc007, 0x64 },
++ { 0xc008, 0x05 },
++ { 0xc00a, 0xfc },
++ { 0xc00b, 0x0f },
++ { 0xc00c, 0x0e },
++ { 0xc00d, 0xef },
++ { 0xc00e, 0xe5 },
++ { 0xc00f, 0xff },
++ { 0xc120, 0xc0 },
++ { 0xc121, 0x00 },
++ { 0xc122, 0x00 },
++ { 0xc123, 0x14 },
++ { 0xc125, 0x00 },
++ { 0xc200, 0x00 },
++ { 0xc201, 0x00 },
++ { 0xc202, 0x00 },
++ { 0xc203, 0x04 },
++ { 0xc204, 0x00 },
++ { 0xc205, 0x00 },
++ { 0xc206, 0x68 },
++ { 0xc207, 0x70 },
++ { 0xc208, 0x00 },
++ { 0xc20a, 0x00 },
++ { 0xc20b, 0x01 },
++ { 0xc20c, 0x7f },
++ { 0xc20d, 0x01 },
++ { 0xc20e, 0x7f },
++ { 0xc300, 0x00 },
++ { 0xc301, 0x00 },
++ { 0xc303, 0x80 },
++ { 0xc320, 0x00 },
++ { 0xc321, 0x09 },
++ { 0xc322, 0x02 },
++ { 0xc410, 0x04 },
++ { 0xc430, 0x00 },
++ { 0xc431, 0x00 },
++ { 0xca00, 0x10 },
++ { 0xca01, 0x00 },
++ { 0xca02, 0x0b },
++ { 0xca10, 0x10 },
++ { 0xca11, 0x00 },
++ { 0xca12, 0x0b },
++ { 0xdd93, 0x00 },
++ { 0xdd94, 0x64 },
++ { 0xe300, 0xa0 },
++ { 0xed00, 0x80 },
++ { 0xed01, 0x0f },
++ { 0xed02, 0xff },
++ { 0xed03, 0x00 },
++ { 0xed04, 0x00 },
++ { 0xed05, 0x0f },
++ { 0xed06, 0xff },
++ { 0xf010, 0x10 },
++ { 0xf011, 0xec },
++ { 0xf012, 0x68 },
++ { 0xf013, 0x21 },
++ { 0xf800, 0x00 },
++ { 0xf801, 0x12 },
++ { 0xf802, 0xe0 },
++ { 0xf803, 0x2f },
++ { 0xf804, 0x00 },
++ { 0xf805, 0x00 },
++ { 0xf806, 0x07 },
++ { 0xf807, 0xff },
++ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
++ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
++ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
++ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
++ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
++};
++
++static bool rt1318_readable_register(struct device *dev, unsigned int reg)
++{
++ switch (reg) {
++ case 0x2f55:
++ case 0x3000:
++ case 0x3004 ... 0x3005:
++ case 0x3202 ... 0x3203:
++ case 0x3206:
++ case 0xc000 ... 0xc00f:
++ case 0xc120 ... 0xc125:
++ case 0xc200 ... 0xc20e:
++ case 0xc300 ... 0xc303:
++ case 0xc320 ... 0xc322:
++ case 0xc410:
++ case 0xc430 ... 0xc431:
++ case 0xca00 ... 0xca02:
++ case 0xca10 ... 0xca12:
++ case 0xcb00 ... 0xcb0b:
++ case 0xcc00 ... 0xcce5:
++ case 0xcd00 ... 0xcde5:
++ case 0xce00 ... 0xce6a:
++ case 0xcf00 ... 0xcf53:
++ case 0xd000 ... 0xd0cc:
++ case 0xd100 ... 0xd1b9:
++ case 0xdb00 ... 0xdc53:
++ case 0xdd00 ... 0xde53:
++ case 0xdf00 ... 0xdf6b:
++ case 0xe300:
++ case 0xeb00 ... 0xebcc:
++ case 0xec00 ... 0xecb9:
++ case 0xed00 ... 0xed06:
++ case 0xf010 ... 0xf014:
++ case 0xf800 ... 0xf807:
++ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L):
++ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R):
++ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
++ return true;
++ default:
++ return false;
++ }
++}
++
++static bool rt1318_volatile_register(struct device *dev, unsigned int reg)
++{
++ switch (reg) {
++ case 0x2f55:
++ case 0x3000 ... 0x3001:
++ case 0xc000:
++ case 0xc301:
++ case 0xc410:
++ case 0xc430 ... 0xc431:
++ case 0xdb06:
++ case 0xdb12:
++ case 0xdb1d ... 0xdb1f:
++ case 0xdb35:
++ case 0xdb37:
++ case 0xdb8a ... 0xdb92:
++ case 0xdbc5 ... 0xdbc8:
++ case 0xdc2b ... 0xdc49:
++ case 0xdd0b:
++ case 0xdd12:
++ case 0xdd1d ... 0xdd1f:
++ case 0xdd35:
++ case 0xdd8a ... 0xdd92:
++ case 0xddc5 ... 0xddc8:
++ case 0xde2b ... 0xde44:
++ case 0xdf4a ... 0xdf55:
++ case 0xe224 ... 0xe23b:
++ case 0xea01:
++ case 0xebc5:
++ case 0xebc8:
++ case 0xebcb ... 0xebcc:
++ case 0xed03 ... 0xed06:
++ case 0xf010 ... 0xf014:
++ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
++ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_SAPU, RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
++ return true;
++ default:
++ return false;
++ }
++}
++
++static const struct regmap_config rt1318_sdw_regmap = {
++ .reg_bits = 32,
++ .val_bits = 8,
++ .readable_reg = rt1318_readable_register,
++ .volatile_reg = rt1318_volatile_register,
++ .max_register = 0x41081488,
++ .reg_defaults = rt1318_reg_defaults,
++ .num_reg_defaults = ARRAY_SIZE(rt1318_reg_defaults),
++ .cache_type = REGCACHE_RBTREE,
++ .use_single_read = true,
++ .use_single_write = true,
++};
++
++static int rt1318_read_prop(struct sdw_slave *slave)
++{
++ struct sdw_slave_prop *prop = &slave->prop;
++ int nval;
++ int i, j;
++ u32 bit;
++ unsigned long addr;
++ struct sdw_dpn_prop *dpn;
++
++ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
++ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
++ prop->is_sdca = true;
++
++ prop->paging_support = true;
++
++ /* first we need to allocate memory for set bits in port lists */
++ prop->source_ports = BIT(2);
++ prop->sink_ports = BIT(1);
++
++ nval = hweight32(prop->source_ports);
++ prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
++ sizeof(*prop->src_dpn_prop), GFP_KERNEL);
++ if (!prop->src_dpn_prop)
++ return -ENOMEM;
++
++ i = 0;
++ dpn = prop->src_dpn_prop;
++ addr = prop->source_ports;
++ for_each_set_bit(bit, &addr, 32) {
++ dpn[i].num = bit;
++ dpn[i].type = SDW_DPN_FULL;
++ dpn[i].simple_ch_prep_sm = true;
++ dpn[i].ch_prep_timeout = 10;
++ i++;
++ }
++
++ /* do this again for sink now */
++ nval = hweight32(prop->sink_ports);
++ prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
++ sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
++ if (!prop->sink_dpn_prop)
++ return -ENOMEM;
++
++ j = 0;
++ dpn = prop->sink_dpn_prop;
++ addr = prop->sink_ports;
++ for_each_set_bit(bit, &addr, 32) {
++ dpn[j].num = bit;
++ dpn[j].type = SDW_DPN_FULL;
++ dpn[j].simple_ch_prep_sm = true;
++ dpn[j].ch_prep_timeout = 10;
++ j++;
++ }
++
++ /* set the timeout values */
++ prop->clk_stop_timeout = 20;
++
++ return 0;
++}
++
++static int rt1318_io_init(struct device *dev, struct sdw_slave *slave)
++{
++ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
++
++ if (rt1318->hw_init)
++ return 0;
++
++ if (rt1318->first_hw_init) {
++ regcache_cache_only(rt1318->regmap, false);
++ regcache_cache_bypass(rt1318->regmap, true);
++ } else {
++ /*
++ * PM runtime is only enabled when a Slave reports as Attached
++ */
++
++ /* set autosuspend parameters */
++ pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
++ pm_runtime_use_autosuspend(&slave->dev);
++
++ /* update count of parent 'active' children */
++ pm_runtime_set_active(&slave->dev);
++
++ /* make sure the device does not suspend immediately */
++ pm_runtime_mark_last_busy(&slave->dev);
++
++ pm_runtime_enable(&slave->dev);
++ }
++
++ pm_runtime_get_noresume(&slave->dev);
++
++ /* blind write */
++ regmap_multi_reg_write(rt1318->regmap, rt1318_blind_write,
++ ARRAY_SIZE(rt1318_blind_write));
++
++ if (rt1318->first_hw_init) {
++ regcache_cache_bypass(rt1318->regmap, false);
++ regcache_mark_dirty(rt1318->regmap);
++ }
++
++ /* Mark Slave initialization complete */
++ rt1318->first_hw_init = true;
++ rt1318->hw_init = true;
++
++ pm_runtime_mark_last_busy(&slave->dev);
++ pm_runtime_put_autosuspend(&slave->dev);
++
++ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
++ return 0;
++}
++
++static int rt1318_update_status(struct sdw_slave *slave,
++ enum sdw_slave_status status)
++{
++ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
++
++ /* Update the status */
++ rt1318->status = status;
++
++ if (status == SDW_SLAVE_UNATTACHED)
++ rt1318->hw_init = false;
++
++ /*
++ * Perform initialization only if slave status is present and
++ * hw_init flag is false
++ */
++ if (rt1318->hw_init || rt1318->status != SDW_SLAVE_ATTACHED)
++ return 0;
++
++ /* perform I/O transfers required for Slave initialization */
++ return rt1318_io_init(&slave->dev, slave);
++}
++
++static int rt1318_classd_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 rt1318_sdw_priv *rt1318 = snd_soc_component_get_drvdata(component);
++ unsigned char ps0 = 0x0, ps3 = 0x3;
++
++ switch (event) {
++ case SND_SOC_DAPM_POST_PMU:
++ regmap_write(rt1318->regmap,
++ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23,
++ RT1318_SDCA_CTL_REQ_POWER_STATE, 0),
++ ps0);
++ break;
++ case SND_SOC_DAPM_PRE_PMD:
++ regmap_write(rt1318->regmap,
++ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23,
++ RT1318_SDCA_CTL_REQ_POWER_STATE, 0),
++ ps3);
++ break;
++
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++static const char * const rt1318_rx_data_ch_select[] = {
++ "L,R",
++ "L,L",
++ "L,R",
++ "L,L+R",
++ "R,L",
++ "R,R",
++ "R,L+R",
++ "L+R,L",
++ "L+R,R",
++ "L+R,L+R",
++};
++
++static SOC_ENUM_SINGLE_DECL(rt1318_rx_data_ch_enum,
++ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0,
++ rt1318_rx_data_ch_select);
++
++static const struct snd_kcontrol_new rt1318_snd_controls[] = {
++
++ /* UDMPU Cluster Selection */
++ SOC_ENUM("RX Channel Select", rt1318_rx_data_ch_enum),
++};
++
++static const struct snd_kcontrol_new rt1318_sto_dac =
++ SOC_DAPM_DOUBLE_R("Switch",
++ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L),
++ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R),
++ 0, 1, 1);
++
++static const struct snd_soc_dapm_widget rt1318_dapm_widgets[] = {
++ /* Audio Interface */
++ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
++ SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0),
++
++ /* Digital Interface */
++ SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1318_sto_dac),
++
++ /* Output */
++ SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
++ rt1318_classd_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
++ SND_SOC_DAPM_OUTPUT("SPOL"),
++ SND_SOC_DAPM_OUTPUT("SPOR"),
++ /* Input */
++ SND_SOC_DAPM_PGA("FB Data", SND_SOC_NOPM, 0, 0, NULL, 0),
++ SND_SOC_DAPM_SIGGEN("FB Gen"),
++};
++
++static const struct snd_soc_dapm_route rt1318_dapm_routes[] = {
++ { "DAC", "Switch", "DP1RX" },
++ { "CLASS D", NULL, "DAC" },
++ { "SPOL", NULL, "CLASS D" },
++ { "SPOR", NULL, "CLASS D" },
++
++ { "FB Data", NULL, "FB Gen" },
++ { "DP2TX", NULL, "FB Data" },
++};
++
++static int rt1318_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
++ int direction)
++{
++ struct sdw_stream_data *stream;
++
++ if (!sdw_stream)
++ return 0;
++
++ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
++ if (!stream)
++ return -ENOMEM;
++
++ stream->sdw_stream = sdw_stream;
++
++ /* Use tx_mask or rx_mask to configure stream tag and set dma_data */
++ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
++ dai->playback_dma_data = stream;
++ else
++ dai->capture_dma_data = stream;
++
++ return 0;
++}
++
++static void rt1318_sdw_shutdown(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ struct sdw_stream_data *stream;
++
++ stream = snd_soc_dai_get_dma_data(dai, substream);
++ snd_soc_dai_set_dma_data(dai, substream, NULL);
++ kfree(stream);
++}
++
++static int rt1318_sdw_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
++{
++ struct snd_soc_component *component = dai->component;
++ struct rt1318_sdw_priv *rt1318 =
++ snd_soc_component_get_drvdata(component);
++ struct sdw_stream_config stream_config;
++ struct sdw_port_config port_config;
++ enum sdw_data_direction direction;
++ struct sdw_stream_data *stream;
++ int retval, port, num_channels, ch_mask;
++ unsigned int sampling_rate;
++
++ dev_dbg(dai->dev, "%s %s", __func__, dai->name);
++ stream = snd_soc_dai_get_dma_data(dai, substream);
++
++ if (!stream)
++ return -EINVAL;
++
++ if (!rt1318->sdw_slave)
++ return -EINVAL;
++
++ /* SoundWire specific configuration */
++ /* port 1 for playback */
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ direction = SDW_DATA_DIR_RX;
++ port = 1;
++ } else {
++ direction = SDW_DATA_DIR_TX;
++ port = 2;
++ }
++
++ num_channels = params_channels(params);
++ ch_mask = (1 << num_channels) - 1;
++
++ stream_config.frame_rate = params_rate(params);
++ stream_config.ch_count = num_channels;
++ stream_config.bps = snd_pcm_format_width(params_format(params));
++ stream_config.direction = direction;
++
++ port_config.ch_mask = ch_mask;
++ port_config.num = port;
++
++ retval = sdw_stream_add_slave(rt1318->sdw_slave, &stream_config,
++ &port_config, 1, stream->sdw_stream);
++ if (retval) {
++ dev_err(dai->dev, "Unable to configure port\n");
++ return retval;
++ }
++
++ /* sampling rate configuration */
++ switch (params_rate(params)) {
++ case 16000:
++ sampling_rate = RT1318_SDCA_RATE_16000HZ;
++ break;
++ case 32000:
++ sampling_rate = RT1318_SDCA_RATE_32000HZ;
++ break;
++ case 44100:
++ sampling_rate = RT1318_SDCA_RATE_44100HZ;
++ break;
++ case 48000:
++ sampling_rate = RT1318_SDCA_RATE_48000HZ;
++ break;
++ case 96000:
++ sampling_rate = RT1318_SDCA_RATE_96000HZ;
++ break;
++ case 192000:
++ sampling_rate = RT1318_SDCA_RATE_192000HZ;
++ break;
++ default:
++ dev_err(component->dev, "Rate %d is not supported\n",
++ params_rate(params));
++ return -EINVAL;
++ }
++
++ /* set sampling frequency */
++ regmap_write(rt1318->regmap,
++ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
++ sampling_rate);
++
++ return 0;
++}
++
++static int rt1318_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ struct snd_soc_component *component = dai->component;
++ struct rt1318_sdw_priv *rt1318 =
++ snd_soc_component_get_drvdata(component);
++ struct sdw_stream_data *stream =
++ snd_soc_dai_get_dma_data(dai, substream);
++
++ if (!rt1318->sdw_slave)
++ return -EINVAL;
++
++ sdw_stream_remove_slave(rt1318->sdw_slave, stream->sdw_stream);
++ return 0;
++}
++
++/*
++ * slave_ops: callbacks for get_clock_stop_mode, clock_stop and
++ * port_prep are not defined for now
++ */
++static struct sdw_slave_ops rt1318_slave_ops = {
++ .read_prop = rt1318_read_prop,
++ .update_status = rt1318_update_status,
++};
++
++static int rt1318_sdw_component_probe(struct snd_soc_component *component)
++{
++ int ret;
++ struct rt1318_sdw_priv *rt1318 = snd_soc_component_get_drvdata(component);
++
++ rt1318->component = component;
++
++ ret = pm_runtime_resume(component->dev);
++ dev_dbg(&rt1318->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret);
++ if (ret < 0 && ret != -EACCES)
++ return ret;
++
++ return 0;
++}
++
++static const struct snd_soc_component_driver soc_component_sdw_rt1318 = {
++ .probe = rt1318_sdw_component_probe,
++ .controls = rt1318_snd_controls,
++ .num_controls = ARRAY_SIZE(rt1318_snd_controls),
++ .dapm_widgets = rt1318_dapm_widgets,
++ .num_dapm_widgets = ARRAY_SIZE(rt1318_dapm_widgets),
++ .dapm_routes = rt1318_dapm_routes,
++ .num_dapm_routes = ARRAY_SIZE(rt1318_dapm_routes),
++ .endianness = 1,
++};
++
++static const struct snd_soc_dai_ops rt1318_aif_dai_ops = {
++ .hw_params = rt1318_sdw_hw_params,
++ .hw_free = rt1318_sdw_pcm_hw_free,
++ .set_stream = rt1318_set_sdw_stream,
++ .shutdown = rt1318_sdw_shutdown,
++};
++
++#define RT1318_STEREO_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
++ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
++#define RT1318_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
++ SNDRV_PCM_FMTBIT_S32_LE)
++
++static struct snd_soc_dai_driver rt1318_sdw_dai[] = {
++ {
++ .name = "rt1318-aif",
++ .playback = {
++ .stream_name = "DP1 Playback",
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = RT1318_STEREO_RATES,
++ .formats = RT1318_FORMATS,
++ },
++ .capture = {
++ .stream_name = "DP2 Capture",
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = RT1318_STEREO_RATES,
++ .formats = RT1318_FORMATS,
++ },
++ .ops = &rt1318_aif_dai_ops,
++ },
++};
++
++static int rt1318_sdw_init(struct device *dev, struct regmap *regmap,
++ struct sdw_slave *slave)
++{
++ struct rt1318_sdw_priv *rt1318;
++ int ret;
++
++ rt1318 = devm_kzalloc(dev, sizeof(*rt1318), GFP_KERNEL);
++ if (!rt1318)
++ return -ENOMEM;
++
++ dev_set_drvdata(dev, rt1318);
++ rt1318->sdw_slave = slave;
++ rt1318->regmap = regmap;
++
++ /*
++ * Mark hw_init to false
++ * HW init will be performed when device reports present
++ */
++ rt1318->hw_init = false;
++ rt1318->first_hw_init = false;
++
++ ret = devm_snd_soc_register_component(dev,
++ &soc_component_sdw_rt1318,
++ rt1318_sdw_dai,
++ ARRAY_SIZE(rt1318_sdw_dai));
++
++ dev_dbg(&slave->dev, "%s\n", __func__);
++
++ return ret;
++}
++
++static int rt1318_sdw_probe(struct sdw_slave *slave,
++ const struct sdw_device_id *id)
++{
++ struct regmap *regmap;
++
++ /* Regmap Initialization */
++ regmap = devm_regmap_init_sdw(slave, &rt1318_sdw_regmap);
++ if (IS_ERR(regmap))
++ return PTR_ERR(regmap);
++
++ return rt1318_sdw_init(&slave->dev, regmap, slave);
++}
++
++static int rt1318_sdw_remove(struct sdw_slave *slave)
++{
++ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
++
++ if (rt1318->first_hw_init)
++ pm_runtime_disable(&slave->dev);
++
++ return 0;
++}
++
++static const struct sdw_device_id rt1318_id[] = {
++ SDW_SLAVE_ENTRY_EXT(0x025d, 0x1318, 0x3, 0x1, 0),
++ {},
++};
++MODULE_DEVICE_TABLE(sdw, rt1318_id);
++
++static int __maybe_unused rt1318_dev_suspend(struct device *dev)
++{
++ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
++
++ if (!rt1318->hw_init)
++ return 0;
++
++ regcache_cache_only(rt1318->regmap, true);
++ return 0;
++}
++
++#define RT1318_PROBE_TIMEOUT 5000
++
++static int __maybe_unused rt1318_dev_resume(struct device *dev)
++{
++ struct sdw_slave *slave = dev_to_sdw_dev(dev);
++ struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
++ unsigned long time;
++
++ if (!rt1318->first_hw_init)
++ return 0;
++
++ if (!slave->unattach_request)
++ goto regmap_sync;
++
++ time = wait_for_completion_timeout(&slave->initialization_complete,
++ msecs_to_jiffies(RT1318_PROBE_TIMEOUT));
++ if (!time) {
++ dev_err(&slave->dev, "Initialization not complete, timed out\n");
++ return -ETIMEDOUT;
++ }
++
++regmap_sync:
++ slave->unattach_request = 0;
++ regcache_cache_only(rt1318->regmap, false);
++ regcache_sync(rt1318->regmap);
++
++ return 0;
++}
++
++static const struct dev_pm_ops rt1318_pm = {
++ SET_SYSTEM_SLEEP_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume)
++ SET_RUNTIME_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume, NULL)
++};
++
++static struct sdw_driver rt1318_sdw_driver = {
++ .driver = {
++ .name = "rt1318-sdca",
++ .owner = THIS_MODULE,
++ .pm = &rt1318_pm,
++ },
++ .probe = rt1318_sdw_probe,
++ .remove = rt1318_sdw_remove,
++ .ops = &rt1318_slave_ops,
++ .id_table = rt1318_id,
++};
++module_sdw_driver(rt1318_sdw_driver);
++
++MODULE_DESCRIPTION("ASoC RT1318 driver SDCA SDW");
++MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
++MODULE_LICENSE("GPL");
+diff --git a/sound/soc/codecs/rt1318-sdw.h b/sound/soc/codecs/rt1318-sdw.h
+new file mode 100644
+index 0000000000000..4d7ac9c4bd8de
+--- /dev/null
++++ b/sound/soc/codecs/rt1318-sdw.h
+@@ -0,0 +1,101 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * rt1318-sdw.h -- RT1318 SDCA ALSA SoC audio driver header
++ *
++ * Copyright(c) 2022 Realtek Semiconductor Corp.
++ */
++
++#ifndef __RT1318_SDW_H__
++#define __RT1318_SDW_H__
++
++#include <linux/regmap.h>
++#include <linux/soundwire/sdw.h>
++#include <linux/soundwire/sdw_type.h>
++#include <linux/soundwire/sdw_registers.h>
++#include <sound/soc.h>
++
++/* imp-defined registers */
++#define RT1318_SAPU_SM 0x3203
++
++#define R1318_TCON 0xc203
++#define R1318_TCON_RELATED_1 0xc206
++
++#define R1318_SPK_TEMPERATRUE_PROTECTION_0 0xdb00
++#define R1318_SPK_TEMPERATRUE_PROTECTION_L_4 0xdb08
++#define R1318_SPK_TEMPERATRUE_PROTECTION_R_4 0xdd08
++
++#define R1318_SPK_TEMPERATRUE_PROTECTION_L_6 0xdb12
++#define R1318_SPK_TEMPERATRUE_PROTECTION_R_6 0xdd12
++
++#define RT1318_INIT_RECIPROCAL_REG_L_24 0xdbb5
++#define RT1318_INIT_RECIPROCAL_REG_L_23_16 0xdbb6
++#define RT1318_INIT_RECIPROCAL_REG_L_15_8 0xdbb7
++#define RT1318_INIT_RECIPROCAL_REG_L_7_0 0xdbb8
++#define RT1318_INIT_RECIPROCAL_REG_R_24 0xddb5
++#define RT1318_INIT_RECIPROCAL_REG_R_23_16 0xddb6
++#define RT1318_INIT_RECIPROCAL_REG_R_15_8 0xddb7
++#define RT1318_INIT_RECIPROCAL_REG_R_7_0 0xddb8
++
++#define RT1318_INIT_R0_RECIPROCAL_SYN_L_24 0xdbc5
++#define RT1318_INIT_R0_RECIPROCAL_SYN_L_23_16 0xdbc6
++#define RT1318_INIT_R0_RECIPROCAL_SYN_L_15_8 0xdbc7
++#define RT1318_INIT_R0_RECIPROCAL_SYN_L_7_0 0xdbc8
++#define RT1318_INIT_R0_RECIPROCAL_SYN_R_24 0xddc5
++#define RT1318_INIT_R0_RECIPROCAL_SYN_R_23_16 0xddc6
++#define RT1318_INIT_R0_RECIPROCAL_SYN_R_15_8 0xddc7
++#define RT1318_INIT_R0_RECIPROCAL_SYN_R_7_0 0xddc8
++
++#define RT1318_R0_COMPARE_FLAG_L 0xdb35
++#define RT1318_R0_COMPARE_FLAG_R 0xdd35
++
++#define RT1318_STP_INITIAL_RS_TEMP_H 0xdd93
++#define RT1318_STP_INITIAL_RS_TEMP_L 0xdd94
++
++/* RT1318 SDCA Control - function number */
++#define FUNC_NUM_SMART_AMP 0x04
++
++/* RT1318 SDCA entity */
++#define RT1318_SDCA_ENT_PDE23 0x31
++#define RT1318_SDCA_ENT_XU24 0x24
++#define RT1318_SDCA_ENT_FU21 0x03
++#define RT1318_SDCA_ENT_UDMPU21 0x02
++#define RT1318_SDCA_ENT_CS21 0x21
++#define RT1318_SDCA_ENT_SAPU 0x29
++
++/* RT1318 SDCA control */
++#define RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
++#define RT1318_SDCA_CTL_REQ_POWER_STATE 0x01
++#define RT1318_SDCA_CTL_FU_MUTE 0x01
++#define RT1318_SDCA_CTL_FU_VOLUME 0x02
++#define RT1318_SDCA_CTL_UDMPU_CLUSTER 0x10
++#define RT1318_SDCA_CTL_SAPU_PROTECTION_MODE 0x10
++#define RT1318_SDCA_CTL_SAPU_PROTECTION_STATUS 0x11
++
++/* RT1318 SDCA channel */
++#define CH_L 0x01
++#define CH_R 0x02
++
++/* sample frequency index */
++#define RT1318_SDCA_RATE_16000HZ 0x04
++#define RT1318_SDCA_RATE_32000HZ 0x07
++#define RT1318_SDCA_RATE_44100HZ 0x08
++#define RT1318_SDCA_RATE_48000HZ 0x09
++#define RT1318_SDCA_RATE_96000HZ 0x0b
++#define RT1318_SDCA_RATE_192000HZ 0x0d
++
++
++struct rt1318_sdw_priv {
++ struct snd_soc_component *component;
++ struct regmap *regmap;
++ struct sdw_slave *sdw_slave;
++ enum sdw_slave_status status;
++ struct sdw_bus_params params;
++ bool hw_init;
++ bool first_hw_init;
++};
++
++struct sdw_stream_data {
++ struct sdw_stream_runtime *sdw_stream;
++};
++
++#endif /* __RT1318_SDW_H__ */
+--
+2.42.0
+
--- /dev/null
+From 3eb856ca929d5861d87aaf04ee7384adea72a3d5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 Oct 2021 12:50:12 +0800
+Subject: ASoC: rt9120: Add rt9210 audio amplifier support
+
+From: ChiYuan Huang <cy_huang@richtek.com>
+
+[ Upstream commit f218b5e2662c261c6acce5036ad4067669e51eac ]
+
+Add Richtek rt9120 audio amplifier support.
+
+Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
+[Fix a Gain->Volume -- broonie]
+Message-Id: <1633668612-25524-3-git-send-email-u0084500@gmail.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: da29b94ed354 ("ASoC: codecs: wcd938x: fix resource leaks on bind errors")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/Kconfig | 10 +
+ sound/soc/codecs/Makefile | 2 +
+ sound/soc/codecs/rt9120.c | 489 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 501 insertions(+)
+ create mode 100644 sound/soc/codecs/rt9120.c
+
+diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
+index 1750cc888bbe8..b193db25c37fe 100644
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -187,6 +187,7 @@ config SND_SOC_ALL_CODECS
+ imply SND_SOC_RT715_SDCA_SDW
+ imply SND_SOC_RT1308_SDW
+ imply SND_SOC_RT1316_SDW
++ imply SND_SOC_RT9120
+ imply SND_SOC_SDW_MOCKUP
+ imply SND_SOC_SGTL5000
+ imply SND_SOC_SI476X
+@@ -1290,6 +1291,15 @@ config SND_SOC_RT715_SDCA_SDW
+ select REGMAP_SOUNDWIRE
+ select REGMAP_SOUNDWIRE_MBQ
+
++config SND_SOC_RT9120
++ tristate "Richtek RT9120 Stereo Class-D Amplifier"
++ depends on I2C
++ select REGMAP_I2C
++ select GPIOLIB
++ help
++ Enable support for Richtek RT9120 20W, stereo, inductor-less,
++ high-efficiency Class-D audio amplifier.
++
+ config SND_SOC_SDW_MOCKUP
+ tristate "SoundWire mockup codec"
+ depends on EXPERT
+diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
+index 8dcea2c4604aa..5ba164d41b300 100644
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -203,6 +203,7 @@ snd-soc-rt711-objs := rt711.o rt711-sdw.o
+ snd-soc-rt711-sdca-objs := rt711-sdca.o rt711-sdca-sdw.o
+ snd-soc-rt715-objs := rt715.o rt715-sdw.o
+ snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o
++snd-soc-rt9120-objs := rt9120.o
+ snd-soc-sdw-mockup-objs := sdw-mockup.o
+ snd-soc-sgtl5000-objs := sgtl5000.o
+ snd-soc-alc5623-objs := alc5623.o
+@@ -531,6 +532,7 @@ obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o
+ obj-$(CONFIG_SND_SOC_RT711_SDCA_SDW) += snd-soc-rt711-sdca.o
+ obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o
+ obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o
++obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o
+ obj-$(CONFIG_SND_SOC_SDW_MOCKUP) += snd-soc-sdw-mockup.o
+ obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
+ obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
+diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c
+new file mode 100644
+index 0000000000000..2c95178f4ff84
+--- /dev/null
++++ b/sound/soc/codecs/rt9120.c
+@@ -0,0 +1,489 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <linux/bits.h>
++#include <linux/delay.h>
++#include <linux/gpio/consumer.h>
++#include <linux/i2c.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/regmap.h>
++#include <linux/regulator/consumer.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/tlv.h>
++
++#define RT9120_REG_DEVID 0x00
++#define RT9120_REG_I2SFMT 0x02
++#define RT9120_REG_I2SWL 0x03
++#define RT9120_REG_SDIOSEL 0x04
++#define RT9120_REG_SYSCTL 0x05
++#define RT9120_REG_SPKGAIN 0x07
++#define RT9120_REG_VOLRAMP 0x0A
++#define RT9120_REG_ERRRPT 0x10
++#define RT9120_REG_MSVOL 0x20
++#define RT9120_REG_SWRESET 0x40
++#define RT9120_REG_INTERNAL0 0x65
++#define RT9120_REG_INTERNAL1 0x69
++#define RT9120_REG_UVPOPT 0x6C
++
++#define RT9120_VID_MASK GENMASK(15, 8)
++#define RT9120_SWRST_MASK BIT(7)
++#define RT9120_MUTE_MASK GENMASK(5, 4)
++#define RT9120_I2SFMT_MASK GENMASK(4, 2)
++#define RT9120_I2SFMT_SHIFT 2
++#define RT9120_CFG_FMT_I2S 0
++#define RT9120_CFG_FMT_LEFTJ 1
++#define RT9120_CFG_FMT_RIGHTJ 2
++#define RT9120_CFG_FMT_DSPA 3
++#define RT9120_CFG_FMT_DSPB 7
++#define RT9120_AUDBIT_MASK GENMASK(1, 0)
++#define RT9120_CFG_AUDBIT_16 0
++#define RT9120_CFG_AUDBIT_20 1
++#define RT9120_CFG_AUDBIT_24 2
++#define RT9120_AUDWL_MASK GENMASK(5, 0)
++#define RT9120_CFG_WORDLEN_16 16
++#define RT9120_CFG_WORDLEN_24 24
++#define RT9120_CFG_WORDLEN_32 32
++#define RT9120_DVDD_UVSEL_MASK GENMASK(5, 4)
++
++#define RT9120_VENDOR_ID 0x4200
++#define RT9120_RESET_WAITMS 20
++#define RT9120_CHIPON_WAITMS 20
++#define RT9120_AMPON_WAITMS 50
++#define RT9120_AMPOFF_WAITMS 100
++#define RT9120_LVAPP_THRESUV 2000000
++
++/* 8000 to 192000 supported , only 176400 not support */
++#define RT9120_RATES_MASK (SNDRV_PCM_RATE_8000_192000 &\
++ ~SNDRV_PCM_RATE_176400)
++#define RT9120_FMTS_MASK (SNDRV_PCM_FMTBIT_S16_LE |\
++ SNDRV_PCM_FMTBIT_S24_LE |\
++ SNDRV_PCM_FMTBIT_S32_LE)
++
++struct rt9120_data {
++ struct device *dev;
++ struct regmap *regmap;
++};
++
++/* 11bit [min,max,step] = [-103.9375dB, 24dB, 0.0625dB] */
++static const DECLARE_TLV_DB_SCALE(digital_gain, -1039375, 625, -1039375);
++
++static const char * const sdo_select_text[] = {
++ "None", "INTF", "Final", "RMS Detect"
++};
++
++static const struct soc_enum sdo_select_enum =
++ SOC_ENUM_SINGLE(RT9120_REG_SDIOSEL, 4, ARRAY_SIZE(sdo_select_text),
++ sdo_select_text);
++
++static const struct snd_kcontrol_new rt9120_snd_controls[] = {
++ SOC_SINGLE_TLV("MS Volume", RT9120_REG_MSVOL, 0, 2047, 1, digital_gain),
++ SOC_SINGLE("SPK Volume", RT9120_REG_SPKGAIN, 0, 7, 0),
++ SOC_SINGLE("PBTL Switch", RT9120_REG_SYSCTL, 3, 1, 0),
++ SOC_ENUM("SDO Select", sdo_select_enum),
++};
++
++static int internal_power_event(struct snd_soc_dapm_widget *w,
++ struct snd_kcontrol *kcontrol, int event)
++{
++ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
++
++ switch (event) {
++ case SND_SOC_DAPM_PRE_PMU:
++ snd_soc_component_write(comp, RT9120_REG_ERRRPT, 0);
++ break;
++ case SND_SOC_DAPM_POST_PMU:
++ msleep(RT9120_AMPON_WAITMS);
++ break;
++ case SND_SOC_DAPM_POST_PMD:
++ msleep(RT9120_AMPOFF_WAITMS);
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++static const struct snd_soc_dapm_widget rt9120_dapm_widgets[] = {
++ SND_SOC_DAPM_MIXER("DMIX", SND_SOC_NOPM, 0, 0, NULL, 0),
++ SND_SOC_DAPM_DAC("LDAC", NULL, SND_SOC_NOPM, 0, 0),
++ SND_SOC_DAPM_DAC("RDAC", NULL, SND_SOC_NOPM, 0, 0),
++ SND_SOC_DAPM_SUPPLY("PWND", RT9120_REG_SYSCTL, 6, 1,
++ internal_power_event, SND_SOC_DAPM_PRE_PMU |
++ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
++ SND_SOC_DAPM_PGA("SPKL PA", SND_SOC_NOPM, 0, 0, NULL, 0),
++ SND_SOC_DAPM_PGA("SPKR PA", SND_SOC_NOPM, 0, 0, NULL, 0),
++ SND_SOC_DAPM_OUTPUT("SPKL"),
++ SND_SOC_DAPM_OUTPUT("SPKR"),
++};
++
++static const struct snd_soc_dapm_route rt9120_dapm_routes[] = {
++ { "DMIX", NULL, "AIF Playback" },
++ /* SPKL */
++ { "LDAC", NULL, "PWND" },
++ { "LDAC", NULL, "DMIX" },
++ { "SPKL PA", NULL, "LDAC" },
++ { "SPKL", NULL, "SPKL PA" },
++ /* SPKR */
++ { "RDAC", NULL, "PWND" },
++ { "RDAC", NULL, "DMIX" },
++ { "SPKR PA", NULL, "RDAC" },
++ { "SPKR", NULL, "SPKR PA" },
++ /* Cap */
++ { "AIF Capture", NULL, "LDAC" },
++ { "AIF Capture", NULL, "RDAC" },
++};
++
++static int rt9120_codec_probe(struct snd_soc_component *comp)
++{
++ struct rt9120_data *data = snd_soc_component_get_drvdata(comp);
++
++ snd_soc_component_init_regmap(comp, data->regmap);
++
++ /* Internal setting */
++ snd_soc_component_write(comp, RT9120_REG_INTERNAL1, 0x03);
++ snd_soc_component_write(comp, RT9120_REG_INTERNAL0, 0x69);
++ return 0;
++}
++
++static const struct snd_soc_component_driver rt9120_component_driver = {
++ .probe = rt9120_codec_probe,
++ .controls = rt9120_snd_controls,
++ .num_controls = ARRAY_SIZE(rt9120_snd_controls),
++ .dapm_widgets = rt9120_dapm_widgets,
++ .num_dapm_widgets = ARRAY_SIZE(rt9120_dapm_widgets),
++ .dapm_routes = rt9120_dapm_routes,
++ .num_dapm_routes = ARRAY_SIZE(rt9120_dapm_routes),
++};
++
++static int rt9120_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
++{
++ struct snd_soc_component *comp = dai->component;
++ unsigned int format;
++
++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
++ case SND_SOC_DAIFMT_I2S:
++ format = RT9120_CFG_FMT_I2S;
++ break;
++ case SND_SOC_DAIFMT_LEFT_J:
++ format = RT9120_CFG_FMT_LEFTJ;
++ break;
++ case SND_SOC_DAIFMT_RIGHT_J:
++ format = RT9120_CFG_FMT_RIGHTJ;
++ break;
++ case SND_SOC_DAIFMT_DSP_A:
++ format = RT9120_CFG_FMT_DSPA;
++ break;
++ case SND_SOC_DAIFMT_DSP_B:
++ format = RT9120_CFG_FMT_DSPB;
++ break;
++ default:
++ dev_err(dai->dev, "Unknown dai format\n");
++ return -EINVAL;
++ }
++
++ snd_soc_component_update_bits(comp, RT9120_REG_I2SFMT,
++ RT9120_I2SFMT_MASK,
++ format << RT9120_I2SFMT_SHIFT);
++ return 0;
++}
++
++static int rt9120_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *param,
++ struct snd_soc_dai *dai)
++{
++ struct snd_soc_component *comp = dai->component;
++ unsigned int param_width, param_slot_width;
++ int width;
++
++ switch (width = params_width(param)) {
++ case 16:
++ param_width = RT9120_CFG_AUDBIT_16;
++ break;
++ case 20:
++ param_width = RT9120_CFG_AUDBIT_20;
++ break;
++ case 24:
++ case 32:
++ param_width = RT9120_CFG_AUDBIT_24;
++ break;
++ default:
++ dev_err(dai->dev, "Unsupported data width [%d]\n", width);
++ return -EINVAL;
++ }
++
++ snd_soc_component_update_bits(comp, RT9120_REG_I2SFMT,
++ RT9120_AUDBIT_MASK, param_width);
++
++ switch (width = params_physical_width(param)) {
++ case 16:
++ param_slot_width = RT9120_CFG_WORDLEN_16;
++ break;
++ case 24:
++ param_slot_width = RT9120_CFG_WORDLEN_24;
++ break;
++ case 32:
++ param_slot_width = RT9120_CFG_WORDLEN_32;
++ break;
++ default:
++ dev_err(dai->dev, "Unsupported slot width [%d]\n", width);
++ return -EINVAL;
++ }
++
++ snd_soc_component_update_bits(comp, RT9120_REG_I2SWL,
++ RT9120_AUDWL_MASK, param_slot_width);
++ return 0;
++}
++
++static const struct snd_soc_dai_ops rt9120_dai_ops = {
++ .set_fmt = rt9120_set_fmt,
++ .hw_params = rt9120_hw_params,
++};
++
++static struct snd_soc_dai_driver rt9120_dai = {
++ .name = "rt9120_aif",
++ .playback = {
++ .stream_name = "AIF Playback",
++ .rates = RT9120_RATES_MASK,
++ .formats = RT9120_FMTS_MASK,
++ .rate_max = 192000,
++ .rate_min = 8000,
++ .channels_min = 1,
++ .channels_max = 2,
++ },
++ .capture = {
++ .stream_name = "AIF Capture",
++ .rates = RT9120_RATES_MASK,
++ .formats = RT9120_FMTS_MASK,
++ .rate_max = 192000,
++ .rate_min = 8000,
++ .channels_min = 1,
++ .channels_max = 2,
++ },
++ .ops = &rt9120_dai_ops,
++ .symmetric_rate = 1,
++ .symmetric_sample_bits = 1,
++};
++
++static const struct regmap_range rt9120_rd_yes_ranges[] = {
++ regmap_reg_range(0x00, 0x0C),
++ regmap_reg_range(0x10, 0x15),
++ regmap_reg_range(0x20, 0x27),
++ regmap_reg_range(0x30, 0x38),
++ regmap_reg_range(0x3A, 0x40),
++ regmap_reg_range(0x65, 0x65),
++ regmap_reg_range(0x69, 0x69),
++ regmap_reg_range(0x6C, 0x6C)
++};
++
++static const struct regmap_access_table rt9120_rd_table = {
++ .yes_ranges = rt9120_rd_yes_ranges,
++ .n_yes_ranges = ARRAY_SIZE(rt9120_rd_yes_ranges),
++};
++
++static const struct regmap_range rt9120_wr_yes_ranges[] = {
++ regmap_reg_range(0x00, 0x00),
++ regmap_reg_range(0x02, 0x0A),
++ regmap_reg_range(0x10, 0x15),
++ regmap_reg_range(0x20, 0x27),
++ regmap_reg_range(0x30, 0x38),
++ regmap_reg_range(0x3A, 0x3D),
++ regmap_reg_range(0x40, 0x40),
++ regmap_reg_range(0x65, 0x65),
++ regmap_reg_range(0x69, 0x69),
++ regmap_reg_range(0x6C, 0x6C)
++};
++
++static const struct regmap_access_table rt9120_wr_table = {
++ .yes_ranges = rt9120_wr_yes_ranges,
++ .n_yes_ranges = ARRAY_SIZE(rt9120_wr_yes_ranges),
++};
++
++static int rt9120_get_reg_size(unsigned int reg)
++{
++ switch (reg) {
++ case 0x00:
++ case 0x09:
++ case 0x20 ... 0x27:
++ return 2;
++ case 0x30 ... 0x3D:
++ return 3;
++ case 0x3E ... 0x3F:
++ return 4;
++ default:
++ return 1;
++ }
++}
++
++static int rt9120_reg_read(void *context, unsigned int reg, unsigned int *val)
++{
++ struct rt9120_data *data = context;
++ struct i2c_client *i2c = to_i2c_client(data->dev);
++ int size = rt9120_get_reg_size(reg);
++ u8 raw[4] = {0};
++ int ret;
++
++ ret = i2c_smbus_read_i2c_block_data(i2c, reg, size, raw);
++ if (ret < 0)
++ return ret;
++ else if (ret != size)
++ return -EIO;
++
++ switch (size) {
++ case 4:
++ *val = be32_to_cpup((__be32 *)raw);
++ break;
++ case 3:
++ *val = raw[0] << 16 | raw[1] << 8 | raw[0];
++ break;
++ case 2:
++ *val = be16_to_cpup((__be16 *)raw);
++ break;
++ default:
++ *val = raw[0];
++ }
++
++ return 0;
++}
++
++static int rt9120_reg_write(void *context, unsigned int reg, unsigned int val)
++{
++ struct rt9120_data *data = context;
++ struct i2c_client *i2c = to_i2c_client(data->dev);
++ int size = rt9120_get_reg_size(reg);
++ __be32 be32_val;
++ u8 *rawp = (u8 *)&be32_val;
++ int offs = 4 - size;
++
++ be32_val = cpu_to_be32(val);
++ return i2c_smbus_write_i2c_block_data(i2c, reg, size, rawp + offs);
++}
++
++static const struct regmap_config rt9120_regmap_config = {
++ .reg_bits = 8,
++ .val_bits = 32,
++ .max_register = RT9120_REG_UVPOPT,
++
++ .reg_read = rt9120_reg_read,
++ .reg_write = rt9120_reg_write,
++
++ .wr_table = &rt9120_wr_table,
++ .rd_table = &rt9120_rd_table,
++};
++
++static int rt9120_check_vendor_info(struct rt9120_data *data)
++{
++ unsigned int devid;
++ int ret;
++
++ ret = regmap_read(data->regmap, RT9120_REG_DEVID, &devid);
++ if (ret)
++ return ret;
++
++ if ((devid & RT9120_VID_MASK) != RT9120_VENDOR_ID) {
++ dev_err(data->dev, "DEVID not correct [0x%04x]\n", devid);
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static int rt9120_do_register_reset(struct rt9120_data *data)
++{
++ int ret;
++
++ ret = regmap_write(data->regmap, RT9120_REG_SWRESET,
++ RT9120_SWRST_MASK);
++ if (ret)
++ return ret;
++
++ msleep(RT9120_RESET_WAITMS);
++ return 0;
++}
++
++static int rt9120_probe(struct i2c_client *i2c)
++{
++ struct rt9120_data *data;
++ struct gpio_desc *pwdnn_gpio;
++ struct regulator *dvdd_supply;
++ int dvdd_supply_volt, ret;
++
++ data = devm_kzalloc(&i2c->dev, sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ data->dev = &i2c->dev;
++ i2c_set_clientdata(i2c, data);
++
++ pwdnn_gpio = devm_gpiod_get_optional(&i2c->dev, "pwdnn",
++ GPIOD_OUT_HIGH);
++ if (IS_ERR(pwdnn_gpio)) {
++ dev_err(&i2c->dev, "Failed to initialize 'pwdnn' gpio\n");
++ return PTR_ERR(pwdnn_gpio);
++ } else if (pwdnn_gpio) {
++ dev_dbg(&i2c->dev, "'pwdnn' from low to high, wait chip on\n");
++ msleep(RT9120_CHIPON_WAITMS);
++ }
++
++ data->regmap = devm_regmap_init(&i2c->dev, NULL, data,
++ &rt9120_regmap_config);
++ if (IS_ERR(data->regmap)) {
++ ret = PTR_ERR(data->regmap);
++ dev_err(&i2c->dev, "Failed to init regmap [%d]\n", ret);
++ return ret;
++ }
++
++ ret = rt9120_check_vendor_info(data);
++ if (ret) {
++ dev_err(&i2c->dev, "Failed to check vendor info\n");
++ return ret;
++ }
++
++ ret = rt9120_do_register_reset(data);
++ if (ret) {
++ dev_err(&i2c->dev, "Failed to do register reset\n");
++ return ret;
++ }
++
++ dvdd_supply = devm_regulator_get(&i2c->dev, "dvdd");
++ if (IS_ERR(dvdd_supply)) {
++ dev_err(&i2c->dev, "No dvdd regulator found\n");
++ return PTR_ERR(dvdd_supply);
++ }
++
++ dvdd_supply_volt = regulator_get_voltage(dvdd_supply);
++ if (dvdd_supply_volt <= RT9120_LVAPP_THRESUV) {
++ dev_dbg(&i2c->dev, "dvdd low voltage design\n");
++ ret = regmap_update_bits(data->regmap, RT9120_REG_UVPOPT,
++ RT9120_DVDD_UVSEL_MASK, 0);
++ if (ret) {
++ dev_err(&i2c->dev, "Failed to config dvdd uvsel\n");
++ return ret;
++ }
++ }
++
++ return devm_snd_soc_register_component(&i2c->dev,
++ &rt9120_component_driver,
++ &rt9120_dai, 1);
++}
++
++static const struct of_device_id __maybe_unused rt9120_device_table[] = {
++ { .compatible = "richtek,rt9120", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, rt9120_device_table);
++
++static struct i2c_driver rt9120_driver = {
++ .driver = {
++ .name = "rt9120",
++ .of_match_table = rt9120_device_table,
++ },
++ .probe_new = rt9120_probe,
++};
++module_i2c_driver(rt9120_driver);
++
++MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
++MODULE_DESCRIPTION("RT9120 Audio Amplifier Driver");
++MODULE_LICENSE("GPL");
+--
+2.42.0
+
--- /dev/null
+From 5a2ce3cfd03d96505f4dbf177a9758e6fea97a3a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Apr 2023 10:33:29 +0200
+Subject: mcb-lpc: Reallocate memory region to avoid memory overlapping
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: RodrÃguez Barbarin, José Javier <JoseJavier.Rodriguez@duagon.com>
+
+[ Upstream commit 2025b2ca8004c04861903d076c67a73a0ec6dfca ]
+
+mcb-lpc requests a fixed-size memory region to parse the chameleon
+table, however, if the chameleon table is smaller that the allocated
+region, it could overlap with the IP Cores' memory regions.
+
+After parsing the chameleon table, drop/reallocate the memory region
+with the actual chameleon table size.
+
+Co-developed-by: Jorge Sanjuan Garcia <jorge.sanjuangarcia@duagon.com>
+Signed-off-by: Jorge Sanjuan Garcia <jorge.sanjuangarcia@duagon.com>
+Signed-off-by: Javier Rodriguez <josejavier.rodriguez@duagon.com>
+Signed-off-by: Johannes Thumshirn <jth@kernel.org>
+Link: https://lore.kernel.org/r/20230411083329.4506-4-jth@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mcb/mcb-lpc.c | 35 +++++++++++++++++++++++++++++++----
+ 1 file changed, 31 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mcb/mcb-lpc.c b/drivers/mcb/mcb-lpc.c
+index 53decd89876ee..a851e02364642 100644
+--- a/drivers/mcb/mcb-lpc.c
++++ b/drivers/mcb/mcb-lpc.c
+@@ -23,7 +23,7 @@ static int mcb_lpc_probe(struct platform_device *pdev)
+ {
+ struct resource *res;
+ struct priv *priv;
+- int ret = 0;
++ int ret = 0, table_size;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+@@ -58,16 +58,43 @@ static int mcb_lpc_probe(struct platform_device *pdev)
+
+ ret = chameleon_parse_cells(priv->bus, priv->mem->start, priv->base);
+ if (ret < 0) {
+- mcb_release_bus(priv->bus);
+- return ret;
++ goto out_mcb_bus;
+ }
+
+- dev_dbg(&pdev->dev, "Found %d cells\n", ret);
++ table_size = ret;
++
++ if (table_size < CHAM_HEADER_SIZE) {
++ /* Release the previous resources */
++ devm_iounmap(&pdev->dev, priv->base);
++ devm_release_mem_region(&pdev->dev, priv->mem->start, resource_size(priv->mem));
++
++ /* Then, allocate it again with the actual chameleon table size */
++ res = devm_request_mem_region(&pdev->dev, priv->mem->start,
++ table_size,
++ KBUILD_MODNAME);
++ if (!res) {
++ dev_err(&pdev->dev, "Failed to request PCI memory\n");
++ ret = -EBUSY;
++ goto out_mcb_bus;
++ }
++
++ priv->base = devm_ioremap(&pdev->dev, priv->mem->start, table_size);
++ if (!priv->base) {
++ dev_err(&pdev->dev, "Cannot ioremap\n");
++ ret = -ENOMEM;
++ goto out_mcb_bus;
++ }
++
++ platform_set_drvdata(pdev, priv);
++ }
+
+ mcb_bus_add_devices(priv->bus);
+
+ return 0;
+
++out_mcb_bus:
++ mcb_release_bus(priv->bus);
++ return ret;
+ }
+
+ static int mcb_lpc_remove(struct platform_device *pdev)
+--
+2.42.0
+
--- /dev/null
+From 5271fed77f4706a29b66cdfe52c1153935822c65 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Apr 2023 10:33:27 +0200
+Subject: mcb: Return actual parsed size when reading chameleon table
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: RodrÃguez Barbarin, José Javier <JoseJavier.Rodriguez@duagon.com>
+
+[ Upstream commit a889c276d33d333ae96697510f33533f6e9d9591 ]
+
+The function chameleon_parse_cells() returns the number of cells
+parsed which has an undetermined size. This return value is only
+used for error checking but the number of cells is never used.
+
+Change return value to be number of bytes parsed to allow for
+memory management improvements.
+
+Co-developed-by: Jorge Sanjuan Garcia <jorge.sanjuangarcia@duagon.com>
+Signed-off-by: Jorge Sanjuan Garcia <jorge.sanjuangarcia@duagon.com>
+Signed-off-by: Javier Rodriguez <josejavier.rodriguez@duagon.com>
+Signed-off-by: Johannes Thumshirn <jth@kernel.org>
+Link: https://lore.kernel.org/r/20230411083329.4506-2-jth@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mcb/mcb-parse.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c
+index c41cbacc75a2c..656b6b71c7682 100644
+--- a/drivers/mcb/mcb-parse.c
++++ b/drivers/mcb/mcb-parse.c
+@@ -128,7 +128,7 @@ static void chameleon_parse_bar(void __iomem *base,
+ }
+ }
+
+-static int chameleon_get_bar(char __iomem **base, phys_addr_t mapbase,
++static int chameleon_get_bar(void __iomem **base, phys_addr_t mapbase,
+ struct chameleon_bar **cb)
+ {
+ struct chameleon_bar *c;
+@@ -177,12 +177,13 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
+ {
+ struct chameleon_fpga_header *header;
+ struct chameleon_bar *cb;
+- char __iomem *p = base;
++ void __iomem *p = base;
+ int num_cells = 0;
+ uint32_t dtype;
+ int bar_count;
+ int ret;
+ u32 hsize;
++ u32 table_size;
+
+ hsize = sizeof(struct chameleon_fpga_header);
+
+@@ -237,12 +238,16 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
+ num_cells++;
+ }
+
+- if (num_cells == 0)
+- num_cells = -EINVAL;
++ if (num_cells == 0) {
++ ret = -EINVAL;
++ goto free_bar;
++ }
+
++ table_size = p - base;
++ pr_debug("%d cell(s) found. Chameleon table size: 0x%04x bytes\n", num_cells, table_size);
+ kfree(cb);
+ kfree(header);
+- return num_cells;
++ return table_size;
+
+ free_bar:
+ kfree(cb);
+--
+2.42.0
+
--- /dev/null
+From c6f89c1cf0b5d658c626c387c3b700cb6e237837 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 25 May 2023 09:56:04 +0000
+Subject: mmc: block: ioctl: do write error check for spi
+
+From: Christian Loehle <CLoehle@hyperstone.com>
+
+[ Upstream commit 568898cbc8b570311b3b94a3202b8233f4168144 ]
+
+SPI doesn't have the usual PROG path we can check for error bits
+after moving back to TRAN. Instead it holds the line LOW until
+completion. We can then check if the card shows any errors or
+is in IDLE state, indicating the line is no longer LOW because
+the card was reset.
+
+Signed-off-by: Christian Loehle <cloehle@hyperstone.com>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/55920f880c9742f486f64aa44e25508e@hyperstone.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Stable-dep-of: f19c5a73e6f7 ("mmc: core: Fix error propagation for some ioctl commands")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/core/block.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
+index 466705b60fb7c..d2d428fafe7fc 100644
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -179,6 +179,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
+ int recovery_mode,
+ struct mmc_queue *mq);
+ static void mmc_blk_hsq_req_done(struct mmc_request *mrq);
++static int mmc_spi_err_check(struct mmc_card *card);
+
+ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
+ {
+@@ -622,6 +623,11 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
+ if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
+ return 0;
+
++ if (mmc_host_is_spi(card->host)) {
++ if (idata->ic.write_flag || r1b_resp || cmd.flags & MMC_RSP_SPI_BUSY)
++ return mmc_spi_err_check(card);
++ return err;
++ }
+ /* Ensure RPMB/R1B command has completed by polling with CMD13. */
+ if (idata->rpmb || r1b_resp)
+ err = mmc_poll_for_busy(card, busy_timeout_ms, false,
+--
+2.42.0
+
--- /dev/null
+From 0e1b1c8d696d3b57537a87da07190aa723dbff6d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Nov 2021 15:32:31 +0900
+Subject: mmc: core: adjust polling interval for CMD1
+
+From: Huijin Park <huijin.park@samsung.com>
+
+[ Upstream commit 76bfc7ccc2fa9d382576f6013b57a0ef93d5a722 ]
+
+In mmc_send_op_cond(), loops are continuously performed at the same
+interval of 10 ms. However the behaviour is not good for some eMMC
+which can be out from a busy state earlier than 10 ms if normal.
+
+Rather than fixing about the interval time in mmc_send_op_cond(),
+let's instead convert into using the common __mmc_poll_for_busy().
+
+The reason for adjusting the interval time is that it is important
+to reduce the eMMC initialization time, especially in devices that
+use eMMC as rootfs.
+
+Test log(eMMC:KLM8G1GETF-B041):
+
+before: 12 ms (0.311016 - 0.298729)
+[ 0.295823] mmc0: starting CMD0 arg 00000000 flags 000000c0
+[ 0.298729] mmc0: starting CMD1 arg 40000080 flags 000000e1<-start
+[ 0.311016] mmc0: starting CMD1 arg 40000080 flags 000000e1<-finish
+[ 0.311336] mmc0: starting CMD2 arg 00000000 flags 00000007
+
+after: 2 ms (0.301270 - 0.298762)
+[ 0.295862] mmc0: starting CMD0 arg 00000000 flags 000000c0
+[ 0.298762] mmc0: starting CMD1 arg 40000080 flags 000000e1<-start
+[ 0.299067] mmc0: starting CMD1 arg 40000080 flags 000000e1
+[ 0.299441] mmc0: starting CMD1 arg 40000080 flags 000000e1
+[ 0.299879] mmc0: starting CMD1 arg 40000080 flags 000000e1
+[ 0.300446] mmc0: starting CMD1 arg 40000080 flags 000000e1
+[ 0.301270] mmc0: starting CMD1 arg 40000080 flags 000000e1<-finish
+[ 0.301572] mmc0: starting CMD2 arg 00000000 flags 00000007
+
+Signed-off-by: Huijin Park <huijin.park@samsung.com>
+Link: https://lore.kernel.org/r/20211104063231.2115-3-huijin.park@samsung.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Stable-dep-of: f19c5a73e6f7 ("mmc: core: Fix error propagation for some ioctl commands")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/core/mmc_ops.c | 83 +++++++++++++++++++++++++-------------
+ 1 file changed, 54 insertions(+), 29 deletions(-)
+
+diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
+index 9946733a34c6d..d63d1c735335c 100644
+--- a/drivers/mmc/core/mmc_ops.c
++++ b/drivers/mmc/core/mmc_ops.c
+@@ -58,6 +58,12 @@ struct mmc_busy_data {
+ enum mmc_busy_cmd busy_cmd;
+ };
+
++struct mmc_op_cond_busy_data {
++ struct mmc_host *host;
++ u32 ocr;
++ struct mmc_command *cmd;
++};
++
+ int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries)
+ {
+ int err;
+@@ -173,43 +179,62 @@ int mmc_go_idle(struct mmc_host *host)
+ return err;
+ }
+
++static int __mmc_send_op_cond_cb(void *cb_data, bool *busy)
++{
++ struct mmc_op_cond_busy_data *data = cb_data;
++ struct mmc_host *host = data->host;
++ struct mmc_command *cmd = data->cmd;
++ u32 ocr = data->ocr;
++ int err = 0;
++
++ err = mmc_wait_for_cmd(host, cmd, 0);
++ if (err)
++ return err;
++
++ if (mmc_host_is_spi(host)) {
++ if (!(cmd->resp[0] & R1_SPI_IDLE)) {
++ *busy = false;
++ return 0;
++ }
++ } else {
++ if (cmd->resp[0] & MMC_CARD_BUSY) {
++ *busy = false;
++ return 0;
++ }
++ }
++
++ *busy = true;
++
++ /*
++ * According to eMMC specification v5.1 section 6.4.3, we
++ * should issue CMD1 repeatedly in the idle state until
++ * the eMMC is ready. Otherwise some eMMC devices seem to enter
++ * the inactive mode after mmc_init_card() issued CMD0 when
++ * the eMMC device is busy.
++ */
++ if (!ocr && !mmc_host_is_spi(host))
++ cmd->arg = cmd->resp[0] | BIT(30);
++
++ return 0;
++}
++
+ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+ {
+ struct mmc_command cmd = {};
+- int i, err = 0;
++ int err = 0;
++ struct mmc_op_cond_busy_data cb_data = {
++ .host = host,
++ .ocr = ocr,
++ .cmd = &cmd
++ };
+
+ cmd.opcode = MMC_SEND_OP_COND;
+ cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
+
+- for (i = 100; i; i--) {
+- err = mmc_wait_for_cmd(host, &cmd, 0);
+- if (err)
+- break;
+-
+- /* wait until reset completes */
+- if (mmc_host_is_spi(host)) {
+- if (!(cmd.resp[0] & R1_SPI_IDLE))
+- break;
+- } else {
+- if (cmd.resp[0] & MMC_CARD_BUSY)
+- break;
+- }
+-
+- err = -ETIMEDOUT;
+-
+- mmc_delay(10);
+-
+- /*
+- * According to eMMC specification v5.1 section 6.4.3, we
+- * should issue CMD1 repeatedly in the idle state until
+- * the eMMC is ready. Otherwise some eMMC devices seem to enter
+- * the inactive mode after mmc_init_card() issued CMD0 when
+- * the eMMC device is busy.
+- */
+- if (!ocr && !mmc_host_is_spi(host))
+- cmd.arg = cmd.resp[0] | BIT(30);
+- }
++ err = __mmc_poll_for_busy(host, 1000, &__mmc_send_op_cond_cb, &cb_data);
++ if (err)
++ return err;
+
+ if (rocr && !mmc_host_is_spi(host))
+ *rocr = cmd.resp[0];
+--
+2.42.0
+
--- /dev/null
+From edb7b47f5e5c4f52f2119266130ff8dd117df53d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Feb 2023 14:37:07 +0100
+Subject: mmc: core: Align to common busy polling behaviour for mmc ioctls
+
+From: Ulf Hansson <ulf.hansson@linaro.org>
+
+[ Upstream commit 51f5b3056790bc0518e49587996f1e6f3058cca9 ]
+
+Let's align to the common busy polling behaviour for mmc ioctls, by
+updating the below two corresponding parts, that comes into play when using
+an R1B response for a command.
+
+*) A command with an R1B response should be prepared by calling
+mmc_prepare_busy_cmd(), which make us respects the host's busy timeout
+constraints.
+**) When an R1B response is being used and the host also supports HW busy
+detection, we should skip to poll for busy completion.
+
+Suggested-by: Christian Loehle <cloehle@hyperstone.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Reviewed-by: Christian Loehle <cloehle@hyperstone.com>
+Link: https://lore.kernel.org/r/20230213133707.27857-1-ulf.hansson@linaro.org
+Stable-dep-of: f19c5a73e6f7 ("mmc: core: Fix error propagation for some ioctl commands")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/core/block.c | 25 +++++++++++++++++--------
+ drivers/mmc/core/mmc_ops.c | 1 +
+ 2 files changed, 18 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
+index c7c23acfd03ed..466705b60fb7c 100644
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -470,6 +470,8 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
+ struct mmc_data data = {};
+ struct mmc_request mrq = {};
+ struct scatterlist sg;
++ bool r1b_resp, use_r1b_resp = false;
++ unsigned int busy_timeout_ms;
+ int err;
+ unsigned int target_part;
+
+@@ -558,6 +560,13 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
+ (cmd.opcode == MMC_SWITCH))
+ return mmc_sanitize(card, idata->ic.cmd_timeout_ms);
+
++ /* If it's an R1B response we need some more preparations. */
++ busy_timeout_ms = idata->ic.cmd_timeout_ms ? : MMC_BLK_TIMEOUT_MS;
++ r1b_resp = (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B;
++ if (r1b_resp)
++ use_r1b_resp = mmc_prepare_busy_cmd(card->host, &cmd,
++ busy_timeout_ms);
++
+ mmc_wait_for_req(card->host, &mrq);
+ memcpy(&idata->ic.response, cmd.resp, sizeof(cmd.resp));
+
+@@ -609,14 +618,14 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
+ if (idata->ic.postsleep_min_us)
+ usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us);
+
+- if (idata->rpmb || (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
+- /*
+- * Ensure RPMB/R1B command has completed by polling CMD13 "Send Status". Here we
+- * allow to override the default timeout value if a custom timeout is specified.
+- */
+- err = mmc_poll_for_busy(card, idata->ic.cmd_timeout_ms ? : MMC_BLK_TIMEOUT_MS,
+- false, MMC_BUSY_IO);
+- }
++ /* No need to poll when using HW busy detection. */
++ if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
++ return 0;
++
++ /* Ensure RPMB/R1B command has completed by polling with CMD13. */
++ if (idata->rpmb || r1b_resp)
++ err = mmc_poll_for_busy(card, busy_timeout_ms, false,
++ MMC_BUSY_IO);
+
+ return err;
+ }
+diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
+index 180d7e9d3400a..dd6b3e116fcd5 100644
+--- a/drivers/mmc/core/mmc_ops.c
++++ b/drivers/mmc/core/mmc_ops.c
+@@ -575,6 +575,7 @@ bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
+ cmd->busy_timeout = timeout_ms;
+ return true;
+ }
++EXPORT_SYMBOL_GPL(mmc_prepare_busy_cmd);
+
+ /**
+ * __mmc_switch - modify EXT_CSD register
+--
+2.42.0
+
--- /dev/null
+From e00fa5b928fe670ad8969dd10ad31190e73314e9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Nov 2021 15:32:30 +0900
+Subject: mmc: core: change __mmc_poll_for_busy() parameter type
+
+From: Huijin Park <huijin.park@samsung.com>
+
+[ Upstream commit 2ebbdace5cc05caea9d12f536a8d0b9a3d930a29 ]
+
+This patch changes the __mmc_poll_for_busy() first parameter type
+from 'struct mmc_card*' to 'struct mmc_host*'.
+Because the function refers only 'struct mmc_host' to get hostname.
+
+Signed-off-by: Huijin Park <huijin.park@samsung.com>
+Link: https://lore.kernel.org/r/20211104063231.2115-2-huijin.park@samsung.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Stable-dep-of: f19c5a73e6f7 ("mmc: core: Fix error propagation for some ioctl commands")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/core/block.c | 4 ++--
+ drivers/mmc/core/mmc.c | 2 +-
+ drivers/mmc/core/mmc_ops.c | 6 +++---
+ drivers/mmc/core/mmc_ops.h | 2 +-
+ drivers/mmc/core/sd.c | 2 +-
+ 5 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
+index 25077a1a3d821..78af9842057ec 100644
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -1955,8 +1955,8 @@ static int mmc_blk_card_busy(struct mmc_card *card, struct request *req)
+
+ cb_data.card = card;
+ cb_data.status = 0;
+- err = __mmc_poll_for_busy(card, MMC_BLK_TIMEOUT_MS, &mmc_blk_busy_cb,
+- &cb_data);
++ err = __mmc_poll_for_busy(card->host, MMC_BLK_TIMEOUT_MS,
++ &mmc_blk_busy_cb, &cb_data);
+
+ /*
+ * Do not assume data transferred correctly if there are any error bits
+diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
+index 5074b3ce38ea0..c28d7218dce39 100644
+--- a/drivers/mmc/core/mmc.c
++++ b/drivers/mmc/core/mmc.c
+@@ -1969,7 +1969,7 @@ static int mmc_sleep(struct mmc_host *host)
+ goto out_release;
+ }
+
+- err = __mmc_poll_for_busy(card, timeout_ms, &mmc_sleep_busy_cb, host);
++ err = __mmc_poll_for_busy(host, timeout_ms, &mmc_sleep_busy_cb, host);
+
+ out_release:
+ mmc_retune_release(host);
+diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
+index 0c54858e89c06..9946733a34c6d 100644
+--- a/drivers/mmc/core/mmc_ops.c
++++ b/drivers/mmc/core/mmc_ops.c
+@@ -470,11 +470,10 @@ static int mmc_busy_cb(void *cb_data, bool *busy)
+ return 0;
+ }
+
+-int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
++int __mmc_poll_for_busy(struct mmc_host *host, unsigned int timeout_ms,
+ int (*busy_cb)(void *cb_data, bool *busy),
+ void *cb_data)
+ {
+- struct mmc_host *host = card->host;
+ int err;
+ unsigned long timeout;
+ unsigned int udelay = 32, udelay_max = 32768;
+@@ -515,13 +514,14 @@ EXPORT_SYMBOL_GPL(__mmc_poll_for_busy);
+ int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+ bool retry_crc_err, enum mmc_busy_cmd busy_cmd)
+ {
++ struct mmc_host *host = card->host;
+ struct mmc_busy_data cb_data;
+
+ cb_data.card = card;
+ cb_data.retry_crc_err = retry_crc_err;
+ cb_data.busy_cmd = busy_cmd;
+
+- return __mmc_poll_for_busy(card, timeout_ms, &mmc_busy_cb, &cb_data);
++ return __mmc_poll_for_busy(host, timeout_ms, &mmc_busy_cb, &cb_data);
+ }
+ EXPORT_SYMBOL_GPL(mmc_poll_for_busy);
+
+diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
+index ae25ffc2e8704..fd266c7fa41a5 100644
+--- a/drivers/mmc/core/mmc_ops.h
++++ b/drivers/mmc/core/mmc_ops.h
+@@ -42,7 +42,7 @@ int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
+ int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
+ bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
+ unsigned int timeout_ms);
+-int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
++int __mmc_poll_for_busy(struct mmc_host *host, unsigned int timeout_ms,
+ int (*busy_cb)(void *cb_data, bool *busy),
+ void *cb_data);
+ int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
+index 592166e53dce8..03636a432e2da 100644
+--- a/drivers/mmc/core/sd.c
++++ b/drivers/mmc/core/sd.c
+@@ -1667,7 +1667,7 @@ static int sd_poweroff_notify(struct mmc_card *card)
+
+ cb_data.card = card;
+ cb_data.reg_buf = reg_buf;
+- err = __mmc_poll_for_busy(card, SD_POWEROFF_NOTIFY_TIMEOUT_MS,
++ err = __mmc_poll_for_busy(card->host, SD_POWEROFF_NOTIFY_TIMEOUT_MS,
+ &sd_busy_poweroff_notify_cb, &cb_data);
+
+ out:
+--
+2.42.0
+
--- /dev/null
+From 9cf75b1a2570c8127e3e908deb124a7c8eac132f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Sep 2023 13:29:21 +0200
+Subject: mmc: core: Fix error propagation for some ioctl commands
+
+From: Ulf Hansson <ulf.hansson@linaro.org>
+
+[ Upstream commit f19c5a73e6f78d69efce66cfdce31148c76a61a6 ]
+
+Userspace has currently no way of checking the internal R1 response error
+bits for some commands. This is a problem for some commands, like RPMB for
+example. Typically, we may detect that the busy completion has successfully
+ended, while in fact the card did not complete the requested operation.
+
+To fix the problem, let's always poll with CMD13 for these commands and
+during the polling, let's also aggregate the R1 response bits. Before
+completing the ioctl request, let's propagate the R1 response bits too.
+
+Reviewed-by: Avri Altman <avri.altman@wdc.com>
+Co-developed-by: Christian Loehle <christian.loehle@arm.com>
+Signed-off-by: Christian Loehle <christian.loehle@arm.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20230913112921.553019-1-ulf.hansson@linaro.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/core/block.c | 31 ++++++++++++++++++++-----------
+ 1 file changed, 20 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
+index d2d428fafe7fc..d82d567f0db49 100644
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -180,6 +180,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
+ struct mmc_queue *mq);
+ static void mmc_blk_hsq_req_done(struct mmc_request *mrq);
+ static int mmc_spi_err_check(struct mmc_card *card);
++static int mmc_blk_busy_cb(void *cb_data, bool *busy);
+
+ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
+ {
+@@ -471,7 +472,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
+ struct mmc_data data = {};
+ struct mmc_request mrq = {};
+ struct scatterlist sg;
+- bool r1b_resp, use_r1b_resp = false;
++ bool r1b_resp;
+ unsigned int busy_timeout_ms;
+ int err;
+ unsigned int target_part;
+@@ -565,8 +566,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
+ busy_timeout_ms = idata->ic.cmd_timeout_ms ? : MMC_BLK_TIMEOUT_MS;
+ r1b_resp = (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B;
+ if (r1b_resp)
+- use_r1b_resp = mmc_prepare_busy_cmd(card->host, &cmd,
+- busy_timeout_ms);
++ mmc_prepare_busy_cmd(card->host, &cmd, busy_timeout_ms);
+
+ mmc_wait_for_req(card->host, &mrq);
+ memcpy(&idata->ic.response, cmd.resp, sizeof(cmd.resp));
+@@ -619,19 +619,28 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
+ if (idata->ic.postsleep_min_us)
+ usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us);
+
+- /* No need to poll when using HW busy detection. */
+- if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
+- return 0;
+-
+ if (mmc_host_is_spi(card->host)) {
+ if (idata->ic.write_flag || r1b_resp || cmd.flags & MMC_RSP_SPI_BUSY)
+ return mmc_spi_err_check(card);
+ return err;
+ }
+- /* Ensure RPMB/R1B command has completed by polling with CMD13. */
+- if (idata->rpmb || r1b_resp)
+- err = mmc_poll_for_busy(card, busy_timeout_ms, false,
+- MMC_BUSY_IO);
++
++ /*
++ * Ensure RPMB, writes and R1B responses are completed by polling with
++ * CMD13. Note that, usually we don't need to poll when using HW busy
++ * detection, but here it's needed since some commands may indicate the
++ * error through the R1 status bits.
++ */
++ if (idata->rpmb || idata->ic.write_flag || r1b_resp) {
++ struct mmc_blk_busy_data cb_data = {
++ .card = card,
++ };
++
++ err = __mmc_poll_for_busy(card->host, 0, busy_timeout_ms,
++ &mmc_blk_busy_cb, &cb_data);
++
++ idata->ic.response[0] = cb_data.status;
++ }
+
+ return err;
+ }
+--
+2.42.0
+
--- /dev/null
+From 5f2b8d5eaedb0c7b50c79bbb2e15b9d6d9c97915 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 4 Mar 2022 11:56:56 +0100
+Subject: mmc: core: Restore (almost) the busy polling for MMC_SEND_OP_COND
+
+From: Ulf Hansson <ulf.hansson@linaro.org>
+
+[ Upstream commit 1760fdb6fe9f796fbdb9b4106b3e0bbacc16b55c ]
+
+Commit 76bfc7ccc2fa ("mmc: core: adjust polling interval for CMD1"),
+significantly decreased the polling period from ~10-12ms into just a couple
+of us. The purpose was to decrease the total time spent in the busy polling
+loop, but unfortunate it has lead to problems, that causes eMMC cards to
+never gets out busy and thus fails to be initialized.
+
+To fix the problem, but also to try to keep some of the new improved
+behaviour, let's start by using a polling period of 1-2ms, which then
+increases for each loop, according to common polling loop in
+__mmc_poll_for_busy().
+
+Reported-by: Jean Rene Dawin <jdawin@math.uni-bielefeld.de>
+Reported-by: H. Nikolaus Schaller <hns@goldelico.com>
+Cc: Huijin Park <huijin.park@samsung.com>
+Fixes: 76bfc7ccc2fa ("mmc: core: adjust polling interval for CMD1")
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Tested-by: Jean Rene Dawin <jdawin@math.uni-bielefeld.de>
+Tested-by: H. Nikolaus Schaller <hns@goldelico.com>
+Link: https://lore.kernel.org/r/20220304105656.149281-1-ulf.hansson@linaro.org
+Stable-dep-of: f19c5a73e6f7 ("mmc: core: Fix error propagation for some ioctl commands")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/core/block.c | 2 +-
+ drivers/mmc/core/mmc.c | 2 +-
+ drivers/mmc/core/mmc_ops.c | 13 +++++++++----
+ drivers/mmc/core/mmc_ops.h | 3 ++-
+ drivers/mmc/core/sd.c | 2 +-
+ 5 files changed, 14 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
+index 78af9842057ec..c7c23acfd03ed 100644
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -1955,7 +1955,7 @@ static int mmc_blk_card_busy(struct mmc_card *card, struct request *req)
+
+ cb_data.card = card;
+ cb_data.status = 0;
+- err = __mmc_poll_for_busy(card->host, MMC_BLK_TIMEOUT_MS,
++ err = __mmc_poll_for_busy(card->host, 0, MMC_BLK_TIMEOUT_MS,
+ &mmc_blk_busy_cb, &cb_data);
+
+ /*
+diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
+index c28d7218dce39..2a6c5d2c5ecf1 100644
+--- a/drivers/mmc/core/mmc.c
++++ b/drivers/mmc/core/mmc.c
+@@ -1969,7 +1969,7 @@ static int mmc_sleep(struct mmc_host *host)
+ goto out_release;
+ }
+
+- err = __mmc_poll_for_busy(host, timeout_ms, &mmc_sleep_busy_cb, host);
++ err = __mmc_poll_for_busy(host, 0, timeout_ms, &mmc_sleep_busy_cb, host);
+
+ out_release:
+ mmc_retune_release(host);
+diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
+index d63d1c735335c..180d7e9d3400a 100644
+--- a/drivers/mmc/core/mmc_ops.c
++++ b/drivers/mmc/core/mmc_ops.c
+@@ -21,6 +21,8 @@
+
+ #define MMC_BKOPS_TIMEOUT_MS (120 * 1000) /* 120s */
+ #define MMC_SANITIZE_TIMEOUT_MS (240 * 1000) /* 240s */
++#define MMC_OP_COND_PERIOD_US (1 * 1000) /* 1ms */
++#define MMC_OP_COND_TIMEOUT_MS 1000 /* 1s */
+
+ static const u8 tuning_blk_pattern_4bit[] = {
+ 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
+@@ -232,7 +234,9 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+ cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
+
+- err = __mmc_poll_for_busy(host, 1000, &__mmc_send_op_cond_cb, &cb_data);
++ err = __mmc_poll_for_busy(host, MMC_OP_COND_PERIOD_US,
++ MMC_OP_COND_TIMEOUT_MS,
++ &__mmc_send_op_cond_cb, &cb_data);
+ if (err)
+ return err;
+
+@@ -495,13 +499,14 @@ static int mmc_busy_cb(void *cb_data, bool *busy)
+ return 0;
+ }
+
+-int __mmc_poll_for_busy(struct mmc_host *host, unsigned int timeout_ms,
++int __mmc_poll_for_busy(struct mmc_host *host, unsigned int period_us,
++ unsigned int timeout_ms,
+ int (*busy_cb)(void *cb_data, bool *busy),
+ void *cb_data)
+ {
+ int err;
+ unsigned long timeout;
+- unsigned int udelay = 32, udelay_max = 32768;
++ unsigned int udelay = period_us ? period_us : 32, udelay_max = 32768;
+ bool expired = false;
+ bool busy = false;
+
+@@ -546,7 +551,7 @@ int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+ cb_data.retry_crc_err = retry_crc_err;
+ cb_data.busy_cmd = busy_cmd;
+
+- return __mmc_poll_for_busy(host, timeout_ms, &mmc_busy_cb, &cb_data);
++ return __mmc_poll_for_busy(host, 0, timeout_ms, &mmc_busy_cb, &cb_data);
+ }
+ EXPORT_SYMBOL_GPL(mmc_poll_for_busy);
+
+diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
+index fd266c7fa41a5..9fc6c320a4620 100644
+--- a/drivers/mmc/core/mmc_ops.h
++++ b/drivers/mmc/core/mmc_ops.h
+@@ -42,7 +42,8 @@ int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
+ int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
+ bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
+ unsigned int timeout_ms);
+-int __mmc_poll_for_busy(struct mmc_host *host, unsigned int timeout_ms,
++int __mmc_poll_for_busy(struct mmc_host *host, unsigned int period_us,
++ unsigned int timeout_ms,
+ int (*busy_cb)(void *cb_data, bool *busy),
+ void *cb_data);
+ int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
+index 03636a432e2da..c2859ce3f6329 100644
+--- a/drivers/mmc/core/sd.c
++++ b/drivers/mmc/core/sd.c
+@@ -1667,7 +1667,7 @@ static int sd_poweroff_notify(struct mmc_card *card)
+
+ cb_data.card = card;
+ cb_data.reg_buf = reg_buf;
+- err = __mmc_poll_for_busy(card->host, SD_POWEROFF_NOTIFY_TIMEOUT_MS,
++ err = __mmc_poll_for_busy(card->host, 0, SD_POWEROFF_NOTIFY_TIMEOUT_MS,
+ &sd_busy_poweroff_notify_cb, &cb_data);
+
+ out:
+--
+2.42.0
+
--- /dev/null
+From 141c3465d213aff03d860801c1823cc610b5741e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 18 Oct 2023 11:23:54 -0700
+Subject: mptcp: more conservative check for zero probes
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit 72377ab2d671befd6390a1d5677f5cca61235b65 ]
+
+Christoph reported that the MPTCP protocol can find the subflow-level
+write queue unexpectedly not empty while crafting a zero-window probe,
+hitting a warning:
+
+------------[ cut here ]------------
+WARNING: CPU: 0 PID: 188 at net/mptcp/protocol.c:1312 mptcp_sendmsg_frag+0xc06/0xe70
+Modules linked in:
+CPU: 0 PID: 188 Comm: kworker/0:2 Not tainted 6.6.0-rc2-g1176aa719d7a #47
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.0-2.el7 04/01/2014
+Workqueue: events mptcp_worker
+RIP: 0010:mptcp_sendmsg_frag+0xc06/0xe70 net/mptcp/protocol.c:1312
+RAX: 47d0530de347ff6a RBX: 47d0530de347ff6b RCX: ffff8881015d3c00
+RDX: ffff8881015d3c00 RSI: 47d0530de347ff6b RDI: 47d0530de347ff6b
+RBP: 47d0530de347ff6b R08: ffffffff8243c6a8 R09: ffffffff82042d9c
+R10: 0000000000000002 R11: ffffffff82056850 R12: ffff88812a13d580
+R13: 0000000000000001 R14: ffff88812b375e50 R15: ffff88812bbf3200
+FS: 0000000000000000(0000) GS:ffff88813bc00000(0000) knlGS:0000000000000000
+CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 0000000000695118 CR3: 0000000115dfc001 CR4: 0000000000170ef0
+Call Trace:
+ <TASK>
+ __subflow_push_pending+0xa4/0x420 net/mptcp/protocol.c:1545
+ __mptcp_push_pending+0x128/0x3b0 net/mptcp/protocol.c:1614
+ mptcp_release_cb+0x218/0x5b0 net/mptcp/protocol.c:3391
+ release_sock+0xf6/0x100 net/core/sock.c:3521
+ mptcp_worker+0x6e8/0x8f0 net/mptcp/protocol.c:2746
+ process_scheduled_works+0x341/0x690 kernel/workqueue.c:2630
+ worker_thread+0x3a7/0x610 kernel/workqueue.c:2784
+ kthread+0x143/0x180 kernel/kthread.c:388
+ ret_from_fork+0x4d/0x60 arch/x86/kernel/process.c:147
+ ret_from_fork_asm+0x1b/0x30 arch/x86/entry/entry_64.S:304
+ </TASK>
+
+The root cause of the issue is that expectations are wrong: e.g. due
+to MPTCP-level re-injection we can hit the critical condition.
+
+Explicitly avoid the zero-window probe when the subflow write queue
+is not empty and drop the related warnings.
+
+Reported-by: Christoph Paasch <cpaasch@apple.com>
+Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/444
+Fixes: f70cad1085d1 ("mptcp: stop relying on tcp_tx_skb_cache")
+Cc: stable@vger.kernel.org
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Mat Martineau <martineau@kernel.org>
+Link: https://lore.kernel.org/r/20231018-send-net-20231018-v1-3-17ecb002e41d@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/protocol.c | 8 +-------
+ 1 file changed, 1 insertion(+), 7 deletions(-)
+
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index b9613e02e2de1..62e1875b92904 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -1337,7 +1337,7 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
+ if (copy == 0) {
+ u64 snd_una = READ_ONCE(msk->snd_una);
+
+- if (snd_una != msk->snd_nxt) {
++ if (snd_una != msk->snd_nxt || tcp_write_queue_tail(ssk)) {
+ tcp_remove_empty_skb(ssk);
+ return 0;
+ }
+@@ -1345,11 +1345,6 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
+ zero_window_probe = true;
+ data_seq = snd_una - 1;
+ copy = 1;
+-
+- /* all mptcp-level data is acked, no skbs should be present into the
+- * ssk write queue
+- */
+- WARN_ON_ONCE(reuse_skb);
+ }
+
+ copy = min_t(size_t, copy, info->limit - info->sent);
+@@ -1379,7 +1374,6 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
+ if (reuse_skb) {
+ TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH;
+ mpext->data_len += copy;
+- WARN_ON_ONCE(zero_window_probe);
+ goto out;
+ }
+
+--
+2.42.0
+
--- /dev/null
+From 5f5506a5b7a6ce6c09eeeec81ac326d7cdc8553d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Oct 2023 16:57:05 +0200
+Subject: pinctrl: qcom: lpass-lpi: fix concurrent register updates
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit c8befdc411e5fd1bf95a13e8744c8ca79b412bee ]
+
+The Qualcomm LPASS LPI pin controller driver uses one lock for guarding
+Read-Modify-Write code for slew rate registers. However the pin
+configuration and muxing registers have exactly the same RMW code but
+are not protected.
+
+Pin controller framework does not provide locking here, thus it is
+possible to trigger simultaneous change of pin configuration registers
+resulting in non-atomic changes.
+
+Protect from concurrent access by re-using the same lock used to cover
+the slew rate register. Using the same lock instead of adding second
+one will make more sense, once we add support for newer Qualcomm SoC,
+where slew rate is configured in the same register as pin
+configuration/muxing.
+
+Fixes: 6e261d1090d6 ("pinctrl: qcom: Add sm8250 lpass lpi pinctrl driver")
+Cc: stable@vger.kernel.org
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/r/20231013145705.219954-1-krzysztof.kozlowski@linaro.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
+index dd1c9fd733c8f..ec37ad43a6364 100644
+--- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
++++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
+@@ -102,7 +102,8 @@ struct lpi_pinctrl {
+ char __iomem *tlmm_base;
+ char __iomem *slew_base;
+ struct clk_bulk_data clks[MAX_LPI_NUM_CLKS];
+- struct mutex slew_access_lock;
++ /* Protects from concurrent register updates */
++ struct mutex lock;
+ const struct lpi_pinctrl_variant_data *data;
+ };
+
+@@ -330,9 +331,11 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
+ if (WARN_ON(i == g->nfuncs))
+ return -EINVAL;
+
++ mutex_lock(&pctrl->lock);
+ val = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG);
+ u32p_replace_bits(&val, i, LPI_GPIO_FUNCTION_MASK);
+ lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val);
++ mutex_unlock(&pctrl->lock);
+
+ return 0;
+ }
+@@ -438,14 +441,14 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
+ if (slew_offset == NO_SLEW)
+ break;
+
+- mutex_lock(&pctrl->slew_access_lock);
++ mutex_lock(&pctrl->lock);
+
+ sval = ioread32(pctrl->slew_base + LPI_SLEW_RATE_CTL_REG);
+ sval &= ~(LPI_SLEW_RATE_MASK << slew_offset);
+ sval |= arg << slew_offset;
+ iowrite32(sval, pctrl->slew_base + LPI_SLEW_RATE_CTL_REG);
+
+- mutex_unlock(&pctrl->slew_access_lock);
++ mutex_unlock(&pctrl->lock);
+ break;
+ default:
+ return -EINVAL;
+@@ -461,6 +464,7 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
+ lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val);
+ }
+
++ mutex_lock(&pctrl->lock);
+ val = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG);
+
+ u32p_replace_bits(&val, pullup, LPI_GPIO_PULL_MASK);
+@@ -469,6 +473,7 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
+ u32p_replace_bits(&val, output_enabled, LPI_GPIO_OE_MASK);
+
+ lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val);
++ mutex_unlock(&pctrl->lock);
+
+ return 0;
+ }
+@@ -642,7 +647,7 @@ static int lpi_pinctrl_probe(struct platform_device *pdev)
+ pctrl->chip.of_gpio_n_cells = 2;
+ pctrl->chip.can_sleep = false;
+
+- mutex_init(&pctrl->slew_access_lock);
++ mutex_init(&pctrl->lock);
+
+ pctrl->ctrl = devm_pinctrl_register(dev, &pctrl->desc, pctrl);
+ if (IS_ERR(pctrl->ctrl)) {
+@@ -660,7 +665,7 @@ static int lpi_pinctrl_probe(struct platform_device *pdev)
+ return 0;
+
+ err_pinctrl:
+- mutex_destroy(&pctrl->slew_access_lock);
++ mutex_destroy(&pctrl->lock);
+ clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks);
+
+ return ret;
+@@ -670,7 +675,7 @@ static int lpi_pinctrl_remove(struct platform_device *pdev)
+ {
+ struct lpi_pinctrl *pctrl = platform_get_drvdata(pdev);
+
+- mutex_destroy(&pctrl->slew_access_lock);
++ mutex_destroy(&pctrl->lock);
+ clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks);
+
+ return 0;
+--
+2.42.0
+
--- /dev/null
+mmc-core-change-__mmc_poll_for_busy-parameter-type.patch
+mmc-core-adjust-polling-interval-for-cmd1.patch
+mmc-core-restore-almost-the-busy-polling-for-mmc_sen.patch
+mmc-core-align-to-common-busy-polling-behaviour-for-.patch
+mmc-block-ioctl-do-write-error-check-for-spi.patch
+mmc-core-fix-error-propagation-for-some-ioctl-comman.patch
+asoc-rt9120-add-rt9210-audio-amplifier-support.patch
+asoc-codecs-add-wsa883x-amplifier-support.patch
+asoc-rt1318-add-rt1318-sdca-vendor-specific-driver.patch
+asoc-codecs-constify-static-sdw_slave_ops-struct.patch
+asoc-codecs-wcd938x-fix-accessing-regmap-on-unattach.patch
+asoc-codecs-wcd938x-fix-resource-leaks-on-bind-error.patch
+asoc-codecs-wcd938x-convert-to-platform-remove-callb.patch
+asoc-codecs-wcd938x-simplify-with-dev_err_probe.patch
+asoc-codecs-wcd938x-fix-regulator-leaks-on-probe-err.patch
+asoc-codecs-wcd938x-fix-runtime-pm-imbalance-on-remo.patch
+pinctrl-qcom-lpass-lpi-fix-concurrent-register-updat.patch
+tcp-remove-dead-code-from-tcp_sendmsg_locked.patch
+tcp-cleanup-tcp_remove_empty_skb-use.patch
+mptcp-more-conservative-check-for-zero-probes.patch
+mcb-return-actual-parsed-size-when-reading-chameleon.patch
+mcb-lpc-reallocate-memory-region-to-avoid-memory-ove.patch
--- /dev/null
+From a97a36302ef8c48118b1973810eabe8f097822e9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Oct 2021 13:19:18 -0700
+Subject: tcp: cleanup tcp_remove_empty_skb() use
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 27728ba80f1eb279b209bbd5922fdeebe52d9e30 ]
+
+All tcp_remove_empty_skb() callers now use tcp_write_queue_tail()
+for the skb argument, we can therefore factorize code.
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 72377ab2d671 ("mptcp: more conservative check for zero probes")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/tcp.h | 2 +-
+ net/ipv4/tcp.c | 9 +++++----
+ net/mptcp/protocol.c | 4 ++--
+ 3 files changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/include/net/tcp.h b/include/net/tcp.h
+index e93a48edf438c..3aee02ad0116b 100644
+--- a/include/net/tcp.h
++++ b/include/net/tcp.h
+@@ -314,7 +314,7 @@ void tcp_shutdown(struct sock *sk, int how);
+ int tcp_v4_early_demux(struct sk_buff *skb);
+ int tcp_v4_rcv(struct sk_buff *skb);
+
+-void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb);
++void tcp_remove_empty_skb(struct sock *sk);
+ int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
+ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
+ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size);
+diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
+index 2115a0e5c98f7..6dcb77a2bde60 100644
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -953,8 +953,10 @@ int tcp_send_mss(struct sock *sk, int *size_goal, int flags)
+ * importantly be able to generate EPOLLOUT for Edge Trigger epoll()
+ * users.
+ */
+-void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb)
++void tcp_remove_empty_skb(struct sock *sk)
+ {
++ struct sk_buff *skb = tcp_write_queue_tail(sk);
++
+ if (skb && TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) {
+ tcp_unlink_write_queue(skb, sk);
+ if (tcp_write_queue_empty(sk))
+@@ -1107,7 +1109,7 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
+ return copied;
+
+ do_error:
+- tcp_remove_empty_skb(sk, tcp_write_queue_tail(sk));
++ tcp_remove_empty_skb(sk);
+ if (copied)
+ goto out;
+ out_err:
+@@ -1429,8 +1431,7 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
+ return copied + copied_syn;
+
+ do_error:
+- skb = tcp_write_queue_tail(sk);
+- tcp_remove_empty_skb(sk, skb);
++ tcp_remove_empty_skb(sk);
+
+ if (copied + copied_syn)
+ goto out;
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index 82b1583f709d3..b9613e02e2de1 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -1338,7 +1338,7 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
+ u64 snd_una = READ_ONCE(msk->snd_una);
+
+ if (snd_una != msk->snd_nxt) {
+- tcp_remove_empty_skb(ssk, tcp_write_queue_tail(ssk));
++ tcp_remove_empty_skb(ssk);
+ return 0;
+ }
+
+@@ -1354,7 +1354,7 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
+
+ copy = min_t(size_t, copy, info->limit - info->sent);
+ if (!sk_wmem_schedule(ssk, copy)) {
+- tcp_remove_empty_skb(ssk, tcp_write_queue_tail(ssk));
++ tcp_remove_empty_skb(ssk);
+ return -ENOMEM;
+ }
+
+--
+2.42.0
+
--- /dev/null
+From 91a98ca6eaaa2065d80085257a52506d8a36f9e5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Oct 2021 13:19:17 -0700
+Subject: tcp: remove dead code from tcp_sendmsg_locked()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 3ded97bc41a1e76e1e72eeb192331c01ceacc4bc ]
+
+TCP sendmsg() no longer puts payload in skb head, we can remove
+dead code.
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 72377ab2d671 ("mptcp: more conservative check for zero probes")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp.c | 10 +---------
+ 1 file changed, 1 insertion(+), 9 deletions(-)
+
+diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
+index a91cf000bb61b..2115a0e5c98f7 100644
+--- a/net/ipv4/tcp.c
++++ b/net/ipv4/tcp.c
+@@ -1330,14 +1330,7 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
+ if (copy > msg_data_left(msg))
+ copy = msg_data_left(msg);
+
+- /* Where to copy to? */
+- if (skb_availroom(skb) > 0 && !zc) {
+- /* We have some space in skb head. Superb! */
+- copy = min_t(int, copy, skb_availroom(skb));
+- err = skb_add_data_nocache(sk, skb, &msg->msg_iter, copy);
+- if (err)
+- goto do_fault;
+- } else if (!zc) {
++ if (!zc) {
+ bool merge = true;
+ int i = skb_shinfo(skb)->nr_frags;
+ struct page_frag *pfrag = sk_page_frag(sk);
+@@ -1437,7 +1430,6 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
+
+ do_error:
+ skb = tcp_write_queue_tail(sk);
+-do_fault:
+ tcp_remove_empty_skb(sk, skb);
+
+ if (copied + copied_syn)
+--
+2.42.0
+