]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.15
authorSasha Levin <sashal@kernel.org>
Wed, 25 Oct 2023 11:48:01 +0000 (07:48 -0400)
committerSasha Levin <sashal@kernel.org>
Wed, 25 Oct 2023 11:48:01 +0000 (07:48 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
23 files changed:
queue-5.15/asoc-codecs-add-wsa883x-amplifier-support.patch [new file with mode: 0644]
queue-5.15/asoc-codecs-constify-static-sdw_slave_ops-struct.patch [new file with mode: 0644]
queue-5.15/asoc-codecs-wcd938x-convert-to-platform-remove-callb.patch [new file with mode: 0644]
queue-5.15/asoc-codecs-wcd938x-fix-accessing-regmap-on-unattach.patch [new file with mode: 0644]
queue-5.15/asoc-codecs-wcd938x-fix-regulator-leaks-on-probe-err.patch [new file with mode: 0644]
queue-5.15/asoc-codecs-wcd938x-fix-resource-leaks-on-bind-error.patch [new file with mode: 0644]
queue-5.15/asoc-codecs-wcd938x-fix-runtime-pm-imbalance-on-remo.patch [new file with mode: 0644]
queue-5.15/asoc-codecs-wcd938x-simplify-with-dev_err_probe.patch [new file with mode: 0644]
queue-5.15/asoc-rt1318-add-rt1318-sdca-vendor-specific-driver.patch [new file with mode: 0644]
queue-5.15/asoc-rt9120-add-rt9210-audio-amplifier-support.patch [new file with mode: 0644]
queue-5.15/mcb-lpc-reallocate-memory-region-to-avoid-memory-ove.patch [new file with mode: 0644]
queue-5.15/mcb-return-actual-parsed-size-when-reading-chameleon.patch [new file with mode: 0644]
queue-5.15/mmc-block-ioctl-do-write-error-check-for-spi.patch [new file with mode: 0644]
queue-5.15/mmc-core-adjust-polling-interval-for-cmd1.patch [new file with mode: 0644]
queue-5.15/mmc-core-align-to-common-busy-polling-behaviour-for-.patch [new file with mode: 0644]
queue-5.15/mmc-core-change-__mmc_poll_for_busy-parameter-type.patch [new file with mode: 0644]
queue-5.15/mmc-core-fix-error-propagation-for-some-ioctl-comman.patch [new file with mode: 0644]
queue-5.15/mmc-core-restore-almost-the-busy-polling-for-mmc_sen.patch [new file with mode: 0644]
queue-5.15/mptcp-more-conservative-check-for-zero-probes.patch [new file with mode: 0644]
queue-5.15/pinctrl-qcom-lpass-lpi-fix-concurrent-register-updat.patch [new file with mode: 0644]
queue-5.15/series [new file with mode: 0644]
queue-5.15/tcp-cleanup-tcp_remove_empty_skb-use.patch [new file with mode: 0644]
queue-5.15/tcp-remove-dead-code-from-tcp_sendmsg_locked.patch [new file with mode: 0644]

diff --git a/queue-5.15/asoc-codecs-add-wsa883x-amplifier-support.patch b/queue-5.15/asoc-codecs-add-wsa883x-amplifier-support.patch
new file mode 100644 (file)
index 0000000..351fcd3
--- /dev/null
@@ -0,0 +1,1385 @@
+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
+
diff --git a/queue-5.15/asoc-codecs-constify-static-sdw_slave_ops-struct.patch b/queue-5.15/asoc-codecs-constify-static-sdw_slave_ops-struct.patch
new file mode 100644 (file)
index 0000000..b2509da
--- /dev/null
@@ -0,0 +1,121 @@
+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
+
diff --git a/queue-5.15/asoc-codecs-wcd938x-convert-to-platform-remove-callb.patch b/queue-5.15/asoc-codecs-wcd938x-convert-to-platform-remove-callb.patch
new file mode 100644 (file)
index 0000000..64f4677
--- /dev/null
@@ -0,0 +1,64 @@
+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
+
diff --git a/queue-5.15/asoc-codecs-wcd938x-fix-accessing-regmap-on-unattach.patch b/queue-5.15/asoc-codecs-wcd938x-fix-accessing-regmap-on-unattach.patch
new file mode 100644 (file)
index 0000000..246e50e
--- /dev/null
@@ -0,0 +1,2169 @@
+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
+
diff --git a/queue-5.15/asoc-codecs-wcd938x-fix-regulator-leaks-on-probe-err.patch b/queue-5.15/asoc-codecs-wcd938x-fix-regulator-leaks-on-probe-err.patch
new file mode 100644 (file)
index 0000000..6b48b9a
--- /dev/null
@@ -0,0 +1,80 @@
+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
+
diff --git a/queue-5.15/asoc-codecs-wcd938x-fix-resource-leaks-on-bind-error.patch b/queue-5.15/asoc-codecs-wcd938x-fix-resource-leaks-on-bind-error.patch
new file mode 100644 (file)
index 0000000..a41a538
--- /dev/null
@@ -0,0 +1,138 @@
+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
+
diff --git a/queue-5.15/asoc-codecs-wcd938x-fix-runtime-pm-imbalance-on-remo.patch b/queue-5.15/asoc-codecs-wcd938x-fix-runtime-pm-imbalance-on-remo.patch
new file mode 100644 (file)
index 0000000..25e0c75
--- /dev/null
@@ -0,0 +1,48 @@
+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
+
diff --git a/queue-5.15/asoc-codecs-wcd938x-simplify-with-dev_err_probe.patch b/queue-5.15/asoc-codecs-wcd938x-simplify-with-dev_err_probe.patch
new file mode 100644 (file)
index 0000000..cae4a30
--- /dev/null
@@ -0,0 +1,65 @@
+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
+
diff --git a/queue-5.15/asoc-rt1318-add-rt1318-sdca-vendor-specific-driver.patch b/queue-5.15/asoc-rt1318-add-rt1318-sdca-vendor-specific-driver.patch
new file mode 100644 (file)
index 0000000..9805d30
--- /dev/null
@@ -0,0 +1,1069 @@
+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
+
diff --git a/queue-5.15/asoc-rt9120-add-rt9210-audio-amplifier-support.patch b/queue-5.15/asoc-rt9120-add-rt9210-audio-amplifier-support.patch
new file mode 100644 (file)
index 0000000..366a859
--- /dev/null
@@ -0,0 +1,570 @@
+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
+
diff --git a/queue-5.15/mcb-lpc-reallocate-memory-region-to-avoid-memory-ove.patch b/queue-5.15/mcb-lpc-reallocate-memory-region-to-avoid-memory-ove.patch
new file mode 100644 (file)
index 0000000..5023f24
--- /dev/null
@@ -0,0 +1,93 @@
+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
+
diff --git a/queue-5.15/mcb-return-actual-parsed-size-when-reading-chameleon.patch b/queue-5.15/mcb-return-actual-parsed-size-when-reading-chameleon.patch
new file mode 100644 (file)
index 0000000..a635340
--- /dev/null
@@ -0,0 +1,81 @@
+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
+
diff --git a/queue-5.15/mmc-block-ioctl-do-write-error-check-for-spi.patch b/queue-5.15/mmc-block-ioctl-do-write-error-check-for-spi.patch
new file mode 100644 (file)
index 0000000..148b51e
--- /dev/null
@@ -0,0 +1,52 @@
+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
+
diff --git a/queue-5.15/mmc-core-adjust-polling-interval-for-cmd1.patch b/queue-5.15/mmc-core-adjust-polling-interval-for-cmd1.patch
new file mode 100644 (file)
index 0000000..3e71d63
--- /dev/null
@@ -0,0 +1,159 @@
+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
+
diff --git a/queue-5.15/mmc-core-align-to-common-busy-polling-behaviour-for-.patch b/queue-5.15/mmc-core-align-to-common-busy-polling-behaviour-for-.patch
new file mode 100644 (file)
index 0000000..a60705f
--- /dev/null
@@ -0,0 +1,95 @@
+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
+
diff --git a/queue-5.15/mmc-core-change-__mmc_poll_for_busy-parameter-type.patch b/queue-5.15/mmc-core-change-__mmc_poll_for_busy-parameter-type.patch
new file mode 100644 (file)
index 0000000..eb6f40e
--- /dev/null
@@ -0,0 +1,116 @@
+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
+
diff --git a/queue-5.15/mmc-core-fix-error-propagation-for-some-ioctl-comman.patch b/queue-5.15/mmc-core-fix-error-propagation-for-some-ioctl-comman.patch
new file mode 100644 (file)
index 0000000..315fd02
--- /dev/null
@@ -0,0 +1,100 @@
+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
+
diff --git a/queue-5.15/mmc-core-restore-almost-the-busy-polling-for-mmc_sen.patch b/queue-5.15/mmc-core-restore-almost-the-busy-polling-for-mmc_sen.patch
new file mode 100644 (file)
index 0000000..fdb8b27
--- /dev/null
@@ -0,0 +1,144 @@
+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
+
diff --git a/queue-5.15/mptcp-more-conservative-check-for-zero-probes.patch b/queue-5.15/mptcp-more-conservative-check-for-zero-probes.patch
new file mode 100644 (file)
index 0000000..0faec63
--- /dev/null
@@ -0,0 +1,98 @@
+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
+
diff --git a/queue-5.15/pinctrl-qcom-lpass-lpi-fix-concurrent-register-updat.patch b/queue-5.15/pinctrl-qcom-lpass-lpi-fix-concurrent-register-updat.patch
new file mode 100644 (file)
index 0000000..09dfaeb
--- /dev/null
@@ -0,0 +1,124 @@
+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
+
diff --git a/queue-5.15/series b/queue-5.15/series
new file mode 100644 (file)
index 0000000..adb2cef
--- /dev/null
@@ -0,0 +1,22 @@
+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
diff --git a/queue-5.15/tcp-cleanup-tcp_remove_empty_skb-use.patch b/queue-5.15/tcp-cleanup-tcp_remove_empty_skb-use.patch
new file mode 100644 (file)
index 0000000..736795a
--- /dev/null
@@ -0,0 +1,95 @@
+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
+
diff --git a/queue-5.15/tcp-remove-dead-code-from-tcp_sendmsg_locked.patch b/queue-5.15/tcp-remove-dead-code-from-tcp_sendmsg_locked.patch
new file mode 100644 (file)
index 0000000..4dbddaf
--- /dev/null
@@ -0,0 +1,51 @@
+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
+