summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Rhodes <drhodes@opensource.cirrus.com>2021-09-07 17:57:18 -0500
committerMark Brown <broonie@kernel.org>2021-09-13 01:45:11 +0100
commit6450ef55905688602175fae4ed1bfbfef6a14dde (patch)
treed5d9bc0e0df96f510625d3d93cc11f7b9388e273
parent0c7985e1b90c1eabc75b01f971eb89733cc51979 (diff)
downloadlinux-6450ef55905688602175fae4ed1bfbfef6a14dde.tar.gz
linux-6450ef55905688602175fae4ed1bfbfef6a14dde.tar.bz2
linux-6450ef55905688602175fae4ed1bfbfef6a14dde.zip
ASoC: cs35l41: CS35L41 Boosted Smart Amplifier
SoC Audio driver for the Cirrus Logic CS35L41 amplifier Signed-off-by: David Rhodes <drhodes@opensource.cirrus.com> Tested-by: Charles Keepax <ckeepax@opensource.cirrus.com> Link: https://lore.kernel.org/r/20210907225719.2018115-2-drhodes@opensource.cirrus.com Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--include/sound/cs35l41.h34
-rw-r--r--sound/soc/codecs/Kconfig12
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/cs35l41-i2c.c114
-rw-r--r--sound/soc/codecs/cs35l41-spi.c143
-rw-r--r--sound/soc/codecs/cs35l41-tables.c597
-rw-r--r--sound/soc/codecs/cs35l41.c1545
-rw-r--r--sound/soc/codecs/cs35l41.h775
8 files changed, 3224 insertions, 0 deletions
diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h
new file mode 100644
index 000000000000..1f1e3c6c9be1
--- /dev/null
+++ b/include/sound/cs35l41.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * linux/sound/cs35l41.h -- Platform data for CS35L41
+ *
+ * Copyright (c) 2017-2021 Cirrus Logic Inc.
+ *
+ * Author: David Rhodes <david.rhodes@cirrus.com>
+ */
+
+#ifndef __CS35L41_H
+#define __CS35L41_H
+
+enum cs35l41_clk_ids {
+ CS35L41_CLKID_SCLK = 0,
+ CS35L41_CLKID_LRCLK = 1,
+ CS35L41_CLKID_MCLK = 4,
+};
+
+struct cs35l41_irq_cfg {
+ bool irq_pol_inv;
+ bool irq_out_en;
+ int irq_src_sel;
+};
+
+struct cs35l41_platform_data {
+ int bst_ind;
+ int bst_ipk;
+ int bst_cap;
+ int dout_hiz;
+ struct cs35l41_irq_cfg irq_config1;
+ struct cs35l41_irq_cfg irq_config2;
+};
+
+#endif /* __CS35L41_H */
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 82ee233a269d..53aa20bc7707 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -61,6 +61,8 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_CS35L34
imply SND_SOC_CS35L35
imply SND_SOC_CS35L36
+ imply SND_SOC_CS35L41_SPI
+ imply SND_SOC_CS35L41_I2C
imply SND_SOC_CS42L42
imply SND_SOC_CS42L51_I2C
imply SND_SOC_CS42L52
@@ -602,6 +604,16 @@ config SND_SOC_CS35L36
tristate "Cirrus Logic CS35L36 CODEC"
depends on I2C
+config SND_SOC_CS35L41_SPI
+ tristate "Cirrus Logic CS35L41 CODEC (SPI)"
+ depends on SPI_MASTER
+ select REGMAP_SPI
+
+config SND_SOC_CS35L41_I2C
+ tristate "Cirrus Logic CS35L41 CODEC (I2C)"
+ depends on I2C
+ select REGMAP_I2C
+
config SND_SOC_CS42L42
tristate "Cirrus Logic CS42L42 CODEC"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8dcea2c4604a..8b580a9004ea 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -54,6 +54,8 @@ snd-soc-cs35l33-objs := cs35l33.o
snd-soc-cs35l34-objs := cs35l34.o
snd-soc-cs35l35-objs := cs35l35.o
snd-soc-cs35l36-objs := cs35l36.o
+snd-soc-cs35l41-spi-objs := cs35l41-spi.o cs35l41.o cs35l41-tables.o
+snd-soc-cs35l41-i2c-objs := cs35l41-i2c.o cs35l41.o cs35l41-tables.o
snd-soc-cs42l42-objs := cs42l42.o
snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
@@ -385,6 +387,8 @@ obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o
obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o
obj-$(CONFIG_SND_SOC_CS35L35) += snd-soc-cs35l35.o
obj-$(CONFIG_SND_SOC_CS35L36) += snd-soc-cs35l36.o
+obj-$(CONFIG_SND_SOC_CS35L41_SPI) += snd-soc-cs35l41-spi.o
+obj-$(CONFIG_SND_SOC_CS35L41_I2C) += snd-soc-cs35l41-i2c.o
obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
diff --git a/sound/soc/codecs/cs35l41-i2c.c b/sound/soc/codecs/cs35l41-i2c.c
new file mode 100644
index 000000000000..dc9da78df412
--- /dev/null
+++ b/sound/soc/codecs/cs35l41-i2c.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// cs35l41-i2c.c -- CS35l41 I2C driver
+//
+// Copyright 2017-2021 Cirrus Logic, Inc.
+//
+// Author: David Rhodes <david.rhodes@cirrus.com>
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <sound/cs35l41.h>
+#include "cs35l41.h"
+
+static struct regmap_config cs35l41_regmap_i2c = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = CS35L41_REGSTRIDE,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .max_register = CS35L41_LASTREG,
+ .reg_defaults = cs35l41_reg,
+ .num_reg_defaults = ARRAY_SIZE(cs35l41_reg),
+ .volatile_reg = cs35l41_volatile_reg,
+ .readable_reg = cs35l41_readable_reg,
+ .precious_reg = cs35l41_precious_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct i2c_device_id cs35l41_id_i2c[] = {
+ { "cs35l40", 0 },
+ { "cs35l41", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs35l41_id_i2c);
+
+static int cs35l41_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct cs35l41_private *cs35l41;
+ struct device *dev = &client->dev;
+ struct cs35l41_platform_data *pdata = dev_get_platdata(dev);
+ const struct regmap_config *regmap_config = &cs35l41_regmap_i2c;
+ int ret;
+
+ cs35l41 = devm_kzalloc(dev, sizeof(struct cs35l41_private), GFP_KERNEL);
+
+ if (!cs35l41)
+ return -ENOMEM;
+
+ cs35l41->dev = dev;
+ cs35l41->irq = client->irq;
+
+ i2c_set_clientdata(client, cs35l41);
+ cs35l41->regmap = devm_regmap_init_i2c(client, regmap_config);
+ if (IS_ERR(cs35l41->regmap)) {
+ ret = PTR_ERR(cs35l41->regmap);
+ dev_err(cs35l41->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ return cs35l41_probe(cs35l41, pdata);
+}
+
+static int cs35l41_i2c_remove(struct i2c_client *client)
+{
+ struct cs35l41_private *cs35l41 = i2c_get_clientdata(client);
+
+ return cs35l41_remove(cs35l41);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id cs35l41_of_match[] = {
+ { .compatible = "cirrus,cs35l40" },
+ { .compatible = "cirrus,cs35l41" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cs35l41_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cs35l41_acpi_match[] = {
+ { "CSC3541", 0 }, /* Cirrus Logic PnP ID + part ID */
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match);
+#endif
+
+static struct i2c_driver cs35l41_i2c_driver = {
+ .driver = {
+ .name = "cs35l41",
+ .of_match_table = of_match_ptr(cs35l41_of_match),
+ .acpi_match_table = ACPI_PTR(cs35l41_acpi_match),
+ },
+ .id_table = cs35l41_id_i2c,
+ .probe = cs35l41_i2c_probe,
+ .remove = cs35l41_i2c_remove,
+};
+
+module_i2c_driver(cs35l41_i2c_driver);
+
+MODULE_DESCRIPTION("I2C CS35L41 driver");
+MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c
new file mode 100644
index 000000000000..e253c6d82ce8
--- /dev/null
+++ b/sound/soc/codecs/cs35l41-spi.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// cs35l41-spi.c -- CS35l41 SPI driver
+//
+// Copyright 2017-2021 Cirrus Logic, Inc.
+//
+// Author: David Rhodes <david.rhodes@cirrus.com>
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#include <sound/cs35l41.h>
+#include "cs35l41.h"
+
+static struct regmap_config cs35l41_regmap_spi = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .pad_bits = 16,
+ .reg_stride = CS35L41_REGSTRIDE,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .max_register = CS35L41_LASTREG,
+ .reg_defaults = cs35l41_reg,
+ .num_reg_defaults = ARRAY_SIZE(cs35l41_reg),
+ .volatile_reg = cs35l41_volatile_reg,
+ .readable_reg = cs35l41_readable_reg,
+ .precious_reg = cs35l41_precious_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct spi_device_id cs35l41_id_spi[] = {
+ { "cs35l40", 0 },
+ { "cs35l41", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(spi, cs35l41_id_spi);
+
+static void cs35l41_spi_otp_setup(struct cs35l41_private *cs35l41,
+ bool is_pre_setup, unsigned int *freq)
+{
+ struct spi_device *spi;
+ u32 orig_spi_freq;
+
+ spi = to_spi_device(cs35l41->dev);
+
+ if (!spi) {
+ dev_err(cs35l41->dev, "%s: No SPI device\n", __func__);
+ return;
+ }
+
+ if (is_pre_setup) {
+ orig_spi_freq = spi->max_speed_hz;
+ if (orig_spi_freq > CS35L41_SPI_MAX_FREQ_OTP) {
+ spi->max_speed_hz = CS35L41_SPI_MAX_FREQ_OTP;
+ spi_setup(spi);
+ }
+ *freq = orig_spi_freq;
+ } else {
+ if (spi->max_speed_hz != *freq) {
+ spi->max_speed_hz = *freq;
+ spi_setup(spi);
+ }
+ }
+}
+
+static int cs35l41_spi_probe(struct spi_device *spi)
+{
+ const struct regmap_config *regmap_config = &cs35l41_regmap_spi;
+ struct cs35l41_platform_data *pdata =
+ dev_get_platdata(&spi->dev);
+ struct cs35l41_private *cs35l41;
+ int ret;
+
+ cs35l41 = devm_kzalloc(&spi->dev,
+ sizeof(struct cs35l41_private),
+ GFP_KERNEL);
+ if (!cs35l41)
+ return -ENOMEM;
+
+
+ spi_set_drvdata(spi, cs35l41);
+ cs35l41->regmap = devm_regmap_init_spi(spi, regmap_config);
+ if (IS_ERR(cs35l41->regmap)) {
+ ret = PTR_ERR(cs35l41->regmap);
+ dev_err(&spi->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ cs35l41->dev = &spi->dev;
+ cs35l41->irq = spi->irq;
+ cs35l41->otp_setup = cs35l41_spi_otp_setup;
+
+ return cs35l41_probe(cs35l41, pdata);
+}
+
+static int cs35l41_spi_remove(struct spi_device *spi)
+{
+ struct cs35l41_private *cs35l41 = spi_get_drvdata(spi);
+
+ return cs35l41_remove(cs35l41);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id cs35l41_of_match[] = {
+ { .compatible = "cirrus,cs35l40" },
+ { .compatible = "cirrus,cs35l41" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cs35l41_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cs35l41_acpi_match[] = {
+ { "CSC3541", 0 }, /* Cirrus Logic PnP ID + part ID */
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match);
+#endif
+
+static struct spi_driver cs35l41_spi_driver = {
+ .driver = {
+ .name = "cs35l41",
+ .of_match_table = of_match_ptr(cs35l41_of_match),
+ .acpi_match_table = ACPI_PTR(cs35l41_acpi_match),
+ },
+ .id_table = cs35l41_id_spi,
+ .probe = cs35l41_spi_probe,
+ .remove = cs35l41_spi_remove,
+};
+
+module_spi_driver(cs35l41_spi_driver);
+
+MODULE_DESCRIPTION("SPI CS35L41 driver");
+MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l41-tables.c b/sound/soc/codecs/cs35l41-tables.c
new file mode 100644
index 000000000000..155db0e6e3d8
--- /dev/null
+++ b/sound/soc/codecs/cs35l41-tables.c
@@ -0,0 +1,597 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// cs35l41-tables.c -- CS35L41 ALSA SoC audio driver
+//
+// Copyright 2017-2021 Cirrus Logic, Inc.
+//
+// Author: David Rhodes <david.rhodes@cirrus.com>
+
+#include "cs35l41.h"
+
+const struct reg_default cs35l41_reg[CS35L41_MAX_CACHE_REG] = {
+ {CS35L41_PWR_CTRL1, 0x00000000},
+ {CS35L41_PWR_CTRL3, 0x01000010},
+ {CS35L41_GPIO_PAD_CONTROL, 0x00000000},
+ {CS35L41_SP_ENABLES, 0x00000000},
+ {CS35L41_SP_RATE_CTRL, 0x00000028},
+ {CS35L41_SP_FORMAT, 0x18180200},
+ {CS35L41_SP_HIZ_CTRL, 0x00000002},
+ {CS35L41_SP_FRAME_TX_SLOT, 0x03020100},
+ {CS35L41_SP_FRAME_RX_SLOT, 0x00000100},
+ {CS35L41_SP_TX_WL, 0x00000018},
+ {CS35L41_SP_RX_WL, 0x00000018},
+ {CS35L41_DAC_PCM1_SRC, 0x00000008},
+ {CS35L41_ASP_TX1_SRC, 0x00000018},
+ {CS35L41_ASP_TX2_SRC, 0x00000019},
+ {CS35L41_ASP_TX3_SRC, 0x00000020},
+ {CS35L41_ASP_TX4_SRC, 0x00000021},
+ {CS35L41_DSP1_RX1_SRC, 0x00000008},
+ {CS35L41_DSP1_RX2_SRC, 0x00000009},
+ {CS35L41_DSP1_RX3_SRC, 0x00000018},
+ {CS35L41_DSP1_RX4_SRC, 0x00000019},
+ {CS35L41_DSP1_RX5_SRC, 0x00000020},
+ {CS35L41_DSP1_RX6_SRC, 0x00000021},
+ {CS35L41_DSP1_RX7_SRC, 0x0000003A},
+ {CS35L41_DSP1_RX8_SRC, 0x00000001},
+ {CS35L41_NGATE1_SRC, 0x00000008},
+ {CS35L41_NGATE2_SRC, 0x00000009},
+ {CS35L41_AMP_DIG_VOL_CTRL, 0x00008000},
+ {CS35L41_CLASSH_CFG, 0x000B0405},
+ {CS35L41_WKFET_CFG, 0x00000111},
+ {CS35L41_NG_CFG, 0x00000033},
+ {CS35L41_AMP_GAIN_CTRL, 0x00000273},
+ {CS35L41_GPIO1_CTRL1, 0xE1000001},
+ {CS35L41_GPIO2_CTRL1, 0xE1000001},
+ {CS35L41_MIXER_NGATE_CFG, 0x00000000},
+ {CS35L41_MIXER_NGATE_CH1_CFG, 0x00000303},
+ {CS35L41_MIXER_NGATE_CH2_CFG, 0x00000303},
+};
+
+bool cs35l41_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS35L41_DEVID:
+ case CS35L41_REVID:
+ case CS35L41_FABID:
+ case CS35L41_RELID:
+ case CS35L41_OTPID:
+ case CS35L41_TEST_KEY_CTL:
+ case CS35L41_USER_KEY_CTL:
+ case CS35L41_OTP_CTRL0:
+ case CS35L41_OTP_CTRL3:
+ case CS35L41_OTP_CTRL4:
+ case CS35L41_OTP_CTRL5:
+ case CS35L41_OTP_CTRL6:
+ case CS35L41_OTP_CTRL7:
+ case CS35L41_OTP_CTRL8:
+ case CS35L41_PWR_CTRL1:
+ case CS35L41_PWR_CTRL2:
+ case CS35L41_PWR_CTRL3:
+ case CS35L41_CTRL_OVRRIDE:
+ case CS35L41_AMP_OUT_MUTE:
+ case CS35L41_PROTECT_REL_ERR_IGN:
+ case CS35L41_GPIO_PAD_CONTROL:
+ case CS35L41_JTAG_CONTROL:
+ case CS35L41_PLL_CLK_CTRL:
+ case CS35L41_DSP_CLK_CTRL:
+ case CS35L41_GLOBAL_CLK_CTRL:
+ case CS35L41_DATA_FS_SEL:
+ case CS35L41_MDSYNC_EN:
+ case CS35L41_MDSYNC_TX_ID:
+ case CS35L41_MDSYNC_PWR_CTRL:
+ case CS35L41_MDSYNC_DATA_TX:
+ case CS35L41_MDSYNC_TX_STATUS:
+ case CS35L41_MDSYNC_DATA_RX:
+ case CS35L41_MDSYNC_RX_STATUS:
+ case CS35L41_MDSYNC_ERR_STATUS:
+ case CS35L41_MDSYNC_SYNC_PTE2:
+ case CS35L41_MDSYNC_SYNC_PTE3:
+ case CS35L41_MDSYNC_SYNC_MSM_STATUS:
+ case CS35L41_BSTCVRT_VCTRL1:
+ case CS35L41_BSTCVRT_VCTRL2:
+ case CS35L41_BSTCVRT_PEAK_CUR:
+ case CS35L41_BSTCVRT_SFT_RAMP:
+ case CS35L41_BSTCVRT_COEFF:
+ case CS35L41_BSTCVRT_SLOPE_LBST:
+ case CS35L41_BSTCVRT_SW_FREQ:
+ case CS35L41_BSTCVRT_DCM_CTRL:
+ case CS35L41_BSTCVRT_DCM_MODE_FORCE:
+ case CS35L41_BSTCVRT_OVERVOLT_CTRL:
+ case CS35L41_VI_VOL_POL:
+ case CS35L41_DTEMP_WARN_THLD:
+ case CS35L41_DTEMP_CFG:
+ case CS35L41_DTEMP_EN:
+ case CS35L41_VPVBST_FS_SEL:
+ case CS35L41_SP_ENABLES:
+ case CS35L41_SP_RATE_CTRL:
+ case CS35L41_SP_FORMAT:
+ case CS35L41_SP_HIZ_CTRL:
+ case CS35L41_SP_FRAME_TX_SLOT:
+ case CS35L41_SP_FRAME_RX_SLOT:
+ case CS35L41_SP_TX_WL:
+ case CS35L41_SP_RX_WL:
+ case CS35L41_DAC_PCM1_SRC:
+ case CS35L41_ASP_TX1_SRC:
+ case CS35L41_ASP_TX2_SRC:
+ case CS35L41_ASP_TX3_SRC:
+ case CS35L41_ASP_TX4_SRC:
+ case CS35L41_DSP1_RX1_SRC:
+ case CS35L41_DSP1_RX2_SRC:
+ case CS35L41_DSP1_RX3_SRC:
+ case CS35L41_DSP1_RX4_SRC:
+ case CS35L41_DSP1_RX5_SRC:
+ case CS35L41_DSP1_RX6_SRC:
+ case CS35L41_DSP1_RX7_SRC:
+ case CS35L41_DSP1_RX8_SRC:
+ case CS35L41_NGATE1_SRC:
+ case CS35L41_NGATE2_SRC:
+ case CS35L41_AMP_DIG_VOL_CTRL:
+ case CS35L41_VPBR_CFG:
+ case CS35L41_VBBR_CFG:
+ case CS35L41_VPBR_STATUS:
+ case CS35L41_VBBR_STATUS:
+ case CS35L41_OVERTEMP_CFG:
+ case CS35L41_AMP_ERR_VOL:
+ case CS35L41_VOL_STATUS_TO_DSP:
+ case CS35L41_CLASSH_CFG:
+ case CS35L41_WKFET_CFG:
+ case CS35L41_NG_CFG:
+ case CS35L41_AMP_GAIN_CTRL:
+ case CS35L41_DAC_MSM_CFG:
+ case CS35L41_IRQ1_CFG:
+ case CS35L41_IRQ1_STATUS:
+ case CS35L41_IRQ1_STATUS1:
+ case CS35L41_IRQ1_STATUS2:
+ case CS35L41_IRQ1_STATUS3:
+ case CS35L41_IRQ1_STATUS4:
+ case CS35L41_IRQ1_RAW_STATUS1:
+ case CS35L41_IRQ1_RAW_STATUS2:
+ case CS35L41_IRQ1_RAW_STATUS3:
+ case CS35L41_IRQ1_RAW_STATUS4:
+ case CS35L41_IRQ1_MASK1:
+ case CS35L41_IRQ1_MASK2:
+ case CS35L41_IRQ1_MASK3:
+ case CS35L41_IRQ1_MASK4:
+ case CS35L41_IRQ1_FRC1:
+ case CS35L41_IRQ1_FRC2:
+ case CS35L41_IRQ1_FRC3:
+ case CS35L41_IRQ1_FRC4:
+ case CS35L41_IRQ1_EDGE1:
+ case CS35L41_IRQ1_EDGE4:
+ case CS35L41_IRQ1_POL1:
+ case CS35L41_IRQ1_POL2:
+ case CS35L41_IRQ1_POL3:
+ case CS35L41_IRQ1_POL4:
+ case CS35L41_IRQ1_DB3:
+ case CS35L41_IRQ2_CFG:
+ case CS35L41_IRQ2_STATUS:
+ case CS35L41_IRQ2_STATUS1:
+ case CS35L41_IRQ2_STATUS2:
+ case CS35L41_IRQ2_STATUS3:
+ case CS35L41_IRQ2_STATUS4:
+ case CS35L41_IRQ2_RAW_STATUS1:
+ case CS35L41_IRQ2_RAW_STATUS2:
+ case CS35L41_IRQ2_RAW_STATUS3:
+ case CS35L41_IRQ2_RAW_STATUS4:
+ case CS35L41_IRQ2_MASK1:
+ case CS35L41_IRQ2_MASK2:
+ case CS35L41_IRQ2_MASK3:
+ case CS35L41_IRQ2_MASK4:
+ case CS35L41_IRQ2_FRC1:
+ case CS35L41_IRQ2_FRC2:
+ case CS35L41_IRQ2_FRC3:
+ case CS35L41_IRQ2_FRC4:
+ case CS35L41_IRQ2_EDGE1:
+ case CS35L41_IRQ2_EDGE4:
+ case CS35L41_IRQ2_POL1:
+ case CS35L41_IRQ2_POL2:
+ case CS35L41_IRQ2_POL3:
+ case CS35L41_IRQ2_POL4:
+ case CS35L41_IRQ2_DB3:
+ case CS35L41_GPIO_STATUS1:
+ case CS35L41_GPIO1_CTRL1:
+ case CS35L41_GPIO2_CTRL1:
+ case CS35L41_MIXER_NGATE_CFG:
+ case CS35L41_MIXER_NGATE_CH1_CFG:
+ case CS35L41_MIXER_NGATE_CH2_CFG:
+ case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8:
+ case CS35L41_CLOCK_DETECT_1:
+ case CS35L41_DIE_STS1:
+ case CS35L41_DIE_STS2:
+ case CS35L41_TEMP_CAL1:
+ case CS35L41_TEMP_CAL2:
+ case CS35L41_OTP_TRIM_1:
+ case CS35L41_OTP_TRIM_2:
+ case CS35L41_OTP_TRIM_3:
+ case CS35L41_OTP_TRIM_4:
+ case CS35L41_OTP_TRIM_5:
+ case CS35L41_OTP_TRIM_6:
+ case CS35L41_OTP_TRIM_7:
+ case CS35L41_OTP_TRIM_8:
+ case CS35L41_OTP_TRIM_9:
+ case CS35L41_OTP_TRIM_10:
+ case CS35L41_OTP_TRIM_11:
+ case CS35L41_OTP_TRIM_12:
+ case CS35L41_OTP_TRIM_13:
+ case CS35L41_OTP_TRIM_14:
+ case CS35L41_OTP_TRIM_15:
+ case CS35L41_OTP_TRIM_16:
+ case CS35L41_OTP_TRIM_17:
+ case CS35L41_OTP_TRIM_18:
+ case CS35L41_OTP_TRIM_19:
+ case CS35L41_OTP_TRIM_20:
+ case CS35L41_OTP_TRIM_21:
+ case CS35L41_OTP_TRIM_22:
+ case CS35L41_OTP_TRIM_23:
+ case CS35L41_OTP_TRIM_24:
+ case CS35L41_OTP_TRIM_25:
+ case CS35L41_OTP_TRIM_26:
+ case CS35L41_OTP_TRIM_27:
+ case CS35L41_OTP_TRIM_28:
+ case CS35L41_OTP_TRIM_29:
+ case CS35L41_OTP_TRIM_30:
+ case CS35L41_OTP_TRIM_31:
+ case CS35L41_OTP_TRIM_32:
+ case CS35L41_OTP_TRIM_33:
+ case CS35L41_OTP_TRIM_34:
+ case CS35L41_OTP_TRIM_35:
+ case CS35L41_OTP_TRIM_36:
+ case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:
+ /*test regs*/
+ case CS35L41_PLL_OVR:
+ case CS35L41_BST_TEST_DUTY:
+ case CS35L41_DIGPWM_IOCTRL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool cs35l41_precious_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool cs35l41_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS35L41_DEVID:
+ case CS35L41_SFT_RESET:
+ case CS35L41_FABID:
+ case CS35L41_REVID:
+ case CS35L41_DTEMP_EN:
+ case CS35L41_IRQ1_STATUS:
+ case CS35L41_IRQ1_STATUS1:
+ case CS35L41_IRQ1_STATUS2:
+ case CS35L41_IRQ1_STATUS3:
+ case CS35L41_IRQ1_STATUS4:
+ case CS35L41_IRQ1_RAW_STATUS1:
+ case CS35L41_IRQ1_RAW_STATUS2:
+ case CS35L41_IRQ1_RAW_STATUS3:
+ case CS35L41_IRQ1_RAW_STATUS4:
+ case CS35L41_IRQ1_FRC1:
+ case CS35L41_IRQ1_FRC2:
+ case CS35L41_IRQ1_FRC3:
+ case CS35L41_IRQ1_FRC4:
+ case CS35L41_IRQ1_EDGE1:
+ case CS35L41_IRQ1_EDGE4:
+ case CS35L41_IRQ1_POL1:
+ case CS35L41_IRQ1_POL2:
+ case CS35L41_IRQ1_POL3:
+ case CS35L41_IRQ1_POL4:
+ case CS35L41_IRQ1_DB3:
+ case CS35L41_IRQ2_STATUS:
+ case CS35L41_IRQ2_STATUS1:
+ case CS35L41_IRQ2_STATUS2:
+ case CS35L41_IRQ2_STATUS3:
+ case CS35L41_IRQ2_STATUS4:
+ case CS35L41_IRQ2_RAW_STATUS1:
+ case CS35L41_IRQ2_RAW_STATUS2:
+ case CS35L41_IRQ2_RAW_STATUS3:
+ case CS35L41_IRQ2_RAW_STATUS4:
+ case CS35L41_IRQ2_FRC1:
+ case CS35L41_IRQ2_FRC2:
+ case CS35L41_IRQ2_FRC3:
+ case CS35L41_IRQ2_FRC4:
+ case CS35L41_IRQ2_EDGE1:
+ case CS35L41_IRQ2_EDGE4:
+ case CS35L41_IRQ2_POL1:
+ case CS35L41_IRQ2_POL2:
+ case CS35L41_IRQ2_POL3:
+ case CS35L41_IRQ2_POL4:
+ case CS35L41_IRQ2_DB3:
+ case CS35L41_GPIO_STATUS1:
+ case CS35L41_OTP_TRIM_1:
+ case CS35L41_OTP_TRIM_2:
+ case CS35L41_OTP_TRIM_3:
+ case CS35L41_OTP_TRIM_4:
+ case CS35L41_OTP_TRIM_5:
+ case CS35L41_OTP_TRIM_6:
+ case CS35L41_OTP_TRIM_7:
+ case CS35L41_OTP_TRIM_8:
+ case CS35L41_OTP_TRIM_9:
+ case CS35L41_OTP_TRIM_10:
+ case CS35L41_OTP_TRIM_11:
+ case CS35L41_OTP_TRIM_12:
+ case CS35L41_OTP_TRIM_13:
+ case CS35L41_OTP_TRIM_14:
+ case CS35L41_OTP_TRIM_15:
+ case CS35L41_OTP_TRIM_16:
+ case CS35L41_OTP_TRIM_17:
+ case CS35L41_OTP_TRIM_18:
+ case CS35L41_OTP_TRIM_19:
+ case CS35L41_OTP_TRIM_20:
+ case CS35L41_OTP_TRIM_21:
+ case CS35L41_OTP_TRIM_22:
+ case CS35L41_OTP_TRIM_23:
+ case CS35L41_OTP_TRIM_24:
+ case CS35L41_OTP_TRIM_25:
+ case CS35L41_OTP_TRIM_26:
+ case CS35L41_OTP_TRIM_27:
+ case CS35L41_OTP_TRIM_28:
+ case CS35L41_OTP_TRIM_29:
+ case CS35L41_OTP_TRIM_30:
+ case CS35L41_OTP_TRIM_31:
+ case CS35L41_OTP_TRIM_32:
+ case CS35L41_OTP_TRIM_33:
+ case CS35L41_OTP_TRIM_34:
+ case CS35L41_OTP_TRIM_35:
+ case CS35L41_OTP_TRIM_36:
+ case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct cs35l41_otp_packed_element_t
+ otp_map_1[CS35L41_NUM_OTP_ELEM] = {
+ /* addr shift size */
+ {0x00002030, 0, 4}, /*TRIM_OSC_FREQ_TRIM*/
+ {0x00002030, 7, 1}, /*TRIM_OSC_TRIM_DONE*/
+ {0x0000208c, 24, 6}, /*TST_DIGREG_VREF_TRIM*/
+ {0x00002090, 14, 4}, /*TST_REF_TRIM*/
+ {0x00002090, 10, 4}, /*TST_REF_TEMPCO_TRIM*/
+ {0x0000300C, 11, 4}, /*PLL_LDOA_TST_VREF_TRIM*/
+ {0x0000394C, 23, 2}, /*BST_ATEST_CM_VOFF*/
+ {0x00003950, 0, 7}, /*BST_ATRIM_IADC_OFFSET*/
+ {0x00003950, 8, 7}, /*BST_ATRIM_IADC_GAIN1*/
+ {0x00003950, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET1*/
+ {0x00003950, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN1*/
+ {0x00003954, 0, 7}, /*BST_ATRIM_IADC_OFFSET2*/
+ {0x00003954, 8, 7}, /*BST_ATRIM_IADC_GAIN2*/
+ {0x00003954, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET2*/
+ {0x00003954, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN2*/
+ {0x00003958, 0, 7}, /*BST_ATRIM_IADC_OFFSET3*/
+ {0x00003958, 8, 7}, /*BST_ATRIM_IADC_GAIN3*/
+ {0x00003958, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET3*/
+ {0x00003958, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN3*/
+ {0x0000395C, 0, 7}, /*BST_ATRIM_IADC_OFFSET4*/
+ {0x0000395C, 8, 7}, /*BST_ATRIM_IADC_GAIN4*/
+ {0x0000395C, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET4*/
+ {0x0000395C, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN4*/
+ {0x0000416C, 0, 8}, /*VMON_GAIN_OTP_VAL*/
+ {0x00004160, 0, 7}, /*VMON_OFFSET_OTP_VAL*/
+ {0x0000416C, 8, 8}, /*IMON_GAIN_OTP_VAL*/
+ {0x00004160, 16, 10}, /*IMON_OFFSET_OTP_VAL*/
+ {0x0000416C, 16, 12}, /*VMON_CM_GAIN_OTP_VAL*/
+ {0x0000416C, 28, 1}, /*VMON_CM_GAIN_SIGN_OTP_VAL*/
+ {0x00004170, 0, 6}, /*IMON_CAL_TEMPCO_OTP_VAL*/
+ {0x00004170, 6, 1}, /*IMON_CAL_TEMPCO_SIGN_OTP*/
+ {0x00004170, 8, 6}, /*IMON_CAL_TEMPCO2_OTP_VAL*/
+ {0x00004170, 14, 1}, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/
+ {0x00004170, 16, 9}, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/
+ {0x00004360, 0, 5}, /*TEMP_GAIN_OTP_VAL*/
+ {0x00004360, 6, 9}, /*TEMP_OFFSET_OTP_VAL*/
+ {0x00004448, 0, 8}, /*VP_SARADC_OFFSET*/
+ {0x00004448, 8, 8}, /*VP_GAIN_INDEX*/
+ {0x00004448, 16, 8}, /*VBST_SARADC_OFFSET*/
+ {0x00004448, 24, 8}, /*VBST_GAIN_INDEX*/
+ {0x0000444C, 0, 3}, /*ANA_SELINVREF*/
+ {0x00006E30, 0, 5}, /*GAIN_ERR_COEFF_0*/
+ {0x00006E30, 8, 5}, /*GAIN_ERR_COEFF_1*/
+ {0x00006E30, 16, 5}, /*GAIN_ERR_COEFF_2*/
+ {0x00006E30, 24, 5}, /*GAIN_ERR_COEFF_3*/
+ {0x00006E34, 0, 5}, /*GAIN_ERR_COEFF_4*/
+ {0x00006E34, 8, 5}, /*GAIN_ERR_COEFF_5*/
+ {0x00006E34, 16, 5}, /*GAIN_ERR_COEFF_6*/
+ {0x00006E34, 24, 5}, /*GAIN_ERR_COEFF_7*/
+ {0x00006E38, 0, 5}, /*GAIN_ERR_COEFF_8*/
+ {0x00006E38, 8, 5}, /*GAIN_ERR_COEFF_9*/
+ {0x00006E38, 16, 5}, /*GAIN_ERR_COEFF_10*/
+ {0x00006E38, 24, 5}, /*GAIN_ERR_COEFF_11*/
+ {0x00006E3C, 0, 5}, /*GAIN_ERR_COEFF_12*/
+ {0x00006E3C, 8, 5}, /*GAIN_ERR_COEFF_13*/
+ {0x00006E3C, 16, 5}, /*GAIN_ERR_COEFF_14*/
+ {0x00006E3C, 24, 5}, /*GAIN_ERR_COEFF_15*/
+ {0x00006E40, 0, 5}, /*GAIN_ERR_COEFF_16*/
+ {0x00006E40, 8, 5}, /*GAIN_ERR_COEFF_17*/
+ {0x00006E40, 16, 5}, /*GAIN_ERR_COEFF_18*/
+ {0x00006E40, 24, 5}, /*GAIN_ERR_COEFF_19*/
+ {0x00006E44, 0, 5}, /*GAIN_ERR_COEFF_20*/
+ {0x00006E48, 0, 10}, /*VOFF_GAIN_0*/
+ {0x00006E48, 10, 10}, /*VOFF_GAIN_1*/
+ {0x00006E48, 20, 10}, /*VOFF_GAIN_2*/
+ {0x00006E4C, 0, 10}, /*VOFF_GAIN_3*/
+ {0x00006E4C, 10, 10}, /*VOFF_GAIN_4*/
+ {0x00006E4C, 20, 10}, /*VOFF_GAIN_5*/
+ {0x00006E50, 0, 10}, /*VOFF_GAIN_6*/
+ {0x00006E50, 10, 10}, /*VOFF_GAIN_7*/
+ {0x00006E50, 20, 10}, /*VOFF_GAIN_8*/
+ {0x00006E54, 0, 10}, /*VOFF_GAIN_9*/
+ {0x00006E54, 10, 10}, /*VOFF_GAIN_10*/
+ {0x00006E54, 20, 10}, /*VOFF_GAIN_11*/
+ {0x00006E58, 0, 10}, /*VOFF_GAIN_12*/
+ {0x00006E58, 10, 10}, /*VOFF_GAIN_13*/
+ {0x00006E58, 20, 10}, /*VOFF_GAIN_14*/
+ {0x00006E5C, 0, 10}, /*VOFF_GAIN_15*/
+ {0x00006E5C, 10, 10}, /*VOFF_GAIN_16*/
+ {0x00006E5C, 20, 10}, /*VOFF_GAIN_17*/
+ {0x00006E60, 0, 10}, /*VOFF_GAIN_18*/
+ {0x00006E60, 10, 10}, /*VOFF_GAIN_19*/
+ {0x00006E60, 20, 10}, /*VOFF_GAIN_20*/
+ {0x00006E64, 0, 10}, /*VOFF_INT1*/
+ {0x00007418, 7, 5}, /*DS_SPK_INT1_CAP_TRIM*/
+ {0x0000741C, 0, 5}, /*DS_SPK_INT2_CAP_TRIM*/
+ {0x0000741C, 11, 4}, /*DS_SPK_LPF_CAP_TRIM*/
+ {0x0000741C, 19, 4}, /*DS_SPK_QUAN_CAP_TRIM*/
+ {0x00007434, 17, 1}, /*FORCE_CAL*/
+ {0x00007434, 18, 7}, /*CAL_OVERRIDE*/
+ {0x00007068, 0, 9}, /*MODIX*/
+ {0x0000410C, 7, 1}, /*VIMON_DLY_NOT_COMB*/
+ {0x0000400C, 0, 7}, /*VIMON_DLY*/
+ {0x00000000, 0, 1}, /*extra bit*/
+ {0x00017040, 0, 8}, /*X_COORDINATE*/
+ {0x00017040, 8, 8}, /*Y_COORDINATE*/
+ {0x00017040, 16, 8}, /*WAFER_ID*/
+ {0x00017040, 24, 8}, /*DVS*/
+ {0x00017044, 0, 24}, /*LOT_NUMBER*/
+};
+
+static const struct cs35l41_otp_packed_element_t
+ otp_map_2[CS35L41_NUM_OTP_ELEM] = {
+ /* addr shift size */
+ {0x00002030, 0, 4}, /*TRIM_OSC_FREQ_TRIM*/
+ {0x00002030, 7, 1}, /*TRIM_OSC_TRIM_DONE*/
+ {0x0000208c, 24, 6}, /*TST_DIGREG_VREF_TRIM*/
+ {0x00002090, 14, 4}, /*TST_REF_TRIM*/
+ {0x00002090, 10, 4}, /*TST_REF_TEMPCO_TRIM*/
+ {0x0000300C, 11, 4}, /*PLL_LDOA_TST_VREF_TRIM*/
+ {0x0000394C, 23, 2}, /*BST_ATEST_CM_VOFF*/
+ {0x00003950, 0, 7}, /*BST_ATRIM_IADC_OFFSET*/
+ {0x00003950, 8, 7}, /*BST_ATRIM_IADC_GAIN1*/
+ {0x00003950, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET1*/
+ {0x00003950, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN1*/
+ {0x00003954, 0, 7}, /*BST_ATRIM_IADC_OFFSET2*/
+ {0x00003954, 8, 7}, /*BST_ATRIM_IADC_GAIN2*/
+ {0x00003954, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET2*/
+ {0x00003954, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN2*/
+ {0x00003958, 0, 7}, /*BST_ATRIM_IADC_OFFSET3*/
+ {0x00003958, 8, 7}, /*BST_ATRIM_IADC_GAIN3*/
+ {0x00003958, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET3*/
+ {0x00003958, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN3*/
+ {0x0000395C, 0, 7}, /*BST_ATRIM_IADC_OFFSET4*/
+ {0x0000395C, 8, 7}, /*BST_ATRIM_IADC_GAIN4*/
+ {0x0000395C, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET4*/
+ {0x0000395C, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN4*/
+ {0x0000416C, 0, 8}, /*VMON_GAIN_OTP_VAL*/
+ {0x00004160, 0, 7}, /*VMON_OFFSET_OTP_VAL*/
+ {0x0000416C, 8, 8}, /*IMON_GAIN_OTP_VAL*/
+ {0x00004160, 16, 10}, /*IMON_OFFSET_OTP_VAL*/
+ {0x0000416C, 16, 12}, /*VMON_CM_GAIN_OTP_VAL*/
+ {0x0000416C, 28, 1}, /*VMON_CM_GAIN_SIGN_OTP_VAL*/
+ {0x00004170, 0, 6}, /*IMON_CAL_TEMPCO_OTP_VAL*/
+ {0x00004170, 6, 1}, /*IMON_CAL_TEMPCO_SIGN_OTP*/
+ {0x00004170, 8, 6}, /*IMON_CAL_TEMPCO2_OTP_VAL*/
+ {0x00004170, 14, 1}, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/
+ {0x00004170, 16, 9}, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/
+ {0x00004360, 0, 5}, /*TEMP_GAIN_OTP_VAL*/
+ {0x00004360, 6, 9}, /*TEMP_OFFSET_OTP_VAL*/
+ {0x00004448, 0, 8}, /*VP_SARADC_OFFSET*/
+ {0x00004448, 8, 8}, /*VP_GAIN_INDEX*/
+ {0x00004448, 16, 8}, /*VBST_SARADC_OFFSET*/
+ {0x00004448, 24, 8}, /*VBST_GAIN_INDEX*/
+ {0x0000444C, 0, 3}, /*ANA_SELINVREF*/
+ {0x00006E30, 0, 5}, /*GAIN_ERR_COEFF_0*/
+ {0x00006E30, 8, 5}, /*GAIN_ERR_COEFF_1*/
+ {0x00006E30, 16, 5}, /*GAIN_ERR_COEFF_2*/
+ {0x00006E30, 24, 5}, /*GAIN_ERR_COEFF_3*/
+ {0x00006E34, 0, 5}, /*GAIN_ERR_COEFF_4*/
+ {0x00006E34, 8, 5}, /*GAIN_ERR_COEFF_5*/
+ {0x00006E34, 16, 5}, /*GAIN_ERR_COEFF_6*/
+ {0x00006E34, 24, 5}, /*GAIN_ERR_COEFF_7*/
+ {0x00006E38, 0, 5}, /*GAIN_ERR_COEFF_8*/
+ {0x00006E38, 8, 5}, /*GAIN_ERR_COEFF_9*/
+ {0x00006E38, 16, 5}, /*GAIN_ERR_COEFF_10*/
+ {0x00006E38, 24, 5}, /*GAIN_ERR_COEFF_11*/
+ {0x00006E3C, 0, 5}, /*GAIN_ERR_COEFF_12*/
+ {0x00006E3C, 8, 5}, /*GAIN_ERR_COEFF_13*/
+ {0x00006E3C, 16, 5}, /*GAIN_ERR_COEFF_14*/
+ {0x00006E3C, 24, 5}, /*GAIN_ERR_COEFF_15*/
+ {0x00006E40, 0, 5}, /*GAIN_ERR_COEFF_16*/
+ {0x00006E40, 8, 5}, /*GAIN_ERR_COEFF_17*/
+ {0x00006E40, 16, 5}, /*GAIN_ERR_COEFF_18*/
+ {0x00006E40, 24, 5}, /*GAIN_ERR_COEFF_19*/
+ {0x00006E44, 0, 5}, /*GAIN_ERR_COEFF_20*/
+ {0x00006E48, 0, 10}, /*VOFF_GAIN_0*/
+ {0x00006E48, 10, 10}, /*VOFF_GAIN_1*/
+ {0x00006E48, 20, 10}, /*VOFF_GAIN_2*/
+ {0x00006E4C, 0, 10}, /*VOFF_GAIN_3*/
+ {0x00006E4C, 10, 10}, /*VOFF_GAIN_4*/
+ {0x00006E4C, 20, 10}, /*VOFF_GAIN_5*/
+ {0x00006E50, 0, 10}, /*VOFF_GAIN_6*/
+ {0x00006E50, 10, 10}, /*VOFF_GAIN_7*/
+ {0x00006E50, 20, 10}, /*VOFF_GAIN_8*/
+ {0x00006E54, 0, 10}, /*VOFF_GAIN_9*/
+ {0x00006E54, 10, 10}, /*VOFF_GAIN_10*/
+ {0x00006E54, 20, 10}, /*VOFF_GAIN_11*/
+ {0x00006E58, 0, 10}, /*VOFF_GAIN_12*/
+ {0x00006E58, 10, 10}, /*VOFF_GAIN_13*/
+ {0x00006E58, 20, 10}, /*VOFF_GAIN_14*/
+ {0x00006E5C, 0, 10}, /*VOFF_GAIN_15*/
+ {0x00006E5C, 10, 10}, /*VOFF_GAIN_16*/
+ {0x00006E5C, 20, 10}, /*VOFF_GAIN_17*/
+ {0x00006E60, 0, 10}, /*VOFF_GAIN_18*/
+ {0x00006E60, 10, 10}, /*VOFF_GAIN_19*/
+ {0x00006E60, 20, 10}, /*VOFF_GAIN_20*/
+ {0x00006E64, 0, 10}, /*VOFF_INT1*/
+ {0x00007418, 7, 5}, /*DS_SPK_INT1_CAP_TRIM*/
+ {0x0000741C, 0, 5}, /*DS_SPK_INT2_CAP_TRIM*/
+ {0x0000741C, 11, 4}, /*DS_SPK_LPF_CAP_TRIM*/
+ {0x0000741C, 19, 4}, /*DS_SPK_QUAN_CAP_TRIM*/
+ {0x00007434, 17, 1}, /*FORCE_CAL*/
+ {0x00007434, 18, 7}, /*CAL_OVERRIDE*/
+ {0x00007068, 0, 9}, /*MODIX*/
+ {0x0000410C, 7, 1}, /*VIMON_DLY_NOT_COMB*/
+ {0x0000400C, 0, 7}, /*VIMON_DLY*/
+ {0x00004000, 11, 1}, /*VMON_POL*/
+ {0x00017040, 0, 8}, /*X_COORDINATE*/
+ {0x00017040, 8, 8}, /*Y_COORDINATE*/
+ {0x00017040, 16, 8}, /*WAFER_ID*/
+ {0x00017040, 24, 8}, /*DVS*/
+ {0x00017044, 0, 24}, /*LOT_NUMBER*/
+};
+
+const struct cs35l41_otp_map_element_t
+ cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS] = {
+ {
+ .id = 0x01,
+ .map = otp_map_1,
+ .num_elements = CS35L41_NUM_OTP_ELEM,
+ .bit_offset = 16,
+ .word_offset = 2,
+ },
+ {
+ .id = 0x02,
+ .map = otp_map_2,
+ .num_elements = CS35L41_NUM_OTP_ELEM,
+ .bit_offset = 16,
+ .word_offset = 2,
+ },
+ {
+ .id = 0x03,
+ .map = otp_map_2,
+ .num_elements = CS35L41_NUM_OTP_ELEM,
+ .bit_offset = 16,
+ .word_offset = 2,
+ },
+ {
+ .id = 0x06,
+ .map = otp_map_2,
+ .num_elements = CS35L41_NUM_OTP_ELEM,
+ .bit_offset = 16,
+ .word_offset = 2,
+ },
+ {
+ .id = 0x08,
+ .map = otp_map_1,
+ .num_elements = CS35L41_NUM_OTP_ELEM,
+ .bit_offset = 16,
+ .word_offset = 2,
+ },
+};
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
new file mode 100644
index 000000000000..dbec54a28a9e
--- /dev/null
+++ b/sound/soc/codecs/cs35l41.c
@@ -0,0 +1,1545 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// cs35l41.c -- CS35l41 ALSA SoC audio driver
+//
+// Copyright 2017-2021 Cirrus Logic, Inc.
+//
+// Author: David Rhodes <david.rhodes@cirrus.com>
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of_device.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "cs35l41.h"
+
+static const char * const cs35l41_supplies[CS35L41_NUM_SUPPLIES] = {
+ "VA",
+ "VP",
+};
+
+struct cs35l41_pll_sysclk_config {
+ int freq;
+ int clk_cfg;
+};
+
+static const struct cs35l41_pll_sysclk_config cs35l41_pll_sysclk[] = {
+ { 32768, 0x00 },
+ { 8000, 0x01 },
+ { 11025, 0x02 },
+ { 12000, 0x03 },
+ { 16000, 0x04 },
+ { 22050, 0x05 },
+ { 24000, 0x06 },
+ { 32000, 0x07 },
+ { 44100, 0x08 },
+ { 48000, 0x09 },
+ { 88200, 0x0A },
+ { 96000, 0x0B },
+ { 128000, 0x0C },
+ { 176400, 0x0D },
+ { 192000, 0x0E },
+ { 256000, 0x0F