summaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/Kconfig3
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/atmel/playpaq_wm8510.c6
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c2
-rw-r--r--sound/soc/atmel/snd-soc-afeb9260.c2
-rw-r--r--sound/soc/au1x/Kconfig30
-rw-r--r--sound/soc/au1x/Makefile10
-rw-r--r--sound/soc/au1x/ac97c.c366
-rw-r--r--sound/soc/au1x/db1000.c75
-rw-r--r--sound/soc/au1x/db1200.c64
-rw-r--r--sound/soc/au1x/dbdma2.c91
-rw-r--r--sound/soc/au1x/dma.c377
-rw-r--r--sound/soc/au1x/i2sc.c349
-rw-r--r--sound/soc/au1x/psc-ac97.c61
-rw-r--r--sound/soc/au1x/psc-i2s.c55
-rw-r--r--sound/soc/au1x/psc.h16
-rw-r--r--sound/soc/blackfin/Kconfig13
-rw-r--r--sound/soc/blackfin/Makefile2
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c2
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c2
-rw-r--r--sound/soc/blackfin/bf5xx-sport.c1
-rw-r--r--sound/soc/blackfin/bfin-eval-adau1373.c202
-rw-r--r--sound/soc/blackfin/bfin-eval-adav80x.c1
-rw-r--r--sound/soc/codecs/88pm860x-codec.c14
-rw-r--r--sound/soc/codecs/Kconfig16
-rw-r--r--sound/soc/codecs/Makefile8
-rw-r--r--sound/soc/codecs/ac97.c1
-rw-r--r--sound/soc/codecs/ad193x.c96
-rw-r--r--sound/soc/codecs/ad193x.h36
-rw-r--r--sound/soc/codecs/ad1980.c11
-rw-r--r--sound/soc/codecs/adau1373.c1414
-rw-r--r--sound/soc/codecs/adau1373.h29
-rw-r--r--sound/soc/codecs/adau1701.c3
-rw-r--r--sound/soc/codecs/adav80x.c3
-rw-r--r--sound/soc/codecs/ads117x.c1
-rw-r--r--sound/soc/codecs/ads117x.h13
-rw-r--r--sound/soc/codecs/ak4104.c2
-rw-r--r--sound/soc/codecs/ak4535.c110
-rw-r--r--sound/soc/codecs/ak4641.c3
-rw-r--r--sound/soc/codecs/ak4642.c105
-rw-r--r--sound/soc/codecs/ak4671.c22
-rw-r--r--sound/soc/codecs/alc5623.c8
-rw-r--r--sound/soc/codecs/cs4270.c14
-rw-r--r--sound/soc/codecs/cs4271.c5
-rw-r--r--sound/soc/codecs/cs42l51.c15
-rw-r--r--sound/soc/codecs/cx20442.c1
-rw-r--r--sound/soc/codecs/da7210.c650
-rw-r--r--sound/soc/codecs/dmic.c1
-rw-r--r--sound/soc/codecs/lm4857.c2
-rw-r--r--sound/soc/codecs/max98088.c36
-rw-r--r--sound/soc/codecs/max98095.c47
-rw-r--r--sound/soc/codecs/pcm3008.c1
-rw-r--r--sound/soc/codecs/rt5631.c1773
-rw-r--r--sound/soc/codecs/rt5631.h701
-rw-r--r--sound/soc/codecs/sgtl5000.c37
-rw-r--r--sound/soc/codecs/sgtl5000.h2
-rw-r--r--sound/soc/codecs/sn95031.c17
-rw-r--r--sound/soc/codecs/ssm2602.c107
-rw-r--r--sound/soc/codecs/ssm2602.h6
-rw-r--r--sound/soc/codecs/sta32x.c54
-rw-r--r--sound/soc/codecs/tlv320aic23.c182
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c65
-rw-r--r--sound/soc/codecs/tlv320aic3x.c26
-rw-r--r--sound/soc/codecs/tlv320dac33.c31
-rw-r--r--sound/soc/codecs/tpa6130a2.c13
-rw-r--r--sound/soc/codecs/twl4030.c69
-rw-r--r--sound/soc/codecs/twl6040.c805
-rw-r--r--sound/soc/codecs/twl6040.h13
-rw-r--r--sound/soc/codecs/wl1273.c2
-rw-r--r--sound/soc/codecs/wm1250-ev1.c140
-rw-r--r--sound/soc/codecs/wm5100-tables.c1531
-rw-r--r--sound/soc/codecs/wm5100.c2813
-rw-r--r--sound/soc/codecs/wm5100.h5155
-rw-r--r--sound/soc/codecs/wm8350.c43
-rw-r--r--sound/soc/codecs/wm8400.c2
-rw-r--r--sound/soc/codecs/wm8510.c21
-rw-r--r--sound/soc/codecs/wm8523.c36
-rw-r--r--sound/soc/codecs/wm8580.c69
-rw-r--r--sound/soc/codecs/wm8711.c42
-rw-r--r--sound/soc/codecs/wm8728.c13
-rw-r--r--sound/soc/codecs/wm8731.c25
-rw-r--r--sound/soc/codecs/wm8737.c10
-rw-r--r--sound/soc/codecs/wm8741.c151
-rw-r--r--sound/soc/codecs/wm8750.c56
-rw-r--r--sound/soc/codecs/wm8753.c13
-rw-r--r--sound/soc/codecs/wm8770.c8
-rw-r--r--sound/soc/codecs/wm8776.c67
-rw-r--r--sound/soc/codecs/wm8782.c2
-rw-r--r--sound/soc/codecs/wm8804.c9
-rw-r--r--sound/soc/codecs/wm8900.c115
-rw-r--r--sound/soc/codecs/wm8904.c4
-rw-r--r--sound/soc/codecs/wm8940.c53
-rw-r--r--sound/soc/codecs/wm8960.c18
-rw-r--r--sound/soc/codecs/wm8961.c4
-rw-r--r--sound/soc/codecs/wm8962.c252
-rw-r--r--sound/soc/codecs/wm8971.c42
-rw-r--r--sound/soc/codecs/wm8974.c15
-rw-r--r--sound/soc/codecs/wm8978.c3
-rw-r--r--sound/soc/codecs/wm8983.c2
-rw-r--r--sound/soc/codecs/wm8988.c33
-rw-r--r--sound/soc/codecs/wm8990.c105
-rw-r--r--sound/soc/codecs/wm8991.c24
-rw-r--r--sound/soc/codecs/wm8993.c7
-rw-r--r--sound/soc/codecs/wm8994-tables.c16
-rw-r--r--sound/soc/codecs/wm8994.c415
-rw-r--r--sound/soc/codecs/wm8994.h2
-rw-r--r--sound/soc/codecs/wm8995.c22
-rw-r--r--sound/soc/codecs/wm8996.c321
-rw-r--r--sound/soc/codecs/wm9081.c14
-rw-r--r--sound/soc/codecs/wm9090.c7
-rw-r--r--sound/soc/codecs/wm_hubs.c68
-rw-r--r--sound/soc/codecs/wm_hubs.h3
-rw-r--r--sound/soc/davinci/davinci-evm.c2
-rw-r--r--sound/soc/davinci/davinci-i2s.c5
-rw-r--r--sound/soc/davinci/davinci-mcasp.c20
-rw-r--r--sound/soc/davinci/davinci-pcm.c123
-rw-r--r--sound/soc/ep93xx/edb93xx.c61
-rw-r--r--sound/soc/ep93xx/ep93xx-ac97.c2
-rw-r--r--sound/soc/ep93xx/ep93xx-pcm.c1
-rw-r--r--sound/soc/ep93xx/simone.c64
-rw-r--r--sound/soc/ep93xx/snappercl15.c54
-rw-r--r--sound/soc/fsl/fsl_dma.c1
-rw-r--r--sound/soc/fsl/fsl_ssi.c206
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c2
-rw-r--r--sound/soc/fsl/p1022_ds.c4
-rw-r--r--sound/soc/imx/Kconfig3
-rw-r--r--sound/soc/imx/imx-pcm-fiq.c12
-rw-r--r--sound/soc/imx/imx-ssi.c9
-rw-r--r--sound/soc/imx/imx-ssi.h6
-rw-r--r--sound/soc/imx/wm1133-ev1.c1
-rw-r--r--sound/soc/jz4740/jz4740-pcm.c2
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c2
-rw-r--r--sound/soc/kirkwood/kirkwood-t5325.c2
-rw-r--r--sound/soc/mid-x86/mfld_machine.c5
-rw-r--r--sound/soc/mid-x86/sst_platform.c20
-rw-r--r--sound/soc/mxs/Kconfig20
-rw-r--r--sound/soc/mxs/Makefile10
-rw-r--r--sound/soc/mxs/mxs-pcm.c359
-rw-r--r--sound/soc/mxs/mxs-pcm.h43
-rw-r--r--sound/soc/mxs/mxs-saif.c798
-rw-r--r--sound/soc/mxs/mxs-saif.h134
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c173
-rw-r--r--sound/soc/nuc900/nuc900-pcm.c5
-rw-r--r--sound/soc/omap/Makefile2
-rw-r--r--sound/soc/omap/am3517evm.c51
-rw-r--r--sound/soc/omap/ams-delta.c2
-rw-r--r--sound/soc/omap/igep0020.c24
-rw-r--r--sound/soc/omap/mcpdm.c470
-rw-r--r--sound/soc/omap/mcpdm.h153
-rw-r--r--sound/soc/omap/n810.c43
-rw-r--r--sound/soc/omap/omap-mcbsp.c27
-rw-r--r--sound/soc/omap/omap-mcpdm.c481
-rw-r--r--sound/soc/omap/omap-mcpdm.h107
-rw-r--r--sound/soc/omap/omap-pcm.c9
-rw-r--r--sound/soc/omap/omap3beagle.c1
-rw-r--r--sound/soc/omap/omap3evm.c24
-rw-r--r--sound/soc/omap/omap3pandora.c29
-rw-r--r--sound/soc/omap/omap4-hdmi-card.c1
-rw-r--r--sound/soc/omap/osk5912.c51
-rw-r--r--sound/soc/omap/overo.c24
-rw-r--r--sound/soc/omap/rx51.c23
-rw-r--r--sound/soc/omap/sdp3430.c89
-rw-r--r--sound/soc/omap/sdp4430.c48
-rw-r--r--sound/soc/omap/zoom2.c97
-rw-r--r--sound/soc/pxa/Kconfig2
-rw-r--r--sound/soc/pxa/corgi.c1
-rw-r--r--sound/soc/pxa/e740_wm9705.c2
-rw-r--r--sound/soc/pxa/e750_wm9705.c2
-rw-r--r--sound/soc/pxa/e800_wm9712.c1
-rw-r--r--sound/soc/pxa/magician.c4
-rw-r--r--sound/soc/pxa/mioa701_wm9713.c1
-rw-r--r--sound/soc/pxa/palm27x.c4
-rw-r--r--sound/soc/pxa/poodle.c1
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c1
-rw-r--r--sound/soc/pxa/raumfeld.c4
-rw-r--r--sound/soc/pxa/saarb.c4
-rw-r--r--sound/soc/pxa/spitz.c3
-rw-r--r--sound/soc/pxa/tavorevb3.c4
-rw-r--r--sound/soc/pxa/tosa.c1
-rw-r--r--sound/soc/pxa/z2.c6
-rw-r--r--sound/soc/pxa/zylonite.c1
-rw-r--r--sound/soc/s6000/s6000-pcm.c1
-rw-r--r--sound/soc/samsung/Kconfig12
-rw-r--r--sound/soc/samsung/ac97.c15
-rw-r--r--sound/soc/samsung/dma.c149
-rw-r--r--sound/soc/samsung/dma.h4
-rw-r--r--sound/soc/samsung/goni_wm8994.c16
-rw-r--r--sound/soc/samsung/h1940_uda1380.c20
-rw-r--r--sound/soc/samsung/i2s.c3
-rw-r--r--sound/soc/samsung/idma.c1
-rw-r--r--sound/soc/samsung/jive_wm8750.c20
-rw-r--r--sound/soc/samsung/ln2440sbc_alc650.c1
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c4
-rw-r--r--sound/soc/samsung/pcm.c3
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c34
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c1
-rw-r--r--sound/soc/samsung/s3c2412-i2s.c7
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c7
-rw-r--r--sound/soc/samsung/s3c24xx_simtec.c3
-rw-r--r--sound/soc/samsung/s3c24xx_simtec_hermes.c12
-rw-r--r--sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c12
-rw-r--r--sound/soc/samsung/s3c24xx_uda134x.c9
-rw-r--r--sound/soc/samsung/smartq_wm8987.c28
-rw-r--r--sound/soc/samsung/smdk_spdif.c1
-rw-r--r--sound/soc/samsung/smdk_wm8580.c52
-rw-r--r--sound/soc/samsung/smdk_wm8580pcm.c5
-rw-r--r--sound/soc/samsung/smdk_wm8994.c2
-rw-r--r--sound/soc/samsung/smdk_wm8994pcm.c1
-rw-r--r--sound/soc/samsung/smdk_wm9713.c1
-rw-r--r--sound/soc/samsung/spdif.c5
-rw-r--r--sound/soc/samsung/speyside.c11
-rw-r--r--sound/soc/samsung/speyside_wm8962.c42
-rw-r--r--sound/soc/sh/fsi-ak4642.c1
-rw-r--r--sound/soc/sh/fsi-da7210.c1
-rw-r--r--sound/soc/sh/fsi-hdmi.c1
-rw-r--r--sound/soc/sh/fsi.c13
-rw-r--r--sound/soc/sh/sh7760-ac97.c7
-rw-r--r--sound/soc/sh/siu_dai.c1
-rw-r--r--sound/soc/sh/ssi.c2
-rw-r--r--sound/soc/soc-cache.c8
-rw-r--r--sound/soc/soc-core.c215
-rw-r--r--sound/soc/soc-dapm.c416
-rw-r--r--sound/soc/soc-io.c358
-rw-r--r--sound/soc/soc-jack.c3
-rw-r--r--sound/soc/soc-pcm.c57
-rw-r--r--sound/soc/soc-utils.c1
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c1
-rw-r--r--sound/soc/tegra/tegra_das.c4
-rw-r--r--sound/soc/tegra/tegra_i2s.c2
-rw-r--r--sound/soc/tegra/tegra_pcm.c2
-rw-r--r--sound/soc/tegra/tegra_spdif.c5
-rw-r--r--sound/soc/tegra/tegra_wm8903.c2
-rw-r--r--sound/soc/tegra/trimslice.c2
-rw-r--r--sound/soc/txx9/txx9aclc-ac97.c2
-rw-r--r--sound/soc/txx9/txx9aclc-generic.c2
235 files changed, 21057 insertions, 4530 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 8224db5f0434..1381db853ef0 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -7,6 +7,8 @@ menuconfig SND_SOC
select SND_PCM
select AC97_BUS if SND_SOC_AC97_BUS
select SND_JACK if INPUT=y || INPUT=SND
+ select REGMAP_I2C if I2C
+ select REGMAP_SPI if SPI_MASTER
---help---
If you want ASoC support, you should say Y here and also to the
@@ -51,6 +53,7 @@ source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
source "sound/soc/kirkwood/Kconfig"
source "sound/soc/mid-x86/Kconfig"
+source "sound/soc/mxs/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/samsung/Kconfig"
source "sound/soc/s6000/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 4f913876f332..9ea8ac827adc 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += imx/
obj-$(CONFIG_SND_SOC) += jz4740/
obj-$(CONFIG_SND_SOC) += mid-x86/
+obj-$(CONFIG_SND_SOC) += mxs/
obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
obj-$(CONFIG_SND_SOC) += kirkwood/
diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c
index 1aac2f4dbcf6..73ae99ad4578 100644
--- a/sound/soc/atmel/playpaq_wm8510.c
+++ b/sound/soc/atmel/playpaq_wm8510.c
@@ -338,7 +338,6 @@ static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
/* always connected pins */
snd_soc_dapm_enable_pin(dapm, "Int Mic");
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
- snd_soc_dapm_sync(dapm);
@@ -383,14 +382,17 @@ static int __init playpaq_asoc_init(void)
_gclk0 = clk_get(NULL, "gclk0");
if (IS_ERR(_gclk0)) {
_gclk0 = NULL;
+ ret = PTR_ERR(_gclk0);
goto err_gclk0;
}
_pll0 = clk_get(NULL, "pll0");
if (IS_ERR(_pll0)) {
_pll0 = NULL;
+ ret = PTR_ERR(_pll0);
goto err_pll0;
}
- if (clk_set_parent(_gclk0, _pll0)) {
+ ret = clk_set_parent(_gclk0, _pll0);
+ if (ret) {
pr_warning("snd-soc-playpaq: "
"Failed to set PLL0 as parent for DAC clock\n");
goto err_set_clk;
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index bad3aa14d5b3..0377c5451aed 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -173,8 +173,6 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
/* always connected */
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
- snd_soc_dapm_sync(dapm);
-
return 0;
}
diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c
index 5e4d499d8434..d427e9217ce4 100644
--- a/sound/soc/atmel/snd-soc-afeb9260.c
+++ b/sound/soc/atmel/snd-soc-afeb9260.c
@@ -117,8 +117,6 @@ static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_enable_pin(dapm, "Line In");
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
- snd_soc_dapm_sync(dapm);
-
return 0;
}
diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig
index 4b67140fdec3..e908a8123110 100644
--- a/sound/soc/au1x/Kconfig
+++ b/sound/soc/au1x/Kconfig
@@ -3,7 +3,7 @@
##
config SND_SOC_AU1XPSC
tristate "SoC Audio for Au1200/Au1250/Au1550"
- depends on SOC_AU1200 || SOC_AU1550
+ depends on MIPS_ALCHEMY
help
This option enables support for the Programmable Serial
Controllers in AC97 and I2S mode, and the Descriptor-Based DMA
@@ -18,10 +18,38 @@ config SND_SOC_AU1XPSC_AC97
select SND_AC97_CODEC
select SND_SOC_AC97_BUS
+##
+## Au1000/1500/1100 DMA + AC97C/I2SC
+##
+config SND_SOC_AU1XAUDIO
+ tristate "SoC Audio for Au1000/Au1500/Au1100"
+ depends on MIPS_ALCHEMY
+ help
+ This is a driver set for the AC97 unit and the
+ old DMA controller as found on the Au1000/Au1500/Au1100 chips.
+
+config SND_SOC_AU1XAC97C
+ tristate
+ select AC97_BUS
+ select SND_AC97_CODEC
+ select SND_SOC_AC97_BUS
+
+config SND_SOC_AU1XI2SC
+ tristate
+
##
## Boards
##
+config SND_SOC_DB1000
+ tristate "DB1000 Audio support"
+ depends on SND_SOC_AU1XAUDIO
+ select SND_SOC_AU1XAC97C
+ select SND_SOC_AC97_CODEC
+ help
+ Select this option to enable AC97 audio on the early DB1x00 series
+ of boards (DB1000/DB1500/DB1100).
+
config SND_SOC_DB1200
tristate "DB1200 AC97+I2S audio support"
depends on SND_SOC_AU1XPSC
diff --git a/sound/soc/au1x/Makefile b/sound/soc/au1x/Makefile
index 16873076e8c4..920710514ea0 100644
--- a/sound/soc/au1x/Makefile
+++ b/sound/soc/au1x/Makefile
@@ -3,11 +3,21 @@ snd-soc-au1xpsc-dbdma-objs := dbdma2.o
snd-soc-au1xpsc-i2s-objs := psc-i2s.o
snd-soc-au1xpsc-ac97-objs := psc-ac97.o
+# Au1000/1500/1100 Audio units
+snd-soc-au1x-dma-objs := dma.o
+snd-soc-au1x-ac97c-objs := ac97c.o
+snd-soc-au1x-i2sc-objs := i2sc.o
+
obj-$(CONFIG_SND_SOC_AU1XPSC) += snd-soc-au1xpsc-dbdma.o
obj-$(CONFIG_SND_SOC_AU1XPSC_I2S) += snd-soc-au1xpsc-i2s.o
obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o
+obj-$(CONFIG_SND_SOC_AU1XAUDIO) += snd-soc-au1x-dma.o
+obj-$(CONFIG_SND_SOC_AU1XAC97C) += snd-soc-au1x-ac97c.o
+obj-$(CONFIG_SND_SOC_AU1XI2SC) += snd-soc-au1x-i2sc.o
# Boards
+snd-soc-db1000-objs := db1000.o
snd-soc-db1200-objs := db1200.o
+obj-$(CONFIG_SND_SOC_DB1000) += snd-soc-db1000.o
obj-$(CONFIG_SND_SOC_DB1200) += snd-soc-db1200.o
diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c
new file mode 100644
index 000000000000..726bd651a105
--- /dev/null
+++ b/sound/soc/au1x/ac97c.c
@@ -0,0 +1,366 @@
+/*
+ * Au1000/Au1500/Au1100 AC97C controller driver for ASoC
+ *
+ * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
+ *
+ * based on the old ALSA driver originally written by
+ * Charles Eidsness <charles@cooper-street.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/suspend.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#include "psc.h"
+
+/* register offsets and bits */
+#define AC97_CONFIG 0x00
+#define AC97_STATUS 0x04
+#define AC97_DATA 0x08
+#define AC97_CMDRESP 0x0c
+#define AC97_ENABLE 0x10
+
+#define CFG_RC(x) (((x) & 0x3ff) << 13) /* valid rx slots mask */
+#define CFG_XS(x) (((x) & 0x3ff) << 3) /* valid tx slots mask */
+#define CFG_SG (1 << 2) /* sync gate */
+#define CFG_SN (1 << 1) /* sync control */
+#define CFG_RS (1 << 0) /* acrst# control */
+#define STAT_XU (1 << 11) /* tx underflow */
+#define STAT_XO (1 << 10) /* tx overflow */
+#define STAT_RU (1 << 9) /* rx underflow */
+#define STAT_RO (1 << 8) /* rx overflow */
+#define STAT_RD (1 << 7) /* codec ready */
+#define STAT_CP (1 << 6) /* command pending */
+#define STAT_TE (1 << 4) /* tx fifo empty */
+#define STAT_TF (1 << 3) /* tx fifo full */
+#define STAT_RE (1 << 1) /* rx fifo empty */
+#define STAT_RF (1 << 0) /* rx fifo full */
+#define CMD_SET_DATA(x) (((x) & 0xffff) << 16)
+#define CMD_GET_DATA(x) ((x) & 0xffff)
+#define CMD_READ (1 << 7)
+#define CMD_WRITE (0 << 7)
+#define CMD_IDX(x) ((x) & 0x7f)
+#define EN_D (1 << 1) /* DISable bit */
+#define EN_CE (1 << 0) /* clock enable bit */
+
+/* how often to retry failed codec register reads/writes */
+#define AC97_RW_RETRIES 5
+
+#define AC97_RATES \
+ SNDRV_PCM_RATE_CONTINUOUS
+
+#define AC97_FMTS \
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE)
+
+/* instance data. There can be only one, MacLeod!!!!, fortunately there IS only
+ * once AC97C on early Alchemy chips. The newer ones aren't so lucky.
+ */
+static struct au1xpsc_audio_data *ac97c_workdata;
+#define ac97_to_ctx(x) ac97c_workdata
+
+static inline unsigned long RD(struct au1xpsc_audio_data *ctx, int reg)
+{
+ return __raw_readl(ctx->mmio + reg);
+}
+
+static inline void WR(struct au1xpsc_audio_data *ctx, int reg, unsigned long v)
+{
+ __raw_writel(v, ctx->mmio + reg);
+ wmb();
+}
+
+static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97,
+ unsigned short r)
+{
+ struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
+ unsigned int tmo, retry;
+ unsigned long data;
+
+ data = ~0;
+ retry = AC97_RW_RETRIES;
+ do {
+ mutex_lock(&ctx->lock);
+
+ tmo = 5;
+ while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
+ udelay(21); /* wait an ac97 frame time */
+ if (!tmo) {
+ pr_debug("ac97rd timeout #1\n");
+ goto next;
+ }
+
+ WR(ctx, AC97_CMDRESP, CMD_IDX(r) | CMD_READ);
+
+ /* stupid errata: data is only valid for 21us, so
+ * poll, Forrest, poll...
+ */
+ tmo = 0x10000;
+ while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
+ asm volatile ("nop");
+ data = RD(ctx, AC97_CMDRESP);
+
+ if (!tmo)
+ pr_debug("ac97rd timeout #2\n");
+
+next:
+ mutex_unlock(&ctx->lock);
+ } while (--retry && !tmo);
+
+ pr_debug("AC97RD %04x %04lx %d\n", r, data, retry);
+
+ return retry ? data & 0xffff : 0xffff;
+}
+
+static void au1xac97c_ac97_write(struct snd_ac97 *ac97, unsigned short r,
+ unsigned short v)
+{
+ struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
+ unsigned int tmo, retry;
+
+ retry = AC97_RW_RETRIES;
+ do {
+ mutex_lock(&ctx->lock);
+
+ for (tmo = 5; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--)
+ udelay(21);
+ if (!tmo) {
+ pr_debug("ac97wr timeout #1\n");
+ goto next;
+ }
+
+ WR(ctx, AC97_CMDRESP, CMD_WRITE | CMD_IDX(r) | CMD_SET_DATA(v));
+
+ for (tmo = 10; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--)
+ udelay(21);
+ if (!tmo)
+ pr_debug("ac97wr timeout #2\n");
+next:
+ mutex_unlock(&ctx->lock);
+ } while (--retry && !tmo);
+
+ pr_debug("AC97WR %04x %04x %d\n", r, v, retry);
+}
+
+static void au1xac97c_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
+
+ WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG | CFG_SN);
+ msleep(20);
+ WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG);
+ WR(ctx, AC97_CONFIG, ctx->cfg);
+}
+
+static void au1xac97c_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+ struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
+ int i;
+
+ WR(ctx, AC97_CONFIG, ctx->cfg | CFG_RS);
+ msleep(500);
+ WR(ctx, AC97_CONFIG, ctx->cfg);
+
+ /* wait for codec ready */
+ i = 50;
+ while (((RD(ctx, AC97_STATUS) & STAT_RD) == 0) && --i)
+ msleep(20);
+ if (!i)
+ printk(KERN_ERR "ac97c: codec not ready after cold reset\n");
+}
+
+/* AC97 controller operations */
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = au1xac97c_ac97_read,
+ .write = au1xac97c_ac97_write,
+ .reset = au1xac97c_ac97_cold_reset,
+ .warm_reset = au1xac97c_ac97_warm_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops); /* globals be gone! */
+
+static int alchemy_ac97c_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
+ snd_soc_dai_set_dma_data(dai, substream, &ctx->dmaids[0]);
+ return 0;
+}
+
+static struct snd_soc_dai_ops alchemy_ac97c_ops = {
+ .startup = alchemy_ac97c_startup,
+};
+
+static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
+{
+ return ac97c_workdata ? 0 : -ENODEV;
+}
+
+static struct snd_soc_dai_driver au1xac97c_dai_driver = {
+ .name = "alchemy-ac97c",
+ .ac97_control = 1,
+ .probe = au1xac97c_dai_probe,
+ .playback = {
+ .rates = AC97_RATES,
+ .formats = AC97_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .capture = {
+ .rates = AC97_RATES,
+ .formats = AC97_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .ops = &alchemy_ac97c_ops,
+};
+
+static int __devinit au1xac97c_drvprobe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *iores, *dmares;
+ struct au1xpsc_audio_data *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ mutex_init(&ctx->lock);
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iores) {
+ ret = -ENODEV;
+ goto out0;
+ }
+
+ ret = -EBUSY;
+ if (!request_mem_region(iores->start, resource_size(iores),
+ pdev->name))
+ goto out0;
+
+ ctx->mmio = ioremap_nocache(iores->start, resource_size(iores));
+ if (!ctx->mmio)
+ goto out1;
+
+ dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmares)
+ goto out2;
+ ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
+
+ dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!dmares)
+ goto out2;
+ ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
+
+ /* switch it on */
+ WR(ctx, AC97_ENABLE, EN_D | EN_CE);
+ WR(ctx, AC97_ENABLE, EN_CE);
+
+ ctx->cfg = CFG_RC(3) | CFG_XS(3);
+ WR(ctx, AC97_CONFIG, ctx->cfg);
+
+ platform_set_drvdata(pdev, ctx);
+
+ ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver);
+ if (ret)
+ goto out2;
+
+ ac97c_workdata = ctx;
+ return 0;
+
+out2:
+ iounmap(ctx->mmio);
+out1:
+ release_mem_region(iores->start, resource_size(iores));
+out0:
+ kfree(ctx);
+ return ret;
+}
+
+static int __devexit au1xac97c_drvremove(struct platform_device *pdev)
+{
+ struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
+ struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */
+
+ iounmap(ctx->mmio);
+ release_mem_region(r->start, resource_size(r));
+ kfree(ctx);
+
+ ac97c_workdata = NULL; /* MDEV */
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int au1xac97c_drvsuspend(struct device *dev)
+{
+ struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev);
+
+ WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */
+
+ return 0;
+}
+
+static int au1xac97c_drvresume(struct device *dev)
+{
+ struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev);
+
+ WR(ctx, AC97_ENABLE, EN_D | EN_CE);
+ WR(ctx, AC97_ENABLE, EN_CE);
+ WR(ctx, AC97_CONFIG, ctx->cfg);
+
+ return 0;
+}
+
+static const struct dev_pm_ops au1xpscac97_pmops = {
+ .suspend = au1xac97c_drvsuspend,
+ .resume = au1xac97c_drvresume,
+};
+
+#define AU1XPSCAC97_PMOPS (&au1xpscac97_pmops)
+
+#else
+
+#define AU1XPSCAC97_PMOPS NULL
+
+#endif
+
+static struct platform_driver au1xac97c_driver = {
+ .driver = {
+ .name = "alchemy-ac97c",
+ .owner = THIS_MODULE,
+ .pm = AU1XPSCAC97_PMOPS,
+ },
+ .probe = au1xac97c_drvprobe,
+ .remove = __devexit_p(au1xac97c_drvremove),
+};
+
+static int __init au1xac97c_load(void)
+{
+ ac97c_workdata = NULL;
+ return platform_driver_register(&au1xac97c_driver);
+}
+
+static void __exit au1xac97c_unload(void)
+{
+ platform_driver_unregister(&au1xac97c_driver);
+}
+
+module_init(au1xac97c_load);
+module_exit(au1xac97c_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ASoC driver");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/db1000.c b/sound/soc/au1x/db1000.c
new file mode 100644
index 000000000000..127477a5e0c7
--- /dev/null
+++ b/sound/soc/au1x/db1000.c
@@ -0,0 +1,75 @@
+/*
+ * DB1000/DB1500/DB1100 ASoC audio fabric support code.
+ *
+ * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-db1x00/bcsr.h>
+
+#include "psc.h"
+
+static struct snd_soc_dai_link db1000_ac97_dai = {
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .codec_dai_name = "ac97-hifi",
+ .cpu_dai_name = "alchemy-ac97c",
+ .platform_name = "alchemy-pcm-dma.0",
+ .codec_name = "ac97-codec",
+};
+
+static struct snd_soc_card db1000_ac97 = {
+ .name = "DB1000_AC97",
+ .dai_link = &db1000_ac97_dai,
+ .num_links = 1,
+};
+
+static int __devinit db1000_audio_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &db1000_ac97;
+ card->dev = &pdev->dev;
+ return snd_soc_register_card(card);
+}
+
+static int __devexit db1000_audio_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ snd_soc_unregister_card(card);
+ return 0;
+}
+
+static struct platform_driver db1000_audio_driver = {
+ .driver = {
+ .name = "db1000-audio",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = db1000_audio_probe,
+ .remove = __devexit_p(db1000_audio_remove),
+};
+
+static int __init db1000_audio_load(void)
+{
+ return platform_driver_register(&db1000_audio_driver);
+}
+
+static void __exit db1000_audio_unload(void)
+{
+ platform_driver_unregister(&db1000_audio_driver);
+}
+
+module_init(db1000_audio_load);
+module_exit(db1000_audio_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DB1000/DB1500/DB1100 ASoC audio");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index 1d3e258c9ea8..289312c14b99 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -1,7 +1,7 @@
/*
* DB1200 ASoC audio fabric support code.
*
- * (c) 2008-9 Manuel Lauss <manuel.lauss@gmail.com>
+ * (c) 2008-2011 Manuel Lauss <manuel.lauss@googlemail.com>
*
*/
@@ -21,6 +21,17 @@
#include "../codecs/wm8731.h"
#include "psc.h"
+static struct platform_device_id db1200_pids[] = {
+ {
+ .name = "db1200-ac97",
+ .driver_data = 0,
+ }, {
+ .name = "db1200-i2s",
+ .driver_data = 1,
+ },
+ {},
+};
+
/*------------------------- AC97 PART ---------------------------*/
static struct snd_soc_dai_link db1200_ac97_dai = {
@@ -89,36 +100,47 @@ static struct snd_soc_card db1200_i2s_machine = {
/*------------------------- COMMON PART ---------------------------*/
-static struct platform_device *db1200_asoc_dev;
+static struct snd_soc_card *db1200_cards[] __devinitdata = {
+ &db1200_ac97_machine,
+ &db1200_i2s_machine,
+};
-static int __init db1200_audio_load(void)
+static int __devinit db1200_audio_probe(struct platform_device *pdev)
{
- int ret;
+ const struct platform_device_id *pid = platform_get_device_id(pdev);
+ struct snd_soc_card *card;
- ret = -ENOMEM;
- db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
- if (!db1200_asoc_dev)
- goto out;
+ card = db1200_cards[pid->driver_data];
+ card->dev = &pdev->dev;
+ return snd_soc_register_card(card);
+}
- /* DB1200 board setup set PSC1MUX to preferred audio device */
- if (bcsr_read(BCSR_RESETS) & BCSR_RESETS_PSC1MUX)
- platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_machine);
- else
- platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_machine);
+static int __devexit db1200_audio_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ snd_soc_unregister_card(card);
+ return 0;
+}
- ret = platform_device_add(db1200_asoc_dev);
+static struct platform_driver db1200_audio_driver = {
+ .driver = {
+ .name = "db1200-ac97",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ },
+ .id_table = db1200_pids,
+ .probe = db1200_audio_probe,
+ .remove = __devexit_p(db1200_audio_remove),
+};
- if (ret) {
- platform_device_put(db1200_asoc_dev);
- db1200_asoc_dev = NULL;
- }
-out:
- return ret;
+static int __init db1200_audio_load(void)
+{
+ return platform_driver_register(&db1200_audio_driver);
}
static void __exit db1200_audio_unload(void)
{
- platform_device_unregister(db1200_asoc_dev);
+ platform_driver_unregister(&db1200_audio_driver);
}
module_init(db1200_audio_load);
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 20bb53a837b1..d7d04e26eee5 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -169,7 +169,7 @@ static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd,
au1x_pcm_dbdma_free(pcd);
- if (stype == PCM_RX)
+ if (stype == SNDRV_PCM_STREAM_CAPTURE)
pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id,
DSCR_CMD0_ALWAYS,
au1x_pcm_dmarx_cb, (void *)pcd);
@@ -198,7 +198,7 @@ static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream
struct snd_soc_pcm_runtime *rtd = ss->private_data;
struct au1xpsc_audio_dmadata *pcd =
snd_soc_platform_get_drvdata(rtd->platform);
- return &pcd[SUBSTREAM_TYPE(ss)];
+ return &pcd[ss->stream];
}
static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -212,7 +212,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
goto out;
- stype = SUBSTREAM_TYPE(substream);
+ stype = substream->stream;
pcd = to_dmadata(substream);
DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
@@ -255,7 +255,7 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
au1xxx_dbdma_reset(pcd->ddma_chan);
- if (SUBSTREAM_TYPE(substream) == PCM_RX) {
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
au1x_pcm_queue_rx(pcd);
au1x_pcm_queue_rx(pcd);
} else {
@@ -293,6 +293,16 @@ au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
{
+ struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int stype = substream->stream, *dmaids;
+
+ dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ if (!dmaids)
+ return -ENODEV; /* whoa, has ordering changed? */
+
+ pcd->ddma_id = dmaids[stype];
+
snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware);
return 0;
}
@@ -340,36 +350,18 @@ struct snd_soc_platform_driver au1xpsc_soc_platform = {
static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
{
struct au1xpsc_audio_dmadata *dmadata;
- struct resource *r;
int ret;
dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
if (!dmadata)
return -ENOMEM;
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!r) {
- ret = -ENODEV;
- goto out1;
- }
- dmadata[PCM_TX].ddma_id = r->start;
-
- /* RX DMA */
- r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!r) {
- ret = -ENODEV;
- goto out1;
- }
- dmadata[PCM_RX].ddma_id = r->start;
-
platform_set_drvdata(pdev, dmadata);
ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
- if (!ret)
- return ret;
+ if (ret)
+ kfree(dmadata);
-out1:
- kfree(dmadata);
return ret;
}
@@ -405,57 +397,6 @@ static void __exit au1xpsc_audio_dbdma_unload(void)
module_init(au1xpsc_audio_dbdma_load);
module_exit(au1xpsc_audio_dbdma_unload);
-
-struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev)
-{
- struct resource *res, *r;
- struct platform_device *pd;
- int id[2];
- int ret;
-
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!r)
- return NULL;
- id[0] = r->start;
-
- r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!r)
- return NULL;
- id[1] = r->start;
-
- res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
- if (!res)
- return NULL;
-
- res[0].start = res[0].end = id[0];
- res[1].start = res[1].end = id[1];
- res[0].flags = res[1].flags = IORESOURCE_DMA;
-
- pd = platform_device_alloc("au1xpsc-pcm", pdev->id);
- if (!pd)
- goto out;
-
- pd->resource = res;
- pd->num_resources = 2;
-
- ret = platform_device_add(pd);
- if (!ret)
- return pd;
-
- platform_device_put(pd);
-out:
- kfree(res);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(au1xpsc_pcm_add);
-
-void au1xpsc_pcm_destroy(struct platform_device *dmapd)
-{
- if (dmapd)
- platform_device_unregister(dmapd);
-}
-EXPORT_SYMBOL_GPL(au1xpsc_pcm_destroy);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
new file mode 100644
index 000000000000..177f7137a9c8
--- /dev/null
+++ b/sound/soc/au1x/dma.c
@@ -0,0 +1,377 @@
+/*
+ * Au1000/Au1500/Au1100 Audio DMA support.
+ *
+ * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
+ *
+ * copied almost verbatim from the old ALSA driver, written by
+ * Charles Eidsness <charles@cooper-street.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1000_dma.h>
+
+#include "psc.h"
+
+#define ALCHEMY_PCM_FMTS \
+ (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
+ SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \
+ SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \
+ 0)
+
+struct pcm_period {
+ u32 start;
+ u32 relative_end; /* relative to start of buffer */
+ struct pcm_period *next;
+};
+
+struct audio_stream {
+ struct snd_pcm_substream *substream;
+ int dma;
+ struct pcm_period *buffer;
+ unsigned int period_size;
+ unsigned int periods;
+};
+
+struct alchemy_pcm_ctx {
+ struct audio_stream stream[2]; /* playback & capture */
+};
+
+static void au1000_release_dma_link(struct audio_stream *stream)
+{
+ struct pcm_period *pointer;
+ struct pcm_period *pointer_next;
+
+ stream->period_size = 0;
+ stream->periods = 0;
+ pointer = stream->buffer;
+ if (!pointer)
+ return;
+ do {
+ pointer_next = pointer->next;
+ kfree(pointer);
+ pointer = pointer_next;
+ } while (pointer != stream->buffer);
+ stream->buffer = NULL;
+}
+
+static int au1000_setup_dma_link(struct audio_stream *stream,
+ unsigned int period_bytes,
+ unsigned int periods)
+{
+ struct snd_pcm_substream *substream = stream->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcm_period *pointer;
+ unsigned long dma_start;
+ int i;
+
+ dma_start = virt_to_phys(runtime->dma_area);
+
+ if (stream->period_size == period_bytes &&
+ stream->periods == periods)
+ return 0; /* not changed */
+
+ au1000_release_dma_link(stream);
+
+ stream->period_size = period_bytes;
+ stream->periods = periods;
+
+ stream->buffer = kmalloc(sizeof(struct pcm_period), GFP_KERNEL);
+ if (!stream->buffer)
+ return -ENOMEM;
+ pointer = stream->buffer;
+ for (i = 0; i < periods; i++) {
+ pointer->start = (u32)(dma_start + (i * period_bytes));
+ pointer->relative_end = (u32) (((i+1) * period_bytes) - 0x1);
+ if (i < periods - 1) {
+ pointer->next = kmalloc(sizeof(struct pcm_period),
+ GFP_KERNEL);
+ if (!pointer->next) {
+ au1000_release_dma_link(stream);
+ return -ENOMEM;
+ }
+ pointer = pointer->next;
+ }
+ }
+ pointer->next = stream->buffer;
+ return 0;
+}
+
+static void au1000_dma_stop(struct audio_stream *stream)
+{
+ if (stream->buffer)
+ disable_dma(stream->dma);
+}
+
+static void au1000_dma_start(struct audio_stream *stream)
+{
+ if (!stream->buffer)
+ return;
+
+ init_dma(stream->dma);
+ if (get_dma_active_buffer(stream->dma) == 0) {
+ clear_dma_done0(stream->dma);
+ set_dma_addr0(stream->dma, stream->buffer->start);
+ set_dma_count0(stream->dma, stream->period_size >> 1);
+ set_dma_addr1(stream->dma, stream->buffer->next->start);
+ set_dma_count1(stream->dma, stream->period_size >> 1);
+ } else {
+ clear_dma_done1(stream->dma);
+ set_dma_addr1(stream->dma, stream->buffer->start);
+ set_dma_count1(stream->dma, stream->period_size >> 1);
+ set_dma_addr0(stream->dma, stream->buffer->next->start);
+ set_dma_count0(stream->dma, stream->period_size >> 1);
+ }
+ enable_dma_buffers(stream->dma);
+ start_dma(stream->dma);
+}
+
+static irqreturn_t au1000_dma_interrupt(int irq, void *ptr)
+{
+ struct audio_stream *stream = (struct audio_stream *)ptr;
+ struct snd_pcm_substream *substream = stream->substream;
+
+ switch (get_dma_buffer_done(stream->dma)) {
+ case DMA_D0:
+ stream->buffer = stream->buffer->next;
+ clear_dma_done0(stream->dma);
+ set_dma_addr0(stream->dma, stream->buffer->next->start);
+ set_dma_count0(stream->dma, stream->period_size >> 1);
+ enable_dma_buffer0(stream->dma);
+ break;
+ case DMA_D1:
+ stream->buffer = stream->buffer->next;
+ clear_dma_done1(stream->dma);
+ set_dma_addr1(stream->dma, stream->buffer->next->start);
+ set_dma_count1(stream->dma, stream->period_size >> 1);
+ enable_dma_buffer1(stream->dma);
+ break;
+ case (DMA_D0 | DMA_D1):
+ pr_debug("DMA %d missed interrupt.\n", stream->dma);
+ au1000_dma_stop(stream);
+ au1000_dma_start(stream);
+ break;
+ case (~DMA_D0 & ~DMA_D1):
+ pr_debug("DMA %d empty irq.\n", stream->dma);
+ }
+ snd_pcm_period_elapsed(substream);
+ return IRQ_HANDLED;
+}
+
+static const struct snd_pcm_hardware alchemy_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH,
+ .formats = ALCHEMY_PCM_FMTS,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .rate_min = SNDRV_PCM_RATE_8000,
+ .rate_max = SNDRV_PCM_RATE_192000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .period_bytes_min = 1024,
+ .period_bytes_max = 16 * 1024 - 1,
+ .periods_min = 4,
+ .periods_max = 255,
+ .buffer_bytes_max = 128 * 1024,
+ .fifo_size = 16,
+};
+
+static inline struct alchemy_pcm_ctx *ss_to_ctx(struct snd_pcm_substream *ss)
+{
+ struct snd_soc_pcm_runtime *rtd = ss->private_data;
+ return snd_soc_platform_get_drvdata(rtd->platform);
+}
+
+static inline struct audio_stream *ss_to_as(struct snd_pcm_substream *ss)
+{
+ struct alchemy_pcm_ctx *ctx = ss_to_ctx(ss);
+ return &(ctx->stream[ss->stream]);
+}
+
+static int alchemy_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int *dmaids, s = substream->stream;
+ char *name;
+
+ dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ if (!dmaids)
+ return -ENODEV; /* whoa, has ordering changed? */
+
+ /* DMA setup */
+ name = (s == SNDRV_PCM_STREAM_PLAYBACK) ? "audio-tx" : "audio-rx";
+ ctx->stream[s].dma = request_au1000_dma(dmaids[s], name,
+ au1000_dma_interrupt, 0,
+ &ctx->stream[s]);
+ set_dma_mode(ctx->stream[s].dma,
+ get_dma_mode(ctx->stream[s].dma) & ~DMA_NC);
+
+ ctx->stream[s].substream = substream;
+ ctx->stream[s].buffer = NULL;
+ snd_soc_set_runtime_hwparams(substream, &alchemy_pcm_hardware);
+
+ return 0;
+}
+
+static int alchemy_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream);
+ int stype = substream->stream;
+
+ ctx->stream[stype].substream = NULL;
+ free_au1000_dma(ctx->stream[stype].dma);
+
+ return 0;
+}
+
+static int alchemy_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct audio_stream *stream = ss_to_as(substream);
+ int err;
+
+ err = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ if (err < 0)
+ return err;
+ err = au1000_setup_dma_link(stream,
+ params_period_bytes(hw_params),
+ params_periods(hw_params));
+ if (err)
+ snd_pcm_lib_free_pages(substream);
+
+ return err;
+}
+
+static int alchemy_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct audio_stream *stream = ss_to_as(substream);
+ au1000_release_dma_link(stream);
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int alchemy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct audio_stream *stream = ss_to_as(substream);
+ int err = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ au1000_dma_start(stream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ au1000_dma_stop(stream);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_pcm_substream *ss)
+{
+ struct audio_stream *stream = ss_to_as(ss);
+ long location;
+
+ location = get_dma_residue(stream->dma);
+ location = stream->buffer->relative_end - location;
+ if (location == -1)
+ location = 0;
+ return bytes_to_frames(ss->runtime, location);
+}
+
+static struct snd_pcm_ops alchemy_pcm_ops = {
+ .open = alchemy_pcm_open,
+ .close = alchemy_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = alchemy_pcm_hw_params,
+ .hw_free = alchemy_pcm_hw_free,
+ .trigger = alchemy_pcm_trigger,
+ .pointer = alchemy_pcm_pointer,
+};
+
+static void alchemy_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm;
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL), 65536, (4096 * 1024) - 1);
+
+ return 0;
+}
+
+struct snd_soc_platform_driver alchemy_pcm_soc_platform = {
+ .ops = &alchemy_pcm_ops,
+ .pcm_new = alchemy_pcm_new,
+ .pcm_free = alchemy_pcm_free_dma_buffers,
+};
+
+static int __devinit alchemy_pcm_drvprobe(struct platform_device *pdev)
+{
+ struct alchemy_pcm_ctx *ctx;
+ int ret;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ctx);
+
+ ret = snd_soc_register_platform(&pdev->dev, &alchemy_pcm_soc_platform);
+ if (ret)
+ kfree(ctx);
+
+ return ret;
+}
+
+static int __devexit alchemy_pcm_drvremove(struct platform_device *pdev)
+{
+ struct alchemy_pcm_ctx *ctx = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_platform(&pdev->dev);
+ kfree(ctx);
+
+ return 0;
+}
+
+static struct platform_driver alchemy_pcmdma_driver = {
+ .driver = {
+ .name = "alchemy-pcm-dma",
+ .owner = THIS_MODULE,
+ },
+ .probe = alchemy_pcm_drvprobe,
+ .remove = __devexit_p(alchemy_pcm_drvremove),
+};
+
+static int __init alchemy_pcmdma_load(void)
+{
+ return platform_driver_register(&alchemy_pcmdma_driver);
+}
+
+static void __exit alchemy_pcmdma_unload(void)
+{
+ platform_driver_unregister(&alchemy_pcmdma_driver);
+}
+
+module_init(alchemy_pcmdma_load);
+module_exit(alchemy_pcmdma_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Au1000/Au1500/Au1100 Audio DMA driver");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c
new file mode 100644
index 000000000000..6bcf48f5884c
--- /dev/null
+++ b/sound/soc/au1x/i2sc.c
@@ -0,0 +1,349 @@
+/*
+ * Au1000/Au1500/Au1100 I2S controller driver for ASoC
+ *
+ * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
+ *
+ * Note: clock supplied to the I2S controller must be 256x samplerate.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#include "psc.h"
+
+#define I2S_RXTX 0x00
+#define I2S_CFG 0x04
+#define I2S_ENABLE 0x08
+
+#define CFG_XU (1 << 25) /* tx underflow */
+#define CFG_XO (1 << 24)
+#define CFG_RU (1 << 23)
+#define CFG_RO (1 << 22)
+#define CFG_TR (1 << 21)
+#define CFG_TE (1 << 20)
+#define CFG_TF (1 << 19)
+#define CFG_RR (1 << 18)
+#define CFG_RF (1 << 17)
+#define CFG_ICK (1 << 12) /* clock invert */
+#define CFG_PD (1 << 11) /* set to make I2SDIO INPUT */
+#define CFG_LB (1 << 10) /* loopback */
+#define CFG_IC (1 << 9) /* word select invert */
+#define CFG_FM_I2S (0 << 7) /* I2S format */
+#define CFG_FM_LJ (1 << 7) /* left-justified */
+#define CFG_FM_RJ (2 << 7) /* right-justified */
+#define CFG_FM_MASK (3 << 7)
+#define CFG_TN (1 << 6) /* tx fifo en */
+#define CFG_RN (1 << 5) /* rx fifo en */
+#define CFG_SZ_8 (0x08)
+#define CFG_SZ_16 (0x10)
+#define CFG_SZ_18 (0x12)
+#define CFG_SZ_20 (0x14)
+#define CFG_SZ_24 (0x18)
+#define CFG_SZ_MASK (0x1f)
+#define EN_D (1 << 1) /* DISable */
+#define EN_CE (1 << 0) /* clock enable */
+
+/* only limited by clock generator and board design */
+#define AU1XI2SC_RATES \
+ SNDRV_PCM_RATE_CONTINUOUS
+
+#define AU1XI2SC_FMTS \
+ (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
+ SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \
+ SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \
+ SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_U18_3BE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
+ SNDRV_PCM_FMTBIT_S20_3BE | SNDRV_PCM_FMTBIT_U20_3BE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \
+ SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE | \
+ 0)
+
+static inline unsigned long RD(struct au1xpsc_audio_data *ctx, int reg)
+{
+ return __raw_readl(ctx->mmio + reg);
+}
+
+static inline void WR(struct au1xpsc_audio_data *ctx, int reg, unsigned long v)
+{
+ __raw_writel(v, ctx->mmio + reg);
+ wmb();
+}
+
+static int au1xi2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+ struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned long c;
+ int ret;
+
+ ret = -EINVAL;
+ c = ctx->cfg;
+
+ c &= ~CFG_FM_MASK;
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ c |= CFG_FM_I2S;
+ break;
+ case SND_SOC_DAIFMT_MSB:
+ c |= CFG_FM_RJ;
+ break;
+ case SND_SOC_DAIFMT_LSB:
+ c |= CFG_FM_LJ;
+ break;
+ default:
+ goto out;
+ }
+
+ c &= ~(CFG_IC | CFG_ICK); /* IB-IF */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ c |= CFG_IC | CFG_ICK;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ c |= CFG_IC;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ c |= CFG_ICK;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ break;
+ default:
+ goto out;
+ }
+
+ /* I2S controller only supports master */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS: /* CODEC slave */
+ break;
+ default:
+ goto out;
+ }
+
+ ret = 0;
+ ctx->cfg = c;
+out:
+ return ret;
+}
+
+static int au1xi2s_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
+ int stype = SUBSTREAM_TYPE(substream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ /* power up */
+ WR(ctx, I2S_ENABLE, EN_D | EN_CE);
+ WR(ctx, I2S_ENABLE, EN_CE);
+ ctx->cfg |= (stype == PCM_TX) ? CFG_TN : CFG_RN;
+ WR(ctx, I2S_CFG, ctx->cfg);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ ctx->cfg &= ~((stype == PCM_TX) ? CFG_TN : CFG_RN);
+ WR(ctx, I2S_CFG, ctx->cfg);
+ WR(ctx, I2S_ENABLE, EN_D); /* power off */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static unsigned long msbits_to_reg(int msbits)
+{
+ switch (msbits) {
+ case 8:
+ return CFG_SZ_8;
+ case 16:
+ return CFG_SZ_16;
+ case 18:
+ return CFG_SZ_18;
+ case 20:
+ return CFG_SZ_20;
+ case 24:
+ return CFG_SZ_24;
+ }
+ return 0;
+}
+
+static int au1xi2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
+ unsigned long v;
+
+ v = msbits_to_reg(params->msbits);
+ if (!v)
+ return -EINVAL;
+
+ ctx->cfg &= ~CFG_SZ_MASK;
+ ctx->cfg |= v;
+ return 0;
+}
+
+static int au1xi2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
+ snd_soc_dai_set_dma_data(dai, substream, &ctx->dmaids[0]);
+ return 0;
+}
+
+static const struct snd_soc_dai_ops au1xi2s_dai_ops = {
+ .startup = au1xi2s_startup,
+ .trigger = au1xi2s_trigger,
+ .hw_params = au1xi2s_hw_params,
+ .set_fmt = au1xi2s_set_fmt,
+};
+
+static struct snd_soc_dai_driver au1xi2s_dai_driver = {
+ .symmetric_rates = 1,
+ .playback = {
+ .rates = AU1XI2SC_RATES,
+ .formats = AU1XI2SC_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .capture = {
+ .rates = AU1XI2SC_RATES,
+ .formats = AU1XI2SC_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .ops = &au1xi2s_dai_ops,
+};
+
+static int __devinit au1xi2s_drvprobe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *iores, *dmares;
+ struct au1xpsc_audio_data *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iores) {
+ ret = -ENODEV;
+ goto out0;
+ }
+
+ ret = -EBUSY;
+ if (!request_mem_region(iores->start, resource_size(iores),
+ pdev->name))
+ goto out0;
+
+ ctx->mmio = ioremap_nocache(iores->start, resource_size(iores));
+ if (!ctx->mmio)
+ goto out1;
+
+ dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmares)
+ goto out2;
+ ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
+
+ dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!dmares)
+ goto out2;
+ ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
+
+ platform_set_drvdata(pdev, ctx);
+
+ ret = snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver);
+ if (ret)
+ goto out2;
+
+ return 0;
+
+out2:
+ iounmap(ctx->mmio);
+out1:
+ release_mem_region(iores->start, resource_size(iores));
+out0:
+ kfree(ctx);
+ return ret;
+}
+
+static int __devexit au1xi2s_drvremove(struct platform_device *pdev)
+{
+ struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
+ struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */
+
+ iounmap(ctx->mmio);
+ release_mem_region(r->start, resource_size(r));
+ kfree(ctx);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int au1xi2s_drvsuspend(struct device *dev)
+{
+ struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev);
+
+ WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */
+
+ return 0;
+}
+
+static int au1xi2s_drvresume(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops au1xi2sc_pmops = {
+ .suspend = au1xi2s_drvsuspend,
+ .resume = au1xi2s_drvresume,
+};
+
+#define AU1XI2SC_PMOPS (&au1xi2sc_pmops)
+
+#else
+
+#define AU1XI2SC_PMOPS NULL
+
+#endif
+
+static struct platform_driver au1xi2s_driver = {
+ .driver = {
+ .name = "alchemy-i2sc",
+ .owner = THIS_MODULE,
+ .pm = AU1XI2SC_PMOPS,
+ },
+ .probe = au1xi2s_drvprobe,
+ .remove = __devexit_p(au1xi2s_drvremove),
+};
+
+static int __init au1xi2s_load(void)
+{
+ return platform_driver_register(&au1xi2s_driver);
+}
+
+static void __exit au1xi2s_unload(void)
+{
+ platform_driver_unregister(&au1xi2s_driver);
+}
+
+module_init(au1xi2s_load);
+module_exit(au1xi2s_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Au1000/1500/1100 I2S ASoC driver");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index d0db66f24a00..0c6acd547141 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -41,14 +41,14 @@
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3BE)
#define AC97PCR_START(stype) \
- ((stype) == PCM_TX ? PSC_AC97PCR_TS : PSC_AC97PCR_RS)
+ ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TS : PSC_AC97PCR_RS)
#define AC97PCR_STOP(stype) \
- ((stype) == PCM_TX ? PSC_AC97PCR_TP : PSC_AC97PCR_RP)
+ ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TP : PSC_AC97PCR_RP)
#define AC97PCR_CLRFIFO(stype) \
- ((stype) == PCM_TX ? PSC_AC97PCR_TC : PSC_AC97PCR_RC)
+ ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TC : PSC_AC97PCR_RC)
#define AC97STAT_BUSY(stype) \
- ((stype) == PCM_TX ? PSC_AC97STAT_TB : PSC_AC97STAT_RB)
+ ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97STAT_TB : PSC_AC97STAT_RB)
/* instance data. There can be only one, MacLeod!!!! */
static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
@@ -215,7 +215,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
{
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
unsigned long r, ro, stat;
- int chans, t, stype = SUBSTREAM_TYPE(substream);
+ int chans, t, stype = substream->stream;
chans = params_channels(params);
@@ -235,7 +235,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
r |= PSC_AC97CFG_SET_LEN(params->msbits);
/* channels: enable slots for front L/R channel */
- if (stype == PCM_TX) {
+ if (stype == SNDRV_PCM_STREAM_PLAYBACK) {
r &= ~PSC_AC97CFG_TXSLOT_MASK;
r |= PSC_AC97CFG_TXSLOT_ENA(3);
r |= PSC_AC97CFG_TXSLOT_ENA(4);
@@ -294,7 +294,7 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
- int ret, stype = SUBSTREAM_TYPE(substream);
+ int ret, stype = substream->stream;
ret = 0;
@@ -324,12 +324,21 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
return ret;
}
+static int au1xpsc_ac97_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
+ snd_soc_dai_set_dma_data(dai, substream, &pscdata->dmaids[0]);
+ return 0;
+}
+
static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
{
return au1xpsc_ac97_workdata ? 0 : -ENODEV;
}
static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
+ .startup = au1xpsc_ac97_startup,
.trigger = au1xpsc_ac97_trigger,
.hw_params = au1xpsc_ac97_hw_params,
};
@@ -355,7 +364,7 @@ static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
{
int ret;
- struct resource *r;
+ struct resource *iores, *dmares;
unsigned long sel;
struct au1xpsc_audio_data *wd;
@@ -365,20 +374,31 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
mutex_init(&wd->lock);
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iores) {
ret = -ENODEV;
goto out0;
}
ret = -EBUSY;
- if (!request_mem_region(r->start, resource_size(r), pdev->name))
+ if (!request_mem_region(iores->start, resource_size(iores),
+ pdev->name))
goto out0;
- wd->mmio = ioremap(r->start, resource_size(r));
+ wd->mmio = ioremap(iores->start, resource_size(iores));
if (!wd->mmio)
goto out1;
+ dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmares)
+ goto out2;
+ wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
+
+ dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!dmares)
+ goto out2;
+ wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
+
/* configuration: max dma trigger threshold, enable ac97 */
wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 |
PSC_AC97CFG_DE_ENABLE;
@@ -401,17 +421,15 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
if (ret)
- goto out1;
+ goto out2;
- wd->dmapd = au1xpsc_pcm_add(pdev);
- if (wd->dmapd) {
- au1xpsc_ac97_workdata = wd;
- return 0;
- }
+ au1xpsc_ac97_workdata = wd;
+ return 0;
- snd_soc_unregister_dai(&pdev->dev);
+out2:
+ iounmap(wd->mmio);
out1:
- release_mem_region(r->start, resource_size(r));
+ release_mem_region(iores->start, resource_size(iores));
out0:
kfree(wd);
return ret;
@@ -422,9 +440,6 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (wd->dmapd)
- au1xpsc_pcm_destroy(wd->dmapd);
-
snd_soc_unregister_dai(&pdev->dev);
/* disable PSC completely */
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index fca091276320..e03c5ce01b30 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -42,13 +42,13 @@
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
#define I2SSTAT_BUSY(stype) \
- ((stype) == PCM_TX ? PSC_I2SSTAT_TB : PSC_I2SSTAT_RB)
+ ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SSTAT_TB : PSC_I2SSTAT_RB)
#define I2SPCR_START(stype) \
- ((stype) == PCM_TX ? PSC_I2SPCR_TS : PSC_I2SPCR_RS)
+ ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SPCR_TS : PSC_I2SPCR_RS)
#define I2SPCR_STOP(stype) \
- ((stype) == PCM_TX ? PSC_I2SPCR_TP : PSC_I2SPCR_RP)
+ ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SPCR_TP : PSC_I2SPCR_RP)
#define I2SPCR_CLRFIFO(stype) \
- ((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
+ ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
@@ -240,7 +240,7 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
- int ret, stype = SUBSTREAM_TYPE(substream);
+ int ret, stype = substream->stream;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -257,7 +257,16 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
return ret;
}
+static int au1xpsc_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
+ snd_soc_dai_set_dma_data(dai, substream, &pscdata->dmaids[0]);
+ return 0;
+}
+
static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
+ .startup = au1xpsc_i2s_startup,
.trigger = au1xpsc_i2s_trigger,
.hw_params = au1xpsc_i2s_hw_params,
.set_fmt = au1xpsc_i2s_set_fmt,
@@ -281,7 +290,7 @@ static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
{
- struct resource *r;
+ struct resource *iores, *dmares;
unsigned long sel;
int ret;
struct au1xpsc_audio_data *wd;
@@ -290,20 +299,31 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
if (!wd)
return -ENOMEM;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iores) {
ret = -ENODEV;
goto out0;
}
ret = -EBUSY;
- if (!request_mem_region(r->start, resource_size(r), pdev->name))
+ if (!request_mem_region(iores->start, resource_size(iores),
+ pdev->name))
goto out0;
- wd->mmio = ioremap(r->start, resource_size(r));
+ wd->mmio = ioremap(iores->start, resource_size(iores));
if (!wd->mmio)
goto out1;
+ dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmares)
+ goto out2;
+ wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
+
+ dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!dmares)
+ goto out2;
+ wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
+
/* preserve PSC clock source set up by platform (dev.platform_data
* is already occupied by soc layer)
*/
@@ -330,17 +350,13 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
platform_set_drvdata(pdev, wd);
ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
- if (ret)
- goto out1;
-
- /* finally add the DMA device for this PSC */
- wd->dmapd = au1xpsc_pcm_add(pdev);
- if (wd->dmapd)
+ if (!ret)
return 0;
- snd_soc_unregister_dai(&pdev->dev);
+out2:
+ iounmap(wd->mmio);
out1:
- release_mem_region(r->start, resource_size(r));
+ release_mem_region(iores->start, resource_size(iores));
out0:
kfree(wd);
return ret;
@@ -351,9 +367,6 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (wd->dmapd)
- au1xpsc_pcm_destroy(wd->dmapd);
-
snd_soc_unregister_dai(&pdev->dev);
au_writel(0, I2S_CFG(wd));
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h
index b30eadd422a7..b16b2e02e0c9 100644
--- a/sound/soc/au1x/psc.h
+++ b/sound/soc/au1x/psc.h
@@ -1,7 +1,7 @@
/*
- * Au12x0/Au1550 PSC ALSA ASoC audio support.
+ * Alchemy ALSA ASoC audio support.
*
- * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
+ * (c) 2007-2011 MSC Vertriebsges.m.b.H.,
* Manuel Lauss <manuel.lauss@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -13,10 +13,6 @@
#ifndef _AU1X_PCM_H
#define _AU1X_PCM_H
-/* DBDMA helpers */
-extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
-extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
-
struct au1xpsc_audio_data {
void __iomem *mmio;
@@ -27,15 +23,9 @@ struct au1xpsc_audio_data {
unsigned long pm[2];
struct mutex lock;
- struct platform_device *dmapd;
+ int dmaids[2];
};
-#define PCM_TX 0
-#define PCM_RX 1
-
-#define SUBSTREAM_TYPE(substream) \
- ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX)
-
/* easy access macros */
#define PSC_CTRL(x) ((unsigned long)((x)->mmio) + PSC_CTRL_OFFSET)
#define PSC_SEL(x) ((unsigned long)((x)->mmio) + PSC_SEL_OFFSET)
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index fe9d548a6837..9f6bc55fc399 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -27,6 +27,19 @@ config SND_SOC_BFIN_EVAL_ADAU1701
board connected to one of the Blackfin evaluation boards like the
BF5XX-STAMP or BF5XX-EZKIT.
+config SND_SOC_BFIN_EVAL_ADAU1373
+ tristate "Support for the EVAL-ADAU1373 board on Blackfin eval boards"
+ depends on SND_BF5XX_I2S && I2C
+ select SND_BF5XX_SOC_I2S
+ select SND_SOC_ADAU1373
+ help
+ Say Y if you want to add support for the Analog Devices EVAL-ADAU1373
+ board connected to one of the Blackfin evaluation boards like the
+ BF5XX-STAMP or BF5XX-EZKIT.
+
+ Note: This driver assumes that first ADAU1373 DAI is connected to the
+ first SPORT port on the BF5XX board.
+
config SND_SOC_BFIN_EVAL_ADAV80X
tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile
index 6018bf52a234..1bf86ccaa8de 100644
--- a/sound/soc/blackfin/Makefile
+++ b/sound/soc/blackfin/Makefile
@@ -21,6 +21,7 @@ snd-ad1980-objs := bf5xx-ad1980.o
snd-ssm2602-objs := bf5xx-ssm2602.o
snd-ad73311-objs := bf5xx-ad73311.o
snd-ad193x-objs := bf5xx-ad193x.o
+snd-soc-bfin-eval-adau1373-objs := bfin-eval-adau1373.o
snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o
snd-soc-bfin-eval-adav80x-objs := bfin-eval-adav80x.o
@@ -29,5 +30,6 @@ obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o
+obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1373) += snd-soc-bfin-eval-adau1373.o
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1701) += snd-soc-bfin-eval-adau1701.o
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAV80X) += snd-soc-bfin-eval-adav80x.o
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 9e59f680bc19..56815c1d47b3 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -418,7 +418,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
-int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd)
+static int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_soc_dai *dai = rtd->cpu_dai;
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index 61ddf942fd4d..7565e1576ffa 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -257,7 +257,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
-int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
+static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_soc_dai *dai = rtd->cpu_dai;
diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c
index a2d40349fcc4..2fd9f2a06968 100644
--- a/sound/soc/blackfin/bf5xx-sport.c
+++ b/sound/soc/blackfin/bf5xx-sport.c
@@ -33,6 +33,7 @@
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <linux/bug.h>
+#include <linux/module.h>
#include <asm/portmux.h>
#include <asm/dma.h>
#include <asm/blackfin.h>
diff --git a/sound/soc/blackfin/bfin-eval-adau1373.c b/sound/soc/blackfin/bfin-eval-adau1373.c
new file mode 100644
index 000000000000..8df2a3b0cb36
--- /dev/null
+++ b/sound/soc/blackfin/bfin-eval-adau1373.c
@@ -0,0 +1,202 @@
+/*
+ * Machine driver for EVAL-ADAU1373 on Analog Devices bfin
+ * evaluation boards.
+ *
+ * Copyright 2011 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+#include "../codecs/adau1373.h"
+
+static const struct snd_soc_dapm_widget bfin_eval_adau1373_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("Line In1", NULL),
+ SND_SOC_DAPM_LINE("Line In2", NULL),
+ SND_SOC_DAPM_LINE("Line In3", NULL),
+ SND_SOC_DAPM_LINE("Line In4", NULL),
+
+ SND_SOC_DAPM_LINE("Line Out1", NULL),
+ SND_SOC_DAPM_LINE("Line Out2", NULL),
+ SND_SOC_DAPM_LINE("Stereo Out", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_HP("Earpiece", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route bfin_eval_adau1373_dapm_routes[] = {
+ { "AIN1L", NULL, "Line In1" },
+ { "AIN1R", NULL, "Line In1" },
+ { "AIN2L", NULL, "Line In2" },
+ { "AIN2R", NULL, "Line In2" },
+ { "AIN3L", NULL, "Line In3" },
+ { "AIN3R", NULL, "Line In3" },
+ { "AIN4L", NULL, "Line In4" },
+ { "AIN4R", NULL, "Line In4" },
+
+ /* MICBIAS can be connected via a jumper to the line-in jack, since w
+ don't know which one is going to be used, just power both. */
+ { "Line In1", NULL, "MICBIAS1" },
+ { "Line In2", NULL, "MICBIAS1" },
+ { "Line In3", NULL, "MICBIAS1" },
+ { "Line In4", NULL, "MICBIAS1" },
+ { "Line In1", NULL, "MICBIAS2" },
+ { "Line In2", NULL, "MICBIAS2" },
+ { "Line In3", NULL, "MICBIAS2" },
+ { "Line In4", NULL, "MICBIAS2" },
+
+ { "Line Out1", NULL, "LOUT1L" },
+ { "Line Out1", NULL, "LOUT1R" },
+ { "Line Out2", NULL, "LOUT2L" },
+ { "Line Out2", NULL, "LOUT2R" },
+ { "Headphone", NULL, "HPL" },
+ { "Headphone", NULL, "HPR" },
+ { "Earpiece", NULL, "EP" },
+ { "Speaker", NULL, "SPKL" },
+ { "Stereo Out", NULL, "SPKR" },
+};
+
+static int bfin_eval_adau1373_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int ret;
+ int pll_rate;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret)
+ return ret;
+
+ switch (params_rate(params)) {
+ case 48000:
+ case 8000:
+ case 12000:
+ case 16000:
+ case 24000:
+ case 32000:
+ pll_rate = 48000 * 1024;
+ break;
+ case 44100:
+ case 7350:
+ case 11025:
+ case 14700:
+ case 22050:
+ case 29400:
+ pll_rate = 44100 * 1024;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, ADAU1373_PLL1,
+ ADAU1373_PLL_SRC_MCLK1, 12288000, pll_rate);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1373_CLK_SRC_PLL1, pll_rate,
+ SND_SOC_CLOCK_IN);
+
+ return ret;
+}
+
+static int bfin_eval_adau1373_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int pll_rate = 48000 * 1024;
+ int ret;
+
+ ret = snd_soc_dai_set_pll(codec_dai, ADAU1373_PLL1,
+ ADAU1373_PLL_SRC_MCLK1, 12288000, pll_rate);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1373_CLK_SRC_PLL1, pll_rate,
+ SND_SOC_CLOCK_IN);
+
+ return ret;
+}
+static struct snd_soc_ops bfin_eval_adau1373_ops = {
+ .hw_params = bfin_eval_adau1373_hw_params,
+};
+
+static struct snd_soc_dai_link bfin_eval_adau1373_dai = {
+ .name = "adau1373",
+ .stream_name = "adau1373",
+ .cpu_dai_name = "bfin-i2s.0",
+ .codec_dai_name = "adau1373-aif1",
+ .platform_name = "bfin-i2s-pcm-audio",
+ .codec_name = "adau1373.0-001a",
+ .ops = &bfin_eval_adau1373_ops,
+ .init = bfin_eval_adau1373_codec_init,
+};
+
+static struct snd_soc_card bfin_eval_adau1373 = {
+ .name = "bfin-eval-adau1373",
+ .dai_link = &bfin_eval_adau1373_dai,
+ .num_links = 1,
+
+ .dapm_widgets = bfin_eval_adau1373_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1373_dapm_widgets),
+ .dapm_routes = bfin_eval_adau1373_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1373_dapm_routes),
+};
+
+static int bfin_eval_adau1373_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &bfin_eval_adau1373;
+
+ card->dev = &pdev->dev;
+
+ return snd_soc_register_card(&bfin_eval_adau1373);
+}
+
+static int __devexit bfin_eval_adau1373_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_card(card);
+
+ return 0;
+}
+
+static struct platform_driver bfin_eval_adau1373_driver = {
+ .driver = {
+ .name = "bfin-eval-adau1373",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = bfin_eval_adau1373_probe,
+ .remove = __devexit_p(bfin_eval_adau1373_remove),
+};
+
+static int __init bfin_eval_adau1373_init(void)
+{
+ return platform_driver_register(&bfin_eval_adau1373_driver);
+}
+module_init(bfin_eval_adau1373_init);
+
+static void __exit bfin_eval_adau1373_exit(void)
+{
+ platform_driver_unregister(&bfin_eval_adau1373_driver);
+}
+module_exit(bfin_eval_adau1373_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ALSA SoC bfin adau1373 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bfin-eval-adau1373");
diff --git a/sound/soc/blackfin/bfin-eval-adav80x.c b/sound/soc/blackfin/bfin-eval-adav80x.c
index 8d014d01626e..897cfa68a2a6 100644
--- a/sound/soc/blackfin/bfin-eval-adav80x.c
+++ b/sound/soc/blackfin/bfin-eval-adav80x.c
@@ -10,6 +10,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index 19241576b6b5..5ca122e51183 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/mfd/88pm860x.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -772,11 +773,12 @@ static const struct snd_soc_dapm_widget pm860x_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("I2S DIN", "I2S Playback", 0,
- PM860X_DAC_EN_2, 0, 0),
+ SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("I2S DIN1", "I2S Playback", 0,
- PM860X_DAC_EN_2, 0, 0),
+ SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("I2S DOUT", "I2S Capture", 0,
PM860X_I2S_IFACE_3, 5, 1),
+ SND_SOC_DAPM_SUPPLY("I2S CLK", PM860X_DAC_EN_2, 0, 0, NULL, 0),
SND_SOC_DAPM_MUX("I2S Mic Mux", SND_SOC_NOPM, 0, 0, &i2s_mic_mux),
SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adcl_mux),
SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
@@ -868,6 +870,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Left ADC", NULL, "Left ADC MOD"},
{"Right ADC", NULL, "Right ADC MOD"},
+ /* I2S Clock */
+ {"I2S DIN", NULL, "I2S CLK"},
+ {"I2S DIN1", NULL, "I2S CLK"},
+ {"I2S DOUT", NULL, "I2S CLK"},
+
/* PCM/AIF1 Inputs */
{"PCM SDO", NULL, "ADC Left Mux"},
{"PCM SDO", NULL, "ADCR EC Mux"},
@@ -1173,6 +1180,9 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
/* Enable Audio PLL & Audio section */
+ data = AUDIO_PLL | AUDIO_SECTION_ON;
+ pm860x_reg_write(codec->control_data, REG_MISC2, data);
+ udelay(300);
data = AUDIO_PLL | AUDIO_SECTION_RESET
| AUDIO_SECTION_ON;
pm860x_reg_write(codec->control_data, REG_MISC2, data);
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 665d9240c4ae..4584514d93d4 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -17,6 +17,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
select SND_SOC_AD73311
+ select SND_SOC_ADAU1373 if I2C
select SND_SOC_ADAV80X
select SND_SOC_ADS117X
select SND_SOC_AK4104 if SPI_MASTER
@@ -39,6 +40,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9877 if I2C
select SND_SOC_PCM3008
+ select SND_SOC_RT5631 if I2C
select SND_SOC_SGTL5000 if I2C
select SND_SOC_SN95031 if INTEL_SCU_IPC
select SND_SOC_SPDIF
@@ -47,7 +49,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_TLV320AIC23 if I2C
select SND_SOC_TLV320AIC26 if SPI_MASTER
- select SND_SOC_TVL320AIC32X4 if I2C
+ select SND_SOC_TLV320AIC32X4 if I2C
select SND_SOC_TLV320AIC3X if I2C
select SND_SOC_TPA6130A2 if I2C
select SND_SOC_TLV320DAC33 if I2C
@@ -58,6 +60,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WL1273 if MFD_WL1273_CORE
select SND_SOC_WM1250_EV1 if I2C
select SND_SOC_WM2000 if I2C
+ select SND_SOC_WM5100 if I2C
select SND_SOC_WM8350 if MFD_WM8350
select SND_SOC_WM8400 if MFD_WM8400
select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
@@ -139,6 +142,9 @@ config SND_SOC_ADAU1701
select SIGMA
tristate
+config SND_SOC_ADAU1373
+ tristate
+
config SND_SOC_ADAV80X
tristate
@@ -214,6 +220,9 @@ config SND_SOC_MAX9850
config SND_SOC_PCM3008
tristate
+config SND_SOC_RT5631
+ tristate
+
#Freescale sgtl5000 codec
config SND_SOC_SGTL5000
tristate
@@ -240,7 +249,7 @@ config SND_SOC_TLV320AIC26
tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE
depends on SPI
-config SND_SOC_TVL320AIC32X4
+config SND_SOC_TLV320AIC32X4
tristate
config SND_SOC_TLV320AIC3X
@@ -269,6 +278,9 @@ config SND_SOC_WL1273
config SND_SOC_WM1250_EV1
tristate
+config SND_SOC_WM5100
+ tristate
+
config SND_SOC_WM8350
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 5119a7e2c1a8..a2c7842e357b 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -5,6 +5,7 @@ snd-soc-ad193x-objs := ad193x.o
snd-soc-ad1980-objs := ad1980.o
snd-soc-ad73311-objs := ad73311.o
snd-soc-adau1701-objs := adau1701.o
+snd-soc-adau1373-objs := adau1373.o
snd-soc-adav80x-objs := adav80x.o
snd-soc-ads117x-objs := ads117x.o
snd-soc-ak4104-objs := ak4104.o
@@ -25,6 +26,7 @@ snd-soc-max98088-objs := max98088.o
snd-soc-max98095-objs := max98095.o
snd-soc-max9850-objs := max9850.o
snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-rt5631-objs := rt5631.o
snd-soc-sgtl5000-objs := sgtl5000.o
snd-soc-alc5623-objs := alc5623.o
snd-soc-sn95031-objs := sn95031.o
@@ -43,6 +45,7 @@ snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o
snd-soc-wl1273-objs := wl1273.o
snd-soc-wm1250-ev1-objs := wm1250-ev1.o
+snd-soc-wm5100-objs := wm5100.o wm5100-tables.o
snd-soc-wm8350-objs := wm8350.o
snd-soc-wm8400-objs := wm8400.o
snd-soc-wm8510-objs := wm8510.o
@@ -100,6 +103,7 @@ obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
+obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o
obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o
obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o
@@ -123,6 +127,7 @@ obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
+obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
@@ -132,7 +137,7 @@ obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
-obj-$(CONFIG_SND_SOC_TVL320AIC32X4) += snd-soc-tlv320aic32x4.o
+obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
@@ -140,6 +145,7 @@ obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
+obj-$(CONFIG_SND_SOC_WM5100) += snd-soc-wm5100.o
obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 3c087936aa57..e715186b4300 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index eedb6f5e5823..120602130b5c 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -23,7 +23,7 @@
/* codec private data */
struct ad193x_priv {
- enum snd_soc_control_type control_type;
+ struct regmap *regmap;
int sysclk;
};
@@ -103,12 +103,14 @@ static const struct snd_soc_dapm_route audio_paths[] = {
static int ad193x_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- int reg;
- reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
- reg = (mute > 0) ? reg | AD193X_DAC_MASTER_MUTE : reg &
- (~AD193X_DAC_MASTER_MUTE);
- snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
+ if (mute)
+ snd_soc_update_bits(codec, AD193X_DAC_CTRL2,
+ AD193X_DAC_MASTER_MUTE,
+ AD193X_DAC_MASTER_MUTE);
+ else
+ snd_soc_update_bits(codec, AD193X_DAC_CTRL2,
+ AD193X_DAC_MASTER_MUTE, 0);
return 0;
}
@@ -262,7 +264,7 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- int word_len = 0, reg = 0, master_rate = 0;
+ int word_len = 0, master_rate = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
@@ -297,18 +299,15 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
break;
}
- reg = snd_soc_read(codec, AD193X_PLL_CLK_CTRL0);
- reg = (reg & AD193X_PLL_INPUT_MASK) | master_rate;
- snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg);
+ snd_soc_update_bits(codec, AD193X_PLL_CLK_CTRL0,
+ AD193X_PLL_INPUT_MASK, master_rate);
- reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
- reg = (reg & (~AD193X_DAC_WORD_LEN_MASK))
- | (word_len << AD193X_DAC_WORD_LEN_SHFT);
- snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
+ snd_soc_update_bits(codec, AD193X_DAC_CTRL2,
+ AD193X_DAC_WORD_LEN_MASK,
+ word_len << AD193X_DAC_WORD_LEN_SHFT);
- reg = snd_soc_read(codec, AD193X_ADC_CTRL1);
- reg = (reg & (~AD193X_ADC_WORD_LEN_MASK)) | word_len;
- snd_soc_write(codec, AD193X_ADC_CTRL1, reg);
+ snd_soc_update_bits(codec, AD193X_ADC_CTRL1,
+ AD193X_ADC_WORD_LEN_MASK, word_len);
return 0;
}
@@ -349,10 +348,8 @@ static int ad193x_probe(struct snd_soc_codec *codec)
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
- if (ad193x->control_type == SND_SOC_I2C)
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->control_type);
- else
- ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->control_type);
+ codec->control_data = ad193x->regmap;
+ ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
if (ret < 0) {
dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
return ret;
@@ -388,6 +385,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
};
#if defined(CONFIG_SPI_MASTER)
+
+static const struct regmap_config ad193x_spi_regmap_config = {
+ .val_bits = 8,
+ .reg_bits = 16,
+ .read_flag_mask = 0x09,
+ .write_flag_mask = 0x08,
+};
+
static int __devinit ad193x_spi_probe(struct spi_device *spi)
{
struct ad193x_priv *ad193x;
@@ -397,20 +402,36 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi)
if (ad193x == NULL)
return -ENOMEM;
+ ad193x->regmap = regmap_init_spi(spi, &ad193x_spi_regmap_config);
+ if (IS_ERR(ad193x->regmap)) {
+ ret = PTR_ERR(ad193x->regmap);
+ goto err_free;
+ }
+
spi_set_drvdata(spi, ad193x);
- ad193x->control_type = SND_SOC_SPI;
ret = snd_soc_register_codec(&spi->dev,
&soc_codec_dev_ad193x, &ad193x_dai, 1);
if (ret < 0)
- kfree(ad193x);
+ goto err_regmap_exit;
+
+ return 0;
+
+err_regmap_exit:
+ regmap_exit(ad193x->regmap);
+err_free:
+ kfree(ad193x);
+
return ret;
}
static int __devexit ad193x_spi_remove(struct spi_device *spi)
{
+ struct ad193x_priv *ad193x = spi_get_drvdata(spi);
+
snd_soc_unregister_codec(&spi->dev);
- kfree(spi_get_drvdata(spi));
+ regmap_exit(ad193x->regmap);
+ kfree(ad193x);
return 0;
}
@@ -425,6 +446,12 @@ static struct spi_driver ad193x_spi_driver = {
#endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+static const struct regmap_config ad193x_i2c_regmap_config = {
+ .val_bits = 8,
+ .reg_bits = 8,
+};
+
static const struct i2c_device_id ad193x_id[] = {
{ "ad1936", 0 },
{ "ad1937", 0 },
@@ -442,20 +469,35 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client,
if (ad193x == NULL)
return -ENOMEM;
+ ad193x->regmap = regmap_init_i2c(client, &ad193x_i2c_regmap_config);
+ if (IS_ERR(ad193x->regmap)) {
+ ret = PTR_ERR(ad193x->regmap);
+ goto err_free;
+ }
+
i2c_set_clientdata(client, ad193x);
- ad193x->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&client->dev,
&soc_codec_dev_ad193x, &ad193x_dai, 1);
if (ret < 0)
- kfree(ad193x);
+ goto err_regmap_exit;
+
+ return 0;
+
+err_regmap_exit:
+ regmap_exit(ad193x->regmap);
+err_free:
+ kfree(ad193x);
return ret;
}
static int __devexit ad193x_i2c_remove(struct i2c_client *client)
{
+ struct ad193x_priv *ad193x = i2c_get_clientdata(client);
+
snd_soc_unregister_codec(&client->dev);
- kfree(i2c_get_clientdata(client));
+ regmap_exit(ad193x->regmap);
+ kfree(ad193x);
return 0;
}
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
index cccc2e8e5fbd..1507eaa425a3 100644
--- a/sound/soc/codecs/ad193x.h
+++ b/sound/soc/codecs/ad193x.h
@@ -9,20 +9,20 @@
#ifndef __AD193X_H__
#define __AD193X_H__
-#define AD193X_PLL_CLK_CTRL0 0x800
+#define AD193X_PLL_CLK_CTRL0 0x00
#define AD193X_PLL_POWERDOWN 0x01
-#define AD193X_PLL_INPUT_MASK (~0x6)
+#define AD193X_PLL_INPUT_MASK 0x6
#define AD193X_PLL_INPUT_256 (0 << 1)
#define AD193X_PLL_INPUT_384 (1 << 1)
#define AD193X_PLL_INPUT_512 (2 << 1)
#define AD193X_PLL_INPUT_768 (3 << 1)
-#define AD193X_PLL_CLK_CTRL1 0x801
-#define AD193X_DAC_CTRL0 0x802
+#define AD193X_PLL_CLK_CTRL1 0x01
+#define AD193X_DAC_CTRL0 0x02
#define AD193X_DAC_POWERDOWN 0x01
#define AD193X_DAC_SERFMT_MASK 0xC0
#define AD193X_DAC_SERFMT_STEREO (0 << 6)
#define AD193X_DAC_SERFMT_TDM (1 << 6)
-#define AD193X_DAC_CTRL1 0x803
+#define AD193X_DAC_CTRL1 0x03
#define AD193X_DAC_2_CHANNELS 0
#define AD193X_DAC_4_CHANNELS 1
#define AD193X_DAC_8_CHANNELS 2
@@ -33,11 +33,11 @@
#define AD193X_DAC_BCLK_MASTER (1 << 5)
#define AD193X_DAC_LEFT_HIGH (1 << 3)
#define AD193X_DAC_BCLK_INV (1 << 7)
-#define AD193X_DAC_CTRL2 0x804
+#define AD193X_DAC_CTRL2 0x04
#define AD193X_DAC_WORD_LEN_SHFT 3
#define AD193X_DAC_WORD_LEN_MASK 0x18
#define AD193X_DAC_MASTER_MUTE 1
-#define AD193X_DAC_CHNL_MUTE 0x805
+#define AD193X_DAC_CHNL_MUTE 0x05
#define AD193X_DACL1_MUTE 0
#define AD193X_DACR1_MUTE 1
#define AD193X_DACL2_MUTE 2
@@ -46,28 +46,28 @@
#define AD193X_DACR3_MUTE 5
#define AD193X_DACL4_MUTE 6
#define AD193X_DACR4_MUTE 7
-#define AD193X_DAC_L1_VOL 0x806
-#define AD193X_DAC_R1_VOL 0x807
-#define AD193X_DAC_L2_VOL 0x808
-#define AD193X_DAC_R2_VOL 0x809
-#define AD193X_DAC_L3_VOL 0x80a
-#define AD193X_DAC_R3_VOL 0x80b
-#define AD193X_DAC_L4_VOL 0x80c
-#define AD193X_DAC_R4_VOL 0x80d
-#define AD193X_ADC_CTRL0 0x80e
+#define AD193X_DAC_L1_VOL 0x06
+#define AD193X_DAC_R1_VOL 0x07
+#define AD193X_DAC_L2_VOL 0x08
+#define AD193X_DAC_R2_VOL 0x09
+#define AD193X_DAC_L3_VOL 0x0a
+#define AD193X_DAC_R3_VOL 0x0b
+#define AD193X_DAC_L4_VOL 0x0c
+#define AD193X_DAC_R4_VOL 0x0d
+#define AD193X_ADC_CTRL0 0x0e
#define AD193X_ADC_POWERDOWN 0x01
#define AD193X_ADC_HIGHPASS_FILTER 1
#define AD193X_ADCL1_MUTE 2
#define AD193X_ADCR1_MUTE 3
#define AD193X_ADCL2_MUTE 4
#define AD193X_ADCR2_MUTE 5
-#define AD193X_ADC_CTRL1 0x80f
+#define AD193X_ADC_CTRL1 0x0f
#define AD193X_ADC_SERFMT_MASK 0x60
#define AD193X_ADC_SERFMT_STEREO (0 << 5)
#define AD193X_ADC_SERFMT_TDM (1 << 5)
#define AD193X_ADC_SERFMT_AUX (2 << 5)
#define AD193X_ADC_WORD_LEN_MASK 0x3
-#define AD193X_ADC_CTRL2 0x810
+#define AD193X_ADC_CTRL2 0x10
#define AD193X_ADC_2_CHANNELS 0
#define AD193X_ADC_4_CHANNELS 1
#define AD193X_ADC_8_CHANNELS 2
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 923b364a3e41..e3931cc5e66c 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -148,7 +148,6 @@ static struct snd_soc_dai_driver ad1980_dai = {
.rates = SNDRV_PCM_RATE_48000,
.formats = SND_SOC_STD_AC97_FMTS, },
};
-EXPORT_SYMBOL_GPL(ad1980_dai);
static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
{
@@ -200,18 +199,22 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
}
/* Read out vendor ID to make sure it is ad1980 */
- if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144)
+ if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) {
+ ret = -ENODEV;
goto reset_err;
+ }
vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2);
if (vendor_id2 != 0x5370) {
- if (vendor_id2 != 0x5374)
+ if (vendor_id2 != 0x5374) {
+ ret = -ENODEV;
goto reset_err;
- else
+ } else {
printk(KERN_WARNING "ad1980: "
"Found AD1981 - only 2/2 IN/OUT Channels "
"supported\n");
+ }
}
/* unmute captures and playbacks volume */
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
new file mode 100644
index 000000000000..1ccf8dd47576
--- /dev/null
+++ b/sound/soc/codecs/adau1373.c
@@ -0,0 +1,1414 @@
+/*
+ * Analog Devices ADAU1373 Audio Codec drive
+ *
+ * Copyright 2011 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/gcd.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/adau1373.h>
+
+#include "adau1373.h"
+
+struct adau1373_dai {
+ unsigned int clk_src;
+ unsigned int sysclk;
+ bool enable_src;
+ bool master;
+};
+
+struct adau1373 {
+ struct adau1373_dai dais[3];
+};
+
+#define ADAU1373_INPUT_MODE 0x00
+#define ADAU1373_AINL_CTRL(x) (0x01 + (x) * 2)
+#define ADAU1373_AINR_CTRL(x) (0x02 + (x) * 2)
+#define ADAU1373_LLINE_OUT(x) (0x9 + (x) * 2)
+#define ADAU1373_RLINE_OUT(x) (0xa + (x) * 2)
+#define ADAU1373_LSPK_OUT 0x0d
+#define ADAU1373_RSPK_OUT 0x0e
+#define ADAU1373_LHP_OUT 0x0f
+#define ADAU1373_RHP_OUT 0x10
+#define ADAU1373_ADC_GAIN 0x11
+#define ADAU1373_LADC_MIXER 0x12
+#define ADAU1373_RADC_MIXER 0x13
+#define ADAU1373_LLINE1_MIX 0x14
+#define ADAU1373_RLINE1_MIX 0x15
+#define ADAU1373_LLINE2_MIX 0x16
+#define ADAU1373_RLINE2_MIX 0x17
+#define ADAU1373_LSPK_MIX 0x18
+#define ADAU1373_RSPK_MIX 0x19
+#define ADAU1373_LHP_MIX 0x1a
+#define ADAU1373_RHP_MIX 0x1b
+#define ADAU1373_EP_MIX 0x1c
+#define ADAU1373_HP_CTRL 0x1d
+#define ADAU1373_HP_CTRL2 0x1e
+#define ADAU1373_LS_CTRL 0x1f
+#define ADAU1373_EP_CTRL 0x21
+#define ADAU1373_MICBIAS_CTRL1 0x22
+#define ADAU1373_MICBIAS_CTRL2 0x23
+#define ADAU1373_OUTPUT_CTRL 0x24
+#define ADAU1373_PWDN_CTRL1 0x25
+#define ADAU1373_PWDN_CTRL2 0x26
+#define ADAU1373_PWDN_CTRL3 0x27
+#define ADAU1373_DPLL_CTRL(x) (0x28 + (x) * 7)
+#define ADAU1373_PLL_CTRL1(x) (0x29 + (x) * 7)
+#define ADAU1373_PLL_CTRL2(x) (0x2a + (x) * 7)
+#define ADAU1373_PLL_CTRL3(x) (0x2b + (x) * 7)
+#define ADAU1373_PLL_CTRL4(x) (0x2c + (x) * 7)
+#define ADAU1373_PLL_CTRL5(x) (0x2d + (x) * 7)
+#define ADAU1373_PLL_CTRL6(x) (0x2e + (x) * 7)
+#define ADAU1373_PLL_CTRL7(x) (0x2f + (x) * 7)
+#define ADAU1373_HEADDECT 0x36
+#define ADAU1373_ADC_DAC_STATUS 0x37
+#define ADAU1373_ADC_CTRL 0x3c
+#define ADAU1373_DAI(x) (0x44 + (x))
+#define ADAU1373_CLK_SRC_DIV(x) (0x40 + (x) * 2)
+#define ADAU1373_BCLKDIV(x) (0x47 + (x))
+#define ADAU1373_SRC_RATIOA(x) (0x4a + (x) * 2)
+#define ADAU1373_SRC_RATIOB(x) (0x4b + (x) * 2)
+#define ADAU1373_DEEMP_CTRL 0x50
+#define ADAU1373_SRC_DAI_CTRL(x) (0x51 + (x))
+#define ADAU1373_DIN_MIX_CTRL(x) (0x56 + (x))
+#define ADAU1373_DOUT_MIX_CTRL(x) (0x5b + (x))
+#define ADAU1373_DAI_PBL_VOL(x) (0x62 + (x) * 2)
+#define ADAU1373_DAI_PBR_VOL(x) (0x63 + (x) * 2)
+#define ADAU1373_DAI_RECL_VOL(x) (0x68 + (x) * 2)
+#define ADAU1373_DAI_RECR_VOL(x) (0x69 + (x) * 2)
+#define ADAU1373_DAC1_PBL_VOL 0x6e
+#define ADAU1373_DAC1_PBR_VOL 0x6f
+#define ADAU1373_DAC2_PBL_VOL 0x70
+#define ADAU1373_DAC2_PBR_VOL 0x71
+#define ADAU1373_ADC_RECL_VOL 0x72
+#define ADAU1373_ADC_RECR_VOL 0x73
+#define ADAU1373_DMIC_RECL_VOL 0x74
+#define ADAU1373_DMIC_RECR_VOL 0x75
+#define ADAU1373_VOL_GAIN1 0x76
+#define ADAU1373_VOL_GAIN2 0x77
+#define ADAU1373_VOL_GAIN3 0x78
+#define ADAU1373_HPF_CTRL 0x7d
+#define ADAU1373_BASS1 0x7e
+#define ADAU1373_BASS2 0x7f
+#define ADAU1373_DRC(x) (0x80 + (x) * 0x10)
+#define ADAU1373_3D_CTRL1 0xc0
+#define ADAU1373_3D_CTRL2 0xc1
+#define ADAU1373_FDSP_SEL1 0xdc
+#define ADAU1373_FDSP_SEL2 0xdd
+#define ADAU1373_FDSP_SEL3 0xde
+#define ADAU1373_FDSP_SEL4 0xdf
+#define ADAU1373_DIGMICCTRL 0xe2
+#define ADAU1373_DIGEN 0xeb
+#define ADAU1373_SOFT_RESET 0xff
+
+
+#define ADAU1373_PLL_CTRL6_DPLL_BYPASS BIT(1)
+#define ADAU1373_PLL_CTRL6_PLL_EN BIT(0)
+
+#define ADAU1373_DAI_INVERT_BCLK BIT(7)
+#define ADAU1373_DAI_MASTER BIT(6)
+#define ADAU1373_DAI_INVERT_LRCLK BIT(4)
+#define ADAU1373_DAI_WLEN_16 0x0
+#define ADAU1373_DAI_WLEN_20 0x4
+#define ADAU1373_DAI_WLEN_24 0x8
+#define ADAU1373_DAI_WLEN_32 0xc
+#define ADAU1373_DAI_WLEN_MASK 0xc
+#define ADAU1373_DAI_FORMAT_RIGHT_J 0x0
+#define ADAU1373_DAI_FORMAT_LEFT_J 0x1
+#define ADAU1373_DAI_FORMAT_I2S 0x2
+#define ADAU1373_DAI_FORMAT_DSP 0x3
+
+#define ADAU1373_BCLKDIV_SOURCE BIT(5)
+#define ADAU1373_BCLKDIV_32 0x03
+#define ADAU1373_BCLKDIV_64 0x02
+#define ADAU1373_BCLKDIV_128 0x01
+#define ADAU1373_BCLKDIV_256 0x00
+
+#define ADAU1373_ADC_CTRL_PEAK_DETECT BIT(0)
+#define ADAU1373_ADC_CTRL_RESET BIT(1)
+#define ADAU1373_ADC_CTRL_RESET_FORCE BIT(2)
+
+#define ADAU1373_OUTPUT_CTRL_LDIFF BIT(3)
+#define ADAU1373_OUTPUT_CTRL_LNFBEN BIT(2)
+
+#define ADAU1373_PWDN_CTRL3_PWR_EN BIT(0)
+
+#define ADAU1373_EP_CTRL_MICBIAS1_OFFSET 4
+#define ADAU1373_EP_CTRL_MICBIAS2_OFFSET 2
+
+static const uint8_t adau1373_default_regs[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* 0x30 */
+ 0x00, 0x00, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x00, /* 0x40 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x80 */
+ 0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00,
+ 0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x90 */
+ 0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00,
+ 0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0xa0 */
+ 0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, /* 0xe0 */
+ 0x00, 0x1f, 0x0f, 0x00, 0x00,
+};
+
+static const unsigned int adau1373_out_tlv[] = {
+ TLV_DB_RANGE_HEAD(4),
+ 0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1),
+ 8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0),
+ 16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0),
+ 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0),
+};
+
+static const DECLARE_TLV_DB_MINMAX(adau1373_digital_tlv, -9563, 0);
+static const DECLARE_TLV_DB_SCALE(adau1373_in_pga_tlv, -1300, 100, 1);
+static const DECLARE_TLV_DB_SCALE(adau1373_ep_tlv, -600, 600, 1);
+
+static const DECLARE_TLV_DB_SCALE(adau1373_input_boost_tlv, 0, 2000, 0);
+static const DECLARE_TLV_DB_SCALE(adau1373_gain_boost_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(adau1373_speaker_boost_tlv, 1200, 600, 0);
+
+static const char *adau1373_fdsp_sel_text[] = {
+ "None",
+ "Channel 1",
+ "Channel 2",
+ "Channel 3",
+ "Channel 4",
+ "Channel 5",
+};
+
+static const SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum,
+ ADAU1373_FDSP_SEL1, 4, adau1373_fdsp_sel_text);
+static const SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum,
+ ADAU1373_FDSP_SEL1, 0, adau1373_fdsp_sel_text);
+static const SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum,
+ ADAU1373_FDSP_SEL2, 0, adau1373_fdsp_sel_text);
+static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum,
+ ADAU1373_FDSP_SEL3, 0, adau1373_fdsp_sel_text);
+static const SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum,
+ ADAU1373_FDSP_SEL4, 4, adau1373_fdsp_sel_text);
+
+static const char *adau1373_hpf_cutoff_text[] = {
+ "3.7Hz", "50Hz", "100Hz", "150Hz", "200Hz", "250Hz", "300Hz", "350Hz",
+ "400Hz", "450Hz", "500Hz", "550Hz", "600Hz", "650Hz", "700Hz", "750Hz",
+ "800Hz",
+};
+
+static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum,
+ ADAU1373_HPF_CTRL, 3, adau1373_hpf_cutoff_text);
+
+static const char *adau1373_bass_lpf_cutoff_text[] = {
+ "801Hz", "1001Hz",
+};
+
+static const char *adau1373_bass_clip_level_text[] = {
+ "0.125", "0.250", "0.370", "0.500", "0.625", "0.750", "0.875",
+};
+
+static const unsigned int adau1373_bass_clip_level_values[] = {
+ 1, 2, 3, 4, 5, 6, 7,
+};
+
+static const char *adau1373_bass_hpf_cutoff_text[] = {
+ "158Hz", "232Hz", "347Hz", "520Hz",
+};
+
+static const unsigned int adau1373_bass_tlv[] = {
+ TLV_DB_RANGE_HEAD(4),
+ 0, 2, TLV_DB_SCALE_ITEM(-600, 600, 1),
+ 3, 4, TLV_DB_SCALE_ITEM(950, 250, 0),
+ 5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0),
+};
+
+static const SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum,
+ ADAU1373_BASS1, 5, adau1373_bass_lpf_cutoff_text);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum,
+ ADAU1373_BASS1, 2, 7, adau1373_bass_clip_level_text,
+ adau1373_bass_clip_level_values);
+
+static const SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum,
+ ADAU1373_BASS1, 0, adau1373_bass_hpf_cutoff_text);
+
+static const char *adau1373_3d_level_text[] = {
+ "0%", "6.67%", "13.33%", "20%", "26.67%", "33.33%",
+ "40%", "46.67%", "53.33%", "60%", "66.67%", "73.33%",
+ "80%", "86.67", "99.33%", "100%"
+};
+
+static const char *adau1373_3d_cutoff_text[] = {
+ "No 3D", "0.03125 fs", "0.04583 fs", "0.075 fs", "0.11458 fs",
+ "0.16875 fs", "0.27083 fs"
+};
+
+static const SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum,
+ ADAU1373_3D_CTRL1, 4, adau1373_3d_level_text);
+static const SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum,
+ ADAU1373_3D_CTRL1, 0, adau1373_3d_cutoff_text);
+
+static const unsigned int adau1373_3d_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+ 1, 7, TLV_DB_LINEAR_ITEM(-1800, -120),
+};
+
+static const char *adau1373_lr_mux_text[] = {
+ "Mute",
+ "Right Channel (L+R)",
+ "Left Channel (L+R)",
+ "Stereo",
+};
+
+static const SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum,
+ ADAU1373_OUTPUT_CTRL, 4, adau1373_lr_mux_text);
+static const SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum,
+ ADAU1373_OUTPUT_CTRL, 6, adau1373_lr_mux_text);
+static const SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum,
+ ADAU1373_LS_CTRL, 4, adau1373_lr_mux_text);
+
+static const struct snd_kcontrol_new adau1373_controls[] = {
+ SOC_DOUBLE_R_TLV("AIF1 Capture Volume", ADAU1373_DAI_RECL_VOL(0),
+ ADAU1373_DAI_RECR_VOL(0), 0, 0xff, 1, adau1373_digital_tlv),
+ SOC_DOUBLE_R_TLV("AIF2 Capture Volume", ADAU1373_DAI_RECL_VOL(1),
+ ADAU1373_DAI_RECR_VOL(1), 0, 0xff, 1, adau1373_digital_tlv),
+ SOC_DOUBLE_R_TLV("AIF3 Capture Volume", ADAU1373_DAI_RECL_VOL(2),
+ ADAU1373_DAI_RECR_VOL(2), 0, 0xff, 1, adau1373_digital_tlv),
+
+ SOC_DOUBLE_R_TLV("ADC Capture Volume", ADAU1373_ADC_RECL_VOL,
+ ADAU1373_ADC_RECR_VOL, 0, 0xff, 1, adau1373_digital_tlv),
+ SOC_DOUBLE_R_TLV("DMIC Capture Volume", ADAU1373_DMIC_RECL_VOL,
+ ADAU1373_DMIC_RECR_VOL, 0, 0xff, 1, adau1373_digital_tlv),
+
+ SOC_DOUBLE_R_TLV("AIF1 Playback Volume", ADAU1373_DAI_PBL_VOL(0),
+ ADAU1373_DAI_PBR_VOL(0), 0, 0xff, 1, adau1373_digital_tlv),
+ SOC_DOUBLE_R_TLV("AIF2 Playback Volume", ADAU1373_DAI_PBL_VOL(1),
+ ADAU1373_DAI_PBR_VOL(1), 0, 0xff, 1, adau1373_digital_tlv),
+ SOC_DOUBLE_R_TLV("AIF3 Playback Volume", ADAU1373_DAI_PBL_VOL(2),
+ ADAU1373_DAI_PBR_VOL(2), 0, 0xff, 1, adau1373_digital_tlv),
+
+ SOC_DOUBLE_R_TLV("DAC1 Playback Volume", ADAU1373_DAC1_PBL_VOL,
+ ADAU1373_DAC1_PBR_VOL, 0, 0xff, 1, adau1373_digital_tlv),
+ SOC_DOUBLE_R_TLV("DAC2 Playback Volume", ADAU1373_DAC2_PBL_VOL,
+ ADAU1373_DAC2_PBR_VOL, 0, 0xff, 1, adau1373_digital_tlv),
+
+ SOC_DOUBLE_R_TLV("Lineout1 Playback Volume", ADAU1373_LLINE_OUT(0),
+ ADAU1373_RLINE_OUT(0), 0, 0x1f, 0, adau1373_out_tlv),
+ SOC_DOUBLE_R_TLV("Speaker Playback Volume", ADAU1373_LSPK_OUT,
+ ADAU1373_RSPK_OUT, 0, 0x1f, 0, adau1373_out_tlv),
+ SOC_DOUBLE_R_TLV("Headphone Playback Volume", ADAU1373_LHP_OUT,
+ ADAU1373_RHP_OUT, 0, 0x1f, 0, adau1373_out_tlv),
+
+ SOC_DOUBLE_R_TLV("Input 1 Capture Volume", ADAU1373_AINL_CTRL(0),
+ ADAU1373_AINR_CTRL(0), 0, 0x1f, 0, adau1373_in_pga_tlv),
+ SOC_DOUBLE_R_TLV("Input 2 Capture Volume", ADAU1373_AINL_CTRL(1),
+ ADAU1373_AINR_CTRL(1), 0, 0x1f, 0, adau1373_in_pga_tlv),
+ SOC_DOUBLE_R_TLV("Input 3 Capture Volume", ADAU1373_AINL_CTRL(2),
+ ADAU1373_AINR_CTRL(2), 0, 0x1f, 0, adau1373_in_pga_tlv),
+ SOC_DOUBLE_R_TLV("Input 4 Capture Volume", ADAU1373_AINL_CTRL(3),
+ ADAU1373_AINR_CTRL(3), 0, 0x1f, 0, adau1373_in_pga_tlv),
+
+ SOC_SINGLE_TLV("Earpiece Playback Volume", ADAU1373_EP_CTRL, 0, 3, 0,
+ adau1373_ep_tlv),
+
+ SOC_DOUBLE_TLV("AIF3 Boost Playback Volume", ADAU1373_VOL_GAIN1, 4, 5,
+ 1, 0, adau1373_gain_boost_tlv),
+ SOC_DOUBLE_TLV("AIF2 Boost Playback Volume", ADAU1373_VOL_GAIN1, 2, 3,
+ 1, 0, adau1373_gain_boost_tlv),
+ SOC_DOUBLE_TLV("AIF1 Boost Playback Volume", ADAU1373_VOL_GAIN1, 0, 1,
+ 1, 0, adau1373_gain_boost_tlv),
+ SOC_DOUBLE_TLV("AIF3 Boost Capture Volume", ADAU1373_VOL_GAIN2, 4, 5,
+ 1, 0, adau1373_gain_boost_tlv),
+ SOC_DOUBLE_TLV("AIF2 Boost Capture Volume", ADAU1373_VOL_GAIN2, 2, 3,
+ 1, 0, adau1373_gain_boost_tlv),
+ SOC_DOUBLE_TLV("AIF1 Boost Capture Volume", ADAU1373_VOL_GAIN2, 0, 1,
+ 1, 0, adau1373_gain_boost_tlv),
+ SOC_DOUBLE_TLV("DMIC Boost Capture Volume", ADAU1373_VOL_GAIN3, 6, 7,
+ 1, 0, adau1373_gain_boost_tlv),
+ SOC_DOUBLE_TLV("ADC Boost Capture Volume", ADAU1373_VOL_GAIN3, 4, 5,
+ 1, 0, adau1373_gain_boost_tlv),
+ SOC_DOUBLE_TLV("DAC2 Boost Playback Volume", ADAU1373_VOL_GAIN3, 2, 3,
+ 1, 0, adau1373_gain_boost_tlv),
+ SOC_DOUBLE_TLV("DAC1 Boost Playback Volume", ADAU1373_VOL_GAIN3, 0, 1,
+ 1, 0, adau1373_gain_boost_tlv),
+
+ SOC_DOUBLE_TLV("Input 1 Boost Capture Volume", ADAU1373_ADC_GAIN, 0, 4,
+ 1, 0, adau1373_input_boost_tlv),
+ SOC_DOUBLE_TLV("Input 2 Boost Capture Volume", ADAU1373_ADC_GAIN, 1, 5,
+ 1, 0, adau1373_input_boost_tlv),
+ SOC_DOUBLE_TLV("Input 3 Boost Capture Volume", ADAU1373_ADC_GAIN, 2, 6,
+ 1, 0, adau1373_input_boost_tlv),
+ SOC_DOUBLE_TLV("Input 4 Boost Capture Volume", ADAU1373_ADC_GAIN, 3, 7,
+ 1, 0, adau1373_input_boost_tlv),
+
+ SOC_DOUBLE_TLV("Speaker Boost Playback Volume", ADAU1373_LS_CTRL, 2, 3,
+ 1, 0, adau1373_speaker_boost_tlv),
+
+ SOC_ENUM("Lineout1 LR Mux", adau1373_lineout1_lr_mux_enum),
+ SOC_ENUM("Speaker LR Mux", adau1373_speaker_lr_mux_enum),
+
+ SOC_ENUM("HPF Cutoff", adau1373_hpf_cutoff_enum),
+ SOC_DOUBLE("HPF Switch", ADAU1373_HPF_CTRL, 1, 0, 1, 0),
+ SOC_ENUM("HPF Channel", adau1373_hpf_channel_enum),
+
+ SOC_ENUM("Bass HPF Cutoff", adau1373_bass_hpf_cutoff_enum),
+ SOC_VALUE_ENUM("Bass Clip Level Threshold",
+ adau1373_bass_clip_level_enum),
+ SOC_ENUM("Bass LPF Cutoff", adau1373_bass_lpf_cutoff_enum),
+ SOC_DOUBLE("Bass Playback Switch", ADAU1373_BASS2, 0, 1, 1, 0),
+ SOC_SINGLE_TLV("Bass Playback Volume", ADAU1373_BASS2, 2, 7, 0,
+ adau1373_bass_tlv),
+ SOC_ENUM("Bass Channel", adau1373_bass_channel_enum),
+
+ SOC_ENUM("3D Freq", adau1373_3d_cutoff_enum),
+ SOC_ENUM("3D Level", adau1373_3d_level_enum),
+ SOC_SINGLE("3D Playback Switch", ADAU1373_3D_CTRL2, 0, 1, 0),
+ SOC_SINGLE_TLV("3D Playback Volume", ADAU1373_3D_CTRL2, 2, 7, 0,
+ adau1373_3d_tlv),
+ SOC_ENUM("3D Channel", adau1373_bass_channel_enum),
+
+ SOC_SINGLE("Zero Cross Switch", ADAU1373_PWDN_CTRL3, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new adau1373_lineout2_controls[] = {
+ SOC_DOUBLE_R_TLV("Lineout2 Playback Volume", ADAU1373_LLINE_OUT(1),
+ ADAU1373_RLINE_OUT(1), 0, 0x1f, 0, adau1373_out_tlv),
+ SOC_ENUM("Lineout2 LR Mux", adau1373_lineout2_lr_mux_enum),
+};
+
+static const struct snd_kcontrol_new adau1373_drc_controls[] = {
+ SOC_ENUM("DRC1 Channel", adau1373_drc1_channel_enum),
+ SOC_ENUM("DRC2 Channel", adau1373_drc2_channel_enum),
+ SOC_ENUM("DRC3 Channel", adau1373_drc3_channel_enum),
+};
+
+static int adau1373_pll_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ unsigned int pll_id = w->name[3] - '1';
+ unsigned int val;
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ val = ADAU1373_PLL_CTRL6_PLL_EN;
+ else
+ val = 0;
+
+ snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id),
+ ADAU1373_PLL_CTRL6_PLL_EN, val);
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ mdelay(5);
+
+ return 0;
+}
+
+static const char *adau1373_decimator_text[] = {
+ "ADC",
+ "DMIC1",
+};
+
+static const struct soc_enum adau1373_decimator_enum =
+ SOC_ENUM_SINGLE(0, 0, 2, adau1373_decimator_text);
+
+static const struct snd_kcontrol_new adau1373_decimator_mux =
+ SOC_DAPM_ENUM_VIRT("Decimator Mux", adau1373_decimator_enum);
+
+static const struct snd_kcontrol_new adau1373_left_adc_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DAC1 Switch", ADAU1373_LADC_MIXER, 4, 1, 0),
+ SOC_DAPM_SINGLE("Input 4 Switch", ADAU1373_LADC_MIXER, 3, 1, 0),
+ SOC_DAPM_SINGLE("Input 3 Switch", ADAU1373_LADC_MIXER, 2, 1, 0),
+ SOC_DAPM_SINGLE("Input 2 Switch", ADAU1373_LADC_MIXER, 1, 1, 0),
+ SOC_DAPM_SINGLE("Input 1 Switch", ADAU1373_LADC_MIXER, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new adau1373_right_adc_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DAC1 Switch", ADAU1373_RADC_MIXER, 4, 1, 0),
+ SOC_DAPM_SINGLE("Input 4 Switch", ADAU1373_RADC_MIXER, 3, 1, 0),
+ SOC_DAPM_SINGLE("Input 3 Switch", ADAU1373_RADC_MIXER, 2, 1, 0),
+ SOC_DAPM_SINGLE("Input 2 Switch", ADAU1373_RADC_MIXER, 1, 1, 0),
+ SOC_DAPM_SINGLE("Input 1 Switch", ADAU1373_RADC_MIXER, 0, 1, 0),
+};
+
+#define DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(_name, _reg) \
+const struct snd_kcontrol_new _name[] = { \
+ SOC_DAPM_SINGLE("Left DAC2 Switch", _reg, 7, 1, 0), \
+ SOC_DAPM_SINGLE("Right DAC2 Switch", _reg, 6, 1, 0), \
+ SOC_DAPM_SINGLE("Left DAC1 Switch", _reg, 5, 1, 0), \
+ SOC_DAPM_SINGLE("Right DAC1 Switch", _reg, 4, 1, 0), \
+ SOC_DAPM_SINGLE("Input 4 Bypass Switch", _reg, 3, 1, 0), \
+ SOC_DAPM_SINGLE("Input 3 Bypass Switch", _reg, 2, 1, 0), \
+ SOC_DAPM_SINGLE("Input 2 Bypass Switch", _reg, 1, 1, 0), \
+ SOC_DAPM_SINGLE("Input 1 Bypass Switch", _reg, 0, 1, 0), \
+}
+
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_left_line1_mixer_controls,
+ ADAU1373_LLINE1_MIX);
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_right_line1_mixer_controls,
+ ADAU1373_RLINE1_MIX);
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_left_line2_mixer_controls,
+ ADAU1373_LLINE2_MIX);
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_right_line2_mixer_controls,
+ ADAU1373_RLINE2_MIX);
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_left_spk_mixer_controls,
+ ADAU1373_LSPK_MIX);
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_right_spk_mixer_controls,
+ ADAU1373_RSPK_MIX);
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_ep_mixer_controls,
+ ADAU1373_EP_MIX);
+
+static const struct snd_kcontrol_new adau1373_left_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC1 Switch", ADAU1373_LHP_MIX, 5, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC2 Switch", ADAU1373_LHP_MIX, 4, 1, 0),
+ SOC_DAPM_SINGLE("Input 4 Bypass Switch", ADAU1373_LHP_MIX, 3, 1, 0),
+ SOC_DAPM_SINGLE("Input 3 Bypass Switch", ADAU1373_LHP_MIX, 2, 1, 0),
+ SOC_DAPM_SINGLE("Input 2 Bypass Switch", ADAU1373_LHP_MIX, 1, 1, 0),
+ SOC_DAPM_SINGLE("Input 1 Bypass Switch", ADAU1373_LHP_MIX, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new adau1373_right_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Right DAC1 Switch", ADAU1373_RHP_MIX, 5, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC2 Switch", ADAU1373_RHP_MIX, 4, 1, 0),
+ SOC_DAPM_SINGLE("Input 4 Bypass Switch", ADAU1373_RHP_MIX, 3, 1, 0),
+ SOC_DAPM_SINGLE("Input 3 Bypass Switch", ADAU1373_RHP_MIX, 2, 1, 0),
+ SOC_DAPM_SINGLE("Input 2 Bypass Switch", ADAU1373_RHP_MIX, 1, 1, 0),
+ SOC_DAPM_SINGLE("Input 1 Bypass Switch", ADAU1373_RHP_MIX, 0, 1, 0),
+};
+
+#define DECLARE_ADAU1373_DSP_CHANNEL_MIXER_CTRLS(_name, _reg) \
+const struct snd_kcontrol_new _name[] = { \
+ SOC_DAPM_SINGLE("DMIC2 Swapped Switch", _reg, 6, 1, 0), \
+ SOC_DAPM_SINGLE("DMIC2 Switch", _reg, 5, 1, 0), \
+ SOC_DAPM_SINGLE("ADC/DMIC1 Swapped Switch", _reg, 4, 1, 0), \
+ SOC_DAPM_SINGLE("ADC/DMIC1 Switch", _reg, 3, 1, 0), \
+ SOC_DAPM_SINGLE("AIF3 Switch", _reg, 2, 1, 0), \
+ SOC_DAPM_SINGLE("AIF2 Switch", _reg, 1, 1, 0), \
+ SOC_DAPM_SINGLE("AIF1 Switch", _reg, 0, 1, 0), \
+}
+
+static DECLARE_ADAU1373_DSP_CHANNEL_MIXER_CTRLS(adau1373_dsp_channel1_mixer_controls,
+ ADAU1373_DIN_MIX_CTRL(0));
+static DECLARE_ADAU1373_DSP_CHANNEL_MIXER_CTRLS(adau1373_dsp_channel2_mixer_controls,
+ ADAU1373_DIN_MIX_CTRL(1));
+static DECLARE_ADAU1373_DSP_CHANNEL_MIXER_CTRLS(adau1373_dsp_channel3_mixer_controls,
+ ADAU1373_DIN_MIX_CTRL(2));
+static DECLARE_ADAU1373_DSP_CHANNEL_MIXER_CTRLS(adau1373_dsp_channel4_mixer_controls,
+ ADAU1373_DIN_MIX_CTRL(3));
+static DECLARE_ADAU1373_DSP_CHANNEL_MIXER_CTRLS(adau1373_dsp_channel5_mixer_controls,
+ ADAU1373_DIN_MIX_CTRL(4));
+
+#define DECLARE_ADAU1373_DSP_OUTPUT_MIXER_CTRLS(_name, _reg) \
+const struct snd_kcontrol_new _name[] = { \
+ SOC_DAPM_SINGLE("DSP Channel5 Switch", _reg, 4, 1, 0), \
+ SOC_DAPM_SINGLE("DSP Channel4 Switch", _reg, 3, 1, 0), \
+ SOC_DAPM_SINGLE("DSP Channel3 Switch", _reg, 2, 1, 0), \
+ SOC_DAPM_SINGLE("DSP Channel2 Switch", _reg, 1, 1, 0), \
+ SOC_DAPM_SINGLE("DSP Channel1 Switch", _reg, 0, 1, 0), \
+}
+
+static DECLARE_ADAU1373_DSP_OUTPUT_MIXER_CTRLS(adau1373_aif1_mixer_controls,
+ ADAU1373_DOUT_MIX_CTRL(0));
+static DECLARE_ADAU1373_DSP_OUTPUT_MIXER_CTRLS(adau1373_aif2_mixer_controls,
+ ADAU1373_DOUT_MIX_CTRL(1));
+static DECLARE_ADAU1373_DSP_OUTPUT_MIXER_CTRLS(adau1373_aif3_mixer_controls,
+ ADAU1373_DOUT_MIX_CTRL(2));
+static DECLARE_ADAU1373_DSP_OUTPUT_MIXER_CTRLS(adau1373_dac1_mixer_controls,
+ ADAU1373_DOUT_MIX_CTRL(3));
+static DECLARE_ADAU1373_DSP_OUTPUT_MIXER_CTRLS(adau1373_dac2_mixer_controls,
+ ADAU1373_DOUT_MIX_CTRL(4));
+
+static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = {
+ /* Datasheet claims Left ADC is bit 6 and Right ADC is bit 7, but that
+ * doesn't seem to be the case. */
+ SND_SOC_DAPM_ADC("Left ADC", NULL, ADAU1373_PWDN_CTRL1, 7, 0),
+ SND_SOC_DAPM_ADC("Right ADC", NULL, ADAU1373_PWDN_CTRL1, 6, 0),
+
+ SND_SOC_DAPM_ADC("DMIC1", NULL, ADAU1373_DIGMICCTRL, 0, 0),
+ SND_SOC_DAPM_ADC("DMIC2", NULL, ADAU1373_DIGMICCTRL, 2, 0),
+
+ SND_SOC_DAPM_VIRT_MUX("Decimator Mux", SND_SOC_NOPM, 0, 0,
+ &adau1373_decimator_mux),
+
+ SND_SOC_DAPM_SUPPLY("MICBIAS2", ADAU1373_PWDN_CTRL1, 5, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS1", ADAU1373_PWDN_CTRL1, 4, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("IN4PGA", ADAU1373_PWDN_CTRL1, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IN3PGA", ADAU1373_PWDN_CTRL1, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IN2PGA", ADAU1373_PWDN_CTRL1, 1, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IN1PGA", ADAU1373_PWDN_CTRL1, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_DAC("Left DAC2", NULL, ADAU1373_PWDN_CTRL2, 7, 0),
+ SND_SOC_DAPM_DAC("Right DAC2", NULL, ADAU1373_PWDN_CTRL2, 6, 0),
+ SND_SOC_DAPM_DAC("Left DAC1", NULL, ADAU1373_PWDN_CTRL2, 5, 0),
+ SND_SOC_DAPM_DAC("Right DAC1", NULL, ADAU1373_PWDN_CTRL2, 4, 0),
+
+ SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_left_adc_mixer_controls),
+ SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_right_adc_mixer_controls),
+
+ SOC_MIXER_ARRAY("Left Lineout2 Mixer", ADAU1373_PWDN_CTRL2, 3, 0,
+ adau1373_left_line2_mixer_controls),
+ SOC_MIXER_ARRAY("Right Lineout2 Mixer", ADAU1373_PWDN_CTRL2, 2, 0,
+ adau1373_right_line2_mixer_controls),
+ SOC_MIXER_ARRAY("Left Lineout1 Mixer", ADAU1373_PWDN_CTRL2, 1, 0,
+ adau1373_left_line1_mixer_controls),
+ SOC_MIXER_ARRAY("Right Lineout1 Mixer", ADAU1373_PWDN_CTRL2, 0, 0,
+ adau1373_right_line1_mixer_controls),
+
+ SOC_MIXER_ARRAY("Earpiece Mixer", ADAU1373_PWDN_CTRL3, 4, 0,
+ adau1373_ep_mixer_controls),
+ SOC_MIXER_ARRAY("Left Speaker Mixer", ADAU1373_PWDN_CTRL3, 3, 0,
+ adau1373_left_spk_mixer_controls),
+ SOC_MIXER_ARRAY("Right Speaker Mixer", ADAU1373_PWDN_CTRL3, 2, 0,
+ adau1373_right_spk_mixer_controls),
+ SOC_MIXER_ARRAY("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_left_hp_mixer_controls),
+ SOC_MIXER_ARRAY("Right Headphone Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_right_hp_mixer_controls),
+ SND_SOC_DAPM_SUPPLY("Headphone Enable", ADAU1373_PWDN_CTRL3, 1, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("AIF1 CLK", ADAU1373_SRC_DAI_CTRL(0), 0, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AIF2 CLK", ADAU1373_SRC_DAI_CTRL(1), 0, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AIF3 CLK", ADAU1373_SRC_DAI_CTRL(2), 0, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AIF1 IN SRC", ADAU1373_SRC_DAI_CTRL(0), 2, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AIF1 OUT SRC", ADAU1373_SRC_DAI_CTRL(0), 1, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AIF2 IN SRC", ADAU1373_SRC_DAI_CTRL(1), 2, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AIF2 OUT SRC", ADAU1373_SRC_DAI_CTRL(1), 1, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AIF3 IN SRC", ADAU1373_SRC_DAI_CTRL(2), 2, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AIF3 OUT SRC", ADAU1373_SRC_DAI_CTRL(2), 1, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_AIF_IN("AIF1 IN", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1 OUT", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF2 IN", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF2 OUT", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF3 IN", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF3 OUT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ SOC_MIXER_ARRAY("DSP Channel1 Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_dsp_channel1_mixer_controls),
+ SOC_MIXER_ARRAY("DSP Channel2 Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_dsp_channel2_mixer_controls),
+ SOC_MIXER_ARRAY("DSP Channel3 Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_dsp_channel3_mixer_controls),
+ SOC_MIXER_ARRAY("DSP Channel4 Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_dsp_channel4_mixer_controls),
+ SOC_MIXER_ARRAY("DSP Channel5 Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_dsp_channel5_mixer_controls),
+
+ SOC_MIXER_ARRAY("AIF1 Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_aif1_mixer_controls),
+ SOC_MIXER_ARRAY("AIF2 Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_aif2_mixer_controls),
+ SOC_MIXER_ARRAY("AIF3 Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_aif3_mixer_controls),
+ SOC_MIXER_ARRAY("DAC1 Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_dac1_mixer_controls),
+ SOC_MIXER_ARRAY("DAC2 Mixer", SND_SOC_NOPM, 0, 0,
+ adau1373_dac2_mixer_controls),
+
+ SND_SOC_DAPM_SUPPLY("DSP", ADAU1373_DIGEN, 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Recording Engine B", ADAU1373_DIGEN, 3, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Recording Engine A", ADAU1373_DIGEN, 2, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Playback Engine B", ADAU1373_DIGEN, 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Playback Engine A", ADAU1373_DIGEN, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("PLL1", SND_SOC_NOPM, 0, 0, adau1373_pll_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("PLL2", SND_SOC_NOPM, 0, 0, adau1373_pll_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("SYSCLK1", ADAU1373_CLK_SRC_DIV(0), 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("SYSCLK2", ADAU1373_CLK_SRC_DIV(1), 7, 0, NULL, 0),
+
+ SND_SOC_DAPM_INPUT("AIN1L"),
+ SND_SOC_DAPM_INPUT("AIN1R"),
+ SND_SOC_DAPM_INPUT("AIN2L"),
+ SND_SOC_DAPM_INPUT("AIN2R"),
+ SND_SOC_DAPM_INPUT("AIN3L"),
+ SND_SOC_DAPM_INPUT("AIN3R"),
+ SND_SOC_DAPM_INPUT("AIN4L"),
+ SND_SOC_DAPM_INPUT("AIN4R"),
+
+ SND_SOC_DAPM_INPUT("DMIC1DAT"),
+ SND_SOC_DAPM_INPUT("DMIC2DAT"),
+
+ SND_SOC_DAPM_OUTPUT("LOUT1L"),
+ SND_SOC_DAPM_OUTPUT("LOUT1R"),
+ SND_SOC_DAPM_OUTPUT("LOUT2L"),
+ SND_SOC_DAPM_OUTPUT("LOUT2R"),
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+ SND_SOC_DAPM_OUTPUT("SPKL"),
+ SND_SOC_DAPM_OUTPUT("SPKR"),
+ SND_SOC_DAPM_OUTPUT("EP"),
+};
+
+static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_codec *codec = source->codec;
+ struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+ unsigned int dai;
+ const char *clk;
+
+ dai = sink->name[3] - '1';
+
+ if (!adau1373->dais[dai].master)
+ return 0;
+
+ if (adau1373->dais[dai].clk_src == ADAU1373_CLK_SRC_PLL1)
+ clk = "SYSCLK1";
+ else
+ clk = "SYSCLK2";
+
+ return strcmp(source->name, clk) == 0;
+}
+
+static int adau1373_check_src(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_codec *codec = source->codec;
+ struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+ unsigned int dai;
+
+ dai = sink->name[3] - '1';
+
+ return adau1373->dais[dai].enable_src;
+}
+
+#define DSP_CHANNEL_MIXER_ROUTES(_sink) \
+ { _sink, "DMIC2 Swapped Switch", "DMIC2" }, \
+ { _sink, "DMIC2 Switch", "DMIC2" }, \
+ { _sink, "ADC/DMIC1 Swapped Switch", "Decimator Mux" }, \
+ { _sink, "ADC/DMIC1 Switch", "Decimator Mux" }, \
+ { _sink, "AIF1 Switch", "AIF1 IN" }, \
+ { _sink, "AIF2 Switch", "AIF2 IN" }, \
+ { _sink, "AIF3 Switch", "AIF3 IN" }
+
+#define DSP_OUTPUT_MIXER_ROUTES(_sink) \
+ { _sink, "DSP Channel1 Switch", "DSP Channel1 Mixer" }, \
+ { _sink, "DSP Channel2 Switch", "DSP Channel2 Mixer" }, \
+ { _sink, "DSP Channel3 Switch", "DSP Channel3 Mixer" }, \
+ { _sink, "DSP Channel4 Switch", "DSP Channel4 Mixer" }, \
+ { _sink, "DSP Channel5 Switch", "DSP Channel5 Mixer" }
+
+#define LEFT_OUTPUT_MIXER_ROUTES(_sink) \
+ { _sink, "Right DAC2 Switch", "Right DAC2" }, \
+ { _sink, "Left DAC2 Switch", "Left DAC2" }, \
+ { _sink, "Right DAC1 Switch", "Right DAC1" }, \
+ { _sink, "Left DAC1 Switch", "Left DAC1" }, \
+ { _sink, "Input 1 Bypass Switch", "IN1PGA" }, \
+ { _sink, "Input 2 Bypass Switch", "IN2PGA" }, \
+ { _sink, "Input 3 Bypass Switch", "IN3PGA" }, \
+ { _sink, "Input 4 Bypass Switch", "IN4PGA" }
+
+#define RIGHT_OUTPUT_MIXER_ROUTES(_sink) \
+ { _sink, "Right DAC2 Switch", "Right DAC2" }, \
+ { _sink, "Left DAC2 Switch", "Left DAC2" }, \
+ { _sink, "Right DAC1 Switch", "Right DAC1" }, \
+ { _sink, "Left DAC1 Switch", "Left DAC1" }, \
+ { _sink, "Input 1 Bypass Switch", "IN1PGA" }, \
+ { _sink, "Input 2 Bypass Switch", "IN2PGA" }, \
+ { _sink, "Input 3 Bypass Switch", "IN3PGA" }, \
+ { _sink, "Input 4 Bypass Switch", "IN4PGA" }
+
+static const struct snd_soc_dapm_route adau1373_dapm_routes[] = {
+ { "Left ADC Mixer", "DAC1 Switch", "Left DAC1" },
+ { "Left ADC Mixer", "Input 1 Switch", "IN1PGA" },
+ { "Left ADC Mixer", "Input 2 Switch", "IN2PGA" },
+ { "Left ADC Mixer", "Input 3 Switch", "IN3PGA" },
+ { "Left ADC Mixer", "Input 4 Switch", "IN4PGA" },
+
+ { "Right ADC Mixer", "DAC1 Switch", "Right DAC1" },
+ { "Right ADC Mixer", "Input 1 Switch", "IN1PGA" },
+ { "Right ADC Mixer", "Input 2 Switch", "IN2PGA" },
+ { "Right ADC Mixer", "Input 3 Switch", "IN3PGA" },
+ { "Right ADC Mixer", "Input 4 Switch", "IN4PGA" },
+
+ { "Left ADC", NULL, "Left ADC Mixer" },
+ { "Right ADC", NULL, "Right ADC Mixer" },
+
+ { "Decimator Mux", "ADC", "Left ADC" },
+ { "Decimator Mux", "ADC", "Right ADC" },
+ { "Decimator Mux", "DMIC1", "DMIC1" },
+
+ DSP_CHANNEL_MIXER_ROUTES("DSP Channel1 Mixer"),
+ DSP_CHANNEL_MIXER_ROUTES("DSP Channel2 Mixer"),
+ DSP_CHANNEL_MIXER_ROUTES("DSP Channel3 Mixer"),
+ DSP_CHANNEL_MIXER_ROUTES("DSP Channel4 Mixer"),
+ DSP_CHANNEL_MIXER_ROUTES("DSP Channel5 Mixer"),
+
+ DSP_OUTPUT_MIXER_ROUTES("AIF1 Mixer"),
+ DSP_OUTPUT_MIXER_ROUTES("AIF2 Mixer"),
+ DSP_OUTPUT_MIXER_ROUTES("AIF3 Mixer"),
+ DSP_OUTPUT_MIXER_ROUTES("DAC1 Mixer"),
+ DSP_OUTPUT_MIXER_ROUTES("DAC2 Mixer"),
+
+ { "AIF1 OUT", NULL, "AIF1 Mixer" },
+ { "AIF2 OUT", NULL, "AIF2 Mixer" },
+ { "AIF3 OUT", NULL, "AIF3 Mixer" },
+ { "Left DAC1", NULL, "DAC1 Mixer" },
+ { "Right DAC1", NULL, "DAC1 Mixer" },
+ { "Left DAC2", NULL, "DAC2 Mixer" },
+ { "Right DAC2", NULL, "DAC2 Mixer" },
+
+ LEFT_OUTPUT_MIXER_ROUTES("Left Lineout1 Mixer"),
+ RIGHT_OUTPUT_MIXER_ROUTES("Right Lineout1 Mixer"),
+ LEFT_OUTPUT_MIXER_ROUTES("Left Lineout2 Mixer"),
+ RIGHT_OUTPUT_MIXER_ROUTES("Right Lineout2 Mixer"),
+ LEFT_OUTPUT_MIXER_ROUTES("Left Speaker Mixer"),
+ RIGHT_OUTPUT_MIXER_ROUTES("Right Speaker Mixer"),
+
+ { "Left Headphone Mixer", "Left DAC2 Switch", "Left DAC2" },
+ { "Left Headphone Mixer", "Left DAC1 Switch", "Left DAC1" },
+ { "Left Headphone Mixer", "Input 1 Bypass Switch", "IN1PGA" },
+ { "Left Headphone Mixer", "Input 2 Bypass Switch", "IN2PGA" },
+ { "Left Headphone Mixer", "Input 3 Bypass Switch", "IN3PGA" },
+ { "Left Headphone Mixer", "Input 4 Bypass Switch", "IN4PGA" },
+ { "Right Headphone Mixer", "Right DAC2 Switch", "Right DAC2" },
+ { "Right Headphone Mixer", "Right DAC1 Switch", "Right DAC1" },
+ { "Right Headphone Mixer", "Input 1 Bypass Switch", "IN1PGA" },
+ { "Right Headphone Mixer", "Input 2 Bypass Switch", "IN2PGA" },
+ { "Right Headphone Mixer", "Input 3 Bypass Switch", "IN3PGA" },
+ { "Right Headphone Mixer", "Input 4 Bypass Switch", "IN4PGA" },
+
+ { "Left Headphone Mixer", NULL, "Headphone Enable" },
+ { "Right Headphone Mixer", NULL, "Headphone Enable" },
+
+ { "Earpiece Mixer", "Right DAC2 Switch", "Right DAC2" },
+ { "Earpiece Mixer", "Left DAC2 Switch", "Left DAC2" },
+ { "Earpiece Mixer", "Right DAC1 Switch", "Right DAC1" },
+ { "Earpiece Mixer", "Left DAC1 Switch", "Left DAC1" },
+ { "Earpiece Mixer", "Input 1 Bypass Switch", "IN1PGA" },
+ { "Earpiece Mixer", "Input 2 Bypass Switch", "IN2PGA" },
+ { "Earpiece Mixer", "Input 3 Bypass Switch", "IN3PGA" },
+ { "Earpiece Mixer", "Input 4 Bypass Switch", "IN4PGA" },
+
+ { "LOUT1L", NULL, "Left Lineout1 Mixer" },
+ { "LOUT1R", NULL, "Right Lineout1 Mixer" },
+ { "LOUT2L", NULL, "Left Lineout2 Mixer" },
+ { "LOUT2R", NULL, "Right Lineout2 Mixer" },
+ { "SPKL", NULL, "Left Speaker Mixer" },
+ { "SPKR", NULL, "Right Speaker Mixer" },
+ { "HPL", NULL, "Left Headphone Mixer" },
+ { "HPR", NULL, "Right Headphone Mixer" },
+ { "EP", NULL, "Earpiece Mixer" },
+
+ { "IN1PGA", NULL, "AIN1L" },
+ { "IN2PGA", NULL, "AIN2L" },
+ { "IN3PGA", NULL, "AIN3L" },
+ { "IN4PGA", NULL, "AIN4L" },
+ { "IN1PGA", NULL, "AIN1R" },
+ { "IN2PGA", NULL, "AIN2R" },
+ { "IN3PGA", NULL, "AIN3R" },
+ { "IN4PGA", NULL, "AIN4R" },
+
+ { "SYSCLK1", NULL, "PLL1" },
+ { "SYSCLK2", NULL, "PLL2" },
+
+ { "Left DAC1", NULL, "SYSCLK1" },
+ { "Right DAC1", NULL, "SYSCLK1" },
+ { "Left DAC2", NULL, "SYSCLK1" },
+ { "Right DAC2", NULL, "SYSCLK1" },
+ { "Left ADC", NULL, "SYSCLK1" },
+ { "Right ADC", NULL, "SYSCLK1" },
+
+ { "DSP", NULL, "SYSCLK1" },
+
+ { "AIF1 Mixer", NULL, "DSP" },
+ { "AIF2 Mixer", NULL, "DSP" },
+ { "AIF3 Mixer", NULL, "DSP" },
+ { "DAC1 Mixer", NULL, "DSP" },
+ { "DAC2 Mixer", NULL, "DSP" },
+ { "DAC1 Mixer", NULL, "Playback Engine A" },
+ { "DAC2 Mixer", NULL, "Playback Engine B" },
+ { "Left ADC Mixer", NULL, "Recording Engine A" },
+ { "Right ADC Mixer", NULL, "Recording Engine A" },
+
+ { "AIF1 CLK", NULL, "SYSCLK1", adau1373_check_aif_clk },
+ { "AIF2 CLK", NULL, "SYSCLK1", adau1373_check_aif_clk },
+ { "AIF3 CLK", NULL, "SYSCLK1", adau1373_check_aif_clk },
+ { "AIF1 CLK", NULL, "SYSCLK2", adau1373_check_aif_clk },
+ { "AIF2 CLK", NULL, "SYSCLK2", adau1373_check_aif_clk },
+ { "AIF3 CLK", NULL, "SYSCLK2", adau1373_check_aif_clk },
+
+ { "AIF1 IN", NULL, "AIF1 CLK" },
+ { "AIF1 OUT", NULL, "AIF1 CLK" },
+ { "AIF2 IN", NULL, "AIF2 CLK" },
+ { "AIF2 OUT", NULL, "AIF2 CLK" },
+ { "AIF3 IN", NULL, "AIF3 CLK" },
+ { "AIF3 OUT", NULL, "AIF3 CLK" },
+ { "AIF1 IN", NULL, "AIF1 IN SRC", adau1373_check_src },
+ { "AIF1 OUT", NULL, "AIF1 OUT SRC", adau1373_check_src },
+ { "AIF2 IN", NULL, "AIF2 IN SRC", adau1373_check_src },
+ { "AIF2 OUT", NULL, "AIF2 OUT SRC", adau1373_check_src },
+ { "AIF3 IN", NULL, "AIF3 IN SRC", adau1373_check_src },
+ { "AIF3 OUT", NULL, "AIF3 OUT SRC", adau1373_check_src },
+
+ { "DMIC1", NULL, "DMIC1DAT" },
+ { "DMIC1", NULL, "SYSCLK1" },
+ { "DMIC1", NULL, "Recording Engine A" },
+ { "DMIC2", NULL, "DMIC2DAT" },
+ { "DMIC2", NULL, "SYSCLK1" },
+ { "DMIC2", NULL, "Recording Engine B" },
+};
+
+static int adau1373_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+ struct adau1373_dai *adau1373_dai = &adau1373->dais[dai->id];
+ unsigned int div;
+ unsigned int freq;
+ unsigned int ctrl;
+
+ freq = adau1373_dai->sysclk;
+
+ if (freq % params_rate(params) != 0)
+ return -EINVAL;
+
+ switch (freq / params_rate(params)) {
+ case 1024: /* sysclk / 256 */
+ div = 0;
+ break;
+ case 1536: /* 2/3 sysclk / 256 */
+ div = 1;
+ break;
+ case 2048: /* 1/2 sysclk / 256 */
+ div = 2;
+ break;
+ case 3072: /* 1/3 sysclk / 256 */
+ div = 3;
+ break;
+ case 4096: /* 1/4 sysclk / 256 */
+ div = 4;
+ break;
+ case 6144: /* 1/6 sysclk / 256 */
+ div = 5;
+ break;
+ case 5632: /* 2/11 sysclk / 256 */
+ div = 6;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ adau1373_dai->enable_src = (div != 0);
+
+ snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id),
+ ~ADAU1373_BCLKDIV_SOURCE, (div << 2) | ADAU1373_BCLKDIV_64);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ ctrl = ADAU1373_DAI_WLEN_16;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ ctrl = ADAU1373_DAI_WLEN_20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ctrl = ADAU1373_DAI_WLEN_24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ctrl = ADAU1373_DAI_WLEN_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return snd_soc_update_bits(codec, ADAU1373_DAI(dai->id),
+ ADAU1373_DAI_WLEN_MASK, ctrl);
+}
+
+static int adau1373_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+ struct adau1373_dai *adau1373_dai = &adau1373->dais[dai->id];
+ unsigned int ctrl;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ ctrl = ADAU1373_DAI_MASTER;
+ adau1373_dai->master = true;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ ctrl = 0;
+ adau1373_dai->master = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ ctrl |= ADAU1373_DAI_FORMAT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ctrl |= ADAU1373_DAI_FORMAT_LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ ctrl |= ADAU1373_DAI_FORMAT_RIGHT_J;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ ctrl |= ADAU1373_DAI_FORMAT_DSP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ ctrl |= ADAU1373_DAI_INVERT_BCLK;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ ctrl |= ADAU1373_DAI_INVERT_LRCLK;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ ctrl |= ADAU1373_DAI_INVERT_LRCLK | ADAU1373_DAI_INVERT_BCLK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, ADAU1373_DAI(dai->id),
+ ~ADAU1373_DAI_WLEN_MASK, ctrl);
+
+ return 0;
+}
+
+static int adau1373_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(dai->codec);
+ struct adau1373_dai *adau1373_dai = &adau1373->dais[dai->id];
+
+ switch (clk_id) {
+ case ADAU1373_CLK_SRC_PLL1:
+ case ADAU1373_CLK_SRC_PLL2:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ adau1373_dai->sysclk = freq;
+ adau1373_dai->clk_src = clk_id;
+
+ snd_soc_update_bits(dai->codec, ADAU1373_BCLKDIV(dai->id),
+ ADAU1373_BCLKDIV_SOURCE, clk_id << 5);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops adau1373_dai_ops = {
+ .hw_params = adau1373_hw_params,
+ .set_sysclk = adau1373_set_dai_sysclk,
+ .set_fmt = adau1373_set_dai_fmt,
+};
+
+#define ADAU1373_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver adau1373_dai_driver[] = {
+ {
+ .id = 0,
+ .name = "adau1373-aif1",
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = ADAU1373_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = ADAU1373_FORMATS,
+ },
+ .ops = &adau1373_dai_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .id = 1,
+ .name = "adau1373-aif2",
+ .playback = {
+ .stream_name = "AIF2 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = ADAU1373_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF2 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = ADAU1373_FORMATS,
+ },
+ .ops = &adau1373_dai_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .id = 2,
+ .name = "adau1373-aif3",
+ .playback = {
+ .stream_name = "AIF3 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = ADAU1373_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF3 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = ADAU1373_FORMATS,
+ },
+ .ops = &adau1373_dai_ops,
+ .symmetric_rates = 1,
+ },
+};
+
+static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
+{
+ unsigned int dpll_div = 0;
+ unsigned int x, r, n, m, i, j, mode;
+
+ switch (pll_id) {
+ case ADAU1373_PLL1:
+ case ADAU1373_PLL2:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (source) {
+ case ADAU1373_PLL_SRC_BCLK1:
+ case ADAU1373_PLL_SRC_BCLK2:
+ case ADAU1373_PLL_SRC_BCLK3:
+ case ADAU1373_PLL_SRC_LRCLK1:
+ case ADAU1373_PLL_SRC_LRCLK2:
+ case ADAU1373_PLL_SRC_LRCLK3:
+ case ADAU1373_PLL_SRC_MCLK1:
+ case ADAU1373_PLL_SRC_MCLK2:
+ case ADAU1373_PLL_SRC_GPIO1:
+ case ADAU1373_PLL_SRC_GPIO2:
+ case ADAU1373_PLL_SRC_GPIO3:
+ case ADAU1373_PLL_SRC_GPIO4:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (freq_in < 7813 || freq_in > 27000000)
+ return -EINVAL;
+
+ if (freq_out < 45158000 || freq_out > 49152000)
+ return -EINVAL;
+
+ /* APLL input needs to be >= 8Mhz, so in case freq_in is less we use the
+ * DPLL to get it there. DPLL_out = (DPLL_in / div) * 1024 */
+ while (freq_in < 8000000) {
+ freq_in *= 2;
+ dpll_div++;
+ }
+
+ if (freq_out % freq_in != 0) {
+ /* fout = fin * (r + (n/m)) / x */
+ x = DIV_ROUND_UP(freq_in, 13500000);
+ freq_in /= x;
+ r = freq_out / freq_in;
+ i = freq_out % freq_in;
+ j = gcd(i, freq_in);
+ n = i / j;
+ m = freq_in / j;
+ x--;
+ mode = 1;
+ } else {
+ /* fout = fin / r */
+ r = freq_out / freq_in;
+ n = 0;
+ m = 0;
+ x = 0;
+ mode = 0;
+ }
+
+ if (r < 2 || r > 8 || x > 3 || m > 0xffff || n > 0xffff)
+ return -EINVAL;
+
+ if (dpll_div) {
+ dpll_div = 11 - dpll_div;
+ snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id),
+ ADAU1373_PLL_CTRL6_DPLL_BYPASS, 0);
+ } else {
+ snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id),
+ ADAU1373_PLL_CTRL6_DPLL_BYPASS,
+ ADAU1373_PLL_CTRL6_DPLL_BYPASS);
+ }
+
+ snd_soc_write(codec, ADAU1373_DPLL_CTRL(pll_id),
+ (source << 4) | dpll_div);
+ snd_soc_write(codec, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff);
+ snd_soc_write(codec, ADAU1373_PLL_CTRL2(pll_id), m & 0xff);
+ snd_soc_write(codec, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff);
+ snd_soc_write(codec, ADAU1373_PLL_CTRL4(pll_id), n & 0xff);
+ snd_soc_write(codec, ADAU1373_PLL_CTRL5(pll_id),
+ (r << 3) | (x << 1) | mode);
+
+ /* Set sysclk to pll_rate / 4 */
+ snd_soc_update_bits(codec, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);
+
+ return 0;
+}
+
+static void adau1373_load_drc_settings(struct snd_soc_codec *codec,
+ unsigned int nr, uint8_t *drc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ADAU1373_DRC_SIZE; ++i)
+ snd_soc_write(codec, ADAU1373_DRC(nr) + i, drc[i]);
+}
+
+static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias)
+{
+ switch (micbias) {
+ case ADAU1373_MICBIAS_2_9V:
+ case ADAU1373_MICBIAS_2_2V:
+ case ADAU1373_MICBIAS_2_6V:
+ case ADAU1373_MICBIAS_1_8V:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static int adau1373_probe(struct snd_soc_codec *codec)
+{
+ struct adau1373_platform_data *pdata = codec->dev->platform_data;
+ bool lineout_differential = false;
+ unsigned int val;
+ int ret;
+ int i;
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ if (ret) {
+ dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ codec->dapm.idle_bias_off = true;
+
+ if (pdata) {
+ if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting))
+ return -EINVAL;
+
+ if (!adau1373_valid_micbias(pdata->micbias1) ||
+ !adau1373_valid_micbias(pdata->micbias2))
+ return -EINVAL;
+
+ for (i = 0; i < pdata->num_drc; ++i) {
+ adau1373_load_drc_settings(codec, i,
+ pdata->drc_setting[i]);
+ }
+
+ snd_soc_add_controls(codec, adau1373_drc_controls,
+ pdata->num_drc);
+
+ val = 0;
+ for (i = 0; i < 4; ++i) {
+ if (pdata->input_differential[i])
+ val |= BIT(i);
+ }
+ snd_soc_write(codec, ADAU1373_INPUT_MODE, val);
+
+ val = 0;
+ if (pdata->lineout_differential)
+ val |= ADAU1373_OUTPUT_CTRL_LDIFF;
+ if (pdata->lineout_ground_sense)
+ val |= ADAU1373_OUTPUT_CTRL_LNFBEN;
+ snd_soc_write(codec, ADAU1373_OUTPUT_CTRL, val);
+
+ lineout_differential = pdata->lineout_differential;
+
+ snd_soc_write(codec, ADAU1373_EP_CTRL,
+ (pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) |
+ (pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET));
+ }
+
+ if (!lineout_differential) {
+ snd_soc_add_controls(codec, adau1373_lineout2_controls,
+ ARRAY_SIZE(adau1373_lineout2_controls));
+ }
+
+ snd_soc_write(codec, ADAU1373_ADC_CTRL,
+ ADAU1373_ADC_CTRL_RESET_FORCE | ADAU1373_ADC_CTRL_PEAK_DETECT);
+
+ return 0;
+}
+
+static int adau1373_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ snd_soc_update_bits(codec, ADAU1373_PWDN_CTRL3,
+ ADAU1373_PWDN_CTRL3_PWR_EN, ADAU1373_PWDN_CTRL3_PWR_EN);
+ break;
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, ADAU1373_PWDN_CTRL3,
+ ADAU1373_PWDN_CTRL3_PWR_EN, 0);
+ break;
+ }
+ codec->dapm.bias_level = level;
+ return 0;
+}
+
+static int adau1373_remove(struct snd_soc_codec *codec)
+{
+ adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int adau1373_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ return adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
+}
+
+static int adau1373_resume(struct snd_soc_codec *codec)
+{
+ adau1373_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_cache_sync(codec);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver adau1373_codec_driver = {
+ .probe = adau1373_probe,
+ .remove = adau1373_remove,
+ .suspend = adau1373_suspend,
+ .resume = adau1373_resume,
+ .set_bias_level = adau1373_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(adau1373_default_regs),
+ .reg_cache_default = adau1373_default_regs,
+ .reg_word_size = sizeof(uint8_t),
+
+ .set_pll = adau1373_set_pll,
+
+ .controls = adau1373_controls,
+ .num_controls = ARRAY_SIZE(adau1373_controls),
+ .dapm_widgets = adau1373_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(adau1373_dapm_widgets),
+ .dapm_routes = adau1373_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(adau1373_dapm_routes),
+};
+
+static int __devinit adau1373_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adau1373 *adau1373;
+ int ret;
+
+ adau1373 = kzalloc(sizeof(*adau1373), GFP_KERNEL);
+ if (!adau1373)
+ return -ENOMEM;
+
+ dev_set_drvdata(&client->dev, adau1373);
+
+ ret = snd_soc_register_codec(&client->dev, &adau1373_codec_driver,
+ adau1373_dai_driver, ARRAY_SIZE(adau1373_dai_driver));
+ if (ret < 0)
+ kfree(adau1373);
+
+ return ret;
+}
+
+static int __devexit adau1373_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(dev_get_drvdata(&client->dev));
+ return 0;
+}
+
+static const struct i2c_device_id adau1373_i2c_id[] = {
+ { "adau1373", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adau1373_i2c_id);
+
+static struct i2c_driver adau1373_i2c_driver = {
+ .driver = {
+ .name = "adau1373",
+ .owner = THIS_MODULE,
+ },
+ .probe = adau1373_i2c_probe,
+ .remove = __devexit_p(adau1373_i2c_remove),
+ .id_table = adau1373_i2c_id,
+};
+
+static int __init adau1373_init(void)
+{
+ return i2c_add_driver(&adau1373_i2c_driver);
+}
+module_init(adau1373_init);
+
+static void __exit adau1373_exit(void)
+{
+ i2c_del_driver(&adau1373_i2c_driver);
+}
+module_exit(adau1373_exit);
+
+MODULE_DESCRIPTION("ASoC ADAU1373 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1373.h b/sound/soc/codecs/adau1373.h
new file mode 100644
index 000000000000..c6ab5530760c
--- /dev/null
+++ b/sound/soc/codecs/adau1373.h
@@ -0,0 +1,29 @@
+#ifndef __ADAU1373_H__
+#define __ADAU1373_H__
+
+enum adau1373_pll_src {
+ ADAU1373_PLL_SRC_MCLK1 = 0,
+ ADAU1373_PLL_SRC_BCLK1 = 1,
+ ADAU1373_PLL_SRC_BCLK2 = 2,
+ ADAU1373_PLL_SRC_BCLK3 = 3,
+ ADAU1373_PLL_SRC_LRCLK1 = 4,
+ ADAU1373_PLL_SRC_LRCLK2 = 5,
+ ADAU1373_PLL_SRC_LRCLK3 = 6,
+ ADAU1373_PLL_SRC_GPIO1 = 7,
+ ADAU1373_PLL_SRC_GPIO2 = 8,
+ ADAU1373_PLL_SRC_GPIO3 = 9,
+ ADAU1373_PLL_SRC_GPIO4 = 10,
+ ADAU1373_PLL_SRC_MCLK2 = 11,
+};
+
+enum adau1373_pll {
+ ADAU1373_PLL1 = 0,
+ ADAU1373_PLL2 = 1,
+};
+
+enum adau1373_clk_src {
+ ADAU1373_CLK_SRC_PLL1 = 0,
+ ADAU1373_CLK_SRC_PLL2 = 1,
+};
+
+#endif
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 2758d5fc60d6..8b7e1c50d6e9 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -401,7 +401,7 @@ static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute)
}
static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
- unsigned int freq, int dir)
+ int source, unsigned int freq, int dir)
{
unsigned int val;
@@ -458,6 +458,7 @@ static int adau1701_probe(struct snd_soc_codec *codec)
int ret;
codec->dapm.idle_bias_off = 1;
+ codec->control_data = to_i2c_client(codec->dev);
ret = adau1701_load_firmware(codec);
if (ret)
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index 300c04b70e71..f9f08948e5e8 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -523,7 +523,8 @@ static int adav80x_hw_params(struct snd_pcm_substream *substream,
}
static int adav80x_set_sysclk(struct snd_soc_codec *codec,
- int clk_id, unsigned int freq, int dir)
+ int clk_id, int source,
+ unsigned int freq, int dir)
{
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
index 8402854ec15e..9082e0f729f3 100644
--- a/sound/soc/codecs/ads117x.c
+++ b/sound/soc/codecs/ads117x.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
diff --git a/sound/soc/codecs/ads117x.h b/sound/soc/codecs/ads117x.h
deleted file mode 100644
index 3ce028614002..000000000000
--- a/sound/soc/codecs/ads117x.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * ads117x.h -- Driver for ads1174/8 ADC chips
- *
- * Copyright 2009 ShotSpotter Inc.
- * Author: Graeme Gregory <gg@slimlogic.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-extern struct snd_soc_dai_driver ads117x_dai;
-extern struct snd_soc_codec_driver soc_codec_dev_ads117x;
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index cbf0b6d400b8..d3b29dce6ed7 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -247,7 +247,7 @@ static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
.probe = ak4104_probe,
.remove = ak4104_remove,
.reg_cache_size = AK4104_NUM_REGS,
- .reg_word_size = sizeof(u16),
+ .reg_word_size = sizeof(u8),
};
static int ak4104_spi_probe(struct spi_device *spi)
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index e1a214ee757f..95d782d86e7d 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -34,74 +34,16 @@
struct ak4535_priv {
unsigned int sysclk;
enum snd_soc_control_type control_type;
- void *control_data;
};
/*
* ak4535 register cache
*/
-static const u16 ak4535_reg[AK4535_CACHEREGNUM] = {
- 0x0000, 0x0080, 0x0000, 0x0003,
- 0x0002, 0x0000, 0x0011, 0x0001,
- 0x0000, 0x0040, 0x0036, 0x0010,
- 0x0000, 0x0000, 0x0057, 0x0000,
-};
-
-/*
- * read ak4535 register cache
- */
-static inline unsigned int ak4535_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- u16 *cache = codec->reg_cache;
- if (reg >= AK4535_CACHEREGNUM)
- return -1;
- return cache[reg];
-}
-
-/*
- * write ak4535 register cache
- */
-static inline void ak4535_write_reg_cache(struct snd_soc_codec *codec,
- u16 reg, unsigned int value)
-{
- u16 *cache = codec->reg_cache;
- if (reg >= AK4535_CACHEREGNUM)
- return;
- cache[reg] = value;
-}
-
-/*
- * write to the AK4535 register space
- */
-static int ak4535_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- u8 data[2];
-
- /* data is
- * D15..D8 AK4535 register offset
- * D7...D0 register data
- */
- data[0] = reg & 0xff;
- data[1] = value & 0xff;
-
- ak4535_write_reg_cache(codec, reg, value);
- if (codec->hw_write(codec->control_data, data, 2) == 2)
- return 0;
- else
- return -EIO;
-}
-
-static int ak4535_sync(struct snd_soc_codec *codec)
-{
- u16 *cache = codec->reg_cache;
- int i, r = 0;
-
- for (i = 0; i < AK4535_CACHEREGNUM; i++)
- r |= ak4535_write(codec, i, cache[i]);
-
- return r;
+static const u8 ak4535_reg[AK4535_CACHEREGNUM] = {
+ 0x00, 0x80, 0x00, 0x03,
+ 0x02, 0x00, 0x11, 0x01,
+ 0x00, 0x40, 0x36, 0x10,
+ 0x00, 0x00, 0x57, 0x00,
};
static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"};
@@ -304,7 +246,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
- u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
+ u8 mode2 = snd_soc_read(codec, AK4535_MODE2) & ~(0x3 << 5);
int rate = params_rate(params), fs = 256;
if (rate)
@@ -323,7 +265,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
}
/* set rate */
- ak4535_write(codec, AK4535_MODE2, mode2);
+ snd_soc_write(codec, AK4535_MODE2, mode2);
return 0;
}
@@ -348,44 +290,37 @@ static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* use 32 fs for BCLK to save power */
mode1 |= 0x4;
- ak4535_write(codec, AK4535_MODE1, mode1);
+ snd_soc_write(codec, AK4535_MODE1, mode1);
return 0;
}
static int ak4535_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC);
+ u16 mute_reg = snd_soc_read(codec, AK4535_DAC);
if (!mute)
- ak4535_write(codec, AK4535_DAC, mute_reg & ~0x20);
+ snd_soc_write(codec, AK4535_DAC, mute_reg & ~0x20);
else
- ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
+ snd_soc_write(codec, AK4535_DAC, mute_reg | 0x20);
return 0;
}
static int ak4535_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 i, mute_reg;
-
switch (level) {
case SND_SOC_BIAS_ON:
- mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC);
- ak4535_write(codec, AK4535_DAC, mute_reg & ~0x20);
+ snd_soc_update_bits(codec, AK4535_DAC, 0x20, 0);
break;
case SND_SOC_BIAS_PREPARE:
- mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC);
- ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
+ snd_soc_update_bits(codec, AK4535_DAC, 0x20, 0x20);
break;
case SND_SOC_BIAS_STANDBY:
- i = ak4535_read_reg_cache(codec, AK4535_PM1);
- ak4535_write(codec, AK4535_PM1, i | 0x80);
- i = ak4535_read_reg_cache(codec, AK4535_PM2);
- ak4535_write(codec, AK4535_PM2, i & (~0x80));
+ snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0x80);
+ snd_soc_update_bits(codec, AK4535_PM2, 0x80, 0);
break;
case SND_SOC_BIAS_OFF:
- i = ak4535_read_reg_cache(codec, AK4535_PM1);
- ak4535_write(codec, AK4535_PM1, i & (~0x80));
+ snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0);
break;
}
codec->dapm.bias_level = level;
@@ -428,7 +363,7 @@ static int ak4535_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int ak4535_resume(struct snd_soc_codec *codec)
{
- ak4535_sync(codec);
+ snd_soc_cache_sync(codec);
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
@@ -436,11 +371,15 @@ static int ak4535_resume(struct snd_soc_codec *codec)
static int ak4535_probe(struct snd_soc_codec *codec)
{
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
+ int ret;
printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
- codec->control_data = ak4535->control_data;
-
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4535->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
/* power on device */
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -461,8 +400,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
.remove = ak4535_remove,
.suspend = ak4535_suspend,
.resume = ak4535_resume,
- .read = ak4535_read_reg_cache,
- .write = ak4535_write,
.set_bias_level = ak4535_set_bias_level,
.reg_cache_size = ARRAY_SIZE(ak4535_reg),
.reg_word_size = sizeof(u8),
@@ -485,7 +422,6 @@ static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
i2c_set_clientdata(i2c, ak4535);
- ak4535->control_data = i2c;
ak4535->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev,
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index 7a64e58cddc4..77838586f358 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -31,7 +31,6 @@
/* codec private data */
struct ak4641_priv {
- struct snd_soc_codec *codec;
unsigned int sysclk;
int deemph;
int playback_fs;
@@ -226,7 +225,7 @@ static const struct snd_soc_dapm_widget ak4641_dapm_widgets[] = {
SND_SOC_DAPM_PGA("Mono Out 2", AK4641_PM2, 3, 0, NULL, 0),
SND_SOC_DAPM_ADC("Voice ADC", "Voice Capture", AK4641_BTIF, 0, 0),
- SND_SOC_DAPM_ADC("Voice DAC", "Voice Playback", AK4641_BTIF, 1, 0),
+ SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AK4641_BTIF, 1, 0),
SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4641_MIC, 3, 0),
SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4641_MIC, 4, 0),
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 65f46047b1cb..12c1bdef6732 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -26,6 +26,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@@ -156,81 +157,22 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
struct ak4642_priv {
unsigned int sysclk;
enum snd_soc_control_type control_type;
- void *control_data;
};
/*
* ak4642 register cache
*/
-static const u16 ak4642_reg[AK4642_CACHEREGNUM] = {
- 0x0000, 0x0000, 0x0001, 0x0000,
- 0x0002, 0x0000, 0x0000, 0x0000,
- 0x00e1, 0x00e1, 0x0018, 0x0000,
- 0x00e1, 0x0018, 0x0011, 0x0008,
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000,
-};
-
-/*
- * read ak4642 register cache
- */
-static inline unsigned int ak4642_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- u16 *cache = codec->reg_cache;
- if (reg >= AK4642_CACHEREGNUM)
- return -1;
- return cache[reg];
-}
-
-/*
- * write ak4642 register cache
- */
-static inline void ak4642_write_reg_cache(struct snd_soc_codec *codec,
- u16 reg, unsigned int value)
-{
- u16 *cache = codec->reg_cache;
- if (reg >= AK4642_CACHEREGNUM)
- return;
-
- cache[reg] = value;
-}
-
-/*
- * write to the AK4642 register space
- */
-static int ak4642_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- u8 data[2];
-
- /* data is
- * D15..D8 AK4642 register offset
- * D7...D0 register data
- */
- data[0] = reg & 0xff;
- data[1] = value & 0xff;
-
- if (codec->hw_write(codec->control_data, data, 2) == 2) {
- ak4642_write_reg_cache(codec, reg, value);
- return 0;
- } else
- return -EIO;
-}
-
-static int ak4642_sync(struct snd_soc_codec *codec)
-{
- u16 *cache = codec->reg_cache;
- int i, r = 0;
-
- for (i = 0; i < AK4642_CACHEREGNUM; i++)
- r |= ak4642_write(codec, i, cache[i]);
-
- return r;
+static const u8 ak4642_reg[AK4642_CACHEREGNUM] = {
+ 0x00, 0x00, 0x01, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0xe1, 0xe1, 0x18, 0x00,
+ 0xe1, 0x18, 0x11, 0x08,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00,
};
static int ak4642_dai_startup(struct snd_pcm_substream *substream,
@@ -252,8 +194,8 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
*/
snd_soc_update_bits(codec, MD_CTL4, DACH, DACH);
snd_soc_update_bits(codec, MD_CTL3, BST1, BST1);
- ak4642_write(codec, L_IVC, 0x91); /* volume */
- ak4642_write(codec, R_IVC, 0x91); /* volume */
+ snd_soc_write(codec, L_IVC, 0x91); /* volume */
+ snd_soc_write(codec, R_IVC, 0x91); /* volume */
snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC,
PMVCM | PMMIN | PMDAC);
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
@@ -272,9 +214,9 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p94.
*/
- ak4642_write(codec, SG_SL1, PMMP | MGAIN0);
- ak4642_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
- ak4642_write(codec, ALC_CTL1, ALC | LMTH0);
+ snd_soc_write(codec, SG_SL1, PMMP | MGAIN0);
+ snd_soc_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
+ snd_soc_write(codec, ALC_CTL1, ALC | LMTH0);
snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL,
PMVCM | PMADL);
snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
@@ -462,7 +404,7 @@ static struct snd_soc_dai_driver ak4642_dai = {
static int ak4642_resume(struct snd_soc_codec *codec)
{
- ak4642_sync(codec);
+ snd_soc_cache_sync(codec);
return 0;
}
@@ -470,11 +412,15 @@ static int ak4642_resume(struct snd_soc_codec *codec)
static int ak4642_probe(struct snd_soc_codec *codec)
{
struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec);
+ int ret;
dev_info(codec->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
- codec->hw_write = (hw_write_t)i2c_master_send;
- codec->control_data = ak4642->control_data;
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4642->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
snd_soc_add_controls(codec, ak4642_snd_controls,
ARRAY_SIZE(ak4642_snd_controls));
@@ -485,8 +431,6 @@ static int ak4642_probe(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
.probe = ak4642_probe,
.resume = ak4642_resume,
- .read = ak4642_read_reg_cache,
- .write = ak4642_write,
.reg_cache_size = ARRAY_SIZE(ak4642_reg),
.reg_word_size = sizeof(u8),
.reg_cache_default = ak4642_reg,
@@ -504,7 +448,6 @@ static __devinit int ak4642_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
i2c_set_clientdata(i2c, ak4642);
- ak4642->control_data = i2c;
ak4642->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev,
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index 88b29f8c748b..de9ff66d3721 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -26,7 +26,6 @@
/* codec private data */
struct ak4671_priv {
enum snd_soc_control_type control_type;
- void *control_data;
};
/* ak4671 register cache & default register settings */
@@ -169,18 +168,15 @@ static int ak4671_out2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- u8 reg;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT);
- reg |= AK4671_MUTEN;
- snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg);
+ snd_soc_update_bits(codec, AK4671_LOUT2_POWER_MANAGERMENT,
+ AK4671_MUTEN, AK4671_MUTEN);
break;
case SND_SOC_DAPM_PRE_PMD:
- reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT);
- reg &= ~AK4671_MUTEN;
- snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg);
+ snd_soc_update_bits(codec, AK4671_LOUT2_POWER_MANAGERMENT,
+ AK4671_MUTEN, 0);
break;
}
@@ -576,15 +572,12 @@ static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
static int ak4671_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u8 reg;
-
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
case SND_SOC_BIAS_STANDBY:
- reg = snd_soc_read(codec, AK4671_AD_DA_POWER_MANAGEMENT);
- snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT,
- reg | AK4671_PMVCM);
+ snd_soc_update_bits(codec, AK4671_AD_DA_POWER_MANAGEMENT,
+ AK4671_PMVCM, AK4671_PMVCM);
break;
case SND_SOC_BIAS_OFF:
snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
@@ -629,8 +622,6 @@ static int ak4671_probe(struct snd_soc_codec *codec)
struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec);
int ret;
- codec->hw_write = (hw_write_t)i2c_master_send;
-
ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
@@ -675,7 +666,6 @@ static int __devinit ak4671_i2c_probe(struct i2c_client *client,
return -ENOMEM;
i2c_set_clientdata(client, ak4671);
- ak4671->control_data = client;
ak4671->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&client->dev,
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index eecffb548947..984b14bcb605 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -40,8 +40,6 @@ MODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)");
/* codec private data */
struct alc5623_priv {
enum snd_soc_control_type control_type;
- void *control_data;
- struct mutex mutex;
u8 id;
unsigned int sysclk;
u16 reg_cache[ALC5623_VENDOR_ID2+2];
@@ -55,8 +53,10 @@ static void alc5623_fill_cache(struct snd_soc_codec *codec)
u16 *cache = codec->reg_cache;
/* not really efficient ... */
+ codec->cache_bypass = 1;
for (i = 0 ; i < codec->driver->reg_cache_size ; i += step)
- cache[i] = codec->hw_read(codec, i);
+ cache[i] = snd_soc_read(codec, i);
+ codec->cache_bypass = 0;
}
static inline int alc5623_reset(struct snd_soc_codec *codec)
@@ -1050,9 +1050,7 @@ static int alc5623_i2c_probe(struct i2c_client *client,
}
i2c_set_clientdata(client, alc5623);
- alc5623->control_data = client;
alc5623->control_type = SND_SOC_I2C;
- mutex_init(&alc5623->mutex);
ret = snd_soc_register_codec(&client->dev,
&soc_codec_device_alc5623, &alc5623_dai, 1);
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 6cc8678f49f3..f1f237ecec2a 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -128,7 +128,6 @@ static const char *supply_names[] = {
/* Private data for the CS4270 */
struct cs4270_private {
enum snd_soc_control_type control_type;
- void *control_data;
unsigned int mclk; /* Input frequency of the MCLK pin */
unsigned int mode; /* The mode (I2S or left-justified) */
unsigned int slave_mode;
@@ -262,7 +261,6 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
{
struct snd_soc_codec *codec = codec_dai->codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
- int ret = 0;
/* set DAI format */
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -272,7 +270,7 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
break;
default:
dev_err(codec->dev, "invalid dai format\n");
- ret = -EINVAL;
+ return -EINVAL;
}
/* set master/slave audio interface */
@@ -285,10 +283,11 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
break;
default:
/* all other modes are unsupported by the hardware */
- ret = -EINVAL;
+ dev_err(codec->dev, "Unknown master/slave configuration\n");
+ return -EINVAL;
}
- return ret;
+ return 0;
}
/**
@@ -490,8 +489,6 @@ static int cs4270_probe(struct snd_soc_codec *codec)
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int i, ret;
- codec->control_data = cs4270->control_data;
-
/* Tell ASoC what kind of I/O to use to read the registers. ASoC will
* then do the I2C transactions itself.
*/
@@ -604,7 +601,7 @@ static int cs4270_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
static int cs4270_soc_resume(struct snd_soc_codec *codec)
{
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
- struct i2c_client *i2c_client = codec->control_data;
+ struct i2c_client *i2c_client = to_i2c_client(codec->dev);
int reg;
regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
@@ -690,7 +687,6 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
}
i2c_set_clientdata(i2c_client, cs4270);
- cs4270->control_data = i2c_client;
cs4270->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c_client->dev,
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index 083aab96ca80..23d1bd5dadda 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -156,7 +156,6 @@ static const u8 cs4271_dflt_reg[CS4271_NR_REGS] = {
struct cs4271_private {
/* SND_SOC_I2C or SND_SOC_SPI */
enum snd_soc_control_type bus_type;
- void *control_data;
unsigned int mclk;
bool master;
bool deemph;
@@ -466,8 +465,6 @@ static int cs4271_probe(struct snd_soc_codec *codec)
int ret;
int gpio_nreset = -EINVAL;
- codec->control_data = cs4271->control_data;
-
if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset))
gpio_nreset = cs4271plat->gpio_nreset;
@@ -555,7 +552,6 @@ static int __devinit cs4271_spi_probe(struct spi_device *spi)
return -ENOMEM;
spi_set_drvdata(spi, cs4271);
- cs4271->control_data = spi;
cs4271->bus_type = SND_SOC_SPI;
return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271,
@@ -595,7 +591,6 @@ static int __devinit cs4271_i2c_probe(struct i2c_client *client,
return -ENOMEM;
i2c_set_clientdata(client, cs4271);
- cs4271->control_data = client;
cs4271->bus_type = SND_SOC_I2C;
return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271,
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 8fb7070108dd..8c3c8205d19e 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -42,7 +42,6 @@ enum master_slave_mode {
struct cs42l51_private {
enum snd_soc_control_type control_type;
- void *control_data;
unsigned int mclk;
unsigned int audio_mode; /* The mode (I2S or left-justified) */
enum master_slave_mode func;
@@ -57,7 +56,7 @@ struct cs42l51_private {
static int cs42l51_fill_cache(struct snd_soc_codec *codec)
{
u8 *cache = codec->reg_cache + 1;
- struct i2c_client *i2c_client = codec->control_data;
+ struct i2c_client *i2c_client = to_i2c_client(codec->dev);
s32 length;
length = i2c_smbus_read_i2c_block_data(i2c_client,
@@ -289,7 +288,6 @@ static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
{
struct snd_soc_codec *codec = codec_dai->codec;
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
- int ret = 0;
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -299,7 +297,7 @@ static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
break;
default:
dev_err(codec->dev, "invalid DAI format\n");
- ret = -EINVAL;
+ return -EINVAL;
}
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -310,11 +308,11 @@ static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
cs42l51->func = MODE_SLAVE_AUTO;
break;
default:
- ret = -EINVAL;
- break;
+ dev_err(codec->dev, "Unknown master/slave configuration\n");
+ return -EINVAL;
}
- return ret;
+ return 0;
}
struct cs42l51_ratios {
@@ -520,8 +518,6 @@ static int cs42l51_probe(struct snd_soc_codec *codec)
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret, reg;
- codec->control_data = cs42l51->control_data;
-
ret = cs42l51_fill_cache(codec);
if (ret < 0) {
dev_err(codec->dev, "failed to fill register cache\n");
@@ -593,7 +589,6 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
}
i2c_set_clientdata(i2c_client, cs42l51);
- cs42l51->control_data = i2c_client;
cs42l51->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c_client->dev,
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index d68ea532cc7f..bc7067db8ae4 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -15,6 +15,7 @@
#include <linux/tty.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/initval.h>
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 92fd9d7a9221..b545b7d37222 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -19,6 +19,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -26,23 +27,41 @@
#include <sound/tlv.h>
/* DA7210 register space */
+#define DA7210_CONTROL 0x01
#define DA7210_STATUS 0x02
#define DA7210_STARTUP1 0x03
+#define DA7210_STARTUP2 0x04
+#define DA7210_STARTUP3 0x05
#define DA7210_MIC_L 0x07
#define DA7210_MIC_R 0x08
+#define DA7210_AUX1_L 0x09
+#define DA7210_AUX1_R 0x0A
+#define DA7210_AUX2 0x0B
+#define DA7210_IN_GAIN 0x0C
#define DA7210_INMIX_L 0x0D
#define DA7210_INMIX_R 0x0E
#define DA7210_ADC_HPF 0x0F
#define DA7210_ADC 0x10
+#define DA7210_ADC_EQ1_2 0X11
+#define DA7210_ADC_EQ3_4 0x12
+#define DA7210_ADC_EQ5 0x13
#define DA7210_DAC_HPF 0x14
#define DA7210_DAC_L 0x15
#define DA7210_DAC_R 0x16
#define DA7210_DAC_SEL 0x17
+#define DA7210_SOFTMUTE 0x18
+#define DA7210_DAC_EQ1_2 0x19
+#define DA7210_DAC_EQ3_4 0x1A
+#define DA7210_DAC_EQ5 0x1B
#define DA7210_OUTMIX_L 0x1C
#define DA7210_OUTMIX_R 0x1D
+#define DA7210_OUT1_L 0x1E
+#define DA7210_OUT1_R 0x1F
+#define DA7210_OUT2 0x20
#define DA7210_HP_L_VOL 0x21
#define DA7210_HP_R_VOL 0x22
#define DA7210_HP_CFG 0x23
+#define DA7210_ZERO_CROSS 0x24
#define DA7210_DAI_SRC_SEL 0x25
#define DA7210_DAI_CFG1 0x26
#define DA7210_DAI_CFG3 0x28
@@ -50,6 +69,12 @@
#define DA7210_PLL_DIV2 0x2A
#define DA7210_PLL_DIV3 0x2B
#define DA7210_PLL 0x2C
+#define DA7210_ALC_MAX 0x83
+#define DA7210_ALC_MIN 0x84
+#define DA7210_ALC_NOIS 0x85
+#define DA7210_ALC_ATT 0x86
+#define DA7210_ALC_REL 0x87
+#define DA7210_ALC_DEL 0x88
#define DA7210_A_HID_UNLOCK 0x8A
#define DA7210_A_TEST_UNLOCK 0x8B
#define DA7210_A_PLL1 0x90
@@ -72,6 +97,7 @@
#define DA7210_IN_R_EN (1 << 7)
/* ADC bit fields */
+#define DA7210_ADC_ALC_EN (1 << 0)
#define DA7210_ADC_L_EN (1 << 3)
#define DA7210_ADC_R_EN (1 << 7)
@@ -105,12 +131,17 @@
/* DAI_CFG1 bit fields */
#define DA7210_DAI_WORD_S16_LE (0 << 0)
+#define DA7210_DAI_WORD_S20_3LE (1 << 0)
#define DA7210_DAI_WORD_S24_LE (2 << 0)
+#define DA7210_DAI_WORD_S32_LE (3 << 0)
#define DA7210_DAI_FLEN_64BIT (1 << 2)
+#define DA7210_DAI_MODE_SLAVE (0 << 7)
#define DA7210_DAI_MODE_MASTER (1 << 7)
/* DAI_CFG3 bit fields */
#define DA7210_DAI_FORMAT_I2SMODE (0 << 0)
+#define DA7210_DAI_FORMAT_LEFT_J (1 << 0)
+#define DA7210_DAI_FORMAT_RIGHT_J (2 << 0)
#define DA7210_DAI_OE (1 << 3)
#define DA7210_DAI_EN (1 << 7)
@@ -133,6 +164,43 @@
#define DA7210_PLL_FS_96000 (0xF << 0)
#define DA7210_PLL_EN (0x1 << 7)
+/* SOFTMUTE bit fields */
+#define DA7210_RAMP_EN (1 << 6)
+
+/* CONTROL bit fields */
+#define DA7210_NOISE_SUP_EN (1 << 3)
+
+/* IN_GAIN bit fields */
+#define DA7210_INPGA_L_VOL (0x0F << 0)
+#define DA7210_INPGA_R_VOL (0xF0 << 0)
+
+/* ZERO_CROSS bit fields */
+#define DA7210_AUX1_L_ZC (1 << 0)
+#define DA7210_AUX1_R_ZC (1 << 1)
+#define DA7210_HP_L_ZC (1 << 6)
+#define DA7210_HP_R_ZC (1 << 7)
+
+/* AUX1_L bit fields */
+#define DA7210_AUX1_L_VOL (0x3F << 0)
+
+/* AUX1_R bit fields */
+#define DA7210_AUX1_R_VOL (0x3F << 0)
+
+/* Minimum INPGA and AUX1 volume to enable noise suppression */
+#define DA7210_INPGA_MIN_VOL_NS 0x0A /* 10.5dB */
+#define DA7210_AUX1_MIN_VOL_NS 0x35 /* 6dB */
+
+/* OUT1_L bit fields */
+#define DA7210_OUT1_L_EN (1 << 7)
+
+/* OUT1_R bit fields */
+#define DA7210_OUT1_R_EN (1 << 7)
+
+/* OUT2 bit fields */
+#define DA7210_OUT2_OUTMIX_R (1 << 5)
+#define DA7210_OUT2_OUTMIX_L (1 << 6)
+#define DA7210_OUT2_EN (1 << 7)
+
#define DA7210_VERSION "0.0.1"
/*
@@ -144,24 +212,351 @@
* mute : 0x10
* reserved : 0x00 - 0x0F
*
- * ** FIXME **
- *
* Reserved area are considered as "mute".
- * -> min = -79.5 dB
*/
-static const DECLARE_TLV_DB_SCALE(hp_out_tlv, -7950, 150, 1);
+static const unsigned int hp_out_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+ /* -54 dB to +15 dB */
+ 0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0),
+};
+
+static const unsigned int lineout_vol_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+ /* -54dB to 15dB */
+ 0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0)
+};
+
+static const unsigned int mono_vol_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0x0, 0x2, TLV_DB_SCALE_ITEM(-1800, 0, 1),
+ /* -18dB to 6dB */
+ 0x3, 0x7, TLV_DB_SCALE_ITEM(-1800, 600, 0)
+};
+
+static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_eq_master_gain_tlv, -1800, 600, 1);
+static const DECLARE_TLV_DB_SCALE(dac_gain_tlv, -7725, 75, 0);
+
+/* ADC and DAC high pass filter f0 value */
+static const char const *da7210_hpf_cutoff_txt[] = {
+ "Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi"
+};
+
+static const struct soc_enum da7210_dac_hpf_cutoff =
+ SOC_ENUM_SINGLE(DA7210_DAC_HPF, 0, 4, da7210_hpf_cutoff_txt);
+
+static const struct soc_enum da7210_adc_hpf_cutoff =
+ SOC_ENUM_SINGLE(DA7210_ADC_HPF, 0, 4, da7210_hpf_cutoff_txt);
+
+/* ADC and DAC voice (8kHz) high pass cutoff value */
+static const char const *da7210_vf_cutoff_txt[] = {
+ "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static const struct soc_enum da7210_dac_vf_cutoff =
+ SOC_ENUM_SINGLE(DA7210_DAC_HPF, 4, 8, da7210_vf_cutoff_txt);
+
+static const struct soc_enum da7210_adc_vf_cutoff =
+ SOC_ENUM_SINGLE(DA7210_ADC_HPF, 4, 8, da7210_vf_cutoff_txt);
+
+static const char *da7210_hp_mode_txt[] = {
+ "Class H", "Class G"
+};
+
+static const struct soc_enum da7210_hp_mode_sel =
+ SOC_ENUM_SINGLE(DA7210_HP_CFG, 0, 2, da7210_hp_mode_txt);
+
+/* ALC can be enabled only if noise suppression is disabled */
+static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (ucontrol->value.integer.value[0]) {
+ /* Check if noise suppression is enabled */
+ if (snd_soc_read(codec, DA7210_CONTROL) & DA7210_NOISE_SUP_EN) {
+ dev_dbg(codec->dev,
+ "Disable noise suppression to enable ALC\n");
+ return -EINVAL;
+ }
+ }
+ /* If all conditions are met or we are actually disabling ALC */
+ return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+/* Noise suppression can be enabled only if following conditions are met
+ * ALC disabled
+ * ZC enabled for HP and AUX1 PGA
+ * INPGA_L_VOL and INPGA_R_VOL >= 10.5 dB
+ * AUX1_L_VOL and AUX1_R_VOL >= 6 dB
+ */
+static int da7210_put_noise_sup_sw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ u8 val;
+
+ if (ucontrol->value.integer.value[0]) {
+ /* Check if ALC is enabled */
+ if (snd_soc_read(codec, DA7210_ADC) & DA7210_ADC_ALC_EN)
+ goto err;
+
+ /* Check ZC for HP and AUX1 PGA */
+ if ((snd_soc_read(codec, DA7210_ZERO_CROSS) &
+ (DA7210_AUX1_L_ZC | DA7210_AUX1_R_ZC | DA7210_HP_L_ZC |
+ DA7210_HP_R_ZC)) != (DA7210_AUX1_L_ZC |
+ DA7210_AUX1_R_ZC | DA7210_HP_L_ZC | DA7210_HP_R_ZC))
+ goto err;
+
+ /* Check INPGA_L_VOL and INPGA_R_VOL */
+ val = snd_soc_read(codec, DA7210_IN_GAIN);
+ if (((val & DA7210_INPGA_L_VOL) < DA7210_INPGA_MIN_VOL_NS) ||
+ (((val & DA7210_INPGA_R_VOL) >> 4) <
+ DA7210_INPGA_MIN_VOL_NS))
+ goto err;
+
+ /* Check AUX1_L_VOL and AUX1_R_VOL */
+ if (((snd_soc_read(codec, DA7210_AUX1_L) & DA7210_AUX1_L_VOL) <
+ DA7210_AUX1_MIN_VOL_NS) ||
+ ((snd_soc_read(codec, DA7210_AUX1_R) & DA7210_AUX1_R_VOL) <
+ DA7210_AUX1_MIN_VOL_NS))
+ goto err;
+ }
+ /* If all conditions are met or we are actually disabling Noise sup */
+ return snd_soc_put_volsw(kcontrol, ucontrol);
+
+err:
+ return -EINVAL;
+}
static const struct snd_kcontrol_new da7210_snd_controls[] = {
SOC_DOUBLE_R_TLV("HeadPhone Playback Volume",
DA7210_HP_L_VOL, DA7210_HP_R_VOL,
0, 0x3F, 0, hp_out_tlv),
+ SOC_DOUBLE_R_TLV("Digital Playback Volume",
+ DA7210_DAC_L, DA7210_DAC_R,
+ 0, 0x77, 1, dac_gain_tlv),
+ SOC_DOUBLE_R_TLV("Lineout Playback Volume",
+ DA7210_OUT1_L, DA7210_OUT1_R,
+ 0, 0x3f, 0, lineout_vol_tlv),
+ SOC_SINGLE_TLV("Mono Playback Volume", DA7210_OUT2, 0, 0x7, 0,
+ mono_vol_tlv),
+
+ /* DAC Equalizer controls */
+ SOC_SINGLE("DAC EQ Switch", DA7210_DAC_EQ5, 7, 1, 0),
+ SOC_SINGLE_TLV("DAC EQ1 Volume", DA7210_DAC_EQ1_2, 0, 0xf, 1,
+ eq_gain_tlv),
+ SOC_SINGLE_TLV("DAC EQ2 Volume", DA7210_DAC_EQ1_2, 4, 0xf, 1,
+ eq_gain_tlv),
+ SOC_SINGLE_TLV("DAC EQ3 Volume", DA7210_DAC_EQ3_4, 0, 0xf, 1,
+ eq_gain_tlv),
+ SOC_SINGLE_TLV("DAC EQ4 Volume", DA7210_DAC_EQ3_4, 4, 0xf, 1,
+ eq_gain_tlv),
+ SOC_SINGLE_TLV("DAC EQ5 Volume", DA7210_DAC_EQ5, 0, 0xf, 1,
+ eq_gain_tlv),
+
+ /* ADC Equalizer controls */
+ SOC_SINGLE("ADC EQ Switch", DA7210_ADC_EQ5, 7, 1, 0),
+ SOC_SINGLE_TLV("ADC EQ Master Volume", DA7210_ADC_EQ5, 4, 0x3,
+ 1, adc_eq_master_gain_tlv),
+ SOC_SINGLE_TLV("ADC EQ1 Volume", DA7210_ADC_EQ1_2, 0, 0xf, 1,
+ eq_gain_tlv),
+ SOC_SINGLE_TLV("ADC EQ2 Volume", DA7210_ADC_EQ1_2, 4, 0xf, 1,
+ eq_gain_tlv),
+ SOC_SINGLE_TLV("ADC EQ3 Volume", DA7210_ADC_EQ3_4, 0, 0xf, 1,
+ eq_gain_tlv),
+ SOC_SINGLE_TLV("ADC EQ4 Volume", DA7210_ADC_EQ3_4, 4, 0xf, 1,
+ eq_gain_tlv),
+ SOC_SINGLE_TLV("ADC EQ5 Volume", DA7210_ADC_EQ5, 0, 0xf, 1,
+ eq_gain_tlv),
+
+ SOC_SINGLE("DAC HPF Switch", DA7210_DAC_HPF, 3, 1, 0),
+ SOC_ENUM("DAC HPF Cutoff", da7210_dac_hpf_cutoff),
+ SOC_SINGLE("DAC Voice Mode Switch", DA7210_DAC_HPF, 7, 1, 0),
+ SOC_ENUM("DAC Voice Cutoff", da7210_dac_vf_cutoff),
+
+ SOC_SINGLE("ADC HPF Switch", DA7210_ADC_HPF, 3, 1, 0),
+ SOC_ENUM("ADC HPF Cutoff", da7210_adc_hpf_cutoff),
+ SOC_SINGLE("ADC Voice Mode Switch", DA7210_ADC_HPF, 7, 1, 0),
+ SOC_ENUM("ADC Voice Cutoff", da7210_adc_vf_cutoff),
+
+ /* Mute controls */
+ SOC_DOUBLE_R("Mic Capture Switch", DA7210_MIC_L, DA7210_MIC_R, 3, 1, 0),
+ SOC_SINGLE("Aux2 Capture Switch", DA7210_AUX2, 2, 1, 0),
+ SOC_DOUBLE("ADC Capture Switch", DA7210_ADC, 2, 6, 1, 0),
+ SOC_SINGLE("Digital Soft Mute Switch", DA7210_SOFTMUTE, 7, 1, 0),
+ SOC_SINGLE("Digital Soft Mute Rate", DA7210_SOFTMUTE, 0, 0x7, 0),
+
+ /* Zero cross controls */
+ SOC_DOUBLE("Aux1 ZC Switch", DA7210_ZERO_CROSS, 0, 1, 1, 0),
+ SOC_DOUBLE("In PGA ZC Switch", DA7210_ZERO_CROSS, 2, 3, 1, 0),
+ SOC_DOUBLE("Lineout ZC Switch", DA7210_ZERO_CROSS, 4, 5, 1, 0),
+ SOC_DOUBLE("Headphone ZC Switch", DA7210_ZERO_CROSS, 6, 7, 1, 0),
+
+ SOC_ENUM("Headphone Class", da7210_hp_mode_sel),
+
+ /* ALC controls */
+ SOC_SINGLE_EXT("ALC Enable Switch", DA7210_ADC, 0, 1, 0,
+ snd_soc_get_volsw, da7210_put_alc_sw),
+ SOC_SINGLE("ALC Capture Max Volume", DA7210_ALC_MAX, 0, 0x3F, 0),
+ SOC_SINGLE("ALC Capture Min Volume", DA7210_ALC_MIN, 0, 0x3F, 0),
+ SOC_SINGLE("ALC Capture Noise Volume", DA7210_ALC_NOIS, 0, 0x3F, 0),
+ SOC_SINGLE("ALC Capture Attack Rate", DA7210_ALC_ATT, 0, 0xFF, 0),
+ SOC_SINGLE("ALC Capture Release Rate", DA7210_ALC_REL, 0, 0xFF, 0),
+ SOC_SINGLE("ALC Capture Release Delay", DA7210_ALC_DEL, 0, 0xFF, 0),
+
+ SOC_SINGLE_EXT("Noise Suppression Enable Switch", DA7210_CONTROL, 3, 1,
+ 0, snd_soc_get_volsw, da7210_put_noise_sup_sw),
+};
+
+/*
+ * DAPM Controls
+ *
+ * Current DAPM implementation covers almost all codec components e.g. IOs,
+ * mixers, PGAs,ADC and DAC.
+ */
+/* In Mixer Left */
+static const struct snd_kcontrol_new da7210_dapm_inmixl_controls[] = {
+ SOC_DAPM_SINGLE("Mic Left Switch", DA7210_INMIX_L, 0, 1, 0),
+ SOC_DAPM_SINGLE("Mic Right Switch", DA7210_INMIX_L, 1, 1, 0),
+};
+
+/* In Mixer Right */
+static const struct snd_kcontrol_new da7210_dapm_inmixr_controls[] = {
+ SOC_DAPM_SINGLE("Mic Right Switch", DA7210_INMIX_R, 0, 1, 0),
+ SOC_DAPM_SINGLE("Mic Left Switch", DA7210_INMIX_R, 1, 1, 0),
+};
+
+/* Out Mixer Left */
+static const struct snd_kcontrol_new da7210_dapm_outmixl_controls[] = {
+ SOC_DAPM_SINGLE("DAC Left Switch", DA7210_OUTMIX_L, 4, 1, 0),
+};
+
+/* Out Mixer Right */
+static const struct snd_kcontrol_new da7210_dapm_outmixr_controls[] = {
+ SOC_DAPM_SINGLE("DAC Right Switch", DA7210_OUTMIX_R, 4, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new da7210_dapm_monomix_controls[] = {
+ SOC_DAPM_SINGLE("Outmix Right Switch", DA7210_OUT2, 5, 1, 0),
+ SOC_DAPM_SINGLE("Outmix Left Switch", DA7210_OUT2, 6, 1, 0),
+};
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget da7210_dapm_widgets[] = {
+ /* Input Side */
+ /* Input Lines */
+ SND_SOC_DAPM_INPUT("MICL"),
+ SND_SOC_DAPM_INPUT("MICR"),
+
+ /* Input PGAs */
+ SND_SOC_DAPM_PGA("Mic Left", DA7210_STARTUP3, 0, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Mic Right", DA7210_STARTUP3, 1, 1, NULL, 0),
+
+ SND_SOC_DAPM_PGA("INPGA Left", DA7210_INMIX_L, 7, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INPGA Right", DA7210_INMIX_R, 7, 0, NULL, 0),
+
+ /* Input Mixers */
+ SND_SOC_DAPM_MIXER("In Mixer Left", SND_SOC_NOPM, 0, 0,
+ &da7210_dapm_inmixl_controls[0],
+ ARRAY_SIZE(da7210_dapm_inmixl_controls)),
+
+ SND_SOC_DAPM_MIXER("In Mixer Right", SND_SOC_NOPM, 0, 0,
+ &da7210_dapm_inmixr_controls[0],
+ ARRAY_SIZE(da7210_dapm_inmixr_controls)),
+
+ /* ADCs */
+ SND_SOC_DAPM_ADC("ADC Left", "Capture", DA7210_STARTUP3, 5, 1),
+ SND_SOC_DAPM_ADC("ADC Right", "Capture", DA7210_STARTUP3, 6, 1),
+
+ /* Output Side */
+ /* DACs */
+ SND_SOC_DAPM_DAC("DAC Left", "Playback", DA7210_STARTUP2, 5, 1),
+ SND_SOC_DAPM_DAC("DAC Right", "Playback", DA7210_STARTUP2, 6, 1),
+
+ /* Output Mixers */
+ SND_SOC_DAPM_MIXER("Out Mixer Left", SND_SOC_NOPM, 0, 0,
+ &da7210_dapm_outmixl_controls[0],
+ ARRAY_SIZE(da7210_dapm_outmixl_controls)),
+
+ SND_SOC_DAPM_MIXER("Out Mixer Right", SND_SOC_NOPM, 0, 0,
+ &da7210_dapm_outmixr_controls[0],
+ ARRAY_SIZE(da7210_dapm_outmixr_controls)),
+
+ SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
+ &da7210_dapm_monomix_controls[0],
+ ARRAY_SIZE(da7210_dapm_monomix_controls)),
+
+ /* Output PGAs */
+ SND_SOC_DAPM_PGA("OUTPGA Left Enable", DA7210_OUTMIX_L, 7, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("OUTPGA Right Enable", DA7210_OUTMIX_R, 7, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("Out1 Left", DA7210_STARTUP2, 0, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Out1 Right", DA7210_STARTUP2, 1, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Out2 Mono", DA7210_STARTUP2, 2, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Headphone Left", DA7210_STARTUP2, 3, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Headphone Right", DA7210_STARTUP2, 4, 1, NULL, 0),
+
+ /* Output Lines */
+ SND_SOC_DAPM_OUTPUT("OUT1L"),
+ SND_SOC_DAPM_OUTPUT("OUT1R"),
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+ SND_SOC_DAPM_OUTPUT("OUT2"),
+};
+
+/* DAPM audio route definition */
+static const struct snd_soc_dapm_route da7210_audio_map[] = {
+ /* Dest Connecting Widget source */
+ /* Input path */
+ {"Mic Left", NULL, "MICL"},
+ {"Mic Right", NULL, "MICR"},
+
+ {"In Mixer Left", "Mic Left Switch", "Mic Left"},
+ {"In Mixer Left", "Mic Right Switch", "Mic Right"},
+
+ {"In Mixer Right", "Mic Right Switch", "Mic Right"},
+ {"In Mixer Right", "Mic Left Switch", "Mic Left"},
+
+ {"INPGA Left", NULL, "In Mixer Left"},
+ {"ADC Left", NULL, "INPGA Left"},
+
+ {"INPGA Right", NULL, "In Mixer Right"},
+ {"ADC Right", NULL, "INPGA Right"},
+
+ /* Output path */
+ {"Out Mixer Left", "DAC Left Switch", "DAC Left"},
+ {"Out Mixer Right", "DAC Right Switch", "DAC Right"},
+
+ {"Mono Mixer", "Outmix Right Switch", "Out Mixer Right"},
+ {"Mono Mixer", "Outmix Left Switch", "Out Mixer Left"},
+
+ {"OUTPGA Left Enable", NULL, "Out Mixer Left"},
+ {"OUTPGA Right Enable", NULL, "Out Mixer Right"},
+
+ {"Out1 Left", NULL, "OUTPGA Left Enable"},
+ {"OUT1L", NULL, "Out1 Left"},
+
+ {"Out1 Right", NULL, "OUTPGA Right Enable"},
+ {"OUT1R", NULL, "Out1 Right"},
+
+ {"Headphone Left", NULL, "OUTPGA Left Enable"},
+ {"HPL", NULL, "Headphone Left"},
+
+ {"Headphone Right", NULL, "OUTPGA Right Enable"},
+ {"HPR", NULL, "Headphone Right"},
+
+ {"Out2 Mono", NULL, "Mono Mixer"},
+ {"OUT2", NULL, "Out2 Mono"},
};
/* Codec private data */
struct da7210_priv {
enum snd_soc_control_type control_type;
- void *control_data;
};
/*
@@ -188,72 +583,15 @@ static const u8 da7210_reg[] = {
0x00, /* R88 */
};
-/*
- * Read da7210 register cache
- */
-static inline u32 da7210_read_reg_cache(struct snd_soc_codec *codec, u32 reg)
-{
- u8 *cache = codec->reg_cache;
- BUG_ON(reg >= ARRAY_SIZE(da7210_reg));
- return cache[reg];
-}
-
-/*
- * Write to the da7210 register space
- */
-static int da7210_write(struct snd_soc_codec *codec, u32 reg, u32 value)
+static int da7210_volatile_register(struct snd_soc_codec *codec,
+ unsigned int reg)
{
- u8 *cache = codec->reg_cache;
- u8 data[2];
-
- BUG_ON(codec->driver->volatile_register);
-
- data[0] = reg & 0xff;
- data[1] = value & 0xff;
-
- if (reg >= codec->driver->reg_cache_size)
- return -EIO;
-
- if (2 != codec->hw_write(codec->control_data, data, 2))
- return -EIO;
-
- cache[reg] = value;
- return 0;
-}
-
-/*
- * Read from the da7210 register space.
- */
-static inline u32 da7210_read(struct snd_soc_codec *codec, u32 reg)
-{
- if (DA7210_STATUS == reg)
- return i2c_smbus_read_byte_data(codec->control_data, reg);
-
- return da7210_read_reg_cache(codec, reg);
-}
-
-static int da7210_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- struct snd_soc_codec *codec = dai->codec;
-
- if (is_play) {
- /* Enable Out */
- snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10);
- snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10);
-
- } else {
- /* Volume 7 */
- snd_soc_update_bits(codec, DA7210_MIC_L, 0x7, 0x7);
- snd_soc_update_bits(codec, DA7210_MIC_R, 0x7, 0x7);
-
- /* Enable Mic */
- snd_soc_update_bits(codec, DA7210_INMIX_L, 0x1F, 0x1);
- snd_soc_update_bits(codec, DA7210_INMIX_R, 0x1F, 0x1);
+ switch (reg) {
+ case DA7210_STATUS:
+ return 1;
+ default:
+ return 0;
}
-
- return 0;
}
/*
@@ -266,93 +604,75 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
u32 dai_cfg1;
- u32 hpf_reg, hpf_mask, hpf_value;
u32 fs, bypass;
/* set DAI source to Left and Right ADC */
- da7210_write(codec, DA7210_DAI_SRC_SEL,
+ snd_soc_write(codec, DA7210_DAI_SRC_SEL,
DA7210_DAI_OUT_R_SRC | DA7210_DAI_OUT_L_SRC);
/* Enable DAI */
- da7210_write(codec, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN);
+ snd_soc_write(codec, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN);
- dai_cfg1 = 0xFC & da7210_read(codec, DA7210_DAI_CFG1);
+ dai_cfg1 = 0xFC & snd_soc_read(codec, DA7210_DAI_CFG1);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
dai_cfg1 |= DA7210_DAI_WORD_S16_LE;
break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ dai_cfg1 |= DA7210_DAI_WORD_S20_3LE;
+ break;
case SNDRV_PCM_FORMAT_S24_LE:
dai_cfg1 |= DA7210_DAI_WORD_S24_LE;
break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ dai_cfg1 |= DA7210_DAI_WORD_S32_LE;
+ break;
default:
return -EINVAL;
}
- da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1);
-
- hpf_reg = (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) ?
- DA7210_DAC_HPF : DA7210_ADC_HPF;
+ snd_soc_write(codec, DA7210_DAI_CFG1, dai_cfg1);
switch (params_rate(params)) {
case 8000:
fs = DA7210_PLL_FS_8000;
- hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
- hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
bypass = DA7210_PLL_BYP;
break;
case 11025:
fs = DA7210_PLL_FS_11025;
- hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
- hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
bypass = 0;
break;
case 12000:
fs = DA7210_PLL_FS_12000;
- hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
- hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
bypass = DA7210_PLL_BYP;
break;
case 16000:
fs = DA7210_PLL_FS_16000;
- hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
- hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
bypass = DA7210_PLL_BYP;
break;
case 22050:
fs = DA7210_PLL_FS_22050;
- hpf_mask = DA7210_VOICE_EN;
- hpf_value = 0;
bypass = 0;
break;
case 32000:
fs = DA7210_PLL_FS_32000;
- hpf_mask = DA7210_VOICE_EN;
- hpf_value = 0;
bypass = DA7210_PLL_BYP;
break;
case 44100:
fs = DA7210_PLL_FS_44100;
- hpf_mask = DA7210_VOICE_EN;
- hpf_value = 0;
bypass = 0;
break;
case 48000:
fs = DA7210_PLL_FS_48000;
- hpf_mask = DA7210_VOICE_EN;
- hpf_value = 0;
bypass = DA7210_PLL_BYP;
break;
case 88200:
fs = DA7210_PLL_FS_88200;
- hpf_mask = DA7210_VOICE_EN;
- hpf_value = 0;
bypass = 0;
break;
case 96000:
fs = DA7210_PLL_FS_96000;
- hpf_mask = DA7210_VOICE_EN;
- hpf_value = 0;
bypass = DA7210_PLL_BYP;
break;
default:
@@ -362,7 +682,6 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
/* Disable active mode */
snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
- snd_soc_update_bits(codec, hpf_reg, hpf_mask, hpf_value);
snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_FS_MASK, fs);
snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, bypass);
@@ -382,13 +701,16 @@ static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
u32 dai_cfg1;
u32 dai_cfg3;
- dai_cfg1 = 0x7f & da7210_read(codec, DA7210_DAI_CFG1);
- dai_cfg3 = 0xfc & da7210_read(codec, DA7210_DAI_CFG3);
+ dai_cfg1 = 0x7f & snd_soc_read(codec, DA7210_DAI_CFG1);
+ dai_cfg3 = 0xfc & snd_soc_read(codec, DA7210_DAI_CFG3);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
dai_cfg1 |= DA7210_DAI_MODE_MASTER;
break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ dai_cfg1 |= DA7210_DAI_MODE_SLAVE;
+ break;
default:
return -EINVAL;
}
@@ -401,6 +723,12 @@ static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
case SND_SOC_DAIFMT_I2S:
dai_cfg3 |= DA7210_DAI_FORMAT_I2SMODE;
break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ dai_cfg3 |= DA7210_DAI_FORMAT_LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ dai_cfg3 |= DA7210_DAI_FORMAT_RIGHT_J;
+ break;
default:
return -EINVAL;
}
@@ -411,19 +739,32 @@ static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
*/
dai_cfg1 |= DA7210_DAI_FLEN_64BIT;
- da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1);
- da7210_write(codec, DA7210_DAI_CFG3, dai_cfg3);
+ snd_soc_write(codec, DA7210_DAI_CFG1, dai_cfg1);
+ snd_soc_write(codec, DA7210_DAI_CFG3, dai_cfg3);
+
+ return 0;
+}
+
+static int da7210_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 mute_reg = snd_soc_read(codec, DA7210_DAC_HPF) & 0xFB;
+ if (mute)
+ snd_soc_write(codec, DA7210_DAC_HPF, mute_reg | 0x4);
+ else
+ snd_soc_write(codec, DA7210_DAC_HPF, mute_reg);
return 0;
}
-#define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+#define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
/* DAI operations */
static struct snd_soc_dai_ops da7210_dai_ops = {
- .startup = da7210_startup,
.hw_params = da7210_hw_params,
.set_fmt = da7210_set_dai_fmt,
+ .digital_mute = da7210_mute,
};
static struct snd_soc_dai_driver da7210_dai = {
@@ -451,11 +792,15 @@ static struct snd_soc_dai_driver da7210_dai = {
static int da7210_probe(struct snd_soc_codec *codec)
{
struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
+ int ret;
dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
- codec->control_data = da7210->control_data;
- codec->hw_write = (hw_write_t)i2c_master_send;
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, da7210->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
/* FIXME
*
@@ -472,8 +817,8 @@ static int da7210_probe(struct snd_soc_codec *codec)
/*
* make sure that DA7210 use bypass mode before start up
*/
- da7210_write(codec, DA7210_STARTUP1, 0);
- da7210_write(codec, DA7210_PLL_DIV3,
+ snd_soc_write(codec, DA7210_STARTUP1, 0);
+ snd_soc_write(codec, DA7210_PLL_DIV3,
DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
/*
@@ -481,36 +826,70 @@ static int da7210_probe(struct snd_soc_codec *codec)
*/
/* Enable Left & Right MIC PGA and Mic Bias */
- da7210_write(codec, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN);
- da7210_write(codec, DA7210_MIC_R, DA7210_MIC_R_EN);
+ snd_soc_write(codec, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN);
+ snd_soc_write(codec, DA7210_MIC_R, DA7210_MIC_R_EN);
/* Enable Left and Right input PGA */
- da7210_write(codec, DA7210_INMIX_L, DA7210_IN_L_EN);
- da7210_write(codec, DA7210_INMIX_R, DA7210_IN_R_EN);
+ snd_soc_write(codec, DA7210_INMIX_L, DA7210_IN_L_EN);
+ snd_soc_write(codec, DA7210_INMIX_R, DA7210_IN_R_EN);
/* Enable Left and Right ADC */
- da7210_write(codec, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN);
+ snd_soc_write(codec, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN);
/*
* DAC settings
*/
/* Enable Left and Right DAC */
- da7210_write(codec, DA7210_DAC_SEL,
+ snd_soc_write(codec, DA7210_DAC_SEL,
DA7210_DAC_L_SRC_DAI_L | DA7210_DAC_L_EN |
DA7210_DAC_R_SRC_DAI_R | DA7210_DAC_R_EN);
/* Enable Left and Right out PGA */
- da7210_write(codec, DA7210_OUTMIX_L, DA7210_OUT_L_EN);
- da7210_write(codec, DA7210_OUTMIX_R, DA7210_OUT_R_EN);
+ snd_soc_write(codec, DA7210_OUTMIX_L, DA7210_OUT_L_EN);
+ snd_soc_write(codec, DA7210_OUTMIX_R, DA7210_OUT_R_EN);
/* Enable Left and Right HeadPhone PGA */
- da7210_write(codec, DA7210_HP_CFG,
+ snd_soc_write(codec, DA7210_HP_CFG,
DA7210_HP_2CAP_MODE | DA7210_HP_SENSE_EN |
DA7210_HP_L_EN | DA7210_HP_MODE | DA7210_HP_R_EN);
+ /* Enable ramp mode for DAC gain update */
+ snd_soc_write(codec, DA7210_SOFTMUTE, DA7210_RAMP_EN);
+
+ /*
+ * For DA7210 codec, there are two ways to enable/disable analog IOs
+ * and ADC/DAC,
+ * (1) Using "Enable Bit" of register associated with that IO
+ * (or ADC/DAC)
+ * e.g. Mic Left can be enabled using bit 7 of MIC_L(0x7) reg
+ *
+ * (2) Using "Standby Bit" of STARTUP2 or STARTUP3 register
+ * e.g. Mic left can be put to STANDBY using bit 0 of STARTUP3(0x5)
+ *
+ * Out of these two methods, the one using STANDBY bits is preferred
+ * way to enable/disable individual blocks. This is because STANDBY
+ * registers are part of system controller which allows system power
+ * up/down in a controlled, pop-free manner. Also, as per application
+ * note of DA7210, STANDBY register bits are only effective if a
+ * particular IO (or ADC/DAC) is already enabled using enable/disable
+ * register bits. Keeping these things in mind, current DAPM
+ * implementation manipulates only STANDBY bits.
+ *
+ * Overall implementation can be outlined as below,
+ *
+ * - "Enable bit" of an IO or ADC/DAC is used to enable it in probe()
+ * - "STANDBY bit" is controlled by DAPM
+ */
+
+ /* Enable Line out amplifiers */
+ snd_soc_write(codec, DA7210_OUT1_L, DA7210_OUT1_L_EN);
+ snd_soc_write(codec, DA7210_OUT1_R, DA7210_OUT1_R_EN);
+ snd_soc_write(codec, DA7210_OUT2, DA7210_OUT2_EN |
+ DA7210_OUT2_OUTMIX_L | DA7210_OUT2_OUTMIX_R);
+
/* Diable PLL and bypass it */
- da7210_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
+ snd_soc_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
/*
* If 48kHz sound came, it use bypass mode,
@@ -521,25 +900,22 @@ static int da7210_probe(struct snd_soc_codec *codec)
* DA7210_PLL_DIV3 :: DA7210_PLL_BYP bit.
* see da7210_hw_params
*/
- da7210_write(codec, DA7210_PLL_DIV1, 0xE5); /* MCLK = 12.288MHz */
- da7210_write(codec, DA7210_PLL_DIV2, 0x99);
- da7210_write(codec, DA7210_PLL_DIV3, 0x0A |
+ snd_soc_write(codec, DA7210_PLL_DIV1, 0xE5); /* MCLK = 12.288MHz */
+ snd_soc_write(codec, DA7210_PLL_DIV2, 0x99);
+ snd_soc_write(codec, DA7210_PLL_DIV3, 0x0A |
DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
/* As suggested by Dialog */
- da7210_write(codec, DA7210_A_HID_UNLOCK, 0x8B); /* unlock */
- da7210_write(codec, DA7210_A_TEST_UNLOCK, 0xB4);
- da7210_write(codec, DA7210_A_PLL1, 0x01);
- da7210_write(codec, DA7210_A_CP_MODE, 0x7C);
- da7210_write(codec, DA7210_A_HID_UNLOCK, 0x00); /* re-lock */
- da7210_write(codec, DA7210_A_TEST_UNLOCK, 0x00);
+ snd_soc_write(codec, DA7210_A_HID_UNLOCK, 0x8B); /* unlock */
+ snd_soc_write(codec, DA7210_A_TEST_UNLOCK, 0xB4);
+ snd_soc_write(codec, DA7210_A_PLL1, 0x01);
+ snd_soc_write(codec, DA7210_A_CP_MODE, 0x7C);
+ snd_soc_write(codec, DA7210_A_HID_UNLOCK, 0x00); /* re-lock */
+ snd_soc_write(codec, DA7210_A_TEST_UNLOCK, 0x00);
/* Activate all enabled subsystem */
- da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
-
- snd_soc_add_controls(codec, da7210_snd_controls,
- ARRAY_SIZE(da7210_snd_controls));
+ snd_soc_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
@@ -548,11 +924,18 @@ static int da7210_probe(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
.probe = da7210_probe,
- .read = da7210_read,
- .write = da7210_write,
.reg_cache_size = ARRAY_SIZE(da7210_reg),
.reg_word_size = sizeof(u8),
.reg_cache_default = da7210_reg,
+ .volatile_register = da7210_volatile_register,
+
+ .controls = da7210_snd_controls,
+ .num_controls = ARRAY_SIZE(da7210_snd_controls),
+
+ .dapm_widgets = da7210_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(da7210_dapm_widgets),
+ .dapm_routes = da7210_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(da7210_audio_map),
};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
@@ -567,7 +950,6 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
i2c_set_clientdata(i2c, da7210);
- da7210->control_data = i2c;
da7210->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev,
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index f9a87737ec16..6fae765e3ad8 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
index 2c2a681da0d7..c387dafc6ab6 100644
--- a/sound/soc/codecs/lm4857.c
+++ b/sound/soc/codecs/lm4857.c
@@ -3,7 +3,7 @@
*
* Copyright 2007 Wolfson Microelectronics PLC.
* Author: Graeme Gregory
- * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ * graeme.gregory@wolfsonmicro.com
* Copyright 2011 Lars-Peter Clausen <lars@metafoo.de>
*
* This program is free software; you can redistribute it and/or modify it
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index ac65a2d36408..ebbf63c79c34 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -40,7 +40,6 @@ struct max98088_cdata {
struct max98088_priv {
enum max98088_type devtype;
- void *control_data;
struct max98088_pdata *pdata;
unsigned int sysclk;
struct max98088_cdata dai[2];
@@ -1697,13 +1696,19 @@ static struct snd_soc_dai_driver max98088_dai[] = {
}
};
-static int max98088_get_channel(const char *name)
+static const char *eq_mode_name[] = {"EQ1 Mode", "EQ2 Mode"};
+
+static int max98088_get_channel(struct snd_soc_codec *codec, const char *name)
{
- if (strcmp(name, "EQ1 Mode") == 0)
- return 0;
- if (strcmp(name, "EQ2 Mode") == 0)
- return 1;
- return -EINVAL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(eq_mode_name); i++)
+ if (strcmp(name, eq_mode_name[i]) == 0)
+ return i;
+
+ /* Shouldn't happen */
+ dev_err(codec->dev, "Bad EQ channel name '%s'\n", name);
+ return -EINVAL;
}
static void max98088_setup_eq1(struct snd_soc_codec *codec)
@@ -1807,10 +1812,13 @@ static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
struct max98088_pdata *pdata = max98088->pdata;
- int channel = max98088_get_channel(kcontrol->id.name);
+ int channel = max98088_get_channel(codec, kcontrol->id.name);
struct max98088_cdata *cdata;
int sel = ucontrol->value.integer.value[0];
+ if (channel < 0)
+ return channel;
+
cdata = &max98088->dai[channel];
if (sel >= pdata->eq_cfgcnt)
@@ -1835,9 +1843,12 @@ static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
- int channel = max98088_get_channel(kcontrol->id.name);
+ int channel = max98088_get_channel(codec, kcontrol->id.name);
struct max98088_cdata *cdata;
+ if (channel < 0)
+ return channel;
+
cdata = &max98088->dai[channel];
ucontrol->value.enumerated.item[0] = cdata->eq_sel;
return 0;
@@ -1852,17 +1863,17 @@ static void max98088_handle_eq_pdata(struct snd_soc_codec *codec)
int i, j;
const char **t;
int ret;
-
struct snd_kcontrol_new controls[] = {
- SOC_ENUM_EXT("EQ1 Mode",
+ SOC_ENUM_EXT((char *)eq_mode_name[0],
max98088->eq_enum,
max98088_get_eq_enum,
max98088_put_eq_enum),
- SOC_ENUM_EXT("EQ2 Mode",
+ SOC_ENUM_EXT((char *)eq_mode_name[1],
max98088->eq_enum,
max98088_get_eq_enum,
max98088_put_eq_enum),
};
+ BUILD_BUG_ON(ARRAY_SIZE(controls) != ARRAY_SIZE(eq_mode_name));
cfg = pdata->eq_cfg;
cfgcnt = pdata->eq_cfgcnt;
@@ -2066,7 +2077,6 @@ static int max98088_i2c_probe(struct i2c_client *i2c,
max98088->devtype = id->driver_data;
i2c_set_clientdata(i2c, max98088);
- max98088->control_data = i2c;
max98088->pdata = i2c->dev.platform_data;
ret = snd_soc_register_codec(&i2c->dev,
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 668434d44303..26d7b089fb9c 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -40,7 +40,6 @@ struct max98095_cdata {
struct max98095_priv {
enum max98095_type devtype;
- void *control_data;
struct max98095_pdata *pdata;
unsigned int sysclk;
struct max98095_cdata dai[3];
@@ -618,14 +617,13 @@ static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg)
static int max98095_hw_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
- u8 data[2];
+ int ret;
- data[0] = reg;
- data[1] = value;
- if (codec->hw_write(codec->control_data, data, 2) == 2)
- return 0;
- else
- return -EIO;
+ codec->cache_bypass = 1;
+ ret = snd_soc_write(codec, reg, value);
+ codec->cache_bypass = 0;
+
+ return ret ? -EIO : 0;
}
/*
@@ -1992,12 +1990,19 @@ static void max98095_handle_eq_pdata(struct snd_soc_codec *codec)
dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
}
-static int max98095_get_bq_channel(const char *name)
+static const char *bq_mode_name[] = {"Biquad1 Mode", "Biquad2 Mode"};
+
+static int max98095_get_bq_channel(struct snd_soc_codec *codec,
+ const char *name)
{
- if (strcmp(name, "Biquad1 Mode") == 0)
- return 0;
- if (strcmp(name, "Biquad2 Mode") == 0)
- return 1;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bq_mode_name); i++)
+ if (strcmp(name, bq_mode_name[i]) == 0)
+ return i;
+
+ /* Shouldn't happen */
+ dev_err(codec->dev, "Bad biquad channel name '%s'\n", name);
return -EINVAL;
}
@@ -2007,14 +2012,15 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
struct max98095_pdata *pdata = max98095->pdata;
- int channel = max98095_get_bq_channel(kcontrol->id.name);
+ int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
struct max98095_cdata *cdata;
int sel = ucontrol->value.integer.value[0];
struct max98095_biquad_cfg *coef_set;
int fs, best, best_val, i;
int regmask, regsave;
- BUG_ON(channel > 1);
+ if (channel < 0)
+ return channel;
if (!pdata || !max98095->bq_textcnt)
return 0;
@@ -2066,9 +2072,12 @@ static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
- int channel = max98095_get_bq_channel(kcontrol->id.name);
+ int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
struct max98095_cdata *cdata;
+ if (channel < 0)
+ return channel;
+
cdata = &max98095->dai[channel];
ucontrol->value.enumerated.item[0] = cdata->bq_sel;
@@ -2086,15 +2095,16 @@ static void max98095_handle_bq_pdata(struct snd_soc_codec *codec)
int ret;
struct snd_kcontrol_new controls[] = {
- SOC_ENUM_EXT("Biquad1 Mode",
+ SOC_ENUM_EXT((char *)bq_mode_name[0],
max98095->bq_enum,
max98095_get_bq_enum,
max98095_put_bq_enum),
- SOC_ENUM_EXT("Biquad2 Mode",
+ SOC_ENUM_EXT((char *)bq_mode_name[1],
max98095->bq_enum,
max98095_get_bq_enum,
max98095_put_bq_enum),
};
+ BUILD_BUG_ON(ARRAY_SIZE(controls) != ARRAY_SIZE(bq_mode_name));
cfg = pdata->bq_cfg;
cfgcnt = pdata->bq_cfgcnt;
@@ -2337,7 +2347,6 @@ static int max98095_i2c_probe(struct i2c_client *i2c,
max98095->devtype = id->driver_data;
i2c_set_clientdata(i2c, max98095);
- max98095->control_data = i2c;
max98095->pdata = i2c->dev.platform_data;
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98095,
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
index bd8f26e41602..f7316519432c 100644
--- a/sound/soc/codecs/pcm3008.c
+++ b/sound/soc/codecs/pcm3008.c
@@ -20,6 +20,7 @@
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
new file mode 100644
index 000000000000..27a078cbb6eb
--- /dev/null
+++ b/sound/soc/codecs/rt5631.c
@@ -0,0 +1,1773 @@
+/*
+ * rt5631.c -- RT5631 ALSA Soc Audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ *
+ * Author: flove <flove@realtek.com>
+ *
+ * Based on WM8753.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt5631.h"
+
+struct rt5631_priv {
+ int codec_version;
+ int master;
+ int sysclk;
+ int rx_rate;
+ int bclk_rate;
+ int dmic_used_flag;
+};
+
+static const u16 rt5631_reg[RT5631_VENDOR_ID2 + 1] = {
+ [RT5631_SPK_OUT_VOL] = 0x8888,
+ [RT5631_HP_OUT_VOL] = 0x8080,
+ [RT5631_MONO_AXO_1_2_VOL] = 0xa080,
+ [RT5631_AUX_IN_VOL] = 0x0808,
+ [RT5631_ADC_REC_MIXER] = 0xf0f0,
+ [RT5631_VDAC_DIG_VOL] = 0x0010,
+ [RT5631_OUTMIXER_L_CTRL] = 0xffc0,
+ [RT5631_OUTMIXER_R_CTRL] = 0xffc0,
+ [RT5631_AXO1MIXER_CTRL] = 0x88c0,
+ [RT5631_AXO2MIXER_CTRL] = 0x88c0,
+ [RT5631_DIG_MIC_CTRL] = 0x3000,
+ [RT5631_MONO_INPUT_VOL] = 0x8808,
+ [RT5631_SPK_MIXER_CTRL] = 0xf8f8,
+ [RT5631_SPK_MONO_OUT_CTRL] = 0xfc00,
+ [RT5631_SPK_MONO_HP_OUT_CTRL] = 0x4440,
+ [RT5631_SDP_CTRL] = 0x8000,
+ [RT5631_MONO_SDP_CTRL] = 0x8000,
+ [RT5631_STEREO_AD_DA_CLK_CTRL] = 0x2010,
+ [RT5631_GEN_PUR_CTRL_REG] = 0x0e00,
+ [RT5631_INT_ST_IRQ_CTRL_2] = 0x071a,
+ [RT5631_MISC_CTRL] = 0x2040,
+ [RT5631_DEPOP_FUN_CTRL_2] = 0x8000,
+ [RT5631_SOFT_VOL_CTRL] = 0x07e0,
+ [RT5631_ALC_CTRL_1] = 0x0206,
+ [RT5631_ALC_CTRL_3] = 0x2000,
+ [RT5631_PSEUDO_SPATL_CTRL] = 0x0553,
+};
+
+/**
+ * rt5631_write_index - write index register of 2nd layer
+ */
+static void rt5631_write_index(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int value)
+{
+ snd_soc_write(codec, RT5631_INDEX_ADD, reg);
+ snd_soc_write(codec, RT5631_INDEX_DATA, value);
+}
+
+/**
+ * rt5631_read_index - read index register of 2nd layer
+ */
+static unsigned int rt5631_read_index(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ unsigned int value;
+
+ snd_soc_write(codec, RT5631_INDEX_ADD, reg);
+ value = snd_soc_read(codec, RT5631_INDEX_DATA);
+
+ return value;
+}
+
+static int rt5631_reset(struct snd_soc_codec *codec)
+{
+ return snd_soc_write(codec, RT5631_RESET, 0);
+}
+
+static int rt5631_volatile_register(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ switch (reg) {
+ case RT5631_RESET:
+ case RT5631_INT_ST_IRQ_CTRL_2:
+ case RT5631_INDEX_ADD:
+ case RT5631_INDEX_DATA:
+ case RT5631_EQ_CTRL:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int rt5631_readable_register(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ switch (reg) {
+ case RT5631_RESET:
+ case RT5631_SPK_OUT_VOL:
+ case RT5631_HP_OUT_VOL:
+ case RT5631_MONO_AXO_1_2_VOL:
+ case RT5631_AUX_IN_VOL:
+ case RT5631_STEREO_DAC_VOL_1:
+ case RT5631_MIC_CTRL_1:
+ case RT5631_STEREO_DAC_VOL_2:
+ case RT5631_ADC_CTRL_1:
+ case RT5631_ADC_REC_MIXER:
+ case RT5631_ADC_CTRL_2:
+ case RT5631_VDAC_DIG_VOL:
+ case RT5631_OUTMIXER_L_CTRL:
+ case RT5631_OUTMIXER_R_CTRL:
+ case RT5631_AXO1MIXER_CTRL:
+ case RT5631_AXO2MIXER_CTRL:
+ case RT5631_MIC_CTRL_2:
+ case RT5631_DIG_MIC_CTRL:
+ case RT5631_MONO_INPUT_VOL:
+ case RT5631_SPK_MIXER_CTRL:
+ case RT5631_SPK_MONO_OUT_CTRL:
+ case RT5631_SPK_MONO_HP_OUT_CTRL:
+ case RT5631_SDP_CTRL:
+ case RT5631_MONO_SDP_CTRL:
+ case RT5631_STEREO_AD_DA_CLK_CTRL:
+ case RT5631_PWR_MANAG_ADD1:
+ case RT5631_PWR_MANAG_ADD2:
+ case RT5631_PWR_MANAG_ADD3:
+ case RT5631_PWR_MANAG_ADD4:
+ case RT5631_GEN_PUR_CTRL_REG:
+ case RT5631_GLOBAL_CLK_CTRL:
+ case RT5631_PLL_CTRL:
+ case RT5631_INT_ST_IRQ_CTRL_1:
+ case RT5631_INT_ST_IRQ_CTRL_2:
+ case RT5631_GPIO_CTRL:
+ case RT5631_MISC_CTRL:
+ case RT5631_DEPOP_FUN_CTRL_1:
+ case RT5631_DEPOP_FUN_CTRL_2:
+ case RT5631_JACK_DET_CTRL:
+ case RT5631_SOFT_VOL_CTRL:
+ case RT5631_ALC_CTRL_1:
+ case RT5631_ALC_CTRL_2:
+ case RT5631_ALC_CTRL_3:
+ case RT5631_PSEUDO_SPATL_CTRL:
+ case RT5631_INDEX_ADD:
+ case RT5631_INDEX_DATA:
+ case RT5631_EQ_CTRL:
+ case RT5631_VENDOR_ID:
+ case RT5631_VENDOR_ID1:
+ case RT5631_VENDOR_ID2:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -95625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52}dB */
+static unsigned int mic_bst_tlv[] = {
+ TLV_DB_RANGE_HEAD(6),
+ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+ 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+ 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+ 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+ 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+ 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
+};
+
+static int rt5631_dmic_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = rt5631->dmic_used_flag;
+
+ return 0;
+}
+
+static int rt5631_dmic_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+
+ rt5631->dmic_used_flag = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+/* MIC Input Type */
+static const char *rt5631_input_mode[] = {
+ "Single ended", "Differential"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1,
+ RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode);
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1,
+ RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode);
+
+/* MONO Input Type */
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL,
+ RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode);
+
+/* SPK Ratio Gain Control */
+static const char *rt5631_spk_ratio[] = {"1.00x", "1.09x", "1.27x", "1.44x",
+ "1.56x", "1.68x", "1.99x", "2.34x"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG,
+ RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio);
+
+static const struct snd_kcontrol_new rt5631_snd_controls[] = {
+ /* MIC */
+ SOC_ENUM("MIC1 Mode Control", rt5631_mic1_mode_enum),
+ SOC_SINGLE_TLV("MIC1 Boost", RT5631_MIC_CTRL_2,
+ RT5631_MIC1_BOOST_SHIFT, 8, 0, mic_bst_tlv),
+ SOC_ENUM("MIC2 Mode Control", rt5631_mic2_mode_enum),
+ SOC_SINGLE_TLV("MIC2 Boost", RT5631_MIC_CTRL_2,
+ RT5631_MIC2_BOOST_SHIFT, 8, 0, mic_bst_tlv),
+ /* MONO IN */
+ SOC_ENUM("MONOIN Mode Control", rt5631_monoin_mode_enum),
+ SOC_DOUBLE_TLV("MONOIN_RX Capture Volume", RT5631_MONO_INPUT_VOL,
+ RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT,
+ RT5631_VOL_MASK, 1, in_vol_tlv),
+ /* AXI */
+ SOC_DOUBLE_TLV("AXI Capture Volume", RT5631_AUX_IN_VOL,
+ RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT,
+ RT5631_VOL_MASK, 1, in_vol_tlv),
+ /* DAC */
+ SOC_DOUBLE_TLV("PCM Playback Volume", RT5631_STEREO_DAC_VOL_2,
+ RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT,
+ RT5631_DAC_VOL_MASK, 1, dac_vol_tlv),
+ SOC_DOUBLE("PCM Playback Switch", RT5631_STEREO_DAC_VOL_1,
+ RT5631_L_MUTE_SHIFT, RT5631_R_MUTE_SHIFT, 1, 1),
+ /* AXO */
+ SOC_SINGLE("AXO1 Playback Switch", RT5631_MONO_AXO_1_2_VOL,
+ RT5631_L_MUTE_SHIFT, 1, 1),
+ SOC_SINGLE("AXO2 Playback Switch", RT5631_MONO_AXO_1_2_VOL,
+ RT5631_R_VOL_SHIFT, 1, 1),
+ /* OUTVOL */
+ SOC_DOUBLE("OUTVOL Channel Switch", RT5631_SPK_OUT_VOL,
+ RT5631_L_EN_SHIFT, RT5631_R_EN_SHIFT, 1, 0),
+
+ /* SPK */
+ SOC_DOUBLE("Speaker Playback Switch", RT5631_SPK_OUT_VOL,
+ RT5631_L_MUTE_SHIFT, RT5631_R_MUTE_SHIFT, 1, 1),
+ SOC_DOUBLE_TLV("Speaker Playback Volume", RT5631_SPK_OUT_VOL,
+ RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT, 39, 1, out_vol_tlv),
+ /* MONO OUT */
+ SOC_SINGLE("MONO Playback Switch", RT5631_MONO_AXO_1_2_VOL,
+ RT5631_MUTE_MONO_SHIFT, 1, 1),
+ /* HP */
+ SOC_DOUBLE("HP Playback Switch", RT5631_HP_OUT_VOL,
+ RT5631_L_MUTE_SHIFT, RT5631_R_MUTE_SHIFT, 1, 1),
+ SOC_DOUBLE_TLV("HP Playback Volume", RT5631_HP_OUT_VOL,
+ RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT,
+ RT5631_VOL_MASK, 1, out_vol_tlv),
+ /* DMIC */
+ SOC_SINGLE_EXT("DMIC Switch", 0, 0, 1, 0,
+ rt5631_dmic_get, rt5631_dmic_put),
+ SOC_DOUBLE("DMIC Capture Switch", RT5631_DIG_MIC_CTRL,
+ RT5631_DMIC_L_CH_MUTE_SHIFT,
+ RT5631_DMIC_R_CH_MUTE_SHIFT, 1, 1),
+
+ /* SPK Ratio Gain Control */
+ SOC_ENUM("SPK Ratio Control", rt5631_spk_ratio_enum),
+};
+
+static int check_sysclk1_source(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int reg;
+
+ reg = snd_soc_read(source->codec, RT5631_GLOBAL_CLK_CTRL);
+ return reg & RT5631_SYSCLK_SOUR_SEL_PLL;
+}
+
+static int check_dmic_used(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(source->codec);
+ return rt5631->dmic_used_flag;
+}
+
+static int check_dacl_to_outmixl(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int reg;
+
+ reg = snd_soc_read(source->codec, RT5631_OUTMIXER_L_CTRL);
+ return !(reg & RT5631_M_DAC_L_TO_OUTMIXER_L);
+}
+
+static int check_dacr_to_outmixr(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int reg;
+
+ reg = snd_soc_read(source->codec, RT5631_OUTMIXER_R_CTRL);
+ return !(reg & RT5631_M_DAC_R_TO_OUTMIXER_R);
+}
+
+static int check_dacl_to_spkmixl(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int reg;
+
+ reg = snd_soc_read(source->codec, RT5631_SPK_MIXER_CTRL);
+ return !(reg & RT5631_M_DAC_L_TO_SPKMIXER_L);
+}
+
+static int check_dacr_to_spkmixr(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int reg;
+
+ reg = snd_soc_read(source->codec, RT5631_SPK_MIXER_CTRL);
+ return !(reg & RT5631_M_DAC_R_TO_SPKMIXER_R);
+}
+
+static int check_adcl_select(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int reg;
+
+ reg = snd_soc_read(source->codec, RT5631_ADC_REC_MIXER);
+ return !(reg & RT5631_M_MIC1_TO_RECMIXER_L);
+}
+
+static int check_adcr_select(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int reg;
+
+ reg = snd_soc_read(source->codec, RT5631_ADC_REC_MIXER);
+ return !(reg & RT5631_M_MIC2_TO_RECMIXER_R);
+}
+
+/**
+ * onebit_depop_power_stage - auto depop in power stage.
+ * @enable: power on/off
+ *
+ * When power on/off headphone, the depop sequence is done by hardware.
+ */
+static void onebit_depop_power_stage(struct snd_soc_codec *codec, int enable)
+{
+ unsigned int soft_vol, hp_zc;
+
+ /* enable one-bit depop function */
+ snd_soc_update_bits(codec, RT5631_DEPOP_FUN_CTRL_2,
+ RT5631_EN_ONE_BIT_DEPOP, 0);
+
+ /* keep soft volume and zero crossing setting */
+ soft_vol = snd_soc_read(codec, RT5631_SOFT_VOL_CTRL);
+ snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, 0);
+ hp_zc = snd_soc_read(codec, RT5631_INT_ST_IRQ_CTRL_2);
+ snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
+ if (enable) {
+ /* config one-bit depop parameter */
+ rt5631_write_index(codec, RT5631_TEST_MODE_CTRL, 0x84c0);
+ rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x309f);
+ rt5631_write_index(codec, RT5631_CP_INTL_REG2, 0x6530);
+ /* power on capless block */
+ snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_2,
+ RT5631_EN_CAP_FREE_DEPOP);
+ } else {
+ /* power off capless block */
+ snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_2, 0);
+ msleep(100);
+ }
+
+ /* recover soft volume and zero crossing setting */
+ snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, soft_vol);
+ snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
+}
+
+/**
+ * onebit_depop_mute_stage - auto depop in mute stage.
+ * @enable: mute/unmute
+ *
+ * When mute/unmute headphone, the depop sequence is done by hardware.
+ */
+static void onebit_depop_mute_stage(struct snd_soc_codec *codec, int enable)
+{
+ unsigned int soft_vol, hp_zc;
+
+ /* enable one-bit depop function */
+ snd_soc_update_bits(codec, RT5631_DEPOP_FUN_CTRL_2,
+ RT5631_EN_ONE_BIT_DEPOP, 0);
+
+ /* keep soft volume and zero crossing setting */
+ soft_vol = snd_soc_read(codec, RT5631_SOFT_VOL_CTRL);
+ snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, 0);
+ hp_zc = snd_soc_read(codec, RT5631_INT_ST_IRQ_CTRL_2);
+ snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
+ if (enable) {
+ schedule_timeout_uninterruptible(msecs_to_jiffies(10));
+ /* config one-bit depop parameter */
+ rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x307f);
+ snd_soc_update_bits(codec, RT5631_HP_OUT_VOL,
+ RT5631_L_MUTE | RT5631_R_MUTE, 0);
+ msleep(300);
+ } else {
+ snd_soc_update_bits(codec, RT5631_HP_OUT_VOL,
+ RT5631_L_MUTE | RT5631_R_MUTE,
+ RT5631_L_MUTE | RT5631_R_MUTE);
+ msleep(100);
+ }
+
+ /* recover soft volume and zero crossing setting */
+ snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, soft_vol);
+ snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
+}
+
+/**
+ * onebit_depop_power_stage - step by step depop sequence in power stage.
+ * @enable: power on/off
+ *
+ * When power on/off headphone, the depop sequence is done in step by step.
+ */
+static void depop_seq_power_stage(struct snd_soc_codec *codec, int enable)
+{
+ unsigned int soft_vol, hp_zc;
+
+ /* depop control by register */
+ snd_soc_update_bits(codec, RT5631_DEPOP_FUN_CTRL_2,
+ RT5631_EN_ONE_BIT_DEPOP, RT5631_EN_ONE_BIT_DEPOP);
+
+ /* keep soft volume and zero crossing setting */
+ soft_vol = snd_soc_read(codec, RT5631_SOFT_VOL_CTRL);
+ snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, 0);
+ hp_zc = snd_soc_read(codec, RT5631_INT_ST_IRQ_CTRL_2);
+ snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
+ if (enable) {
+ /* config depop sequence parameter */
+ rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x303e);
+
+ /* power on headphone and charge pump */
+ snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+ RT5631_PWR_CHARGE_PUMP | RT5631_PWR_HP_L_AMP |
+ RT5631_PWR_HP_R_AMP,
+ RT5631_PWR_CHARGE_PUMP | RT5631_PWR_HP_L_AMP |
+ RT5631_PWR_HP_R_AMP);
+
+ /* power on soft generator and depop mode2 */
+ snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+ RT5631_POW_ON_SOFT_GEN | RT5631_EN_DEPOP2_FOR_HP);
+ msleep(100);
+
+ /* stop depop mode */
+ snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+ RT5631_PWR_HP_DEPOP_DIS, RT5631_PWR_HP_DEPOP_DIS);
+ } else {
+ /* config depop sequence parameter */
+ rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x303F);
+ snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+ RT5631_POW_ON_SOFT_GEN | RT5631_EN_MUTE_UNMUTE_DEPOP |
+ RT5631_PD_HPAMP_L_ST_UP | RT5631_PD_HPAMP_R_ST_UP);
+ msleep(75);
+ snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+ RT5631_POW_ON_SOFT_GEN | RT5631_PD_HPAMP_L_ST_UP |
+ RT5631_PD_HPAMP_R_ST_UP);
+
+ /* start depop mode */
+ snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+ RT5631_PWR_HP_DEPOP_DIS, 0);
+
+ /* config depop sequence parameter */
+ snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+ RT5631_POW_ON_SOFT_GEN | RT5631_EN_DEPOP2_FOR_HP |
+ RT5631_PD_HPAMP_L_ST_UP | RT5631_PD_HPAMP_R_ST_UP);
+ msleep(80);
+ snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+ RT5631_POW_ON_SOFT_GEN);
+
+ /* power down headphone and charge pump */
+ snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+ RT5631_PWR_CHARGE_PUMP | RT5631_PWR_HP_L_AMP |
+ RT5631_PWR_HP_R_AMP, 0);
+ }
+
+ /* recover soft volume and zero crossing setting */
+ snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, soft_vol);
+ snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
+}
+
+/**
+ * depop_seq_mute_stage - step by step depop sequence in mute stage.
+ * @enable: mute/unmute
+ *
+ * When mute/unmute headphone, the depop sequence is done in step by step.
+ */
+static void depop_seq_mute_stage(struct snd_soc_codec *codec, int enable)
+{
+ unsigned int soft_vol, hp_zc;
+
+ /* depop control by register */
+ snd_soc_update_bits(codec, RT5631_DEPOP_FUN_CTRL_2,
+ RT5631_EN_ONE_BIT_DEPOP, RT5631_EN_ONE_BIT_DEPOP);
+
+ /* keep soft volume and zero crossing setting */
+ soft_vol = snd_soc_read(codec, RT5631_SOFT_VOL_CTRL);
+ snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, 0);
+ hp_zc = snd_soc_read(codec, RT5631_INT_ST_IRQ_CTRL_2);
+ snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
+ if (enable) {
+ schedule_timeout_uninterruptible(msecs_to_jiffies(10));
+
+ /* config depop sequence parameter */
+ rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x302f);
+ snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+ RT5631_POW_ON_SOFT_GEN | RT5631_EN_MUTE_UNMUTE_DEPOP |
+ RT5631_EN_HP_R_M_UN_MUTE_DEPOP |
+ RT5631_EN_HP_L_M_UN_MUTE_DEPOP);
+
+ snd_soc_update_bits(codec, RT5631_HP_OUT_VOL,
+ RT5631_L_MUTE | RT5631_R_MUTE, 0);
+ msleep(160);
+ } else {
+ /* config depop sequence parameter */
+ rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x302f);
+ snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1,
+ RT5631_POW_ON_SOFT_GEN | RT5631_EN_MUTE_UNMUTE_DEPOP |
+ RT5631_EN_HP_R_M_UN_MUTE_DEPOP |
+ RT5631_EN_HP_L_M_UN_MUTE_DEPOP);
+
+ snd_soc_update_bits(codec, RT5631_HP_OUT_VOL,
+ RT5631_L_MUTE | RT5631_R_MUTE,
+ RT5631_L_MUTE | RT5631_R_MUTE);
+ msleep(150);
+ }
+
+ /* recover soft volume and zero crossing setting */
+ snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, soft_vol);
+ snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
+}
+
+static int hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMD:
+ if (rt5631->codec_version) {
+ onebit_depop_mute_stage(codec, 0);
+ onebit_depop_power_stage(codec, 0);
+ } else {
+ depop_seq_mute_stage(codec, 0);
+ depop_seq_power_stage(codec, 0);
+ }
+ break;
+
+ case SND_SOC_DAPM_POST_PMU:
+ if (rt5631->codec_version) {
+ onebit_depop_power_stage(codec, 1);
+ onebit_depop_mute_stage(codec, 1);
+ } else {
+ depop_seq_power_stage(codec, 1);
+ depop_seq_mute_stage(codec, 1);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int set_dmic_params(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+
+ switch (rt5631->rx_rate) {
+ case 44100:
+ case 48000:
+ snd_soc_update_bits(codec, RT5631_DIG_MIC_CTRL,
+ RT5631_DMIC_CLK_CTRL_MASK,
+ RT5631_DMIC_CLK_CTRL_TO_32FS);
+ break;
+
+ case 32000:
+ case 22050:
+ snd_soc_update_bits(codec, RT5631_DIG_MIC_CTRL,
+ RT5631_DMIC_CLK_CTRL_MASK,
+ RT5631_DMIC_CLK_CTRL_TO_64FS);
+ break;
+
+ case 16000:
+ case 11025:
+ case 8000:
+ snd_soc_update_bits(codec, RT5631_DIG_MIC_CTRL,
+ RT5631_DMIC_CLK_CTRL_MASK,
+ RT5631_DMIC_CLK_CTRL_TO_128FS);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new rt5631_recmixl_mixer_controls[] = {
+ SOC_DAPM_SINGLE("OUTMIXL Capture Switch", RT5631_ADC_REC_MIXER,
+ RT5631_M_OUTMIXL_RECMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("MIC1_BST1 Capture Switch", RT5631_ADC_REC_MIXER,
+ RT5631_M_MIC1_RECMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("AXILVOL Capture Switch", RT5631_ADC_REC_MIXER,
+ RT5631_M_AXIL_RECMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("MONOIN_RX Capture Switch", RT5631_ADC_REC_MIXER,
+ RT5631_M_MONO_IN_RECMIXL_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_recmixr_mixer_controls[] = {
+ SOC_DAPM_SINGLE("MONOIN_RX Capture Switch", RT5631_ADC_REC_MIXER,
+ RT5631_M_MONO_IN_RECMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("AXIRVOL Capture Switch", RT5631_ADC_REC_MIXER,
+ RT5631_M_AXIR_RECMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("MIC2_BST2 Capture Switch", RT5631_ADC_REC_MIXER,
+ RT5631_M_MIC2_RECMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("OUTMIXR Capture Switch", RT5631_ADC_REC_MIXER,
+ RT5631_M_OUTMIXR_RECMIXR_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_spkmixl_mixer_controls[] = {
+ SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_SPK_MIXER_CTRL,
+ RT5631_M_RECMIXL_SPKMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("MIC1_P Playback Switch", RT5631_SPK_MIXER_CTRL,
+ RT5631_M_MIC1P_SPKMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("DACL Playback Switch", RT5631_SPK_MIXER_CTRL,
+ RT5631_M_DACL_SPKMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("OUTMIXL Playback Switch", RT5631_SPK_MIXER_CTRL,
+ RT5631_M_OUTMIXL_SPKMIXL_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_spkmixr_mixer_controls[] = {
+ SOC_DAPM_SINGLE("OUTMIXR Playback Switch", RT5631_SPK_MIXER_CTRL,
+ RT5631_M_OUTMIXR_SPKMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("DACR Playback Switch", RT5631_SPK_MIXER_CTRL,
+ RT5631_M_DACR_SPKMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("MIC2_P Playback Switch", RT5631_SPK_MIXER_CTRL,
+ RT5631_M_MIC2P_SPKMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_SPK_MIXER_CTRL,
+ RT5631_M_RECMIXR_SPKMIXR_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_outmixl_mixer_controls[] = {
+ SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_OUTMIXER_L_CTRL,
+ RT5631_M_RECMIXL_OUTMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_OUTMIXER_L_CTRL,
+ RT5631_M_RECMIXR_OUTMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("DACL Playback Switch", RT5631_OUTMIXER_L_CTRL,
+ RT5631_M_DACL_OUTMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_OUTMIXER_L_CTRL,
+ RT5631_M_MIC1_OUTMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_OUTMIXER_L_CTRL,
+ RT5631_M_MIC2_OUTMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("MONOIN_RXP Playback Switch", RT5631_OUTMIXER_L_CTRL,
+ RT5631_M_MONO_INP_OUTMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("AXILVOL Playback Switch", RT5631_OUTMIXER_L_CTRL,
+ RT5631_M_AXIL_OUTMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("AXIRVOL Playback Switch", RT5631_OUTMIXER_L_CTRL,
+ RT5631_M_AXIR_OUTMIXL_BIT, 1, 1),
+ SOC_DAPM_SINGLE("VDAC Playback Switch", RT5631_OUTMIXER_L_CTRL,
+ RT5631_M_VDAC_OUTMIXL_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_outmixr_mixer_controls[] = {
+ SOC_DAPM_SINGLE("VDAC Playback Switch", RT5631_OUTMIXER_R_CTRL,
+ RT5631_M_VDAC_OUTMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("AXIRVOL Playback Switch", RT5631_OUTMIXER_R_CTRL,
+ RT5631_M_AXIR_OUTMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("AXILVOL Playback Switch", RT5631_OUTMIXER_R_CTRL,
+ RT5631_M_AXIL_OUTMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("MONOIN_RXN Playback Switch", RT5631_OUTMIXER_R_CTRL,
+ RT5631_M_MONO_INN_OUTMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_OUTMIXER_R_CTRL,
+ RT5631_M_MIC2_OUTMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_OUTMIXER_R_CTRL,
+ RT5631_M_MIC1_OUTMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("DACR Playback Switch", RT5631_OUTMIXER_R_CTRL,
+ RT5631_M_DACR_OUTMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_OUTMIXER_R_CTRL,
+ RT5631_M_RECMIXR_OUTMIXR_BIT, 1, 1),
+ SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_OUTMIXER_R_CTRL,
+ RT5631_M_RECMIXL_OUTMIXR_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_AXO1MIX_mixer_controls[] = {
+ SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_AXO1MIXER_CTRL,
+ RT5631_M_MIC1_AXO1MIX_BIT , 1, 1),
+ SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_AXO1MIXER_CTRL,
+ RT5631_M_MIC2_AXO1MIX_BIT, 1, 1),
+ SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_AXO1MIXER_CTRL,
+ RT5631_M_OUTMIXL_AXO1MIX_BIT , 1 , 1),
+ SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_AXO1MIXER_CTRL,
+ RT5631_M_OUTMIXR_AXO1MIX_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_AXO2MIX_mixer_controls[] = {
+ SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_AXO2MIXER_CTRL,
+ RT5631_M_MIC1_AXO2MIX_BIT, 1, 1),
+ SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_AXO2MIXER_CTRL,
+ RT5631_M_MIC2_AXO2MIX_BIT, 1, 1),
+ SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_AXO2MIXER_CTRL,
+ RT5631_M_OUTMIXL_AXO2MIX_BIT, 1, 1),
+ SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_AXO2MIXER_CTRL,
+ RT5631_M_OUTMIXR_AXO2MIX_BIT, 1 , 1),
+};
+
+static const struct snd_kcontrol_new rt5631_spolmix_mixer_controls[] = {
+ SOC_DAPM_SINGLE("SPKVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL,
+ RT5631_M_SPKVOLL_SPOLMIX_BIT, 1, 1),
+ SOC_DAPM_SINGLE("SPKVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL,
+ RT5631_M_SPKVOLR_SPOLMIX_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_spormix_mixer_controls[] = {
+ SOC_DAPM_SINGLE("SPKVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL,
+ RT5631_M_SPKVOLL_SPORMIX_BIT, 1, 1),
+ SOC_DAPM_SINGLE("SPKVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL,
+ RT5631_M_SPKVOLR_SPORMIX_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_monomix_mixer_controls[] = {
+ SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL,
+ RT5631_M_OUTVOLL_MONOMIX_BIT, 1, 1),
+ SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL,
+ RT5631_M_OUTVOLR_MONOMIX_BIT, 1, 1),
+};
+
+/* Left SPK Volume Input */
+static const char *rt5631_spkvoll_sel[] = {"Vmid", "SPKMIXL"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL,
+ RT5631_L_EN_SHIFT, rt5631_spkvoll_sel);
+
+static const struct snd_kcontrol_new rt5631_spkvoll_mux_control =
+ SOC_DAPM_ENUM("Left SPKVOL SRC", rt5631_spkvoll_enum);
+
+/* Left HP Volume Input */
+static const char *rt5631_hpvoll_sel[] = {"Vmid", "OUTMIXL"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_hpvoll_enum, RT5631_HP_OUT_VOL,
+ RT5631_L_EN_SHIFT, rt5631_hpvoll_sel);
+
+static const struct snd_kcontrol_new rt5631_hpvoll_mux_control =
+ SOC_DAPM_ENUM("Left HPVOL SRC", rt5631_hpvoll_enum);
+
+/* Left Out Volume Input */
+static const char *rt5631_outvoll_sel[] = {"Vmid", "OUTMIXL"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL,
+ RT5631_L_EN_SHIFT, rt5631_outvoll_sel);
+
+static const struct snd_kcontrol_new rt5631_outvoll_mux_control =
+ SOC_DAPM_ENUM("Left OUTVOL SRC", rt5631_outvoll_enum);
+
+/* Right Out Volume Input */
+static const char *rt5631_outvolr_sel[] = {"Vmid", "OUTMIXR"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL,
+ RT5631_R_EN_SHIFT, rt5631_outvolr_sel);
+
+static const struct snd_kcontrol_new rt5631_outvolr_mux_control =
+ SOC_DAPM_ENUM("Right OUTVOL SRC", rt5631_outvolr_enum);
+
+/* Right HP Volume Input */
+static const char *rt5631_hpvolr_sel[] = {"Vmid", "OUTMIXR"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_hpvolr_enum, RT5631_HP_OUT_VOL,
+ RT5631_R_EN_SHIFT, rt5631_hpvolr_sel);
+
+static const struct snd_kcontrol_new rt5631_hpvolr_mux_control =
+ SOC_DAPM_ENUM("Right HPVOL SRC", rt5631_hpvolr_enum);
+
+/* Right SPK Volume Input */
+static const char *rt5631_spkvolr_sel[] = {"Vmid", "SPKMIXR"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL,
+ RT5631_R_EN_SHIFT, rt5631_spkvolr_sel);
+
+static const struct snd_kcontrol_new rt5631_spkvolr_mux_control =
+ SOC_DAPM_ENUM("Right SPKVOL SRC", rt5631_spkvolr_enum);
+
+/* SPO Left Channel Input */
+static const char *rt5631_spol_src_sel[] = {
+ "SPOLMIX", "MONOIN_RX", "VDAC", "DACL"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+ RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel);
+
+static const struct snd_kcontrol_new rt5631_spol_mux_control =
+ SOC_DAPM_ENUM("SPOL SRC", rt5631_spol_src_enum);
+
+/* SPO Right Channel Input */
+static const char *rt5631_spor_src_sel[] = {
+ "SPORMIX", "MONOIN_RX", "VDAC", "DACR"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+ RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel);
+
+static const struct snd_kcontrol_new rt5631_spor_mux_control =
+ SOC_DAPM_ENUM("SPOR SRC", rt5631_spor_src_enum);
+
+/* MONO Input */
+static const char *rt5631_mono_src_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+ RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel);
+
+static const struct snd_kcontrol_new rt5631_mono_mux_control =
+ SOC_DAPM_ENUM("MONO SRC", rt5631_mono_src_enum);
+
+/* Left HPO Input */
+static const char *rt5631_hpl_src_sel[] = {"Left HPVOL", "Left DAC"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+ RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel);
+
+static const struct snd_kcontrol_new rt5631_hpl_mux_control =
+ SOC_DAPM_ENUM("HPL SRC", rt5631_hpl_src_enum);
+
+/* Right HPO Input */
+static const char *rt5631_hpr_src_sel[] = {"Right HPVOL", "Right DAC"};
+
+static const SOC_ENUM_SINGLE_DECL(
+ rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+ RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel);
+
+static const struct snd_kcontrol_new rt5631_hpr_mux_control =
+ SOC_DAPM_ENUM("HPR SRC", rt5631_hpr_src_enum);
+
+static const struct snd_soc_dapm_widget rt5631_dapm_widgets[] = {
+ /* Vmid */
+ SND_SOC_DAPM_VMID("Vmid"),
+ /* PLL1 */
+ SND_SOC_DAPM_SUPPLY("PLL1", RT5631_PWR_MANAG_ADD2,
+ RT5631_PWR_PLL1_BIT, 0, NULL, 0),
+
+ /* Input Side */
+ /* Input Lines */
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("AXIL"),
+ SND_SOC_DAPM_INPUT("AXIR"),
+ SND_SOC_DAPM_INPUT("MONOIN_RXN"),
+ SND_SOC_DAPM_INPUT("MONOIN_RXP"),
+ SND_SOC_DAPM_INPUT("DMIC"),
+
+ /* MICBIAS */
+ SND_SOC_DAPM_MICBIAS("MIC Bias1", RT5631_PWR_MANAG_ADD2,
+ RT5631_PWR_MICBIAS1_VOL_BIT, 0),
+ SND_SOC_DAPM_MICBIAS("MIC Bias2", RT5631_PWR_MANAG_ADD2,
+ RT5631_PWR_MICBIAS2_VOL_BIT, 0),
+
+ /* Boost */
+ SND_SOC_DAPM_PGA("MIC1 Boost", RT5631_PWR_MANAG_ADD2,
+ RT5631_PWR_MIC1_BOOT_GAIN_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("MIC2 Boost", RT5631_PWR_MANAG_ADD2,
+ RT5631_PWR_MIC2_BOOT_GAIN_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("MONOIN_RXP Boost", RT5631_PWR_MANAG_ADD4,
+ RT5631_PWR_MONO_IN_P_VOL_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("MONOIN_RXN Boost", RT5631_PWR_MANAG_ADD4,
+ RT5631_PWR_MONO_IN_N_VOL_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("AXIL Boost", RT5631_PWR_MANAG_ADD4,
+ RT5631_PWR_AXIL_IN_VOL_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("AXIR Boost", RT5631_PWR_MANAG_ADD4,
+ RT5631_PWR_AXIR_IN_VOL_BIT, 0, NULL, 0),
+
+ /* MONO In */
+ SND_SOC_DAPM_MIXER("MONO_IN", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* REC Mixer */
+ SND_SOC_DAPM_MIXER("RECMIXL Mixer", RT5631_PWR_MANAG_ADD2,
+ RT5631_PWR_RECMIXER_L_BIT, 0,
+ &rt5631_recmixl_mixer_controls[0],
+ ARRAY_SIZE(rt5631_recmixl_mixer_controls)),
+ SND_SOC_DAPM_MIXER("RECMIXR Mixer", RT5631_PWR_MANAG_ADD2,
+ RT5631_PWR_RECMIXER_R_BIT, 0,
+ &rt5631_recmixr_mixer_controls[0],
+ ARRAY_SIZE(rt5631_recmixr_mixer_controls)),
+ /* Because of record duplication for L/R channel,
+ * L/R ADCs need power up at the same time */
+ SND_SOC_DAPM_MIXER("ADC Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* DMIC */
+ SND_SOC_DAPM_SUPPLY("DMIC Supply", RT5631_DIG_MIC_CTRL,
+ RT5631_DMIC_ENA_SHIFT, 0,
+ set_dmic_params, SND_SOC_DAPM_PRE_PMU),
+ /* ADC Data Srouce */
+ SND_SOC_DAPM_SUPPLY("Left ADC Select", RT5631_INT_ST_IRQ_CTRL_2,
+ RT5631_ADC_DATA_SEL_MIC1_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Right ADC Select", RT5631_INT_ST_IRQ_CTRL_2,
+ RT5631_ADC_DATA_SEL_MIC2_SHIFT, 0, NULL, 0),
+
+ /* ADCs */
+ SND_SOC_DAPM_ADC("Left ADC", "HIFI Capture",
+ RT5631_PWR_MANAG_ADD1, RT5631_PWR_ADC_L_CLK_BIT, 0),
+ SND_SOC_DAPM_ADC("Right ADC", "HIFI Capture",
+ RT5631_PWR_MANAG_ADD1, RT5631_PWR_ADC_R_CLK_BIT, 0),
+
+ /* DAC and ADC supply power */
+ SND_SOC_DAPM_SUPPLY("I2S", RT5631_PWR_MANAG_ADD1,
+ RT5631_PWR_MAIN_I2S_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC REF", RT5631_PWR_MANAG_ADD1,
+ RT5631_PWR_DAC_REF_BIT, 0, NULL, 0),
+
+ /* Output Side */
+ /* DACs */
+ SND_SOC_DAPM_DAC("Left DAC", "HIFI Playback",
+ RT5631_PWR_MANAG_ADD1, RT5631_PWR_DAC_L_CLK_BIT, 0),
+ SND_SOC_DAPM_DAC("Right DAC", "HIFI Playback",
+ RT5631_PWR_MANAG_ADD1, RT5631_PWR_DAC_R_CLK_BIT, 0),
+ SND_SOC_DAPM_DAC("Voice DAC", "Voice DAC Mono Playback",
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_PGA("Voice DAC Boost", SND_SOC_NOPM, 0, 0, NULL, 0),
+ /* DAC supply power */
+ SND_SOC_DAPM_SUPPLY("Left DAC To Mixer", RT5631_PWR_MANAG_ADD1,
+ RT5631_PWR_DAC_L_TO_MIXER_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Right DAC To Mixer", RT5631_PWR_MANAG_ADD1,
+ RT5631_PWR_DAC_R_TO_MIXER_BIT, 0, NULL, 0),
+
+ /* Left SPK Mixer */
+ SND_SOC_DAPM_MIXER("SPKMIXL Mixer", RT5631_PWR_MANAG_ADD2,
+ RT5631_PWR_SPKMIXER_L_BIT, 0,
+ &rt5631_spkmixl_mixer_controls[0],
+ ARRAY_SIZE(rt5631_spkmixl_mixer_controls)),
+ /* Left Out Mixer */
+ SND_SOC_DAPM_MIXER("OUTMIXL Mixer", RT5631_PWR_MANAG_ADD2,
+ RT5631_PWR_OUTMIXER_L_BIT, 0,
+ &rt5631_outmixl_mixer_controls[0],
+ ARRAY_SIZE(rt5631_outmixl_mixer_controls)),
+ /* Right Out Mixer */
+ SND_SOC_DAPM_MIXER("OUTMIXR Mixer", RT5631_PWR_MANAG_ADD2,
+ RT5631_PWR_OUTMIXER_R_BIT, 0,
+ &rt5631_outmixr_mixer_controls[0],
+ ARRAY_SIZE(rt5631_outmixr_mixer_controls)),
+ /* Right SPK Mixer */
+ SND_SOC_DAPM_MIXER("SPKMIXR Mixer", RT5631_PWR_MANAG_ADD2,
+ RT5631_PWR_SPKMIXER_R_BIT, 0,
+ &rt5631_spkmixr_mixer_controls[0],
+ ARRAY_SIZE(rt5631_spkmixr_mixer_controls)),
+
+ /* Volume Mux */
+ SND_SOC_DAPM_MUX("Left SPKVOL Mux", RT5631_PWR_MANAG_ADD4,
+ RT5631_PWR_SPK_L_VOL_BIT, 0,
+ &rt5631_spkvoll_mux_control),
+ SND_SOC_DAPM_MUX("Left HPVOL Mux", RT5631_PWR_MANAG_ADD4,
+ RT5631_PWR_HP_L_OUT_VOL_BIT, 0,
+ &rt5631_hpvoll_mux_control),
+ SND_SOC_DAPM_MUX("Left OUTVOL Mux", RT5631_PWR_MANAG_ADD4,
+ RT5631_PWR_LOUT_VOL_BIT, 0,
+ &rt5631_outvoll_mux_control),
+ SND_SOC_DAPM_MUX("Right OUTVOL Mux", RT5631_PWR_MANAG_ADD4,
+ RT5631_PWR_ROUT_VOL_BIT, 0,
+ &rt5631_outvolr_mux_control),
+ SND_SOC_DAPM_MUX("Right HPVOL Mux", RT5631_PWR_MANAG_ADD4,
+ RT5631_PWR_HP_R_OUT_VOL_BIT, 0,
+ &rt5631_hpvolr_mux_control),
+ SND_SOC_DAPM_MUX("Right SPKVOL Mux", RT5631_PWR_MANAG_ADD4,
+ RT5631_PWR_SPK_R_VOL_BIT, 0,
+ &rt5631_spkvolr_mux_control),
+
+ /* DAC To HP */
+ SND_SOC_DAPM_PGA_S("Left DAC_HP", 0, SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_S("Right DAC_HP", 0, SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* HP Depop */
+ SND_SOC_DAPM_PGA_S("HP Depop", 1, SND_SOC_NOPM, 0, 0,
+ hp_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+ /* AXO1 Mixer */
+ SND_SOC_DAPM_MIXER("AXO1MIX Mixer", RT5631_PWR_MANAG_ADD3,
+ RT5631_PWR_AXO1MIXER_BIT, 0,
+ &rt5631_AXO1MIX_mixer_controls[0],
+ ARRAY_SIZE(rt5631_AXO1MIX_mixer_controls)),
+ /* SPOL Mixer */
+ SND_SOC_DAPM_MIXER("SPOLMIX Mixer", SND_SOC_NOPM, 0, 0,
+ &rt5631_spolmix_mixer_controls[0],
+ ARRAY_SIZE(rt5631_spolmix_mixer_controls)),
+ /* MONO Mixer */
+ SND_SOC_DAPM_MIXER("MONOMIX Mixer", RT5631_PWR_MANAG_ADD3,
+ RT5631_PWR_MONOMIXER_BIT, 0,
+ &rt5631_monomix_mixer_controls[0],
+ ARRAY_SIZE(rt5631_monomix_mixer_controls)),
+ /* SPOR Mixer */
+ SND_SOC_DAPM_MIXER("SPORMIX Mixer", SND_SOC_NOPM, 0, 0,
+ &rt5631_spormix_mixer_controls[0],
+ ARRAY_SIZE(rt5631_spormix_mixer_controls)),
+ /* AXO2 Mixer */
+ SND_SOC_DAPM_MIXER("AXO2MIX Mixer", RT5631_PWR_MANAG_ADD3,
+ RT5631_PWR_AXO2MIXER_BIT, 0,
+ &rt5631_AXO2MIX_mixer_controls[0],
+ ARRAY_SIZE(rt5631_AXO2MIX_mixer_controls)),
+
+ /* Mux */
+ SND_SOC_DAPM_MUX("SPOL Mux", SND_SOC_NOPM, 0, 0,
+ &rt5631_spol_mux_control),
+ SND_SOC_DAPM_MUX("SPOR Mux", SND_SOC_NOPM, 0, 0,
+ &rt5631_spor_mux_control),
+ SND_SOC_DAPM_MUX("MONO Mux", SND_SOC_NOPM, 0, 0,
+ &rt5631_mono_mux_control),
+ SND_SOC_DAPM_MUX("HPL Mux", SND_SOC_NOPM, 0, 0,
+ &rt5631_hpl_mux_control),
+ SND_SOC_DAPM_MUX("HPR Mux", SND_SOC_NOPM, 0, 0,
+ &rt5631_hpr_mux_control),
+
+ /* AMP supply */
+ SND_SOC_DAPM_SUPPLY("MONO Depop", RT5631_PWR_MANAG_ADD3,
+ RT5631_PWR_MONO_DEPOP_DIS_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Class D", RT5631_PWR_MANAG_ADD1,
+ RT5631_PWR_CLASS_D_BIT, 0, NULL, 0),
+
+ /* Output Lines */
+ SND_SOC_DAPM_OUTPUT("AUXO1"),
+ SND_SOC_DAPM_OUTPUT("AUXO2"),
+ SND_SOC_DAPM_OUTPUT("SPOL"),
+ SND_SOC_DAPM_OUTPUT("SPOR"),
+ SND_SOC_DAPM_OUTPUT("HPOL"),
+ SND_SOC_DAPM_OUTPUT("HPOR"),
+ SND_SOC_DAPM_OUTPUT("MONO"),
+};
+
+static const struct snd_soc_dapm_route rt5631_dapm_routes[] = {
+ {"MIC1 Boost", NULL, "MIC1"},
+ {"MIC2 Boost", NULL, "MIC2"},
+ {"MONOIN_RXP Boost", NULL, "MONOIN_RXP"},
+ {"MONOIN_RXN Boost", NULL, "MONOIN_RXN"},
+ {"AXIL Boost", NULL, "AXIL"},
+ {"AXIR Boost", NULL, "AXIR"},
+
+ {"MONO_IN", NULL, "MONOIN_RXP Boost"},
+ {"MONO_IN", NULL, "MONOIN_RXN Boost"},
+
+ {"RECMIXL Mixer", "OUTMIXL Capture Switch", "OUTMIXL Mixer"},
+ {"RECMIXL Mixer", "MIC1_BST1 Capture Switch", "MIC1 Boost"},
+ {"RECMIXL Mixer", "AXILVOL Capture Switch", "AXIL Boost"},
+ {"RECMIXL Mixer", "MONOIN_RX Capture Switch", "MONO_IN"},
+
+ {"RECMIXR Mixer", "OUTMIXR Capture Switch", "OUTMIXR Mixer"},
+ {"RECMIXR Mixer", "MIC2_BST2 Capture Switch", "MIC2 Boost"},
+ {"RECMIXR Mixer", "AXIRVOL Capture Switch", "AXIR Boost"},
+ {"RECMIXR Mixer", "MONOIN_RX Capture Switch", "MONO_IN"},
+
+ {"ADC Mixer", NULL, "RECMIXL Mixer"},
+ {"ADC Mixer", NULL, "RECMIXR Mixer"},
+
+ {"Left ADC", NULL, "ADC Mixer"},
+ {"Left ADC", NULL, "Left ADC Select", check_adcl_select},
+ {"Left ADC", NULL, "PLL1", check_sysclk1_source},
+ {"Left ADC", NULL, "I2S"},
+ {"Left ADC", NULL, "DAC REF"},
+
+ {"Right ADC", NULL, "ADC Mixer"},
+ {"Right ADC", NULL, "Right ADC Select", check_adcr_select},
+ {"Right ADC", NULL, "PLL1", check_sysclk1_source},
+ {"Right ADC", NULL, "I2S"},
+ {"Right ADC", NULL, "DAC REF"},
+
+ {"DMIC", NULL, "DMIC Supply", check_dmic_used},
+ {"Left ADC", NULL, "DMIC"},
+ {"Right ADC", NULL, "DMIC"},
+
+ {"Left DAC", NULL, "PLL1", check_sysclk1_source},
+ {"Left DAC", NULL, "I2S"},
+ {"Left DAC", NULL, "DAC REF"},
+ {"Right DAC", NULL, "PLL1", check_sysclk1_source},
+ {"Right DAC", NULL, "I2S"},
+ {"Right DAC", NULL, "DAC REF"},
+
+ {"Voice DAC Boost", NULL, "Voice DAC"},
+
+ {"SPKMIXL Mixer", NULL, "Left DAC To Mixer", check_dacl_to_spkmixl},
+ {"SPKMIXL Mixer", "RECMIXL Playback Switch", "RECMIXL Mixer"},
+ {"SPKMIXL Mixer", "MIC1_P Playback Switch", "MIC1"},
+ {"SPKMIXL Mixer", "DACL Playback Switch", "Left DAC"},
+ {"SPKMIXL Mixer", "OUTMIXL Playback Switch", "OUTMIXL Mixer"},
+
+ {"SPKMIXR Mixer", NULL, "Right DAC To Mixer", check_dacr_to_spkmixr},
+ {"SPKMIXR Mixer", "OUTMIXR Playback Switch", "OUTMIXR Mixer"},
+ {"SPKMIXR Mixer", "DACR Playback Switch", "Right DAC"},
+ {"SPKMIXR Mixer", "MIC2_P Playback Switch", "MIC2"},
+ {"SPKMIXR Mixer", "RECMIXR Playback Switch", "RECMIXR Mixer"},
+
+ {"OUTMIXL Mixer", NULL, "Left DAC To Mixer", check_dacl_to_outmixl},
+ {"OUTMIXL Mixer", "RECMIXL Playback Switch", "RECMIXL Mixer"},
+ {"OUTMIXL Mixer", "RECMIXR Playback Switch", "RECMIXR Mixer"},
+ {"OUTMIXL Mixer", "DACL Playback Switch", "Left DAC"},
+ {"OUTMIXL Mixer", "MIC1_BST1 Playback Switch", "MIC1 Boost"},
+ {"OUTMIXL Mixer", "MIC2_BST2 Playback Switch", "MIC2 Boost"},
+ {"OUTMIXL Mixer", "MONOIN_RXP Playback Switch", "MONOIN_RXP Boost"},
+ {"OUTMIXL Mixer", "AXILVOL Playback Switch", "AXIL Boost"},
+ {"OUTMIXL Mixer", "AXIRVOL Playback Switch", "AXIR Boost"},
+ {"OUTMIXL Mixer", "VDAC Playback Switch", "Voice DAC Boost"},
+
+ {"OUTMIXR Mixer", NULL, "Right DAC To Mixer", check_dacr_to_outmixr},
+ {"OUTMIXR Mixer", "RECMIXL Playback Switch", "RECMIXL Mixer"},
+ {"OUTMIXR Mixer", "RECMIXR Playback Switch", "RECMIXR Mixer"},
+ {"OUTMIXR Mixer", "DACR Playback Switch", "Right DAC"},
+ {"OUTMIXR Mixer", "MIC1_BST1 Playback Switch", "MIC1 Boost"},
+ {"OUTMIXR Mixer", "MIC2_BST2 Playback Switch", "MIC2 Boost"},
+ {"OUTMIXR Mixer", "MONOIN_RXN Playback Switch", "MONOIN_RXN Boost"},
+ {"OUTMIXR Mixer", "AXILVOL Playback Switch", "AXIL Boost"},
+ {"OUTMIXR Mixer", "AXIRVOL Playback Switch", "AXIR Boost"},
+ {"OUTMIXR Mixer", "VDAC Playback Switch", "Voice DAC Boost"},
+
+ {"Left SPKVOL Mux", "SPKMIXL", "SPKMIXL Mixer"},
+ {"Left SPKVOL Mux", "Vmid", "Vmid"},
+ {"Left HPVOL Mux", "OUTMIXL", "OUTMIXL Mixer"},
+ {"Left HPVOL Mux", "Vmid", "Vmid"},
+ {"Left OUTVOL Mux", "OUTMIXL", "OUTMIXL Mixer"},
+ {"Left OUTVOL Mux", "Vmid", "Vmid"},
+ {"Right OUTVOL Mux", "OUTMIXR", "OUTMIXR Mixer"},
+ {"Right OUTVOL Mux", "Vmid", "Vmid"},
+ {"Right HPVOL Mux", "OUTMIXR", "OUTMIXR Mixer"},
+ {"Right HPVOL Mux", "Vmid", "Vmid"},
+ {"Right SPKVOL Mux", "SPKMIXR", "SPKMIXR Mixer"},
+ {"Right SPKVOL Mux", "Vmid", "Vmid"},
+
+ {"AXO1MIX Mixer", "MIC1_BST1 Playback Switch", "MIC1 Boost"},
+ {"AXO1MIX Mixer", "OUTVOLL Playback Switch", "Left OUTVOL Mux"},
+ {"AXO1MIX Mixer", "OUTVOLR Playback Switch", "Right OUTVOL Mux"},
+ {"AXO1MIX Mixer", "MIC2_BST2 Playback Switch", "MIC2 Boost"},
+
+ {"AXO2MIX Mixer", "MIC1_BST1 Playback Switch", "MIC1 Boost"},
+ {"AXO2MIX Mixer", "OUTVOLL Playback Switch", "Left OUTVOL Mux"},
+ {"AXO2MIX Mixer", "OUTVOLR Playback Switch", "Right OUTVOL Mux"},
+ {"AXO2MIX Mixer", "MIC2_BST2 Playback Switch", "MIC2 Boost"},
+
+ {"SPOLMIX Mixer", "SPKVOLL Playback Switch", "Left SPKVOL Mux"},
+ {"SPOLMIX Mixer", "SPKVOLR Playback Switch", "Right SPKVOL Mux"},
+
+ {"SPORMIX Mixer", "SPKVOLL Playback Switch", "Left SPKVOL Mux"},
+ {"SPORMIX Mixer", "SPKVOLR Playback Switch", "Right SPKVOL Mux"},
+
+ {"MONOMIX Mixer", "OUTVOLL Playback Switch", "Left OUTVOL Mux"},
+ {"MONOMIX Mixer", "OUTVOLR Playback Switch", "Right OUTVOL Mux"},
+
+ {"SPOL Mux", "SPOLMIX", "SPOLMIX Mixer"},
+ {"SPOL Mux", "MONOIN_RX", "MONO_IN"},
+ {"SPOL Mux", "VDAC", "Voice DAC Boost"},
+ {"SPOL Mux", "DACL", "Left DAC"},
+
+ {"SPOR Mux", "SPORMIX", "SPORMIX Mixer"},
+ {"SPOR Mux", "MONOIN_RX", "MONO_IN"},
+ {"SPOR Mux", "VDAC", "Voice DAC Boost"},
+ {"SPOR Mux", "DACR", "Right DAC"},
+
+ {"MONO Mux", "MONOMIX", "MONOMIX Mixer"},
+ {"MONO Mux", "MONOIN_RX", "MONO_IN"},
+ {"MONO Mux", "VDAC", "Voice DAC Boost"},
+
+ {"Right DAC_HP", NULL, "Right DAC"},
+ {"Left DAC_HP", NULL, "Left DAC"},
+
+ {"HPL Mux", "Left HPVOL", "Left HPVOL Mux"},
+ {"HPL Mux", "Left DAC", "Left DAC_HP"},
+ {"HPR Mux", "Right HPVOL", "Right HPVOL Mux"},
+ {"HPR Mux", "Right DAC", "Right DAC_HP"},
+
+ {"HP Depop", NULL, "HPL Mux"},
+ {"HP Depop", NULL, "HPR Mux"},
+
+ {"AUXO1", NULL, "AXO1MIX Mixer"},
+ {"AUXO2", NULL, "AXO2MIX Mixer"},
+
+ {"SPOL", NULL, "Class D"},
+ {"SPOL", NULL, "SPOL Mux"},
+ {"SPOR", NULL, "Class D"},
+ {"SPOR", NULL, "SPOR Mux"},
+
+ {"HPOL", NULL, "HP Depop"},
+ {"HPOR", NULL, "HP Depop"},
+
+ {"MONO", NULL, "MONO Depop"},
+ {"MONO", NULL, "MONO Mux"},
+};
+
+struct coeff_clk_div {
+ u32 mclk;
+ u32 bclk;
+ u32 rate;
+ u16 reg_val;
+};
+
+/* PLL divisors */
+struct pll_div {
+ u32 pll_in;
+ u32 pll_out;
+ u16 reg_val;
+};
+
+static const struct pll_div codec_master_pll_div[] = {
+ {2048000, 8192000, 0x0ea0},
+ {3686400, 8192000, 0x4e27},
+ {12000000, 8192000, 0x456b},
+ {13000000, 8192000, 0x495f},
+ {13100000, 8192000, 0x0320},
+ {2048000, 11289600, 0xf637},
+ {3686400, 11289600, 0x2f22},
+ {12000000, 11289600, 0x3e2f},
+ {13000000, 11289600, 0x4d5b},
+ {13100000, 11289600, 0x363b},
+ {2048000, 16384000, 0x1ea0},
+ {3686400, 16384000, 0x9e27},
+ {12000000, 16384000, 0x452b},
+ {13000000, 16384000, 0x542f},
+ {13100000, 16384000, 0x03a0},
+ {2048000, 16934400, 0xe625},
+ {3686400, 16934400, 0x9126},
+ {12000000, 16934400, 0x4d2c},
+ {13000000, 16934400, 0x742f},
+ {13100000, 16934400, 0x3c27},
+ {2048000, 22579200, 0x2aa0},
+ {3686400, 22579200, 0x2f20},
+ {12000000, 22579200, 0x7e2f},
+ {13000000, 22579200, 0x742f},
+ {13100000, 22579200, 0x3c27},
+ {2048000, 24576000, 0x2ea0},
+ {3686400, 24576000, 0xee27},
+ {12000000, 24576000, 0x2915},
+ {13000000, 24576000, 0x772e},
+ {13100000, 24576000, 0x0d20},
+ {26000000, 24576000, 0x2027},
+ {26000000, 22579200, 0x392f},
+ {24576000, 22579200, 0x0921},
+ {24576000, 24576000, 0x02a0},
+};
+
+static const struct pll_div codec_slave_pll_div[] = {
+ {256000, 2048000, 0x46f0},
+ {256000, 4096000, 0x3ea0},
+ {352800, 5644800, 0x3ea0},
+ {512000, 8192000, 0x3ea0},
+ {1024000, 8192000, 0x46f0},
+ {705600, 11289600, 0x3ea0},
+ {1024000, 16384000, 0x3ea0},
+ {1411200, 22579200, 0x3ea0},
+ {1536000, 24576000, 0x3ea0},
+ {2048000, 16384000, 0x1ea0},
+ {2822400, 22579200, 0x1ea0},
+ {2822400, 45158400, 0x5ec0},
+ {5644800, 45158400, 0x46f0},
+ {3072000, 24576000, 0x1ea0},
+ {3072000, 49152000, 0x5ec0},
+ {6144000, 49152000, 0x46f0},
+ {705600, 11289600, 0x3ea0},
+ {705600, 8467200, 0x3ab0},
+ {24576000, 24576000, 0x02a0},
+ {1411200, 11289600, 0x1690},
+ {2822400, 11289600, 0x0a90},
+ {1536000, 12288000, 0x1690},
+ {3072000, 12288000, 0x0a90},
+};
+
+static struct coeff_clk_div coeff_div[] = {
+ /* sysclk is 256fs */
+ {2048000, 8000 * 32, 8000, 0x1000},
+ {2048000, 8000 * 64, 8000, 0x0000},
+ {2822400, 11025 * 32, 11025, 0x1000},
+ {2822400, 11025 * 64, 11025, 0x0000},
+ {4096000, 16000 * 32, 16000, 0x1000},
+ {4096000, 16000 * 64, 16000, 0x0000},
+ {5644800, 22050 * 32, 22050, 0x1000},
+ {5644800, 22050 * 64, 22050, 0x0000},
+ {8192000, 32000 * 32, 32000, 0x1000},
+ {8192000, 32000 * 64, 32000, 0x0000},
+ {11289600, 44100 * 32, 44100, 0x1000},
+ {11289600, 44100 * 64, 44100, 0x0000},
+ {12288000, 48000 * 32, 48000, 0x1000},
+ {12288000, 48000 * 64, 48000, 0x0000},
+ {22579200, 88200 * 32, 88200, 0x1000},
+ {22579200, 88200 * 64, 88200, 0x0000},
+ {24576000, 96000 * 32, 96000, 0x1000},
+ {24576000, 96000 * 64, 96000, 0x0000},
+ /* sysclk is 512fs */
+ {4096000, 8000 * 32, 8000, 0x3000},
+ {4096000, 8000 * 64, 8000, 0x2000},
+ {5644800, 11025 * 32, 11025, 0x3000},
+ {5644800, 11025 * 64, 11025, 0x2000},
+ {8192000, 16000 * 32, 16000, 0x3000},
+ {8192000, 16000 * 64, 16000, 0x2000},
+ {11289600, 22050 * 32, 22050, 0x3000},
+ {11289600, 22050 * 64, 22050, 0x2000},
+ {16384000, 32000 * 32, 32000, 0x3000},
+ {16384000, 32000 * 64, 32000, 0x2000},
+ {22579200, 44100 * 32, 44100, 0x3000},
+ {22579200, 44100 * 64, 44100, 0x2000},
+ {24576000, 48000 * 32, 48000, 0x3000},
+ {24576000, 48000 * 64, 48000, 0x2000},
+ {45158400, 88200 * 32, 88200, 0x3000},
+ {45158400, 88200 * 64, 88200, 0x2000},
+ {49152000, 96000 * 32, 96000, 0x3000},
+ {49152000, 96000 * 64, 96000, 0x2000},
+ /* sysclk is 24.576Mhz or 22.5792Mhz */
+ {24576000, 8000 * 32, 8000, 0x7080},
+ {24576000, 8000 * 64, 8000, 0x6080},
+ {24576000, 16000 * 32, 16000, 0x5080},
+ {24576000, 16000 * 64, 16000, 0x4080},
+ {24576000, 24000 * 32, 24000, 0x5000},
+ {24576000, 24000 * 64, 24000, 0x4000},
+ {24576000, 32000 * 32, 32000, 0x3080},
+ {24576000, 32000 * 64, 32000, 0x2080},
+ {22579200, 11025 * 32, 11025, 0x7000},
+ {22579200, 11025 * 64, 11025, 0x6000},
+ {22579200, 22050 * 32, 22050, 0x5000},
+ {22579200, 22050 * 64, 22050, 0x4000},
+};
+
+static int get_coeff(int mclk, int rate, int timesofbclk)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+ if (coeff_div[i].mclk == mclk && coeff_div[i].rate == rate &&
+ (coeff_div[i].bclk / coeff_div[i].rate) == timesofbclk)
+ return i;
+ }
+ return -EINVAL;
+}
+
+static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+ int timesofbclk = 32, coeff;
+ unsigned int iface = 0;
+
+ dev_dbg(codec->dev, "enter %s\n", __func__);
+
+ rt5631->bclk_rate = snd_soc_params_to_bclk(params);
+ if (rt5631->bclk_rate < 0) {
+ dev_err(codec->dev, "Fail to get BCLK rate\n");
+ return rt5631->bclk_rate;
+ }
+ rt5631->rx_rate = params_rate(params);
+
+ if (rt5631->master)
+ coeff = get_coeff(rt5631->sysclk, rt5631->rx_rate,
+ rt5631->bclk_rate / rt5631->rx_rate);
+ else
+ coeff = get_coeff(rt5631->sysclk, rt5631->rx_rate,
+ timesofbclk);
+ if (coeff < 0) {
+ dev_err(codec->dev, "Fail to get coeff\n");
+ return -EINVAL;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ iface |= RT5631_SDP_I2S_DL_20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iface |= RT5631_SDP_I2S_DL_24;
+ break;
+ case SNDRV_PCM_FORMAT_S8:
+ iface |= RT5631_SDP_I2S_DL_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, RT5631_SDP_CTRL,
+ RT5631_SDP_I2S_DL_MASK, iface);
+ snd_soc_write(codec, RT5631_STEREO_AD_DA_CLK_CTRL,
+ coeff_div[coeff].reg_val);
+
+ return 0;
+}
+
+static int rt5631_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+ unsigned int iface = 0;
+
+ dev_dbg(codec->dev, "enter %s\n", __func__);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ rt5631->master = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ iface |= RT5631_SDP_MODE_SEL_SLAVE;
+ rt5631->master = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface |= RT5631_SDP_I2S_DF_LEFT;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface |= RT5631_SDP_I2S_DF_PCM_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ iface |= RT5631_SDP_I2S_DF_PCM_B;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= RT5631_SDP_I2S_BCLK_POL_CTRL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec, RT5631_SDP_CTRL, iface);
+
+ return 0;
+}
+
+static int rt5631_hifi_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "enter %s, syclk=%d\n", __func__, freq);
+
+ if ((freq >= (256 * 8000)) && (freq <= (512 * 96000))) {
+ rt5631->sysclk = freq;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int rt5631_codec_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+ int i, ret = -EINVAL;
+
+ dev_dbg(codec->dev, "enter %s\n", __func__);
+
+ if (!freq_in || !freq_out) {
+ dev_dbg(codec->dev, "PLL disabled\n");
+
+ snd_soc_update_bits(codec, RT5631_GLOBAL_CLK_CTRL,
+ RT5631_SYSCLK_SOUR_SEL_MASK,
+ RT5631_SYSCLK_SOUR_SEL_MCLK);
+
+ return 0;
+ }
+
+ if (rt5631->master) {
+ for (i = 0; i < ARRAY_SIZE(codec_master_pll_div); i++)
+ if (freq_in == codec_master_pll_div[i].pll_in &&
+ freq_out == codec_master_pll_div[i].pll_out) {
+ dev_info(codec->dev,
+ "change PLL in master mode\n");
+ snd_soc_write(codec, RT5631_PLL_CTRL,
+ codec_master_pll_div[i].reg_val);
+ schedule_timeout_uninterruptible(
+ msecs_to_jiffies(20));
+ snd_soc_update_bits(codec,
+ RT5631_GLOBAL_CLK_CTRL,
+ RT5631_SYSCLK_SOUR_SEL_MASK |
+ RT5631_PLLCLK_SOUR_SEL_MASK,
+ RT5631_SYSCLK_SOUR_SEL_PLL |
+ RT5631_PLLCLK_SOUR_SEL_MCLK);
+ ret = 0;
+ break;
+ }
+ } else {
+ for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++)
+ if (freq_in == codec_slave_pll_div[i].pll_in &&
+ freq_out == codec_slave_pll_div[i].pll_out) {
+ dev_info(codec->dev,
+ "change PLL in slave mode\n");
+ snd_soc_write(codec, RT5631_PLL_CTRL,
+ codec_slave_pll_div[i].reg_val);
+ schedule_timeout_uninterruptible(
+ msecs_to_jiffies(20));
+ snd_soc_update_bits(codec,
+ RT5631_GLOBAL_CLK_CTRL,
+ RT5631_SYSCLK_SOUR_SEL_MASK |
+ RT5631_PLLCLK_SOUR_SEL_MASK,
+ RT5631_SYSCLK_SOUR_SEL_PLL |
+ RT5631_PLLCLK_SOUR_SEL_BCLK);
+ ret = 0;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int rt5631_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD2,
+ RT5631_PWR_MICBIAS1_VOL | RT5631_PWR_MICBIAS2_VOL,
+ RT5631_PWR_MICBIAS1_VOL | RT5631_PWR_MICBIAS2_VOL);
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+ RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS,
+ RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS);
+ msleep(80);
+ snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+ RT5631_PWR_FAST_VREF_CTRL,
+ RT5631_PWR_FAST_VREF_CTRL);
+ codec->cache_only = false;
+ snd_soc_cache_sync(codec);
+ }
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_write(codec, RT5631_PWR_MANAG_ADD1, 0x0000);
+ snd_soc_write(codec, RT5631_PWR_MANAG_ADD2, 0x0000);
+ snd_soc_write(codec, RT5631_PWR_MANAG_ADD3, 0x0000);
+ snd_soc_write(codec, RT5631_PWR_MANAG_ADD4, 0x0000);
+ break;
+
+ default:
+ break;
+ }
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+static int rt5631_probe(struct snd_soc_codec *codec)
+{
+ struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val;
+ int ret;
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ val = rt5631_read_index(codec, RT5631_ADDA_MIXER_INTL_REG3);
+ if (val & 0x0002)
+ rt5631->codec_version = 1;
+ else
+ rt5631->codec_version = 0;
+
+ rt5631_reset(codec);
+ snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+ RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS,
+ RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS);
+ msleep(80);
+ snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
+ RT5631_PWR_FAST_VREF_CTRL, RT5631_PWR_FAST_VREF_CTRL);
+ /* enable HP zero cross */
+ snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, 0x0f18);
+ /* power off ClassD auto Recovery */
+ if (rt5631->codec_version)
+ snd_soc_update_bits(codec, RT5631_INT_ST_IRQ_CTRL_2,
+ 0x2000, 0x2000);
+ else
+ snd_soc_update_bits(codec, RT5631_INT_ST_IRQ_CTRL_2,
+ 0x2000, 0);
+ /* DMIC */
+ if (rt5631->dmic_used_flag) {
+ snd_soc_update_bits(codec, RT5631_GPIO_CTRL,
+ RT5631_GPIO_PIN_FUN_SEL_MASK |
+ RT5631_GPIO_DMIC_FUN_SEL_MASK,
+ RT5631_GPIO_PIN_FUN_SEL_GPIO_DIMC |
+ RT5631_GPIO_DMIC_FUN_SEL_DIMC);
+ snd_soc_update_bits(codec, RT5631_DIG_MIC_CTRL,
+ RT5631_DMIC_L_CH_LATCH_MASK |
+ RT5631_DMIC_R_CH_LATCH_MASK,
+ RT5631_DMIC_L_CH_LATCH_FALLING |
+ RT5631_DMIC_R_CH_LATCH_RISING);
+ }
+
+ codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
+
+ return 0;
+}
+
+static int rt5631_remove(struct snd_soc_codec *codec)
+{
+ rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5631_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int rt5631_resume(struct snd_soc_codec *codec)
+{
+ rt5631_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+}
+#else
+#define rt5631_suspend NULL
+#define rt5631_resume NULL
+#endif
+
+#define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5631_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S8)
+
+static struct snd_soc_dai_ops rt5631_ops = {
+ .hw_params = rt5631_hifi_pcm_params,
+ .set_fmt = rt5631_hifi_codec_set_dai_fmt,
+ .set_sysclk = rt5631_hifi_codec_set_dai_sysclk,
+ .set_pll = rt5631_codec_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5631_dai[] = {
+ {
+ .name = "rt5631-hifi",
+ .id = 1,
+ .playback = {
+ .stream_name = "HIFI Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5631_STEREO_RATES,
+ .formats = RT5631_FORMAT,
+ },
+ .capture = {
+ .stream_name = "HIFI Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5631_STEREO_RATES,
+ .formats = RT5631_FORMAT,
+ },
+ .ops = &rt5631_ops,
+ },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
+ .probe = rt5631_probe,
+ .remove = rt5631_remove,
+ .suspend = rt5631_suspend,
+ .resume = rt5631_resume,
+ .set_bias_level = rt5631_set_bias_level,
+ .reg_cache_size = RT5631_VENDOR_ID2 + 1,
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = rt5631_reg,
+ .volatile_register = rt5631_volatile_register,
+ .readable_register = rt5631_readable_register,
+ .reg_cache_step = 1,
+ .controls = rt5631_snd_controls,
+ .num_controls = ARRAY_SIZE(rt5631_snd_controls),
+ .dapm_widgets = rt5631_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt5631_dapm_widgets),
+ .dapm_routes = rt5631_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt5631_dapm_routes),
+};
+
+static const struct i2c_device_id rt5631_i2c_id[] = {
+ { "rt5631", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
+
+static int rt5631_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt5631_priv *rt5631;
+ int ret;
+
+ rt5631 = kzalloc(sizeof(struct rt5631_priv), GFP_KERNEL);
+ if (NULL == rt5631)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt5631);
+
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5631,
+ rt5631_dai, ARRAY_SIZE(rt5631_dai));
+ if (ret < 0)
+ kfree(rt5631);
+
+ return ret;
+}
+
+static __devexit int rt5631_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static struct i2c_driver rt5631_i2c_driver = {
+ .driver = {
+ .name = "rt5631",
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5631_i2c_probe,
+ .remove = __devexit_p(rt5631_i2c_remove),
+ .id_table = rt5631_i2c_id,
+};
+
+static int __init rt5631_modinit(void)
+{
+ return i2c_add_driver(&rt5631_i2c_driver);
+}
+module_init(rt5631_modinit);
+
+static void __exit rt5631_modexit(void)
+{
+ i2c_del_driver(&rt5631_i2c_driver);
+}
+module_exit(rt5631_modexit);
+
+MODULE_DESCRIPTION("ASoC RT5631 driver");
+MODULE_AUTHOR("flove <flove@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt5631.h b/sound/soc/codecs/rt5631.h
new file mode 100644
index 000000000000..13401581b0df
--- /dev/null
+++ b/sound/soc/codecs/rt5631.h
@@ -0,0 +1,701 @@
+#ifndef __RTCODEC5631_H__
+#define __RTCODEC5631_H__
+
+
+#define RT5631_RESET 0x00
+#define RT5631_SPK_OUT_VOL 0x02
+#define RT5631_HP_OUT_VOL 0x04
+#define RT5631_MONO_AXO_1_2_VOL 0x06
+#define RT5631_AUX_IN_VOL 0x0A
+#define RT5631_STEREO_DAC_VOL_1 0x0C
+#define RT5631_MIC_CTRL_1 0x0E
+#define RT5631_STEREO_DAC_VOL_2 0x10
+#define RT5631_ADC_CTRL_1 0x12
+#define RT5631_ADC_REC_MIXER 0x14
+#define RT5631_ADC_CTRL_2 0x16
+#define RT5631_VDAC_DIG_VOL 0x18
+#define RT5631_OUTMIXER_L_CTRL 0x1A
+#define RT5631_OUTMIXER_R_CTRL 0x1C
+#define RT5631_AXO1MIXER_CTRL 0x1E
+#define RT5631_AXO2MIXER_CTRL 0x20
+#define RT5631_MIC_CTRL_2 0x22
+#define RT5631_DIG_MIC_CTRL 0x24
+#define RT5631_MONO_INPUT_VOL 0x26
+#define RT5631_SPK_MIXER_CTRL 0x28
+#define RT5631_SPK_MONO_OUT_CTRL 0x2A
+#define RT5631_SPK_MONO_HP_OUT_CTRL 0x2C
+#define RT5631_SDP_CTRL 0x34
+#define RT5631_MONO_SDP_CTRL 0x36
+#define RT5631_STEREO_AD_DA_CLK_CTRL 0x38
+#define RT5631_PWR_MANAG_ADD1 0x3A
+#define RT5631_PWR_MANAG_ADD2 0x3B
+#define RT5631_PWR_MANAG_ADD3 0x3C
+#define RT5631_PWR_MANAG_ADD4 0x3E
+#define RT5631_GEN_PUR_CTRL_REG 0x40
+#define RT5631_GLOBAL_CLK_CTRL 0x42
+#define RT5631_PLL_CTRL 0x44
+#define RT5631_INT_ST_IRQ_CTRL_1 0x48
+#define RT5631_INT_ST_IRQ_CTRL_2 0x4A
+#define RT5631_GPIO_CTRL 0x4C
+#define RT5631_MISC_CTRL 0x52
+#define RT5631_DEPOP_FUN_CTRL_1 0x54
+#define RT5631_DEPOP_FUN_CTRL_2 0x56
+#define RT5631_JACK_DET_CTRL 0x5A
+#define RT5631_SOFT_VOL_CTRL 0x5C
+#define RT5631_ALC_CTRL_1 0x64
+#define RT5631_ALC_CTRL_2 0x65
+#define RT5631_ALC_CTRL_3 0x66
+#define RT5631_PSEUDO_SPATL_CTRL 0x68
+#define RT5631_INDEX_ADD 0x6A
+#define RT5631_INDEX_DATA 0x6C
+#define RT5631_EQ_CTRL 0x6E
+#define RT5631_VENDOR_ID 0x7A
+#define RT5631_VENDOR_ID1 0x7C
+#define RT5631_VENDOR_ID2 0x7E
+
+/* Index of Codec Private Register definition */
+#define RT5631_EQ_BW_LOP 0x00
+#define RT5631_EQ_GAIN_LOP 0x01
+#define RT5631_EQ_FC_BP1 0x02
+#define RT5631_EQ_BW_BP1 0x03
+#define RT5631_EQ_GAIN_BP1 0x04
+#define RT5631_EQ_FC_BP2 0x05
+#define RT5631_EQ_BW_BP2 0x06
+#define RT5631_EQ_GAIN_BP2 0x07
+#define RT5631_EQ_FC_BP3 0x08
+#define RT5631_EQ_BW_BP3 0x09
+#define RT5631_EQ_GAIN_BP3 0x0a
+#define RT5631_EQ_BW_HIP 0x0b
+#define RT5631_EQ_GAIN_HIP 0x0c
+#define RT5631_EQ_HPF_A1 0x0d
+#define RT5631_EQ_HPF_A2 0x0e
+#define RT5631_EQ_HPF_GAIN 0x0f
+#define RT5631_EQ_PRE_VOL_CTRL 0x11
+#define RT5631_EQ_POST_VOL_CTRL 0x12
+#define RT5631_TEST_MODE_CTRL 0x39
+#define RT5631_CP_INTL_REG2 0x45
+#define RT5631_ADDA_MIXER_INTL_REG3 0x52
+#define RT5631_SPK_INTL_CTRL 0x56
+
+
+/* global definition */
+#define RT5631_L_MUTE (0x1 << 15)
+#define RT5631_L_MUTE_SHIFT 15
+#define RT5631_L_EN (0x1 << 14)
+#define RT5631_L_EN_SHIFT 14
+#define RT5631_R_MUTE (0x1 << 7)
+#define RT5631_R_MUTE_SHIFT 7
+#define RT5631_R_EN (0x1 << 6)
+#define RT5631_R_EN_SHIFT 6
+#define RT5631_VOL_MASK 0x1f
+#define RT5631_L_VOL_SHIFT 8
+#define RT5631_R_VOL_SHIFT 0
+
+/* Speaker Output Control(0x02) */
+#define RT5631_SPK_L_VOL_SEL_MASK (0x1 << 14)
+#define RT5631_SPK_L_VOL_SEL_VMID (0x0 << 14)
+#define RT5631_SPK_L_VOL_SEL_SPKMIX_L (0x1 << 14)
+#define RT5631_SPK_R_VOL_SEL_MASK (0x1 << 6)
+#define RT5631_SPK_R_VOL_SEL_VMID (0x0 << 6)
+#define RT5631_SPK_R_VOL_SEL_SPKMIX_R (0x1 << 6)
+
+/* Headphone Output Control(0x04) */
+#define RT5631_HP_L_VOL_SEL_MASK (0x1 << 14)
+#define RT5631_HP_L_VOL_SEL_VMID (0x0 << 14)
+#define RT5631_HP_L_VOL_SEL_OUTMIX_L (0x1 << 14)
+#define RT5631_HP_R_VOL_SEL_MASK (0x1 << 6)
+#define RT5631_HP_R_VOL_SEL_VMID (0x0 << 6)
+#define RT5631_HP_R_VOL_SEL_OUTMIX_R (0x1 << 6)
+
+/* Output Control for AUXOUT/MONO(0x06) */
+#define RT5631_AUXOUT_1_VOL_SEL_MASK (0x1 << 14)
+#define RT5631_AUXOUT_1_VOL_SEL_VMID (0x0 << 14)
+#define RT5631_AUXOUT_1_VOL_SEL_OUTMIX_L (0x1 << 14)
+#define RT5631_MUTE_MONO (0x1 << 13)
+#define RT5631_MUTE_MONO_SHIFT 13
+#define RT5631_AUXOUT_2_VOL_SEL_MASK (0x1 << 6)
+#define RT5631_AUXOUT_2_VOL_SEL_VMID (0x0 << 6)
+#define RT5631_AUXOUT_2_VOL_SEL_OUTMIX_R (0x1 << 6)
+
+/* Microphone Input Control 1(0x0E) */
+#define RT5631_MIC1_DIFF_INPUT_CTRL (0x1 << 15)
+#define RT5631_MIC1_DIFF_INPUT_SHIFT 15
+#define RT5631_MIC2_DIFF_INPUT_CTRL (0x1 << 7)
+#define RT5631_MIC2_DIFF_INPUT_SHIFT 7
+
+/* Stereo DAC Digital Volume2(0x10) */
+#define RT5631_DAC_VOL_MASK 0xff
+
+/* ADC Recording Mixer Control(0x14) */
+#define RT5631_M_OUTMIXER_L_TO_RECMIXER_L (0x1 << 15)
+#define RT5631_M_OUTMIXL_RECMIXL_BIT 15
+#define RT5631_M_MIC1_TO_RECMIXER_L (0x1 << 14)
+#define RT5631_M_MIC1_RECMIXL_BIT 14
+#define RT5631_M_AXIL_TO_RECMIXER_L (0x1 << 13)
+#define RT5631_M_AXIL_RECMIXL_BIT 13
+#define RT5631_M_MONO_IN_TO_RECMIXER_L (0x1 << 12)
+#define RT5631_M_MONO_IN_RECMIXL_BIT 12
+#define RT5631_M_OUTMIXER_R_TO_RECMIXER_R (0x1 << 7)
+#define RT5631_M_OUTMIXR_RECMIXR_BIT 7
+#define RT5631_M_MIC2_TO_RECMIXER_R (0x1 << 6)
+#define RT5631_M_MIC2_RECMIXR_BIT 6
+#define RT5631_M_AXIR_TO_RECMIXER_R (0x1 << 5)
+#define RT5631_M_AXIR_RECMIXR_BIT 5
+#define RT5631_M_MONO_IN_TO_RECMIXER_R (0x1 << 4)
+#define RT5631_M_MONO_IN_RECMIXR_BIT 4
+
+/* Left Output Mixer Control(0x1A) */
+#define RT5631_M_RECMIXER_L_TO_OUTMIXER_L (0x1 << 15)
+#define RT5631_M_RECMIXL_OUTMIXL_BIT 15
+#define RT5631_M_RECMIXER_R_TO_OUTMIXER_L (0x1 << 14)
+#define RT5631_M_RECMIXR_OUTMIXL_BIT 14
+#define RT5631_M_DAC_L_TO_OUTMIXER_L (0x1 << 13)
+#define RT5631_M_DACL_OUTMIXL_BIT 13
+#define RT5631_M_MIC1_TO_OUTMIXER_L (0x1 << 12)
+#define RT5631_M_MIC1_OUTMIXL_BIT 12
+#define RT5631_M_MIC2_TO_OUTMIXER_L (0x1 << 11)
+#define RT5631_M_MIC2_OUTMIXL_BIT 11
+#define RT5631_M_MONO_IN_P_TO_OUTMIXER_L (0x1 << 10)
+#define RT5631_M_MONO_INP_OUTMIXL_BIT 10
+#define RT5631_M_AXIL_TO_OUTMIXER_L (0x1 << 9)
+#define RT5631_M_AXIL_OUTMIXL_BIT 9
+#define RT5631_M_AXIR_TO_OUTMIXER_L (0x1 << 8)
+#define RT5631_M_AXIR_OUTMIXL_BIT 8
+#define RT5631_M_VDAC_TO_OUTMIXER_L (0x1 << 7)
+#define RT5631_M_VDAC_OUTMIXL_BIT 7
+
+/* Right Output Mixer Control(0x1C) */
+#define RT5631_M_RECMIXER_L_TO_OUTMIXER_R (0x1 << 15)
+#define RT5631_M_RECMIXL_OUTMIXR_BIT 15
+#define RT5631_M_RECMIXER_R_TO_OUTMIXER_R (0x1 << 14)
+#define RT5631_M_RECMIXR_OUTMIXR_BIT 14
+#define RT5631_M_DAC_R_TO_OUTMIXER_R (0x1 << 13)
+#define RT5631_M_DACR_OUTMIXR_BIT 13
+#define RT5631_M_MIC1_TO_OUTMIXER_R (0x1 << 12)
+#define RT5631_M_MIC1_OUTMIXR_BIT 12
+#define RT5631_M_MIC2_TO_OUTMIXER_R (0x1 << 11)
+#define RT5631_M_MIC2_OUTMIXR_BIT 11
+#define RT5631_M_MONO_IN_N_TO_OUTMIXER_R (0x1 << 10)
+#define RT5631_M_MONO_INN_OUTMIXR_BIT 10
+#define RT5631_M_AXIL_TO_OUTMIXER_R (0x1 << 9)
+#define RT5631_M_AXIL_OUTMIXR_BIT 9
+#define RT5631_M_AXIR_TO_OUTMIXER_R (0x1 << 8)
+#define RT5631_M_AXIR_OUTMIXR_BIT 8
+#define RT5631_M_VDAC_TO_OUTMIXER_R (0x1 << 7)
+#define RT5631_M_VDAC_OUTMIXR_BIT 7
+
+/* Lout Mixer Control(0x1E) */
+#define RT5631_M_MIC1_TO_AXO1MIXER (0x1 << 15)
+#define RT5631_M_MIC1_AXO1MIX_BIT 15
+#define RT5631_M_MIC2_TO_AXO1MIXER (0x1 << 11)
+#define RT5631_M_MIC2_AXO1MIX_BIT 11
+#define RT5631_M_OUTMIXER_L_TO_AXO1MIXER (0x1 << 7)
+#define RT5631_M_OUTMIXL_AXO1MIX_BIT 7
+#define RT5631_M_OUTMIXER_R_TO_AXO1MIXER (0x1 << 6)
+#define RT5631_M_OUTMIXR_AXO1MIX_BIT 6
+
+/* Rout Mixer Control(0x20) */
+#define RT5631_M_MIC1_TO_AXO2MIXER (0x1 << 15)
+#define RT5631_M_MIC1_AXO2MIX_BIT 15
+#define RT5631_M_MIC2_TO_AXO2MIXER (0x1 << 11)
+#define RT5631_M_MIC2_AXO2MIX_BIT 11
+#define RT5631_M_OUTMIXER_L_TO_AXO2MIXER (0x1 << 7)
+#define RT5631_M_OUTMIXL_AXO2MIX_BIT 7
+#define RT5631_M_OUTMIXER_R_TO_AXO2MIXER (0x1 << 6)
+#define RT5631_M_OUTMIXR_AXO2MIX_BIT 6
+
+/* Micphone Input Control 2(0x22) */
+#define RT5631_MIC_BIAS_90_PRECNET_AVDD 1
+#define RT5631_MIC_BIAS_75_PRECNET_AVDD 2
+
+#define RT5631_MIC1_BOOST_CTRL_MASK (0xf << 12)
+#define RT5631_MIC1_BOOST_CTRL_BYPASS (0x0 << 12)
+#define RT5631_MIC1_BOOST_CTRL_20DB (0x1 << 12)
+#define RT5631_MIC1_BOOST_CTRL_24DB (0x2 << 12)
+#define RT5631_MIC1_BOOST_CTRL_30DB (0x3 << 12)
+#define RT5631_MIC1_BOOST_CTRL_35DB (0x4 << 12)
+#define RT5631_MIC1_BOOST_CTRL_40DB (0x5 << 12)
+#define RT5631_MIC1_BOOST_CTRL_34DB (0x6 << 12)
+#define RT5631_MIC1_BOOST_CTRL_50DB (0x7 << 12)
+#define RT5631_MIC1_BOOST_CTRL_52DB (0x8 << 12)
+#define RT5631_MIC1_BOOST_SHIFT 12
+
+#define RT5631_MIC2_BOOST_CTRL_MASK (0xf << 8)
+#define RT5631_MIC2_BOOST_CTRL_BYPASS (0x0 << 8)
+#define RT5631_MIC2_BOOST_CTRL_20DB (0x1 << 8)
+#define RT5631_MIC2_BOOST_CTRL_24DB (0x2 << 8)
+#define RT5631_MIC2_BOOST_CTRL_30DB (0x3 << 8)
+#define RT5631_MIC2_BOOST_CTRL_35DB (0x4 << 8)
+#define RT5631_MIC2_BOOST_CTRL_40DB (0x5 << 8)
+#define RT5631_MIC2_BOOST_CTRL_34DB (0x6 << 8)
+#define RT5631_MIC2_BOOST_CTRL_50DB (0x7 << 8)
+#define RT5631_MIC2_BOOST_CTRL_52DB (0x8 << 8)
+#define RT5631_MIC2_BOOST_SHIFT 8
+
+#define RT5631_MICBIAS1_VOLT_CTRL_MASK (0x1 << 7)
+#define RT5631_MICBIAS1_VOLT_CTRL_90P (0x0 << 7)
+#define RT5631_MICBIAS1_VOLT_CTRL_75P (0x1 << 7)
+
+#define RT5631_MICBIAS1_S_C_DET_MASK (0x1 << 6)
+#define RT5631_MICBIAS1_S_C_DET_DIS (0x0 << 6)
+#define RT5631_MICBIAS1_S_C_DET_ENA (0x1 << 6)
+
+#define RT5631_MICBIAS1_SHORT_CURR_DET_MASK (0x3 << 4)
+#define RT5631_MICBIAS1_SHORT_CURR_DET_600UA (0x0 << 4)
+#define RT5631_MICBIAS1_SHORT_CURR_DET_1500UA (0x1 << 4)
+#define RT5631_MICBIAS1_SHORT_CURR_DET_2000UA (0x2 << 4)
+
+#define RT5631_MICBIAS2_VOLT_CTRL_MASK (0x1 << 3)
+#define RT5631_MICBIAS2_VOLT_CTRL_90P (0x0 << 3)
+#define RT5631_MICBIAS2_VOLT_CTRL_75P (0x1 << 3)
+
+#define RT5631_MICBIAS2_S_C_DET_MASK (0x1 << 2)
+#define RT5631_MICBIAS2_S_C_DET_DIS (0x0 << 2)
+#define RT5631_MICBIAS2_S_C_DET_ENA (0x1 << 2)
+
+#define RT5631_MICBIAS2_SHORT_CURR_DET_MASK (0x3)
+#define RT5631_MICBIAS2_SHORT_CURR_DET_600UA (0x0)
+#define RT5631_MICBIAS2_SHORT_CURR_DET_1500UA (0x1)
+#define RT5631_MICBIAS2_SHORT_CURR_DET_2000UA (0x2)
+
+
+/* Digital Microphone Control(0x24) */
+#define RT5631_DMIC_ENA_MASK (0x1 << 15)
+#define RT5631_DMIC_ENA_SHIFT 15
+/* DMIC_ENA: DMIC to ADC Digital filter */
+#define RT5631_DMIC_ENA (0x1 << 15)
+/* DMIC_DIS: ADC mixer to ADC Digital filter */
+#define RT5631_DMIC_DIS (0x0 << 15)
+#define RT5631_DMIC_L_CH_MUTE (0x1 << 13)
+#define RT5631_DMIC_L_CH_MUTE_SHIFT 13
+#define RT5631_DMIC_R_CH_MUTE (0x1 << 12)
+#define RT5631_DMIC_R_CH_MUTE_SHIFT 12
+#define RT5631_DMIC_L_CH_LATCH_MASK (0x1 << 9)
+#define RT5631_DMIC_L_CH_LATCH_RISING (0x1 << 9)
+#define RT5631_DMIC_L_CH_LATCH_FALLING (0x0 << 9)
+#define RT5631_DMIC_R_CH_LATCH_MASK (0x1 << 8)
+#define RT5631_DMIC_R_CH_LATCH_RISING (0x1 << 8)
+#define RT5631_DMIC_R_CH_LATCH_FALLING (0x0 << 8)
+#define RT5631_DMIC_CLK_CTRL_MASK (0x3 << 4)
+#define RT5631_DMIC_CLK_CTRL_TO_128FS (0x0 << 4)
+#define RT5631_DMIC_CLK_CTRL_TO_64FS (0x1 << 4)
+#define RT5631_DMIC_CLK_CTRL_TO_32FS (0x2 << 4)
+
+/* Microphone Input Volume(0x26) */
+#define RT5631_MONO_DIFF_INPUT_SHIFT 15
+
+/* Speaker Mixer Control(0x28) */
+#define RT5631_M_RECMIXER_L_TO_SPKMIXER_L (0x1 << 15)
+#define RT5631_M_RECMIXL_SPKMIXL_BIT 15
+#define RT5631_M_MIC1_P_TO_SPKMIXER_L (0x1 << 14)
+#define RT5631_M_MIC1P_SPKMIXL_BIT 14
+#define RT5631_M_DAC_L_TO_SPKMIXER_L (0x1 << 13)
+#define RT5631_M_DACL_SPKMIXL_BIT 13
+#define RT5631_M_OUTMIXER_L_TO_SPKMIXER_L (0x1 << 12)
+#define RT5631_M_OUTMIXL_SPKMIXL_BIT 12
+
+#define RT5631_M_RECMIXER_R_TO_SPKMIXER_R (0x1 << 7)
+#define RT5631_M_RECMIXR_SPKMIXR_BIT 7
+#define RT5631_M_MIC2_P_TO_SPKMIXER_R (0x1 << 6)
+#define RT5631_M_MIC2P_SPKMIXR_BIT 6
+#define RT5631_M_DAC_R_TO_SPKMIXER_R (0x1 << 5)
+#define RT5631_M_DACR_SPKMIXR_BIT 5
+#define RT5631_M_OUTMIXER_R_TO_SPKMIXER_R (0x1 << 4)
+#define RT5631_M_OUTMIXR_SPKMIXR_BIT 4
+
+/* Speaker/Mono Output Control(0x2A) */
+#define RT5631_M_SPKVOL_L_TO_SPOL_MIXER (0x1 << 15)
+#define RT5631_M_SPKVOLL_SPOLMIX_BIT 15
+#define RT5631_M_SPKVOL_R_TO_SPOL_MIXER (0x1 << 14)
+#define RT5631_M_SPKVOLR_SPOLMIX_BIT 14
+#define RT5631_M_SPKVOL_L_TO_SPOR_MIXER (0x1 << 13)
+#define RT5631_M_SPKVOLL_SPORMIX_BIT 13
+#define RT5631_M_SPKVOL_R_TO_SPOR_MIXER (0x1 << 12)
+#define RT5631_M_SPKVOLR_SPORMIX_BIT 12
+#define RT5631_M_OUTVOL_L_TO_MONOMIXER (0x1 << 11)
+#define RT5631_M_OUTVOLL_MONOMIX_BIT 11
+#define RT5631_M_OUTVOL_R_TO_MONOMIXER (0x1 << 10)
+#define RT5631_M_OUTVOLR_MONOMIX_BIT 10
+
+/* Speaker/Mono/HP Output Control(0x2C) */
+#define RT5631_SPK_L_MUX_SEL_MASK (0x3 << 14)
+#define RT5631_SPK_L_MUX_SEL_SPKMIXER_L (0x0 << 14)
+#define RT5631_SPK_L_MUX_SEL_MONO_IN (0x1 << 14)
+#define RT5631_SPK_L_MUX_SEL_DAC_L (0x3 << 14)
+#define RT5631_SPK_L_MUX_SEL_SHIFT 14
+
+#define RT5631_SPK_R_MUX_SEL_MASK (0x3 << 10)
+#define RT5631_SPK_R_MUX_SEL_SPKMIXER_R (0x0 << 10)
+#define RT5631_SPK_R_MUX_SEL_MONO_IN (0x1 << 10)
+#define RT5631_SPK_R_MUX_SEL_DAC_R (0x3 << 10)
+#define RT5631_SPK_R_MUX_SEL_SHIFT 10
+
+#define RT5631_MONO_MUX_SEL_MASK (0x3 << 6)
+#define RT5631_MONO_MUX_SEL_MONOMIXER (0x0 << 6)
+#define RT5631_MONO_MUX_SEL_MONO_IN (0x1 << 6)
+#define RT5631_MONO_MUX_SEL_SHIFT 6
+
+#define RT5631_HP_L_MUX_SEL_MASK (0x1 << 3)
+#define RT5631_HP_L_MUX_SEL_HPVOL_L (0x0 << 3)
+#define RT5631_HP_L_MUX_SEL_DAC_L (0x1 << 3)
+#define RT5631_HP_L_MUX_SEL_SHIFT 3
+
+#define RT5631_HP_R_MUX_SEL_MASK (0x1 << 2)
+#define RT5631_HP_R_MUX_SEL_HPVOL_R (0x0 << 2)
+#define RT5631_HP_R_MUX_SEL_DAC_R (0x1 << 2)
+#define RT5631_HP_R_MUX_SEL_SHIFT 2
+
+/* Stereo I2S Serial Data Port Control(0x34) */
+#define RT5631_SDP_MODE_SEL_MASK (0x1 << 15)
+#define RT5631_SDP_MODE_SEL_MASTER (0x0 << 15)
+#define RT5631_SDP_MODE_SEL_SLAVE (0x1 << 15)
+
+#define RT5631_SDP_ADC_CPS_SEL_MASK (0x3 << 10)
+#define RT5631_SDP_ADC_CPS_SEL_OFF (0x0 << 10)
+#define RT5631_SDP_ADC_CPS_SEL_U_LAW (0x1 << 10)
+#define RT5631_SDP_ADC_CPS_SEL_A_LAW (0x2 << 10)
+
+#define RT5631_SDP_DAC_CPS_SEL_MASK (0x3 << 8)
+#define RT5631_SDP_DAC_CPS_SEL_OFF (0x0 << 8)
+#define RT5631_SDP_DAC_CPS_SEL_U_LAW (0x1 << 8)
+#define RT5631_SDP_DAC_CPS_SEL_A_LAW (0x2 << 8)
+/* 0:Normal 1:Invert */
+#define RT5631_SDP_I2S_BCLK_POL_CTRL (0x1 << 7)
+/* 0:Normal 1:Invert */
+#define RT5631_SDP_DAC_R_INV (0x1 << 6)
+/* 0:ADC data appear at left phase of LRCK
+ * 1:ADC data appear at right phase of LRCK
+ */
+#define RT5631_SDP_ADC_DATA_L_R_SWAP (0x1 << 5)
+/* 0:DAC data appear at left phase of LRCK
+ * 1:DAC data appear at right phase of LRCK
+ */
+#define RT5631_SDP_DAC_DATA_L_R_SWAP (0x1 << 4)
+
+/* Data Length Slection */
+#define RT5631_SDP_I2S_DL_MASK (0x3 << 2)
+#define RT5631_SDP_I2S_DL_16 (0x0 << 2)
+#define RT5631_SDP_I2S_DL_20 (0x1 << 2)
+#define RT5631_SDP_I2S_DL_24 (0x2 << 2)
+#define RT5631_SDP_I2S_DL_8 (0x3 << 2)
+
+/* PCM Data Format Selection */
+#define RT5631_SDP_I2S_DF_MASK (0x3)
+#define RT5631_SDP_I2S_DF_I2S (0x0)
+#define RT5631_SDP_I2S_DF_LEFT (0x1)
+#define RT5631_SDP_I2S_DF_PCM_A (0x2)
+#define RT5631_SDP_I2S_DF_PCM_B (0x3)
+
+/* Stereo AD/DA Clock Control(0x38h) */
+#define RT5631_I2S_PRE_DIV_MASK (0x7 << 13)
+#define RT5631_I2S_PRE_DIV_1 (0x0 << 13)
+#define RT5631_I2S_PRE_DIV_2 (0x1 << 13)
+#define RT5631_I2S_PRE_DIV_4 (0x2 << 13)
+#define RT5631_I2S_PRE_DIV_8 (0x3 << 13)
+#define RT5631_I2S_PRE_DIV_16 (0x4 << 13)
+#define RT5631_I2S_PRE_DIV_32 (0x5 << 13)
+/* CLOCK RELATIVE OF BCLK AND LCRK */
+#define RT5631_I2S_LRCK_SEL_N_BCLK_MASK (0x1 << 12)
+#define RT5631_I2S_LRCK_SEL_64_BCLK (0x0 << 12) /* 64FS */
+#define RT5631_I2S_LRCK_SEL_32_BCLK (0x1 << 12) /* 32FS */
+
+#define RT5631_DAC_OSR_SEL_MASK (0x3 << 10)
+#define RT5631_DAC_OSR_SEL_128FS (0x3 << 10)
+#define RT5631_DAC_OSR_SEL_64FS (0x3 << 10)
+#define RT5631_DAC_OSR_SEL_32FS (0x3 << 10)
+#define RT5631_DAC_OSR_SEL_16FS (0x3 << 10)
+
+#define RT5631_ADC_OSR_SEL_MASK (0x3 << 8)
+#define RT5631_ADC_OSR_SEL_128FS (0x3 << 8)
+#define RT5631_ADC_OSR_SEL_64FS (0x3 << 8)
+#define RT5631_ADC_OSR_SEL_32FS (0x3 << 8)
+#define RT5631_ADC_OSR_SEL_16FS (0x3 << 8)
+
+#define RT5631_ADDA_FILTER_CLK_SEL_256FS (0 << 7) /* 256FS */
+#define RT5631_ADDA_FILTER_CLK_SEL_384FS (1 << 7) /* 384FS */
+
+/* Power managment addition 1 (0x3A) */
+#define RT5631_PWR_MAIN_I2S_EN (0x1 << 15)
+#define RT5631_PWR_MAIN_I2S_BIT 15
+#define RT5631_PWR_CLASS_D (0x1 << 12)
+#define RT5631_PWR_CLASS_D_BIT 12
+#define RT5631_PWR_ADC_L_CLK (0x1 << 11)
+#define RT5631_PWR_ADC_L_CLK_BIT 11
+#define RT5631_PWR_ADC_R_CLK (0x1 << 10)
+#define RT5631_PWR_ADC_R_CLK_BIT 10
+#define RT5631_PWR_DAC_L_CLK (0x1 << 9)
+#define RT5631_PWR_DAC_L_CLK_BIT 9
+#define RT5631_PWR_DAC_R_CLK (0x1 << 8)
+#define RT5631_PWR_DAC_R_CLK_BIT 8
+#define RT5631_PWR_DAC_REF (0x1 << 7)
+#define RT5631_PWR_DAC_REF_BIT 7
+#define RT5631_PWR_DAC_L_TO_MIXER (0x1 << 6)
+#define RT5631_PWR_DAC_L_TO_MIXER_BIT 6
+#define RT5631_PWR_DAC_R_TO_MIXER (0x1 << 5)
+#define RT5631_PWR_DAC_R_TO_MIXER_BIT 5
+
+/* Power managment addition 2 (0x3B) */
+#define RT5631_PWR_OUTMIXER_L (0x1 << 15)
+#define RT5631_PWR_OUTMIXER_L_BIT 15
+#define RT5631_PWR_OUTMIXER_R (0x1 << 14)
+#define RT5631_PWR_OUTMIXER_R_BIT 14
+#define RT5631_PWR_SPKMIXER_L (0x1 << 13)
+#define RT5631_PWR_SPKMIXER_L_BIT 13
+#define RT5631_PWR_SPKMIXER_R (0x1 << 12)
+#define RT5631_PWR_SPKMIXER_R_BIT 12
+#define RT5631_PWR_RECMIXER_L (0x1 << 11)
+#define RT5631_PWR_RECMIXER_L_BIT 11
+#define RT5631_PWR_RECMIXER_R (0x1 << 10)
+#define RT5631_PWR_RECMIXER_R_BIT 10
+#define RT5631_PWR_MIC1_BOOT_GAIN (0x1 << 5)
+#define RT5631_PWR_MIC1_BOOT_GAIN_BIT 5
+#define RT5631_PWR_MIC2_BOOT_GAIN (0x1 << 4)
+#define RT5631_PWR_MIC2_BOOT_GAIN_BIT 4
+#define RT5631_PWR_MICBIAS1_VOL (0x1 << 3)
+#define RT5631_PWR_MICBIAS1_VOL_BIT 3
+#define RT5631_PWR_MICBIAS2_VOL (0x1 << 2)
+#define RT5631_PWR_MICBIAS2_VOL_BIT 2
+#define RT5631_PWR_PLL1 (0x1 << 1)
+#define RT5631_PWR_PLL1_BIT 1
+#define RT5631_PWR_PLL2 (0x1 << 0)
+#define RT5631_PWR_PLL2_BIT 0
+
+/* Power managment addition 3(0x3C) */
+#define RT5631_PWR_VREF (0x1 << 15)
+#define RT5631_PWR_VREF_BIT 15
+#define RT5631_PWR_FAST_VREF_CTRL (0x1 << 14)
+#define RT5631_PWR_FAST_VREF_CTRL_BIT 14
+#define RT5631_PWR_MAIN_BIAS (0x1 << 13)
+#define RT5631_PWR_MAIN_BIAS_BIT 13
+#define RT5631_PWR_AXO1MIXER (0x1 << 11)
+#define RT5631_PWR_AXO1MIXER_BIT 11
+#define RT5631_PWR_AXO2MIXER (0x1 << 10)
+#define RT5631_PWR_AXO2MIXER_BIT 10
+#define RT5631_PWR_MONOMIXER (0x1 << 9)
+#define RT5631_PWR_MONOMIXER_BIT 9
+#define RT5631_PWR_MONO_DEPOP_DIS (0x1 << 8)
+#define RT5631_PWR_MONO_DEPOP_DIS_BIT 8
+#define RT5631_PWR_MONO_AMP_EN (0x1 << 7)
+#define RT5631_PWR_MONO_AMP_EN_BIT 7
+#define RT5631_PWR_CHARGE_PUMP (0x1 << 4)
+#define RT5631_PWR_CHARGE_PUMP_BIT 4
+#define RT5631_PWR_HP_L_AMP (0x1 << 3)
+#define RT5631_PWR_HP_L_AMP_BIT 3
+#define RT5631_PWR_HP_R_AMP (0x1 << 2)
+#define RT5631_PWR_HP_R_AMP_BIT 2
+#define RT5631_PWR_HP_DEPOP_DIS (0x1 << 1)
+#define RT5631_PWR_HP_DEPOP_DIS_BIT 1
+#define RT5631_PWR_HP_AMP_DRIVING (0x1 << 0)
+#define RT5631_PWR_HP_AMP_DRIVING_BIT 0
+
+/* Power managment addition 4(0x3E) */
+#define RT5631_PWR_SPK_L_VOL (0x1 << 15)
+#define RT5631_PWR_SPK_L_VOL_BIT 15
+#define RT5631_PWR_SPK_R_VOL (0x1 << 14)
+#define RT5631_PWR_SPK_R_VOL_BIT 14
+#define RT5631_PWR_LOUT_VOL (0x1 << 13)
+#define RT5631_PWR_LOUT_VOL_BIT 13
+#define RT5631_PWR_ROUT_VOL (0x1 << 12)
+#define RT5631_PWR_ROUT_VOL_BIT 12
+#define RT5631_PWR_HP_L_OUT_VOL (0x1 << 11)
+#define RT5631_PWR_HP_L_OUT_VOL_BIT 11
+#define RT5631_PWR_HP_R_OUT_VOL (0x1 << 10)
+#define RT5631_PWR_HP_R_OUT_VOL_BIT 10
+#define RT5631_PWR_AXIL_IN_VOL (0x1 << 9)
+#define RT5631_PWR_AXIL_IN_VOL_BIT 9
+#define RT5631_PWR_AXIR_IN_VOL (0x1 << 8)
+#define RT5631_PWR_AXIR_IN_VOL_BIT 8
+#define RT5631_PWR_MONO_IN_P_VOL (0x1 << 7)
+#define RT5631_PWR_MONO_IN_P_VOL_BIT 7
+#define RT5631_PWR_MONO_IN_N_VOL (0x1 << 6)
+#define RT5631_PWR_MONO_IN_N_VOL_BIT 6
+
+/* General Purpose Control Register(0x40) */
+#define RT5631_SPK_AMP_AUTO_RATIO_EN (0x1 << 15)
+
+#define RT5631_SPK_AMP_RATIO_CTRL_MASK (0x7 << 12)
+#define RT5631_SPK_AMP_RATIO_CTRL_2_34 (0x0 << 12) /* 7.40DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_99 (0x1 << 12) /* 5.99DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_68 (0x2 << 12) /* 4.50DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_56 (0x3 << 12) /* 3.86DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_44 (0x4 << 12) /* 3.16DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_27 (0x5 << 12) /* 2.10DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_09 (0x6 << 12) /* 0.80DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_00 (0x7 << 12) /* 0.00DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_SHIFT 12
+
+#define RT5631_STEREO_DAC_HI_PASS_FILT_EN (0x1 << 11)
+#define RT5631_STEREO_ADC_HI_PASS_FILT_EN (0x1 << 10)
+/* Select ADC Wind Filter Clock type */
+#define RT5631_ADC_WIND_FILT_MASK (0x3 << 4)
+#define RT5631_ADC_WIND_FILT_8_16_32K (0x0 << 4) /*8/16/32k*/
+#define RT5631_ADC_WIND_FILT_11_22_44K (0x1 << 4) /*11/22/44k*/
+#define RT5631_ADC_WIND_FILT_12_24_48K (0x2 << 4) /*12/24/48k*/
+#define RT5631_ADC_WIND_FILT_EN (0x1 << 3)
+/* SelectADC Wind Filter Corner Frequency */
+#define RT5631_ADC_WIND_CNR_FREQ_MASK (0x7 << 0)
+#define RT5631_ADC_WIND_CNR_FREQ_82_113_122 (0x0 << 0) /* 82/113/122 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_102_141_153 (0x1 << 0) /* 102/141/153 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_131_180_156 (0x2 << 0) /* 131/180/156 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_163_225_245 (0x3 << 0) /* 163/225/245 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_204_281_306 (0x4 << 0) /* 204/281/306 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_261_360_392 (0x5 << 0) /* 261/360/392 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_327_450_490 (0x6 << 0) /* 327/450/490 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_408_563_612 (0x7 << 0) /* 408/563/612 Hz */
+
+/* Global Clock Control Register(0x42) */
+#define RT5631_SYSCLK_SOUR_SEL_MASK (0x3 << 14)
+#define RT5631_SYSCLK_SOUR_SEL_MCLK (0x0 << 14)
+#define RT5631_SYSCLK_SOUR_SEL_PLL (0x1 << 14)
+#define RT5631_SYSCLK_SOUR_SEL_PLL_TCK (0x2 << 14)
+
+#define RT5631_PLLCLK_SOUR_SEL_MASK (0x3 << 12)
+#define RT5631_PLLCLK_SOUR_SEL_MCLK (0x0 << 12)
+#define RT5631_PLLCLK_SOUR_SEL_BCLK (0x1 << 12)
+#define RT5631_PLLCLK_SOUR_SEL_VBCLK (0x2 << 12)
+
+#define RT5631_PLLCLK_PRE_DIV1 (0x0 << 11)
+#define RT5631_PLLCLK_PRE_DIV2 (0x1 << 11)
+
+/* PLL Control(0x44) */
+#define RT5631_PLL_CTRL_M_VAL(m) ((m)&0xf)
+#define RT5631_PLL_CTRL_K_VAL(k) (((k)&0x7) << 4)
+#define RT5631_PLL_CTRL_N_VAL(n) (((n)&0xff) << 8)
+
+/* Internal Status and IRQ Control2(0x4A) */
+#define RT5631_ADC_DATA_SEL_MASK (0x3 << 14)
+#define RT5631_ADC_DATA_SEL_Disable (0x0 << 14)
+#define RT5631_ADC_DATA_SEL_MIC1 (0x1 << 14)
+#define RT5631_ADC_DATA_SEL_MIC1_SHIFT 14
+#define RT5631_ADC_DATA_SEL_MIC2 (0x2 << 14)
+#define RT5631_ADC_DATA_SEL_MIC2_SHIFT 15
+#define RT5631_ADC_DATA_SEL_STO (0x3 << 14)
+#define RT5631_ADC_DATA_SEL_SHIFT 14
+
+/* GPIO Pin Configuration(0x4C) */
+#define RT5631_GPIO_PIN_FUN_SEL_MASK (0x1 << 15)
+#define RT5631_GPIO_PIN_FUN_SEL_IRQ (0x1 << 15)
+#define RT5631_GPIO_PIN_FUN_SEL_GPIO_DIMC (0x0 << 15)
+
+#define RT5631_GPIO_DMIC_FUN_SEL_MASK (0x1 << 3)
+#define RT5631_GPIO_DMIC_FUN_SEL_DIMC (0x1 << 3)
+#define RT5631_GPIO_DMIC_FUN_SEL_GPIO (0x0 << 3)
+
+#define RT5631_GPIO_PIN_CON_MASK (0x1 << 2)
+#define RT5631_GPIO_PIN_SET_INPUT (0x0 << 2)
+#define RT5631_GPIO_PIN_SET_OUTPUT (0x1 << 2)
+
+/* De-POP function Control 1(0x54) */
+#define RT5631_POW_ON_SOFT_GEN (0x1 << 15)
+#define RT5631_EN_MUTE_UNMUTE_DEPOP (0x1 << 14)
+#define RT5631_EN_DEPOP2_FOR_HP (0x1 << 7)
+/* Power Down HPAMP_L Starts Up Signal */
+#define RT5631_PD_HPAMP_L_ST_UP (0x1 << 5)
+/* Power Down HPAMP_R Starts Up Signal */
+#define RT5631_PD_HPAMP_R_ST_UP (0x1 << 4)
+/* Enable left HP mute/unmute depop */
+#define RT5631_EN_HP_L_M_UN_MUTE_DEPOP (0x1 << 1)
+/* Enable right HP mute/unmute depop */
+#define RT5631_EN_HP_R_M_UN_MUTE_DEPOP (0x1 << 0)
+
+/* De-POP Fnction Control(0x56) */
+#define RT5631_EN_ONE_BIT_DEPOP (0x1 << 15)
+#define RT5631_EN_CAP_FREE_DEPOP (0x1 << 14)
+
+/* Jack Detect Control Register(0x5A) */
+#define RT5631_JD_USE_MASK (0x3 << 14)
+#define RT5631_JD_USE_JD2 (0x3 << 14)
+#define RT5631_JD_USE_JD1 (0x2 << 14)
+#define RT5631_JD_USE_GPIO (0x1 << 14)
+#define RT5631_JD_OFF (0x0 << 14)
+/* JD trigger enable for HP */
+#define RT5631_JD_HP_EN (0x1 << 11)
+#define RT5631_JD_HP_TRI_MASK (0x1 << 10)
+#define RT5631_JD_HP_TRI_HI (0x1 << 10)
+#define RT5631_JD_HP_TRI_LO (0x1 << 10)
+/* JD trigger enable for speaker LP/LN */
+#define RT5631_JD_SPK_L_EN (0x1 << 9)
+#define RT5631_JD_SPK_L_TRI_MASK (0x1 << 8)
+#define RT5631_JD_SPK_L_TRI_HI (0x1 << 8)
+#define RT5631_JD_SPK_L_TRI_LO (0x0 << 8)
+/* JD trigger enable for speaker RP/RN */
+#define RT5631_JD_SPK_R_EN (0x1 << 7)
+#define RT5631_JD_SPK_R_TRI_MASK (0x1 << 6)
+#define RT5631_JD_SPK_R_TRI_HI (0x1 << 6)
+#define RT5631_JD_SPK_R_TRI_LO (0x0 << 6)
+/* JD trigger enable for monoout */
+#define RT5631_JD_MONO_EN (0x1 << 5)
+#define RT5631_JD_MONO_TRI_MASK (0x1 << 4)
+#define RT5631_JD_MONO_TRI_HI (0x1 << 4)
+#define RT5631_JD_MONO_TRI_LO (0x0 << 4)
+/* JD trigger enable for Lout */
+#define RT5631_JD_AUX_1_EN (0x1 << 3)
+#define RT5631_JD_AUX_1_MASK (0x1 << 2)
+#define RT5631_JD_AUX_1_TRI_HI (0x1 << 2)
+#define RT5631_JD_AUX_1_TRI_LO (0x0 << 2)
+/* JD trigger enable for Rout */
+#define RT5631_JD_AUX_2_EN (0x1 << 1)
+#define RT5631_JD_AUX_2_MASK (0x1 << 0)
+#define RT5631_JD_AUX_2_TRI_HI (0x1 << 0)
+#define RT5631_JD_AUX_2_TRI_LO (0x0 << 0)
+
+/* ALC CONTROL 1(0x64) */
+#define RT5631_ALC_ATTACK_RATE_MASK (0x1F << 8)
+#define RT5631_ALC_RECOVERY_RATE_MASK (0x1F << 0)
+
+/* ALC CONTROL 2(0x65) */
+/* select Compensation gain for Noise gate function */
+#define RT5631_ALC_COM_NOISE_GATE_MASK (0xF << 0)
+
+/* ALC CONTROL 3(0x66) */
+#define RT5631_ALC_FUN_MASK (0x3 << 14)
+#define RT5631_ALC_FUN_DIS (0x0 << 14)
+#define RT5631_ALC_ENA_DAC_PATH (0x1 << 14)
+#define RT5631_ALC_ENA_ADC_PATH (0x3 << 14)
+#define RT5631_ALC_PARA_UPDATE (0x1 << 13)
+#define RT5631_ALC_LIMIT_LEVEL_MASK (0x1F << 8)
+#define RT5631_ALC_NOISE_GATE_FUN_MASK (0x1 << 7)
+#define RT5631_ALC_NOISE_GATE_FUN_DIS (0x0 << 7)
+#define RT5631_ALC_NOISE_GATE_FUN_ENA (0x1 << 7)
+/* ALC noise gate hold data function */
+#define RT5631_ALC_NOISE_GATE_H_D_MASK (0x1 << 6)
+#define RT5631_ALC_NOISE_GATE_H_D_DIS (0x0 << 6)
+#define RT5631_ALC_NOISE_GATE_H_D_ENA (0x1 << 6)
+
+/* Psedueo Stereo & Spatial Effect Block Control(0x68) */
+#define RT5631_SPATIAL_CTRL_EN (0x1 << 15)
+#define RT5631_ALL_PASS_FILTER_EN (0x1 << 14)
+#define RT5631_PSEUDO_STEREO_EN (0x1 << 13)
+#define RT5631_STEREO_EXPENSION_EN (0x1 << 12)
+/* 3D gain parameter */
+#define RT5631_GAIN_3D_PARA_MASK (0x3 << 6)
+#define RT5631_GAIN_3D_PARA_1_00 (0x0 << 6) /* 3D gain 1.0 */
+#define RT5631_GAIN_3D_PARA_1_50 (0x1 << 6) /* 3D gain 1.5 */
+#define RT5631_GAIN_3D_PARA_2_00 (0x2 << 6) /* 3D gain 2.0 */
+/* 3D ratio parameter */
+#define RT5631_RATIO_3D_MASK (0x3 << 4)
+#define RT5631_RATIO_3D_0_0 (0x0 << 4) /* 3D ratio 0.0 */
+#define RT5631_RATIO_3D_0_66 (0x1 << 4) /* 3D ratio 0.66 */
+#define RT5631_RATIO_3D_1_0 (0x2 << 4) /* 3D ratio 1.0 */
+/* select samplerate for all pass filter */
+#define RT5631_APF_FUN_SLE_MASK (0x3 << 0)
+#define RT5631_APF_FUN_SEL_48K (0x3 << 0)
+#define RT5631_APF_FUN_SEL_44_1K (0x2 << 0)
+#define RT5631_APF_FUN_SEL_32K (0x1 << 0)
+#define RT5631_APF_FUN_DIS (0x0 << 0)
+
+/* EQ CONTROL 1(0x6E) */
+#define RT5631_HW_EQ_PATH_SEL_MASK (0x1 << 15)
+#define RT5631_HW_EQ_PATH_SEL_DAC (0x0 << 15)
+#define RT5631_HW_EQ_PATH_SEL_ADC (0x1 << 15)
+#define RT5631_HW_EQ_UPDATE_CTRL (0x1 << 14)
+
+#define RT5631_EN_HW_EQ_HPF2 (0x1 << 5)
+#define RT5631_EN_HW_EQ_HPF1 (0x1 << 4)
+#define RT5631_EN_HW_EQ_BP3 (0x1 << 3)
+#define RT5631_EN_HW_EQ_BP2 (0x1 << 2)
+#define RT5631_EN_HW_EQ_BP1 (0x1 << 1)
+#define RT5631_EN_HW_EQ_LPF (0x1 << 0)
+
+
+#endif /* __RTCODEC5631_H__ */
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 7e4066e131e6..d15695d1c273 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -20,6 +20,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/consumer.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/tlv.h>
#include <sound/pcm.h>
@@ -130,16 +131,13 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
/* change mic bias resistor to 4Kohm */
snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
- SGTL5000_BIAS_R_4k, SGTL5000_BIAS_R_4k);
+ SGTL5000_BIAS_R_MASK,
+ SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT);
break;
case SND_SOC_DAPM_PRE_PMD:
- /*
- * SGTL5000_BIAS_R_8k as mask to clean the two bits
- * of mic bias and output impedance
- */
snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
- SGTL5000_BIAS_R_8k, 0);
+ SGTL5000_BIAS_R_MASK, 0);
break;
}
return 0;
@@ -725,7 +723,9 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- snd_soc_update_bits(codec, SGTL5000_CHIP_I2S_CTRL, i2s_ctl, i2s_ctl);
+ snd_soc_update_bits(codec, SGTL5000_CHIP_I2S_CTRL,
+ SGTL5000_I2S_DLEN_MASK | SGTL5000_I2S_SCLKFREQ_MASK,
+ i2s_ctl);
return 0;
}
@@ -756,7 +756,7 @@ static int ldo_regulator_enable(struct regulator_dev *dev)
/* set voltage to register */
snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
- (0x1 << 4) - 1, reg);
+ SGTL5000_LINREG_VDDD_MASK, reg);
snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
SGTL5000_LINEREG_D_POWERUP,
@@ -782,7 +782,7 @@ static int ldo_regulator_disable(struct regulator_dev *dev)
/* clear voltage info */
snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
- (0x1 << 4) - 1, 0);
+ SGTL5000_LINREG_VDDD_MASK, 0);
ldo->enabled = 0;
@@ -808,6 +808,7 @@ static int ldo_regulator_register(struct snd_soc_codec *codec,
int voltage)
{
struct ldo_regulator *ldo;
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
ldo = kzalloc(sizeof(struct ldo_regulator), GFP_KERNEL);
@@ -842,6 +843,7 @@ static int ldo_regulator_register(struct snd_soc_codec *codec,
return ret;
}
+ sgtl5000->ldo = ldo;
return 0;
}
@@ -1115,7 +1117,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
/* set voltage to register */
snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
- (0x1 << 4) - 1, 0x8);
+ SGTL5000_LINREG_VDDD_MASK, 0x8);
/*
* if vddd linear reg has been enabled,
@@ -1146,8 +1148,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
vag = (vag - SGTL5000_ANA_GND_BASE) / SGTL5000_ANA_GND_STP;
snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL,
- vag << SGTL5000_ANA_GND_SHIFT,
- vag << SGTL5000_ANA_GND_SHIFT);
+ SGTL5000_ANA_GND_MASK, vag << SGTL5000_ANA_GND_SHIFT);
/* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */
vag = vddio / 2;
@@ -1161,9 +1162,8 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
SGTL5000_LINE_OUT_GND_STP;
snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
- vag << SGTL5000_LINE_OUT_GND_SHIFT |
- SGTL5000_LINE_OUT_CURRENT_360u <<
- SGTL5000_LINE_OUT_CURRENT_SHIFT,
+ SGTL5000_LINE_OUT_CURRENT_MASK |
+ SGTL5000_LINE_OUT_GND_MASK,
vag << SGTL5000_LINE_OUT_GND_SHIFT |
SGTL5000_LINE_OUT_CURRENT_360u <<
SGTL5000_LINE_OUT_CURRENT_SHIFT);
@@ -1436,10 +1436,17 @@ static const struct i2c_device_id sgtl5000_id[] = {
MODULE_DEVICE_TABLE(i2c, sgtl5000_id);
+static const struct of_device_id sgtl5000_dt_ids[] = {
+ { .compatible = "fsl,sgtl5000", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sgtl5000_dt_ids);
+
static struct i2c_driver sgtl5000_i2c_driver = {
.driver = {
.name = "sgtl5000",
.owner = THIS_MODULE,
+ .of_match_table = sgtl5000_dt_ids,
},
.probe = sgtl5000_i2c_probe,
.remove = __devexit_p(sgtl5000_i2c_remove),
diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h
index eec3ab368f39..8a9f43534b79 100644
--- a/sound/soc/codecs/sgtl5000.h
+++ b/sound/soc/codecs/sgtl5000.h
@@ -280,7 +280,7 @@
/*
* SGTL5000_CHIP_MIC_CTRL
*/
-#define SGTL5000_BIAS_R_MASK 0x0200
+#define SGTL5000_BIAS_R_MASK 0x0300
#define SGTL5000_BIAS_R_SHIFT 8
#define SGTL5000_BIAS_R_WIDTH 2
#define SGTL5000_BIAS_R_off 0x0
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
index 84ffdebb8a8b..887d618f4a63 100644
--- a/sound/soc/codecs/sn95031.c
+++ b/sound/soc/codecs/sn95031.c
@@ -28,6 +28,7 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <asm/intel_scu_ipc.h>
#include <sound/pcm.h>
@@ -79,7 +80,7 @@ static void configure_adc(struct snd_soc_codec *sn95031_codec, int val)
*/
static int find_free_channel(struct snd_soc_codec *sn95031_codec)
{
- int ret = 0, i, value;
+ int i, value;
/* check whether ADC is enabled */
value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1);
@@ -91,12 +92,10 @@ static int find_free_channel(struct snd_soc_codec *sn95031_codec)
for (i = 0; i < SN95031_ADC_CHANLS_MAX; i++) {
value = snd_soc_read(sn95031_codec,
SN95031_ADC_CHNL_START_ADDR + i);
- if (value & SN95031_STOPBIT_MASK) {
- ret = i;
+ if (value & SN95031_STOPBIT_MASK)
break;
- }
}
- return (ret > SN95031_ADC_LOOP_MAX) ? (-EINVAL) : ret;
+ return (i == SN95031_ADC_CHANLS_MAX) ? (-EINVAL) : i;
}
/* Initialize the ADC for reading micbias values. Can sleep. */
@@ -104,7 +103,7 @@ static int sn95031_initialize_adc(struct snd_soc_codec *sn95031_codec)
{
int base_addr, chnl_addr;
int value;
- static int channel_index;
+ int channel_index;
/* Index of the first channel in which the stop bit is set */
channel_index = find_free_channel(sn95031_codec);
@@ -163,7 +162,6 @@ static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec)
pr_debug("mic bias = %dmV\n", mic_bias);
return mic_bias;
}
-EXPORT_SYMBOL_GPL(sn95031_get_mic_bias);
/*end - adc helper functions */
static inline unsigned int sn95031_read(struct snd_soc_codec *codec,
@@ -660,7 +658,7 @@ static int sn95031_pcm_spkr_mute(struct snd_soc_dai *dai, int mute)
return 0;
}
-int sn95031_pcm_hw_params(struct snd_pcm_substream *substream,
+static int sn95031_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
unsigned int format, rate;
@@ -718,7 +716,7 @@ static struct snd_soc_dai_ops sn95031_vib2_dai_ops = {
.hw_params = sn95031_pcm_hw_params,
};
-struct snd_soc_dai_driver sn95031_dais[] = {
+static struct snd_soc_dai_driver sn95031_dais[] = {
{
.name = "SN95031 Headset",
.playback = {
@@ -829,7 +827,6 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
{
pr_debug("codec_probe called\n");
- codec->dapm.bias_level = SND_SOC_BIAS_OFF;
codec->dapm.idle_bias_off = 1;
/* PCM interface config
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 9801cd7cfcb5..3cb3271c5fe2 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -59,6 +59,7 @@ struct ssm2602_priv {
struct snd_pcm_substream *slave_substream;
enum ssm2602_type type;
+ unsigned int clk_out_pwr;
};
/*
@@ -294,7 +295,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
- struct i2c_client *i2c = codec->control_data;
struct snd_pcm_runtime *master_runtime;
/* The DAI has shared clocks so if we already have a playback or
@@ -303,7 +303,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
*/
if (ssm2602->master_substream) {
master_runtime = ssm2602->master_substream->runtime;
- dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n",
+ dev_dbg(codec->dev, "Constraining to %d bits at %dHz\n",
master_runtime->sample_bits,
master_runtime->rate);
@@ -343,12 +343,14 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- u16 mute_reg = snd_soc_read(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
+
if (mute)
- snd_soc_write(codec, SSM2602_APDIGI,
- mute_reg | APDIGI_ENABLE_DAC_MUTE);
+ snd_soc_update_bits(codec, SSM2602_APDIGI,
+ APDIGI_ENABLE_DAC_MUTE,
+ APDIGI_ENABLE_DAC_MUTE);
else
- snd_soc_write(codec, SSM2602_APDIGI, mute_reg);
+ snd_soc_update_bits(codec, SSM2602_APDIGI,
+ APDIGI_ENABLE_DAC_MUTE, 0);
return 0;
}
@@ -357,16 +359,46 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
{
struct snd_soc_codec *codec = codec_dai->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
- switch (freq) {
- case 11289600:
- case 12000000:
- case 12288000:
- case 16934400:
- case 18432000:
- ssm2602->sysclk = freq;
- return 0;
+
+ if (dir == SND_SOC_CLOCK_IN) {
+ if (clk_id != SSM2602_SYSCLK)
+ return -EINVAL;
+
+ switch (freq) {
+ case 11289600:
+ case 12000000:
+ case 12288000:
+ case 16934400:
+ case 18432000:
+ ssm2602->sysclk = freq;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ unsigned int mask;
+
+ switch (clk_id) {
+ case SSM2602_CLK_CLKOUT:
+ mask = PWR_CLK_OUT_PDN;
+ break;
+ case SSM2602_CLK_XTO:
+ mask = PWR_OSC_PDN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (freq == 0)
+ ssm2602->clk_out_pwr |= mask;
+ else
+ ssm2602->clk_out_pwr &= ~mask;
+
+ snd_soc_update_bits(codec, SSM2602_PWR,
+ PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr);
}
- return -EINVAL;
+
+ return 0;
}
static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
@@ -431,23 +463,27 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 reg = snd_soc_read(codec, SSM2602_PWR);
- reg &= ~(PWR_POWER_OFF | PWR_OSC_PDN);
+ struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
switch (level) {
case SND_SOC_BIAS_ON:
- /* vref/mid, osc on, dac unmute */
- snd_soc_write(codec, SSM2602_PWR, reg);
+ /* vref/mid on, osc and clkout on if enabled */
+ snd_soc_update_bits(codec, SSM2602_PWR,
+ PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
+ ssm2602->clk_out_pwr);
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
/* everything off except vref/vmid, */
- snd_soc_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
+ snd_soc_update_bits(codec, SSM2602_PWR,
+ PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
+ PWR_CLK_OUT_PDN | PWR_OSC_PDN);
break;
case SND_SOC_BIAS_OFF:
- /* everything off, dac mute, inactive */
- snd_soc_write(codec, SSM2602_PWR, 0xffff);
+ /* everything off */
+ snd_soc_update_bits(codec, SSM2602_PWR,
+ PWR_POWER_OFF, PWR_POWER_OFF);
break;
}
@@ -506,12 +542,12 @@ static int ssm2602_resume(struct snd_soc_codec *codec)
static int ssm2602_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret, reg;
+ int ret;
- reg = snd_soc_read(codec, SSM2602_LOUT1V);
- snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
- reg = snd_soc_read(codec, SSM2602_ROUT1V);
- snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
+ snd_soc_update_bits(codec, SSM2602_LOUT1V,
+ LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH);
+ snd_soc_update_bits(codec, SSM2602_ROUT1V,
+ ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);
ret = snd_soc_add_controls(codec, ssm2602_snd_controls,
ARRAY_SIZE(ssm2602_snd_controls));
@@ -544,7 +580,7 @@ static int ssm2604_probe(struct snd_soc_codec *codec)
static int ssm260x_probe(struct snd_soc_codec *codec)
{
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
- int ret, reg;
+ int ret;
pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
@@ -561,10 +597,10 @@ static int ssm260x_probe(struct snd_soc_codec *codec)
}
/* set the update bits */
- reg = snd_soc_read(codec, SSM2602_LINVOL);
- snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
- reg = snd_soc_read(codec, SSM2602_RINVOL);
- snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
+ snd_soc_update_bits(codec, SSM2602_LINVOL,
+ LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH);
+ snd_soc_update_bits(codec, SSM2602_RINVOL,
+ RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH);
/*select Line in as default input*/
snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
APANA_ENABLE_MIC_BOOST);
@@ -578,7 +614,12 @@ static int ssm260x_probe(struct snd_soc_codec *codec)
break;
}
- return ret;
+ if (ret)
+ return ret;
+
+ ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
}
/* remove everything here */
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h
index b98c69168036..fbd07d7b73ca 100644
--- a/sound/soc/codecs/ssm2602.h
+++ b/sound/soc/codecs/ssm2602.h
@@ -116,6 +116,10 @@
#define SSM2602_CACHEREGNUM 10
-#define SSM2602_SYSCLK 0
+enum ssm2602_clk {
+ SSM2602_SYSCLK,
+ SSM2602_CLK_CLKOUT,
+ SSM2602_CLK_XTO
+};
#endif
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index fbd7eb9e61ce..bb82408ab8e1 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -524,13 +524,17 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
rate = params_rate(params);
pr_debug("rate: %u\n", rate);
for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++)
- if (interpolation_ratios[i].fs == rate)
+ if (interpolation_ratios[i].fs == rate) {
ir = interpolation_ratios[i].ir;
+ break;
+ }
if (ir < 0)
return -EINVAL;
for (i = 0; mclk_ratios[ir][i].ratio; i++)
- if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk)
+ if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) {
mcs = mclk_ratios[ir][i].mcs;
+ break;
+ }
if (mcs < 0)
return -EINVAL;
@@ -752,25 +756,19 @@ static int sta32x_probe(struct snd_soc_codec *codec)
return ret;
}
- /* read reg reset values into cache */
- for (i = 0; i < STA32X_REGISTER_COUNT; i++)
- snd_soc_cache_write(codec, i, sta32x_regs[i]);
-
- /* preserve reset values of reserved register bits */
- snd_soc_cache_write(codec, STA32X_CONFC,
- codec->hw_read(codec, STA32X_CONFC));
- snd_soc_cache_write(codec, STA32X_CONFE,
- codec->hw_read(codec, STA32X_CONFE));
- snd_soc_cache_write(codec, STA32X_CONFF,
- codec->hw_read(codec, STA32X_CONFF));
- snd_soc_cache_write(codec, STA32X_MMUTE,
- codec->hw_read(codec, STA32X_MMUTE));
- snd_soc_cache_write(codec, STA32X_AUTO1,
- codec->hw_read(codec, STA32X_AUTO1));
- snd_soc_cache_write(codec, STA32X_AUTO3,
- codec->hw_read(codec, STA32X_AUTO3));
- snd_soc_cache_write(codec, STA32X_C3CFG,
- codec->hw_read(codec, STA32X_C3CFG));
+ /* Chip documentation explicitly requires that the reset values
+ * of reserved register bits are left untouched.
+ * Write the register default value to cache for reserved registers,
+ * so the write to the these registers are suppressed by the cache
+ * restore code when it skips writes of default registers.
+ */
+ snd_soc_cache_write(codec, STA32X_CONFC, 0xc2);
+ snd_soc_cache_write(codec, STA32X_CONFE, 0xc2);
+ snd_soc_cache_write(codec, STA32X_CONFF, 0x5c);
+ snd_soc_cache_write(codec, STA32X_MMUTE, 0x10);
+ snd_soc_cache_write(codec, STA32X_AUTO1, 0x60);
+ snd_soc_cache_write(codec, STA32X_AUTO3, 0x00);
+ snd_soc_cache_write(codec, STA32X_C3CFG, 0x40);
/* FIXME enable thermal warning adjustment and recovery */
snd_soc_update_bits(codec, STA32X_CONFA,
@@ -808,6 +806,7 @@ static int sta32x_remove(struct snd_soc_codec *codec)
{
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+ sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
@@ -832,6 +831,7 @@ static const struct snd_soc_codec_driver sta32x_codec = {
.resume = sta32x_resume,
.reg_cache_size = STA32X_REGISTER_COUNT,
.reg_word_size = sizeof(u8),
+ .reg_cache_default = sta32x_regs,
.volatile_register = sta32x_reg_is_volatile,
.set_bias_level = sta32x_set_bias_level,
.controls = sta32x_snd_controls,
@@ -867,18 +867,8 @@ static __devinit int sta32x_i2c_probe(struct i2c_client *i2c,
static __devexit int sta32x_i2c_remove(struct i2c_client *client)
{
struct sta32x_priv *sta32x = i2c_get_clientdata(client);
- struct snd_soc_codec *codec = sta32x->codec;
-
- if (codec)
- sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
-
- if (codec) {
- snd_soc_unregister_codec(&client->dev);
- snd_soc_codec_set_drvdata(codec, NULL);
- }
+ snd_soc_unregister_codec(&client->dev);
kfree(sta32x);
return 0;
}
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 33bb52f3f683..336de8f69a02 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -47,63 +47,6 @@ static const u16 tlv320aic23_reg[] = {
0x0000, 0x0000, 0x0000, 0x0000, /* 12 */
};
-/*
- * read tlv320aic23 register cache
- */
-static inline unsigned int tlv320aic23_read_reg_cache(struct snd_soc_codec
- *codec, unsigned int reg)
-{
- u16 *cache = codec->reg_cache;
- if (reg >= ARRAY_SIZE(tlv320aic23_reg))
- return -1;
- return cache[reg];
-}
-
-/*
- * write tlv320aic23 register cache
- */
-static inline void tlv320aic23_write_reg_cache(struct snd_soc_codec *codec,
- u8 reg, u16 value)
-{
- u16 *cache = codec->reg_cache;
- if (reg >= ARRAY_SIZE(tlv320aic23_reg))
- return;
- cache[reg] = value;
-}
-
-/*
- * write to the tlv320aic23 register space
- */
-static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
-
- u8 data[2];
-
- /* TLV320AIC23 has 7 bit address and 9 bits of data
- * so we need to switch one data bit into reg and rest
- * of data into val
- */
-
- if (reg > 9 && reg != 15) {
- printk(KERN_WARNING "%s Invalid register R%u\n", __func__, reg);
- return -1;
- }
-
- data[0] = (reg << 1) | (value >> 8 & 0x01);
- data[1] = value & 0xff;
-
- tlv320aic23_write_reg_cache(codec, reg, value);
-
- if (codec->hw_write(codec->control_data, data, 2) == 2)
- return 0;
-
- printk(KERN_ERR "%s cannot write %03x to register R%u\n", __func__,
- value, reg);
-
- return -EIO;
-}
-
static const char *rec_src_text[] = { "Line", "Mic" };
static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
@@ -139,8 +82,8 @@ static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
*/
val = (val >= 4) ? 4 : (3 - val);
- reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (~0x1C0);
- tlv320aic23_write(codec, TLV320AIC23_ANLG, reg | (val << 6));
+ reg = snd_soc_read(codec, TLV320AIC23_ANLG) & (~0x1C0);
+ snd_soc_write(codec, TLV320AIC23_ANLG, reg | (val << 6));
return 0;
}
@@ -151,7 +94,7 @@ static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
u16 val;
- val = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (0x1C0);
+ val = snd_soc_read(codec, TLV320AIC23_ANLG) & (0x1C0);
val = val >> 6;
val = (val >= 4) ? 4 : (3 - val);
ucontrol->value.integer.value[0] = val;
@@ -159,15 +102,6 @@ static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
}
-#define SOC_TLV320AIC23_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
- SNDRV_CTL_ELEM_ACCESS_READWRITE,\
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw, .get = snd_soc_tlv320aic23_get_volsw,\
- .put = snd_soc_tlv320aic23_put_volsw, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
-
static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL,
TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv),
@@ -178,8 +112,9 @@ static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv),
SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1),
SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0),
- SOC_TLV320AIC23_SINGLE_TLV("Sidetone Volume", TLV320AIC23_ANLG,
- 6, 4, 0, sidetone_vol_tlv),
+ SOC_SINGLE_EXT_TLV("Sidetone Volume", TLV320AIC23_ANLG, 6, 4, 0,
+ snd_soc_tlv320aic23_get_volsw,
+ snd_soc_tlv320aic23_put_volsw, sidetone_vol_tlv),
SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
};
@@ -240,7 +175,6 @@ static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {
/* AIC23 driver data */
struct aic23 {
enum snd_soc_control_type control_type;
- void *control_data;
int mclk;
int requested_adc;
int requested_dac;
@@ -352,7 +286,7 @@ static int find_rate(int mclk, u32 need_adc, u32 need_dac)
static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk,
u32 *sample_rate_adc, u32 *sample_rate_dac)
{
- int src = tlv320aic23_read_reg_cache(codec, TLV320AIC23_SRATE);
+ int src = snd_soc_read(codec, TLV320AIC23_SRATE);
int sr = (src >> 2) & 0x0f;
int val = (mclk / bosr_usb_divisor_table[src & 3]);
int adc = (val * sr_adc_mult_table[sr]) / SR_MULT;
@@ -376,7 +310,7 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
__func__, sample_rate_adc, sample_rate_dac);
return -EINVAL;
}
- tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
+ snd_soc_write(codec, TLV320AIC23_SRATE, data);
#ifdef DEBUG
{
u32 adc, dac;
@@ -415,9 +349,8 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- iface_reg =
- tlv320aic23_read_reg_cache(codec,
- TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
+ iface_reg = snd_soc_read(codec, TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
+
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
break;
@@ -431,7 +364,7 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
iface_reg |= (0x03 << 2);
break;
}
- tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+ snd_soc_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
return 0;
}
@@ -443,7 +376,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec;
/* set active */
- tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
+ snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0001);
return 0;
}
@@ -458,7 +391,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
/* deactivate */
if (!codec->active) {
udelay(50);
- tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+ snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0);
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
aic23->requested_dac = 0;
@@ -471,14 +404,14 @@ static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
struct snd_soc_codec *codec = dai->codec;
u16 reg;
- reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT);
+ reg = snd_soc_read(codec, TLV320AIC23_DIGT);
if (mute)
reg |= TLV320AIC23_DACM_MUTE;
else
reg &= ~TLV320AIC23_DACM_MUTE;
- tlv320aic23_write(codec, TLV320AIC23_DIGT, reg);
+ snd_soc_write(codec, TLV320AIC23_DIGT, reg);
return 0;
}
@@ -489,8 +422,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
struct snd_soc_codec *codec = codec_dai->codec;
u16 iface_reg;
- iface_reg =
- tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & (~0x03);
+ iface_reg = snd_soc_read(codec, TLV320AIC23_DIGT_FMT) & (~0x03);
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -498,6 +430,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
iface_reg |= TLV320AIC23_MS_MASTER;
break;
case SND_SOC_DAIFMT_CBS_CFS:
+ iface_reg &= ~TLV320AIC23_MS_MASTER;
break;
default:
return -EINVAL;
@@ -524,7 +457,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
}
- tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+ snd_soc_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
return 0;
}
@@ -540,26 +473,26 @@ static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_PWR) & 0xff7f;
+ u16 reg = snd_soc_read(codec, TLV320AIC23_PWR) & 0xff7f;
switch (level) {
case SND_SOC_BIAS_ON:
/* vref/mid, osc on, dac unmute */
reg &= ~(TLV320AIC23_DEVICE_PWR_OFF | TLV320AIC23_OSC_OFF | \
TLV320AIC23_DAC_OFF);
- tlv320aic23_write(codec, TLV320AIC23_PWR, reg);
+ snd_soc_write(codec, TLV320AIC23_PWR, reg);
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
/* everything off except vref/vmid, */
- tlv320aic23_write(codec, TLV320AIC23_PWR, reg | \
- TLV320AIC23_CLK_OFF);
+ snd_soc_write(codec, TLV320AIC23_PWR,
+ reg | TLV320AIC23_CLK_OFF);
break;
case SND_SOC_BIAS_OFF:
/* everything off, dac mute, inactive */
- tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
- tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff);
+ snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0);
+ snd_soc_write(codec, TLV320AIC23_PWR, 0xffff);
break;
}
codec->dapm.bias_level = level;
@@ -606,13 +539,7 @@ static int tlv320aic23_suspend(struct snd_soc_codec *codec,
static int tlv320aic23_resume(struct snd_soc_codec *codec)
{
- u16 reg;
-
- /* Sync reg_cache with the hardware */
- for (reg = 0; reg <= TLV320AIC23_ACTIVE; reg++) {
- u16 val = tlv320aic23_read_reg_cache(codec, reg);
- tlv320aic23_write(codec, reg, val);
- }
+ snd_soc_cache_sync(codec);
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -621,46 +548,52 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec)
static int tlv320aic23_probe(struct snd_soc_codec *codec)
{
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
- int reg;
+ int ret;
printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
- codec->control_data = aic23->control_data;
- codec->hw_write = (hw_write_t)i2c_master_send;
- codec->hw_read = NULL;
+
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, aic23->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
/* Reset codec */
- tlv320aic23_write(codec, TLV320AIC23_RESET, 0);
+ snd_soc_write(codec, TLV320AIC23_RESET, 0);
+
+ /* Write the register default value to cache for reserved registers,
+ * so the write to the these registers are suppressed by the cache
+ * restore code when it skips writes of default registers.
+ */
+ snd_soc_cache_write(codec, 0x0A, 0);
+ snd_soc_cache_write(codec, 0x0B, 0);
+ snd_soc_cache_write(codec, 0x0C, 0);
+ snd_soc_cache_write(codec, 0x0D, 0);
+ snd_soc_cache_write(codec, 0x0E, 0);
/* power on device */
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- tlv320aic23_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
+ snd_soc_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
/* Unmute input */
- reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_LINVOL);
- tlv320aic23_write(codec, TLV320AIC23_LINVOL,
- (reg & (~TLV320AIC23_LIM_MUTED)) |
- (TLV320AIC23_LRS_ENABLED));
+ snd_soc_update_bits(codec, TLV320AIC23_LINVOL,
+ TLV320AIC23_LIM_MUTED, TLV320AIC23_LRS_ENABLED);
- reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_RINVOL);
- tlv320aic23_write(codec, TLV320AIC23_RINVOL,
- (reg & (~TLV320AIC23_LIM_MUTED)) |
- TLV320AIC23_LRS_ENABLED);
+ snd_soc_update_bits(codec, TLV320AIC23_RINVOL,
+ TLV320AIC23_LIM_MUTED, TLV320AIC23_LRS_ENABLED);
- reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG);
- tlv320aic23_write(codec, TLV320AIC23_ANLG,
- (reg) & (~TLV320AIC23_BYPASS_ON) &
- (~TLV320AIC23_MICM_MUTED));
+ snd_soc_update_bits(codec, TLV320AIC23_ANLG,
+ TLV320AIC23_BYPASS_ON | TLV320AIC23_MICM_MUTED,
+ 0);
/* Default output volume */
- tlv320aic23_write(codec, TLV320AIC23_LCHNVOL,
- TLV320AIC23_DEFAULT_OUT_VOL &
- TLV320AIC23_OUT_VOL_MASK);
- tlv320aic23_write(codec, TLV320AIC23_RCHNVOL,
- TLV320AIC23_DEFAULT_OUT_VOL &
- TLV320AIC23_OUT_VOL_MASK);
+ snd_soc_write(codec, TLV320AIC23_LCHNVOL,
+ TLV320AIC23_DEFAULT_OUT_VOL & TLV320AIC23_OUT_VOL_MASK);
+ snd_soc_write(codec, TLV320AIC23_RCHNVOL,
+ TLV320AIC23_DEFAULT_OUT_VOL & TLV320AIC23_OUT_VOL_MASK);
- tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1);
+ snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x1);
snd_soc_add_controls(codec, tlv320aic23_snd_controls,
ARRAY_SIZE(tlv320aic23_snd_controls));
@@ -682,8 +615,6 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
.remove = tlv320aic23_remove,
.suspend = tlv320aic23_suspend,
.resume = tlv320aic23_resume,
- .read = tlv320aic23_read_reg_cache,
- .write = tlv320aic23_write,
.set_bias_level = tlv320aic23_set_bias_level,
.dapm_widgets = tlv320aic23_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
@@ -710,7 +641,6 @@ static int tlv320aic23_codec_probe(struct i2c_client *i2c,
return -ENOMEM;
i2c_set_clientdata(i2c, aic23);
- aic23->control_data = i2c;
aic23->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev,
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index e93b9d1ae1dd..b21c610051c0 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -528,40 +528,33 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
- u8 value;
switch (level) {
case SND_SOC_BIAS_ON:
if (aic32x4->master) {
/* Switch on PLL */
- value = snd_soc_read(codec, AIC32X4_PLLPR);
- snd_soc_write(codec, AIC32X4_PLLPR,
- (value | AIC32X4_PLLEN));
+ snd_soc_update_bits(codec, AIC32X4_PLLPR,
+ AIC32X4_PLLEN, AIC32X4_PLLEN);
/* Switch on NDAC Divider */
- value = snd_soc_read(codec, AIC32X4_NDAC);
- snd_soc_write(codec, AIC32X4_NDAC,
- value | AIC32X4_NDACEN);
+ snd_soc_update_bits(codec, AIC32X4_NDAC,
+ AIC32X4_NDACEN, AIC32X4_NDACEN);
/* Switch on MDAC Divider */
- value = snd_soc_read(codec, AIC32X4_MDAC);
- snd_soc_write(codec, AIC32X4_MDAC,
- value | AIC32X4_MDACEN);
+ snd_soc_update_bits(codec, AIC32X4_MDAC,
+ AIC32X4_MDACEN, AIC32X4_MDACEN);
/* Switch on NADC Divider */
- value = snd_soc_read(codec, AIC32X4_NADC);
- snd_soc_write(codec, AIC32X4_NADC,
- value | AIC32X4_MDACEN);
+ snd_soc_update_bits(codec, AIC32X4_NADC,
+ AIC32X4_NADCEN, AIC32X4_NADCEN);
/* Switch on MADC Divider */
- value = snd_soc_read(codec, AIC32X4_MADC);
- snd_soc_write(codec, AIC32X4_MADC,
- value | AIC32X4_MDACEN);
+ snd_soc_update_bits(codec, AIC32X4_MADC,
+ AIC32X4_MADCEN, AIC32X4_MADCEN);
/* Switch on BCLK_N Divider */
- value = snd_soc_read(codec, AIC32X4_BCLKN);
- snd_soc_write(codec, AIC32X4_BCLKN,
- value | AIC32X4_BCLKEN);
+ snd_soc_update_bits(codec, AIC32X4_BCLKN,
+ AIC32X4_BCLKEN, AIC32X4_BCLKEN);
}
break;
case SND_SOC_BIAS_PREPARE:
@@ -569,34 +562,28 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
if (aic32x4->master) {
/* Switch off PLL */
- value = snd_soc_read(codec, AIC32X4_PLLPR);
- snd_soc_write(codec, AIC32X4_PLLPR,
- (value & ~AIC32X4_PLLEN));
+ snd_soc_update_bits(codec, AIC32X4_PLLPR,
+ AIC32X4_PLLEN, 0);
/* Switch off NDAC Divider */
- value = snd_soc_read(codec, AIC32X4_NDAC);
- snd_soc_write(codec, AIC32X4_NDAC,
- value & ~AIC32X4_NDACEN);
+ snd_soc_update_bits(codec, AIC32X4_NDAC,
+ AIC32X4_NDACEN, 0);
/* Switch off MDAC Divider */
- value = snd_soc_read(codec, AIC32X4_MDAC);
- snd_soc_write(codec, AIC32X4_MDAC,
- value & ~AIC32X4_MDACEN);
+ snd_soc_update_bits(codec, AIC32X4_MDAC,
+ AIC32X4_MDACEN, 0);
/* Switch off NADC Divider */
- value = snd_soc_read(codec, AIC32X4_NADC);
- snd_soc_write(codec, AIC32X4_NADC,
- value & ~AIC32X4_NDACEN);
+ snd_soc_update_bits(codec, AIC32X4_NADC,
+ AIC32X4_NADCEN, 0);
/* Switch off MADC Divider */
- value = snd_soc_read(codec, AIC32X4_MADC);
- snd_soc_write(codec, AIC32X4_MADC,
- value & ~AIC32X4_MDACEN);
- value = snd_soc_read(codec, AIC32X4_BCLKN);
+ snd_soc_update_bits(codec, AIC32X4_MADC,
+ AIC32X4_MADCEN, 0);
/* Switch off BCLK_N Divider */
- snd_soc_write(codec, AIC32X4_BCLKN,
- value & ~AIC32X4_BCLKEN);
+ snd_soc_update_bits(codec, AIC32X4_BCLKN,
+ AIC32X4_BCLKEN, 0);
}
break;
case SND_SOC_BIAS_OFF:
@@ -685,10 +672,10 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
}
/* Mic PGA routing */
- if (aic32x4->micpga_routing | AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) {
+ if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) {
snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K);
}
- if (aic32x4->micpga_routing | AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) {
+ if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) {
snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K);
}
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 0963c4c7a83f..87d5ef188e29 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -76,7 +76,6 @@ struct aic3x_priv {
struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
enum snd_soc_control_type control_type;
struct aic3x_setup_data *setup;
- void *control_data;
unsigned int sysclk;
struct list_head list;
int master;
@@ -138,7 +137,10 @@ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
if (reg >= AIC3X_CACHEREGNUM)
return -1;
- *value = codec->hw_read(codec, reg);
+ codec->cache_bypass = 1;
+ *value = snd_soc_read(codec, reg);
+ codec->cache_bypass = 0;
+
cache[reg] = *value;
return 0;
@@ -198,6 +200,10 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
else
/* old connection must be powered down */
path->connect = invert ? 1 : 0;
+
+ dapm_mark_dirty(path->source, "tlv320aic3x source");
+ dapm_mark_dirty(path->sink, "tlv320aic3x sink");
+
break;
}
@@ -1017,6 +1023,7 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
break;
case SND_SOC_DAIFMT_CBS_CFS:
aic3x->master = 0;
+ iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER);
break;
default:
return -EINVAL;
@@ -1383,7 +1390,6 @@ static int aic3x_probe(struct snd_soc_codec *codec)
int ret, i;
INIT_LIST_HEAD(&aic3x->list);
- codec->control_data = aic3x->control_data;
aic3x->codec = codec;
codec->dapm.idle_bias_off = 1;
@@ -1495,9 +1501,9 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
*/
static const struct i2c_device_id aic3x_i2c_id[] = {
- [AIC3X_MODEL_3X] = { "tlv320aic3x", 0 },
- [AIC3X_MODEL_33] = { "tlv320aic33", 0 },
- [AIC3X_MODEL_3007] = { "tlv320aic3007", 0 },
+ { "tlv320aic3x", AIC3X_MODEL_3X },
+ { "tlv320aic33", AIC3X_MODEL_33 },
+ { "tlv320aic3007", AIC3X_MODEL_3007 },
{ }
};
MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
@@ -1512,7 +1518,6 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
struct aic3x_pdata *pdata = i2c->dev.platform_data;
struct aic3x_priv *aic3x;
int ret;
- const struct i2c_device_id *tbl;
aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
if (aic3x == NULL) {
@@ -1520,7 +1525,6 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
}
- aic3x->control_data = i2c;
aic3x->control_type = SND_SOC_I2C;
i2c_set_clientdata(i2c, aic3x);
@@ -1531,11 +1535,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
aic3x->gpio_reset = -1;
}
- for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) {
- if (!strcmp(tbl->name, id->name))
- break;
- }
- aic3x->model = tbl - aic3x_i2c_id;
+ aic3x->model = id->driver_data;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_aic3x, &aic3x_dai, 1);
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index faa5e9fb1471..dc8a2b2bdc1c 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -55,13 +55,13 @@
#define BURST_BASEFREQ_HZ 49152000
#define SAMPLES_TO_US(rate, samples) \
- (1000000000 / ((rate * 1000) / samples))
+ (1000000000 / (((rate) * 1000) / (samples)))
#define US_TO_SAMPLES(rate, us) \
- (rate / (1000000 / (us < 1000000 ? us : 1000000)))
+ ((rate) / (1000000 / ((us) < 1000000 ? (us) : 1000000)))
#define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \
- ((samples * 5000) / ((burstrate * 5000) / (burstrate - playrate)))
+ (((samples)*5000) / (((burstrate)*5000) / ((burstrate) - (playrate))))
static void dac33_calculate_times(struct snd_pcm_substream *substream);
static int dac33_prepare_chip(struct snd_pcm_substream *substream);
@@ -627,18 +627,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"RIGHT_LO", NULL, "Codec Power"},
};
-static int dac33_add_widgets(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- snd_soc_dapm_new_controls(dapm, dac33_dapm_widgets,
- ARRAY_SIZE(dac33_dapm_widgets));
- /* set up audio path interconnects */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- return 0;
-}
-
static int dac33_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
@@ -1431,7 +1419,7 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
/* Check if the IRQ number is valid and request it */
if (dac33->irq >= 0) {
ret = request_irq(dac33->irq, dac33_interrupt_handler,
- IRQF_TRIGGER_RISING | IRQF_DISABLED,
+ IRQF_TRIGGER_RISING,
codec->name, codec);
if (ret < 0) {
dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
@@ -1451,15 +1439,11 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
}
}
- snd_soc_add_controls(codec, dac33_snd_controls,
- ARRAY_SIZE(dac33_snd_controls));
/* Only add the FIFO controls, if we have valid IRQ number */
if (dac33->irq >= 0)
snd_soc_add_controls(codec, dac33_mode_snd_controls,
ARRAY_SIZE(dac33_mode_snd_controls));
- dac33_add_widgets(codec);
-
err_power:
return ret;
}
@@ -1502,6 +1486,13 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
.remove = dac33_soc_remove,
.suspend = dac33_soc_suspend,
.resume = dac33_soc_resume,
+
+ .controls = dac33_snd_controls,
+ .num_controls = ARRAY_SIZE(dac33_snd_controls),
+ .dapm_widgets = dac33_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(dac33_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
#define DAC33_RATES (SNDRV_PCM_RATE_44100 | \
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 239e0c461068..7eeca79d7387 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -33,6 +33,11 @@
#include "tpa6130a2.h"
+enum tpa_model {
+ TPA6130A2,
+ TPA6140A2,
+};
+
static struct i2c_client *tpa6130a2_client;
/* This struct is used to save the context */
@@ -383,7 +388,7 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
pdata = client->dev.platform_data;
data->power_gpio = pdata->power_gpio;
- data->id = pdata->id;
+ data->id = id->driver_data;
mutex_init(&data->mutex);
@@ -405,7 +410,7 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
switch (data->id) {
default:
dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
- pdata->id);
+ data->id);
case TPA6130A2:
regulator = "Vdd";
break;
@@ -446,7 +451,6 @@ err_regulator:
gpio_free(data->power_gpio);
err_gpio:
kfree(data);
- i2c_set_clientdata(tpa6130a2_client, NULL);
tpa6130a2_client = NULL;
return ret;
@@ -470,7 +474,8 @@ static int __devexit tpa6130a2_remove(struct i2c_client *client)
}
static const struct i2c_device_id tpa6130a2_id[] = {
- { "tpa6130a2", 0 },
+ { "tpa6130a2", TPA6130A2 },
+ { "tpa6140a2", TPA6140A2 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tpa6130a2_id);
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 71674bec9604..f798247ac1b2 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -863,34 +863,6 @@ static int digimic_event(struct snd_soc_dapm_widget *w,
* Inverting not going to help with these.
* Custom volsw and volsw_2r get/put functions to handle these gain bits.
*/
-#define SOC_DOUBLE_TLV_TWL4030(xname, xreg, shift_left, shift_right, xmax,\
- xinvert, tlv_array) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
- SNDRV_CTL_ELEM_ACCESS_READWRITE,\
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw, \
- .get = snd_soc_get_volsw_twl4030, \
- .put = snd_soc_put_volsw_twl4030, \
- .private_value = (unsigned long)&(struct soc_mixer_control) \
- {.reg = xreg, .shift = shift_left, .rshift = shift_right,\
- .max = xmax, .invert = xinvert} }
-#define SOC_DOUBLE_R_TLV_TWL4030(xname, reg_left, reg_right, xshift, xmax,\
- xinvert, tlv_array) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
- SNDRV_CTL_ELEM_ACCESS_READWRITE,\
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw_2r, \
- .get = snd_soc_get_volsw_r2_twl4030,\
- .put = snd_soc_put_volsw_r2_twl4030, \
- .private_value = (unsigned long)&(struct soc_mixer_control) \
- {.reg = reg_left, .rreg = reg_right, .shift = xshift, \
- .rshift = xshift, .max = xmax, .invert = xinvert} }
-#define SOC_SINGLE_TLV_TWL4030(xname, xreg, xshift, xmax, xinvert, tlv_array) \
- SOC_DOUBLE_TLV_TWL4030(xname, xreg, xshift, xshift, xmax, \
- xinvert, tlv_array)
-
static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1197,19 +1169,23 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = {
TWL4030_REG_VDL_APGA_CTL, 1, 1, 0),
/* Separate output gain controls */
- SOC_DOUBLE_R_TLV_TWL4030("PreDriv Playback Volume",
+ SOC_DOUBLE_R_EXT_TLV("PreDriv Playback Volume",
TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL,
- 4, 3, 0, output_tvl),
+ 4, 3, 0, snd_soc_get_volsw_r2_twl4030,
+ snd_soc_put_volsw_r2_twl4030, output_tvl),
- SOC_DOUBLE_TLV_TWL4030("Headset Playback Volume",
- TWL4030_REG_HS_GAIN_SET, 0, 2, 3, 0, output_tvl),
+ SOC_DOUBLE_EXT_TLV("Headset Playback Volume",
+ TWL4030_REG_HS_GAIN_SET, 0, 2, 3, 0, snd_soc_get_volsw_twl4030,
+ snd_soc_put_volsw_twl4030, output_tvl),
- SOC_DOUBLE_R_TLV_TWL4030("Carkit Playback Volume",
+ SOC_DOUBLE_R_EXT_TLV("Carkit Playback Volume",
TWL4030_REG_PRECKL_CTL, TWL4030_REG_PRECKR_CTL,
- 4, 3, 0, output_tvl),
+ 4, 3, 0, snd_soc_get_volsw_r2_twl4030,
+ snd_soc_put_volsw_r2_twl4030, output_tvl),
- SOC_SINGLE_TLV_TWL4030("Earpiece Playback Volume",
- TWL4030_REG_EAR_CTL, 4, 3, 0, output_ear_tvl),
+ SOC_SINGLE_EXT_TLV("Earpiece Playback Volume",
+ TWL4030_REG_EAR_CTL, 4, 3, 0, snd_soc_get_volsw_twl4030,
+ snd_soc_put_volsw_twl4030, output_ear_tvl),
/* Common capture gain controls */
SOC_DOUBLE_R_TLV("TX1 Digital Capture Volume",
@@ -1633,17 +1609,6 @@ static const struct snd_soc_dapm_route intercon[] = {
};
-static int twl4030_add_widgets(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- snd_soc_dapm_new_controls(dapm, twl4030_dapm_widgets,
- ARRAY_SIZE(twl4030_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
- return 0;
-}
-
static int twl4030_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
@@ -2265,9 +2230,6 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec)
twl4030_init_chip(codec);
- snd_soc_add_controls(codec, twl4030_snd_controls,
- ARRAY_SIZE(twl4030_snd_controls));
- twl4030_add_widgets(codec);
return 0;
}
@@ -2293,6 +2255,13 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
.reg_cache_size = sizeof(twl4030_reg),
.reg_word_size = sizeof(u8),
.reg_cache_default = twl4030_reg,
+
+ .controls = twl4030_snd_controls,
+ .num_controls = ARRAY_SIZE(twl4030_snd_controls),
+ .dapm_widgets = twl4030_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(twl4030_dapm_widgets),
+ .dapm_routes = intercon,
+ .num_dapm_routes = ARRAY_SIZE(intercon),
};
static int __devinit twl4030_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 443032b3b329..73e11f022ded 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -57,6 +57,13 @@
#define TWL6040_HF_VOL_MASK 0x1F
#define TWL6040_HF_VOL_SHIFT 0
+/* Shadow register used by the driver */
+#define TWL6040_REG_SW_SHADOW 0x2F
+#define TWL6040_CACHEREGNUM (TWL6040_REG_SW_SHADOW + 1)
+
+/* TWL6040_REG_SW_SHADOW (0x2F) fields */
+#define TWL6040_EAR_PATH_ENABLE 0x01
+
struct twl6040_output {
u16 active;
u16 left_vol;
@@ -65,12 +72,13 @@ struct twl6040_output {
u16 right_step;
unsigned int step_delay;
u16 ramp;
- u16 mute;
+ struct delayed_work work;
struct completion ramp_done;
};
struct twl6040_jack_data {
struct snd_soc_jack *jack;
+ struct delayed_work work;
int report;
};
@@ -79,7 +87,6 @@ struct twl6040_data {
int plug_irq;
int codec_powered;
int pll;
- int non_lp;
int pll_power_mode;
int hs_power_mode;
int hs_power_mode_locked;
@@ -92,104 +99,68 @@ struct twl6040_data {
struct twl6040_jack_data hs_jack;
struct snd_soc_codec *codec;
struct workqueue_struct *workqueue;
- struct delayed_work delayed_work;
struct mutex mutex;
struct twl6040_output headset;
struct twl6040_output handsfree;
- struct workqueue_struct *hf_workqueue;
- struct workqueue_struct *hs_workqueue;
- struct delayed_work hs_delayed_work;
- struct delayed_work hf_delayed_work;
};
/*
* twl6040 register cache & default register settings
*/
static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = {
- 0x00, /* not used 0x00 */
- 0x4B, /* TWL6040_ASICID (ro) 0x01 */
- 0x00, /* TWL6040_ASICREV (ro) 0x02 */
- 0x00, /* TWL6040_INTID 0x03 */
- 0x00, /* TWL6040_INTMR 0x04 */
- 0x00, /* TWL6040_NCPCTRL 0x05 */
- 0x00, /* TWL6040_LDOCTL 0x06 */
- 0x60, /* TWL6040_HPPLLCTL 0x07 */
- 0x00, /* TWL6040_LPPLLCTL 0x08 */
- 0x4A, /* TWL6040_LPPLLDIV 0x09 */
- 0x00, /* TWL6040_AMICBCTL 0x0A */
- 0x00, /* TWL6040_DMICBCTL 0x0B */
- 0x18, /* TWL6040_MICLCTL 0x0C - No input selected on Left Mic */
- 0x18, /* TWL6040_MICRCTL 0x0D - No input selected on Right Mic */
- 0x00, /* TWL6040_MICGAIN 0x0E */
- 0x1B, /* TWL6040_LINEGAIN 0x0F */
- 0x00, /* TWL6040_HSLCTL 0x10 */
- 0x00, /* TWL6040_HSRCTL 0x11 */
- 0x00, /* TWL6040_HSGAIN 0x12 */
- 0x00, /* TWL6040_EARCTL 0x13 */
- 0x00, /* TWL6040_HFLCTL 0x14 */
- 0x00, /* TWL6040_HFLGAIN 0x15 */
- 0x00, /* TWL6040_HFRCTL 0x16 */
- 0x00, /* TWL6040_HFRGAIN 0x17 */
- 0x00, /* TWL6040_VIBCTLL 0x18 */
- 0x00, /* TWL6040_VIBDATL 0x19 */
- 0x00, /* TWL6040_VIBCTLR 0x1A */
- 0x00, /* TWL6040_VIBDATR 0x1B */
- 0x00, /* TWL6040_HKCTL1 0x1C */
- 0x00, /* TWL6040_HKCTL2 0x1D */
- 0x00, /* TWL6040_GPOCTL 0x1E */
- 0x00, /* TWL6040_ALB 0x1F */
- 0x00, /* TWL6040_DLB 0x20 */
- 0x00, /* not used 0x21 */
- 0x00, /* not used 0x22 */
- 0x00, /* not used 0x23 */
- 0x00, /* not used 0x24 */
- 0x00, /* not used 0x25 */
- 0x00, /* not used 0x26 */
- 0x00, /* not used 0x27 */
- 0x00, /* TWL6040_TRIM1 0x28 */
- 0x00, /* TWL6040_TRIM2 0x29 */
- 0x00, /* TWL6040_TRIM3 0x2A */
- 0x00, /* TWL6040_HSOTRIM 0x2B */
- 0x00, /* TWL6040_HFOTRIM 0x2C */
- 0x09, /* TWL6040_ACCCTL 0x2D */
- 0x00, /* TWL6040_STATUS (ro) 0x2E */
-};
-
-/*
- * twl6040 vio/gnd registers:
- * registers under vio/gnd supply can be accessed
- * before the power-up sequence, after NRESPWRON goes high
- */
-static const int twl6040_vio_reg[TWL6040_VIOREGNUM] = {
- TWL6040_REG_ASICID,
- TWL6040_REG_ASICREV,
- TWL6040_REG_INTID,
- TWL6040_REG_INTMR,
- TWL6040_REG_NCPCTL,
- TWL6040_REG_LDOCTL,
- TWL6040_REG_AMICBCTL,
- TWL6040_REG_DMICBCTL,
- TWL6040_REG_HKCTL1,
- TWL6040_REG_HKCTL2,
- TWL6040_REG_GPOCTL,
- TWL6040_REG_TRIM1,
- TWL6040_REG_TRIM2,
- TWL6040_REG_TRIM3,
- TWL6040_REG_HSOTRIM,
- TWL6040_REG_HFOTRIM,
- TWL6040_REG_ACCCTL,
- TWL6040_REG_STATUS,
+ 0x00, /* not used 0x00 */
+ 0x4B, /* REG_ASICID 0x01 (ro) */
+ 0x00, /* REG_ASICREV 0x02 (ro) */
+ 0x00, /* REG_INTID 0x03 */
+ 0x00, /* REG_INTMR 0x04 */
+ 0x00, /* REG_NCPCTRL 0x05 */
+ 0x00, /* REG_LDOCTL 0x06 */
+ 0x60, /* REG_HPPLLCTL 0x07 */
+ 0x00, /* REG_LPPLLCTL 0x08 */
+ 0x4A, /* REG_LPPLLDIV 0x09 */
+ 0x00, /* REG_AMICBCTL 0x0A */
+ 0x00, /* REG_DMICBCTL 0x0B */
+ 0x00, /* REG_MICLCTL 0x0C */
+ 0x00, /* REG_MICRCTL 0x0D */
+ 0x00, /* REG_MICGAIN 0x0E */
+ 0x1B, /* REG_LINEGAIN 0x0F */
+ 0x00, /* REG_HSLCTL 0x10 */
+ 0x00, /* REG_HSRCTL 0x11 */
+ 0x00, /* REG_HSGAIN 0x12 */
+ 0x00, /* REG_EARCTL 0x13 */
+ 0x00, /* REG_HFLCTL 0x14 */
+ 0x00, /* REG_HFLGAIN 0x15 */
+ 0x00, /* REG_HFRCTL 0x16 */
+ 0x00, /* REG_HFRGAIN 0x17 */
+ 0x00, /* REG_VIBCTLL 0x18 */
+ 0x00, /* REG_VIBDATL 0x19 */
+ 0x00, /* REG_VIBCTLR 0x1A */
+ 0x00, /* REG_VIBDATR 0x1B */
+ 0x00, /* REG_HKCTL1 0x1C */
+ 0x00, /* REG_HKCTL2 0x1D */
+ 0x00, /* REG_GPOCTL 0x1E */
+ 0x00, /* REG_ALB 0x1F */
+ 0x00, /* REG_DLB 0x20 */
+ 0x00, /* not used 0x21 */
+ 0x00, /* not used 0x22 */
+ 0x00, /* not used 0x23 */
+ 0x00, /* not used 0x24 */
+ 0x00, /* not used 0x25 */
+ 0x00, /* not used 0x26 */
+ 0x00, /* not used 0x27 */
+ 0x00, /* REG_TRIM1 0x28 */
+ 0x00, /* REG_TRIM2 0x29 */
+ 0x00, /* REG_TRIM3 0x2A */
+ 0x00, /* REG_HSOTRIM 0x2B */
+ 0x00, /* REG_HFOTRIM 0x2C */
+ 0x09, /* REG_ACCCTL 0x2D */
+ 0x00, /* REG_STATUS 0x2E (ro) */
+
+ 0x00, /* REG_SW_SHADOW 0x2F - Shadow, non HW register */
};
-/*
- * twl6040 vdd/vss registers:
- * registers under vdd/vss supplies can only be accessed
- * after the power-up sequence
- */
-static const int twl6040_vdd_reg[TWL6040_VDDREGNUM] = {
- TWL6040_REG_HPPLLCTL,
- TWL6040_REG_LPPLLCTL,
- TWL6040_REG_LPPLLDIV,
+/* List of registers to be restored after power up */
+static const int twl6040_restore_list[] = {
TWL6040_REG_MICLCTL,
TWL6040_REG_MICRCTL,
TWL6040_REG_MICGAIN,
@@ -202,12 +173,6 @@ static const int twl6040_vdd_reg[TWL6040_VDDREGNUM] = {
TWL6040_REG_HFLGAIN,
TWL6040_REG_HFRCTL,
TWL6040_REG_HFRGAIN,
- TWL6040_REG_VIBCTLL,
- TWL6040_REG_VIBDATL,
- TWL6040_REG_VIBCTLR,
- TWL6040_REG_VIBDATR,
- TWL6040_REG_ALB,
- TWL6040_REG_DLB,
};
/* set of rates for each pll: low-power and high-performance */
@@ -275,8 +240,12 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
if (reg >= TWL6040_CACHEREGNUM)
return -EIO;
- value = twl6040_reg_read(twl6040, reg);
- twl6040_write_reg_cache(codec, reg, value);
+ if (likely(reg < TWL6040_REG_SW_SHADOW)) {
+ value = twl6040_reg_read(twl6040, reg);
+ twl6040_write_reg_cache(codec, reg, value);
+ } else {
+ value = twl6040_read_reg_cache(codec, reg);
+ }
return value;
}
@@ -293,59 +262,51 @@ static int twl6040_write(struct snd_soc_codec *codec,
return -EIO;
twl6040_write_reg_cache(codec, reg, value);
- return twl6040_reg_write(twl6040, reg, value);
+ if (likely(reg < TWL6040_REG_SW_SHADOW))
+ return twl6040_reg_write(twl6040, reg, value);
+ else
+ return 0;
}
-static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
+static void twl6040_init_chip(struct snd_soc_codec *codec)
{
- u8 *cache = codec->reg_cache;
- int reg, i;
-
- for (i = 0; i < TWL6040_VIOREGNUM; i++) {
- reg = twl6040_vio_reg[i];
- /*
- * skip read-only registers (ASICID, ASICREV, STATUS)
- * and registers shared among MFD children
- */
- switch (reg) {
- case TWL6040_REG_ASICID:
- case TWL6040_REG_ASICREV:
- case TWL6040_REG_INTID:
- case TWL6040_REG_INTMR:
- case TWL6040_REG_NCPCTL:
- case TWL6040_REG_LDOCTL:
- case TWL6040_REG_GPOCTL:
- case TWL6040_REG_ACCCTL:
- case TWL6040_REG_STATUS:
- continue;
- default:
- break;
- }
- twl6040_write(codec, reg, cache[reg]);
- }
+ struct twl6040 *twl6040 = codec->control_data;
+ u8 val;
+
+ /* Update reg_cache: ASICREV, and TRIM values */
+ val = twl6040_get_revid(twl6040);
+ twl6040_write_reg_cache(codec, TWL6040_REG_ASICREV, val);
+
+ twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM1);
+ twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM2);
+ twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM3);
+ twl6040_read_reg_volatile(codec, TWL6040_REG_HSOTRIM);
+ twl6040_read_reg_volatile(codec, TWL6040_REG_HFOTRIM);
+
+ /* Change chip defaults */
+ /* No imput selected for microphone amplifiers */
+ twl6040_write_reg_cache(codec, TWL6040_REG_MICLCTL, 0x18);
+ twl6040_write_reg_cache(codec, TWL6040_REG_MICRCTL, 0x18);
+
+ /*
+ * We need to lower the default gain values, so the ramp code
+ * can work correctly for the first playback.
+ * This reduces the pop noise heard at the first playback.
+ */
+ twl6040_write_reg_cache(codec, TWL6040_REG_HSGAIN, 0xff);
+ twl6040_write_reg_cache(codec, TWL6040_REG_EARCTL, 0x1e);
+ twl6040_write_reg_cache(codec, TWL6040_REG_HFLGAIN, 0x1d);
+ twl6040_write_reg_cache(codec, TWL6040_REG_HFRGAIN, 0x1d);
+ twl6040_write_reg_cache(codec, TWL6040_REG_LINEGAIN, 0);
}
-static void twl6040_init_vdd_regs(struct snd_soc_codec *codec)
+static void twl6040_restore_regs(struct snd_soc_codec *codec)
{
u8 *cache = codec->reg_cache;
int reg, i;
- for (i = 0; i < TWL6040_VDDREGNUM; i++) {
- reg = twl6040_vdd_reg[i];
- /* skip vibra and PLL registers */
- switch (reg) {
- case TWL6040_REG_VIBCTLL:
- case TWL6040_REG_VIBDATL:
- case TWL6040_REG_VIBCTLR:
- case TWL6040_REG_VIBDATR:
- case TWL6040_REG_HPPLLCTL:
- case TWL6040_REG_LPPLLCTL:
- case TWL6040_REG_LPPLLDIV:
- continue;
- default:
- break;
- }
-
+ for (i = 0; i < ARRAY_SIZE(twl6040_restore_list); i++) {
+ reg = twl6040_restore_list[i];
twl6040_write(codec, reg, cache[reg]);
}
}
@@ -524,18 +485,17 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
static void twl6040_pga_hs_work(struct work_struct *work)
{
struct twl6040_data *priv =
- container_of(work, struct twl6040_data, hs_delayed_work.work);
+ container_of(work, struct twl6040_data, headset.work.work);
struct snd_soc_codec *codec = priv->codec;
struct twl6040_output *headset = &priv->headset;
- unsigned int delay = headset->step_delay;
int i, headset_complete;
/* do we need to ramp at all ? */
if (headset->ramp == TWL6040_RAMP_NONE)
return;
- /* HS PGA volumes have 4 bits of resolution to ramp */
- for (i = 0; i <= 16; i++) {
+ /* HS PGA gain range: 0x0 - 0xf (0 - 15) */
+ for (i = 0; i < 16; i++) {
headset_complete = twl6040_hs_ramp_step(codec,
headset->left_step,
headset->right_step);
@@ -544,15 +504,8 @@ static void twl6040_pga_hs_work(struct work_struct *work)
if (headset_complete)
break;
- /*
- * TODO: tune: delay is longer over 0dB
- * as increases are larger.
- */
- if (i >= 8)
- schedule_timeout_interruptible(msecs_to_jiffies(delay +
- (delay >> 1)));
- else
- schedule_timeout_interruptible(msecs_to_jiffies(delay));
+ schedule_timeout_interruptible(
+ msecs_to_jiffies(headset->step_delay));
}
if (headset->ramp == TWL6040_RAMP_DOWN) {
@@ -567,18 +520,18 @@ static void twl6040_pga_hs_work(struct work_struct *work)
static void twl6040_pga_hf_work(struct work_struct *work)
{
struct twl6040_data *priv =
- container_of(work, struct twl6040_data, hf_delayed_work.work);
+ container_of(work, struct twl6040_data, handsfree.work.work);
struct snd_soc_codec *codec = priv->codec;
struct twl6040_output *handsfree = &priv->handsfree;
- unsigned int delay = handsfree->step_delay;
int i, handsfree_complete;
/* do we need to ramp at all ? */
if (handsfree->ramp == TWL6040_RAMP_NONE)
return;
- /* HF PGA volumes have 5 bits of resolution to ramp */
- for (i = 0; i <= 32; i++) {
+ /*
+ * HF PGA gain range: 0x00 - 0x1d (0 - 29) */
+ for (i = 0; i < 30; i++) {
handsfree_complete = twl6040_hf_ramp_step(codec,
handsfree->left_step,
handsfree->right_step);
@@ -587,15 +540,8 @@ static void twl6040_pga_hf_work(struct work_struct *work)
if (handsfree_complete)
break;
- /*
- * TODO: tune: delay is longer over 0dB
- * as increases are larger.
- */
- if (i >= 16)
- schedule_timeout_interruptible(msecs_to_jiffies(delay +
- (delay >> 1)));
- else
- schedule_timeout_interruptible(msecs_to_jiffies(delay));
+ schedule_timeout_interruptible(
+ msecs_to_jiffies(handsfree->step_delay));
}
@@ -607,36 +553,40 @@ static void twl6040_pga_hf_work(struct work_struct *work)
handsfree->ramp = TWL6040_RAMP_NONE;
}
-static int pga_event(struct snd_soc_dapm_widget *w,
+static int out_drv_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct twl6040_output *out;
struct delayed_work *work;
- struct workqueue_struct *queue;
switch (w->shift) {
- case 2:
- case 3:
+ case 2: /* Headset output driver */
out = &priv->headset;
- work = &priv->hs_delayed_work;
- queue = priv->hs_workqueue;
+ work = &out->work;
+ /*
+ * Make sure, that we do not mess up variables for already
+ * executing work.
+ */
+ cancel_delayed_work_sync(work);
+
out->left_step = priv->hs_left_step;
out->right_step = priv->hs_right_step;
out->step_delay = 5; /* 5 ms between volume ramp steps */
break;
- case 4:
+ case 4: /* Handsfree output driver */
out = &priv->handsfree;
- work = &priv->hf_delayed_work;
- queue = priv->hf_workqueue;
+ work = &out->work;
+ /*
+ * Make sure, that we do not mess up variables for already
+ * executing work.
+ */
+ cancel_delayed_work_sync(work);
+
out->left_step = priv->hf_left_step;
out->right_step = priv->hf_right_step;
out->step_delay = 5; /* 5 ms between volume ramp steps */
- if (SND_SOC_DAPM_EVENT_ON(event))
- priv->non_lp++;
- else
- priv->non_lp--;
break;
default:
return -1;
@@ -648,31 +598,25 @@ static int pga_event(struct snd_soc_dapm_widget *w,
break;
/* don't use volume ramp for power-up */
+ out->ramp = TWL6040_RAMP_UP;
out->left_step = out->left_vol;
out->right_step = out->right_vol;
- if (!delayed_work_pending(work)) {
- out->ramp = TWL6040_RAMP_UP;
- queue_delayed_work(queue, work,
- msecs_to_jiffies(1));
- }
+ queue_delayed_work(priv->workqueue, work, msecs_to_jiffies(1));
break;
case SND_SOC_DAPM_PRE_PMD:
if (!out->active)
break;
- if (!delayed_work_pending(work)) {
- /* use volume ramp for power-down */
- out->ramp = TWL6040_RAMP_DOWN;
- INIT_COMPLETION(out->ramp_done);
+ /* use volume ramp for power-down */
+ out->ramp = TWL6040_RAMP_DOWN;
+ INIT_COMPLETION(out->ramp_done);
- queue_delayed_work(queue, work,
- msecs_to_jiffies(1));
+ queue_delayed_work(priv->workqueue, work, msecs_to_jiffies(1));
- wait_for_completion_timeout(&out->ramp_done,
- msecs_to_jiffies(2000));
- }
+ wait_for_completion_timeout(&out->ramp_done,
+ msecs_to_jiffies(2000));
break;
}
@@ -683,7 +627,7 @@ static int pga_event(struct snd_soc_dapm_widget *w,
static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
{
int hslctl, hsrctl;
- int mask = TWL6040_HSDRVMODEL | TWL6040_HSDACMODEL;
+ int mask = TWL6040_HSDRVMODE | TWL6040_HSDACMODE;
hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);
@@ -705,11 +649,31 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
+ struct snd_soc_codec *codec = w->codec;
+ u8 hslctl, hsrctl;
+
+ /*
+ * Workaround for Headset DC offset caused pop noise:
+ * Both HS DAC need to be turned on (before the HS driver) and off at
+ * the same time.
+ */
+ hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
+ hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ hslctl |= TWL6040_HSDACENA;
+ hsrctl |= TWL6040_HSDACENA;
+ } else {
+ hslctl &= ~TWL6040_HSDACENA;
+ hsrctl &= ~TWL6040_HSDACENA;
+ }
+ twl6040_write(codec, TWL6040_REG_HSLCTL, hslctl);
+ twl6040_write(codec, TWL6040_REG_HSRCTL, hsrctl);
+
msleep(1);
return 0;
}
-static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
+static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
@@ -717,18 +681,12 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
int ret = 0;
if (SND_SOC_DAPM_EVENT_ON(event)) {
- priv->non_lp++;
- if (!strcmp(w->name, "Earphone Driver")) {
- /* Earphone doesn't support low power mode */
- priv->hs_power_mode_locked = 1;
- ret = headset_power_mode(codec, 1);
- }
+ /* Earphone doesn't support low power mode */
+ priv->hs_power_mode_locked = 1;
+ ret = headset_power_mode(codec, 1);
} else {
- priv->non_lp--;
- if (!strcmp(w->name, "Earphone Driver")) {
- priv->hs_power_mode_locked = 0;
- ret = headset_power_mode(codec, priv->hs_power_mode);
- }
+ priv->hs_power_mode_locked = 0;
+ ret = headset_power_mode(codec, priv->hs_power_mode);
}
msleep(1);
@@ -770,7 +728,7 @@ EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect);
static void twl6040_accessory_work(struct work_struct *work)
{
struct twl6040_data *priv = container_of(work,
- struct twl6040_data, delayed_work.work);
+ struct twl6040_data, hs_jack.work.work);
struct snd_soc_codec *codec = priv->codec;
struct twl6040_jack_data *hs_jack = &priv->hs_jack;
@@ -781,15 +739,10 @@ static void twl6040_accessory_work(struct work_struct *work)
static irqreturn_t twl6040_audio_handler(int irq, void *data)
{
struct snd_soc_codec *codec = data;
- struct twl6040 *twl6040 = codec->control_data;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
- u8 intid;
-
- intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
- if ((intid & TWL6040_PLUGINT) || (intid & TWL6040_UNPLUGINT))
- queue_delayed_work(priv->workqueue, &priv->delayed_work,
- msecs_to_jiffies(200));
+ queue_delayed_work(priv->workqueue, &priv->hs_jack.work,
+ msecs_to_jiffies(200));
return IRQ_HANDLED;
}
@@ -803,25 +756,27 @@ static int twl6040_put_volsw(struct snd_kcontrol *kcontrol,
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
int ret;
- unsigned int reg = mc->reg;
/* For HS and HF we shadow the values and only actually write
* them out when active in order to ensure the amplifier comes on
* as quietly as possible. */
- switch (reg) {
+ switch (mc->reg) {
case TWL6040_REG_HSGAIN:
out = &twl6040_priv->headset;
break;
- default:
+ case TWL6040_REG_HFLGAIN:
+ out = &twl6040_priv->handsfree;
break;
+ default:
+ dev_warn(codec->dev, "%s: Unexpected register: 0x%02x\n",
+ __func__, mc->reg);
+ return -EINVAL;
}
- if (out) {
- out->left_vol = ucontrol->value.integer.value[0];
- out->right_vol = ucontrol->value.integer.value[1];
- if (!out->active)
- return 1;
- }
+ out->left_vol = ucontrol->value.integer.value[0];
+ out->right_vol = ucontrol->value.integer.value[1];
+ if (!out->active)
+ return 1;
ret = snd_soc_put_volsw(kcontrol, ucontrol);
if (ret < 0)
@@ -838,112 +793,42 @@ static int twl6040_get_volsw(struct snd_kcontrol *kcontrol,
struct twl6040_output *out = &twl6040_priv->headset;
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- switch (reg) {
+ switch (mc->reg) {
case TWL6040_REG_HSGAIN:
out = &twl6040_priv->headset;
- ucontrol->value.integer.value[0] = out->left_vol;
- ucontrol->value.integer.value[1] = out->right_vol;
- return 0;
-
- default:
break;
- }
-
- return snd_soc_get_volsw(kcontrol, ucontrol);
-}
-
-static int twl6040_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
- struct twl6040_output *out = NULL;
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int ret;
- unsigned int reg = mc->reg;
-
- /* For HS and HF we shadow the values and only actually write
- * them out when active in order to ensure the amplifier comes on
- * as quietly as possible. */
- switch (reg) {
case TWL6040_REG_HFLGAIN:
- case TWL6040_REG_HFRGAIN:
out = &twl6040_priv->handsfree;
break;
default:
- break;
- }
-
- if (out) {
- out->left_vol = ucontrol->value.integer.value[0];
- out->right_vol = ucontrol->value.integer.value[1];
- if (!out->active)
- return 1;
+ dev_warn(codec->dev, "%s: Unexpected register: 0x%02x\n",
+ __func__, mc->reg);
+ return -EINVAL;
}
- ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
- if (ret < 0)
- return ret;
-
- return 1;
+ ucontrol->value.integer.value[0] = out->left_vol;
+ ucontrol->value.integer.value[1] = out->right_vol;
+ return 0;
}
-static int twl6040_get_volsw_2r(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
- struct twl6040_output *out = &twl6040_priv->handsfree;
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
-
- /* If these are cached registers use the cache */
- switch (reg) {
- case TWL6040_REG_HFLGAIN:
- case TWL6040_REG_HFRGAIN:
- out = &twl6040_priv->handsfree;
- ucontrol->value.integer.value[0] = out->left_vol;
- ucontrol->value.integer.value[1] = out->right_vol;
- return 0;
-
- default:
- break;
- }
-
- return snd_soc_get_volsw_2r(kcontrol, ucontrol);
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_codec *codec = widget->codec;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int val;
+
+ /* Do not allow changes while Input/FF efect is running */
+ val = twl6040_read_reg_volatile(codec, e->reg);
+ if (val & TWL6040_VIBENA && !(val & TWL6040_VIBSEL))
+ return -EBUSY;
+
+ return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
}
-/* double control with volume update */
-#define SOC_TWL6040_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax,\
- xinvert, tlv_array)\
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
- SNDRV_CTL_ELEM_ACCESS_READWRITE,\
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw, .get = twl6040_get_volsw, \
- .put = twl6040_put_volsw, \
- .private_value = (unsigned long)&(struct soc_mixer_control) \
- {.reg = xreg, .shift = shift_left, .rshift = shift_right,\
- .max = xmax, .platform_max = xmax, .invert = xinvert} }
-
-/* double control with volume update */
-#define SOC_TWL6040_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax,\
- xinvert, tlv_array)\
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
- SNDRV_CTL_ELEM_ACCESS_READWRITE | \
- SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw_2r, \
- .get = twl6040_get_volsw_2r, .put = twl6040_put_volsw_2r_vu, \
- .private_value = (unsigned long)&(struct soc_mixer_control) \
- {.reg = reg_left, .rreg = reg_right, .shift = xshift, \
- .rshift = xshift, .max = xmax, .invert = xinvert}, }
-
/*
* MICATT volume control:
* from -6 to 0 dB in 6 dB steps
@@ -1015,6 +900,19 @@ static const struct soc_enum twl6040_hf_enum[] = {
twl6040_hf_texts),
};
+static const char *twl6040_vibrapath_texts[] = {
+ "Input FF", "Audio PDM"
+};
+
+static const struct soc_enum twl6040_vibra_enum[] = {
+ SOC_ENUM_SINGLE(TWL6040_REG_VIBCTLL, 1,
+ ARRAY_SIZE(twl6040_vibrapath_texts),
+ twl6040_vibrapath_texts),
+ SOC_ENUM_SINGLE(TWL6040_REG_VIBCTLR, 1,
+ ARRAY_SIZE(twl6040_vibrapath_texts),
+ twl6040_vibrapath_texts),
+};
+
static const struct snd_kcontrol_new amicl_control =
SOC_DAPM_ENUM("Route", twl6040_enum[0]);
@@ -1035,8 +933,25 @@ static const struct snd_kcontrol_new hfl_mux_controls =
static const struct snd_kcontrol_new hfr_mux_controls =
SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]);
-static const struct snd_kcontrol_new ep_driver_switch_controls =
- SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0);
+static const struct snd_kcontrol_new ep_path_enable_control =
+ SOC_DAPM_SINGLE("Switch", TWL6040_REG_SW_SHADOW, 0, 1, 0);
+
+static const struct snd_kcontrol_new auxl_switch_control =
+ SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 6, 1, 0);
+
+static const struct snd_kcontrol_new auxr_switch_control =
+ SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 6, 1, 0);
+
+/* Vibra playback switches */
+static const struct snd_kcontrol_new vibral_mux_controls =
+ SOC_DAPM_ENUM_EXT("Route", twl6040_vibra_enum[0],
+ snd_soc_dapm_get_enum_double,
+ twl6040_soc_dapm_put_vibra_enum);
+
+static const struct snd_kcontrol_new vibrar_mux_controls =
+ SOC_DAPM_ENUM_EXT("Route", twl6040_vibra_enum[1],
+ snd_soc_dapm_get_enum_double,
+ twl6040_soc_dapm_put_vibra_enum);
/* Headset power mode */
static const char *twl6040_power_mode_texts[] = {
@@ -1105,6 +1020,15 @@ int twl6040_get_clk_id(struct snd_soc_codec *codec)
}
EXPORT_SYMBOL_GPL(twl6040_get_clk_id);
+int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim)
+{
+ if (unlikely(trim >= TWL6040_TRIM_INVAL))
+ return -EINVAL;
+
+ return twl6040_read_reg_cache(codec, TWL6040_REG_TRIM1 + trim);
+}
+EXPORT_SYMBOL_GPL(twl6040_get_trim_value);
+
static const struct snd_kcontrol_new twl6040_snd_controls[] = {
/* Capture gains */
SOC_DOUBLE_TLV("Capture Preamplifier Volume",
@@ -1117,10 +1041,12 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv),
/* Playback gains */
- SOC_TWL6040_DOUBLE_TLV("Headset Playback Volume",
- TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, hs_tlv),
- SOC_TWL6040_DOUBLE_R_TLV("Handsfree Playback Volume",
- TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
+ SOC_DOUBLE_EXT_TLV("Headset Playback Volume",
+ TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, twl6040_get_volsw,
+ twl6040_put_volsw, hs_tlv),
+ SOC_DOUBLE_R_EXT_TLV("Handsfree Playback Volume",
+ TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1,
+ twl6040_get_volsw, twl6040_put_volsw, hf_tlv),
SOC_SINGLE_TLV("Earphone Playback Volume",
TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
@@ -1146,6 +1072,10 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("HFL"),
SND_SOC_DAPM_OUTPUT("HFR"),
SND_SOC_DAPM_OUTPUT("EP"),
+ SND_SOC_DAPM_OUTPUT("AUXL"),
+ SND_SOC_DAPM_OUTPUT("AUXR"),
+ SND_SOC_DAPM_OUTPUT("VIBRAL"),
+ SND_SOC_DAPM_OUTPUT("VIBRAR"),
/* Analog input muxes for the capture amplifiers */
SND_SOC_DAPM_MUX("Analog Left Capture Route",
@@ -1182,59 +1112,76 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
TWL6040_REG_DMICBCTL, 4, 0),
/* DACs */
- SND_SOC_DAPM_DAC_E("HSDAC Left", "Headset Playback",
- TWL6040_REG_HSLCTL, 0, 0,
- twl6040_hs_dac_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_DAC_E("HSDAC Right", "Headset Playback",
- TWL6040_REG_HSRCTL, 0, 0,
- twl6040_hs_dac_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_DAC_E("HFDAC Left", "Handsfree Playback",
- TWL6040_REG_HFLCTL, 0, 0,
- twl6040_power_mode_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_DAC_E("HFDAC Right", "Handsfree Playback",
- TWL6040_REG_HFRCTL, 0, 0,
- twl6040_power_mode_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MUX("HF Left Playback",
+ SND_SOC_DAPM_DAC("HSDAC Left", "Headset Playback", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("HSDAC Right", "Headset Playback", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("HFDAC Left", "Handsfree Playback",
+ TWL6040_REG_HFLCTL, 0, 0),
+ SND_SOC_DAPM_DAC("HFDAC Right", "Handsfree Playback",
+ TWL6040_REG_HFRCTL, 0, 0),
+ /* Virtual DAC for vibra path (DL4 channel) */
+ SND_SOC_DAPM_DAC("VIBRA DAC", "Vibra Playback",
+ SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_MUX("Handsfree Left Playback",
SND_SOC_NOPM, 0, 0, &hfl_mux_controls),
- SND_SOC_DAPM_MUX("HF Right Playback",
+ SND_SOC_DAPM_MUX("Handsfree Right Playback",
SND_SOC_NOPM, 0, 0, &hfr_mux_controls),
/* Analog playback Muxes */
- SND_SOC_DAPM_MUX("HS Left Playback",
+ SND_SOC_DAPM_MUX("Headset Left Playback",
SND_SOC_NOPM, 0, 0, &hsl_mux_controls),
- SND_SOC_DAPM_MUX("HS Right Playback",
+ SND_SOC_DAPM_MUX("Headset Right Playback",
SND_SOC_NOPM, 0, 0, &hsr_mux_controls),
+ SND_SOC_DAPM_MUX("Vibra Left Playback", SND_SOC_NOPM, 0, 0,
+ &vibral_mux_controls),
+ SND_SOC_DAPM_MUX("Vibra Right Playback", SND_SOC_NOPM, 0, 0,
+ &vibrar_mux_controls),
+
+ SND_SOC_DAPM_SWITCH("Earphone Playback", SND_SOC_NOPM, 0, 0,
+ &ep_path_enable_control),
+ SND_SOC_DAPM_SWITCH("AUXL Playback", SND_SOC_NOPM, 0, 0,
+ &auxl_switch_control),
+ SND_SOC_DAPM_SWITCH("AUXR Playback", SND_SOC_NOPM, 0, 0,
+ &auxr_switch_control),
+
/* Analog playback drivers */
- SND_SOC_DAPM_OUT_DRV_E("Handsfree Left Driver",
+ SND_SOC_DAPM_OUT_DRV_E("HF Left Driver",
TWL6040_REG_HFLCTL, 4, 0, NULL, 0,
- pga_event,
+ out_drv_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_OUT_DRV_E("Handsfree Right Driver",
+ SND_SOC_DAPM_OUT_DRV_E("HF Right Driver",
TWL6040_REG_HFRCTL, 4, 0, NULL, 0,
- pga_event,
+ out_drv_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_OUT_DRV_E("Headset Left Driver",
+ SND_SOC_DAPM_OUT_DRV_E("HS Left Driver",
TWL6040_REG_HSLCTL, 2, 0, NULL, 0,
- pga_event,
+ out_drv_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_OUT_DRV_E("Headset Right Driver",
+ SND_SOC_DAPM_OUT_DRV_E("HS Right Driver",
TWL6040_REG_HSRCTL, 2, 0, NULL, 0,
- pga_event,
+ out_drv_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_SWITCH_E("Earphone Driver",
- SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls,
- twl6040_power_mode_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUT_DRV_E("Earphone Driver",
+ TWL6040_REG_EARCTL, 0, 0, NULL, 0,
+ twl6040_ep_drv_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUT_DRV("Vibra Left Driver",
+ TWL6040_REG_VIBCTLL, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("Vibra Right Driver",
+ TWL6040_REG_VIBCTLR, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("Vibra Left Control", TWL6040_REG_VIBCTLL, 2, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Vibra Right Control", TWL6040_REG_VIBCTLR, 2, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("HSDAC Power", 1, SND_SOC_NOPM, 0, 0,
+ twl6040_hs_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* Analog playback PGAs */
- SND_SOC_DAPM_PGA("HFDAC Left PGA",
+ SND_SOC_DAPM_PGA("HF Left PGA",
TWL6040_REG_HFLCTL, 1, 0, NULL, 0),
- SND_SOC_DAPM_PGA("HFDAC Right PGA",
+ SND_SOC_DAPM_PGA("HF Right PGA",
TWL6040_REG_HFRCTL, 1, 0, NULL, 0),
};
@@ -1256,52 +1203,62 @@ static const struct snd_soc_dapm_route intercon[] = {
{"ADC Right", NULL, "MicAmpR"},
/* AFM path */
- {"AFMAmpL", "NULL", "AFML"},
- {"AFMAmpR", "NULL", "AFMR"},
+ {"AFMAmpL", NULL, "AFML"},
+ {"AFMAmpR", NULL, "AFMR"},
+
+ {"HSDAC Left", NULL, "HSDAC Power"},
+ {"HSDAC Right", NULL, "HSDAC Power"},
- {"HS Left Playback", "HS DAC", "HSDAC Left"},
- {"HS Left Playback", "Line-In amp", "AFMAmpL"},
+ {"Headset Left Playback", "HS DAC", "HSDAC Left"},
+ {"Headset Left Playback", "Line-In amp", "AFMAmpL"},
- {"HS Right Playback", "HS DAC", "HSDAC Right"},
- {"HS Right Playback", "Line-In amp", "AFMAmpR"},
+ {"Headset Right Playback", "HS DAC", "HSDAC Right"},
+ {"Headset Right Playback", "Line-In amp", "AFMAmpR"},
- {"Headset Left Driver", "NULL", "HS Left Playback"},
- {"Headset Right Driver", "NULL", "HS Right Playback"},
+ {"HS Left Driver", NULL, "Headset Left Playback"},
+ {"HS Right Driver", NULL, "Headset Right Playback"},
- {"HSOL", NULL, "Headset Left Driver"},
- {"HSOR", NULL, "Headset Right Driver"},
+ {"HSOL", NULL, "HS Left Driver"},
+ {"HSOR", NULL, "HS Right Driver"},
/* Earphone playback path */
- {"Earphone Driver", "Switch", "HSDAC Left"},
+ {"Earphone Playback", "Switch", "HSDAC Left"},
+ {"Earphone Driver", NULL, "Earphone Playback"},
{"EP", NULL, "Earphone Driver"},
- {"HF Left Playback", "HF DAC", "HFDAC Left"},
- {"HF Left Playback", "Line-In amp", "AFMAmpL"},
+ {"Handsfree Left Playback", "HF DAC", "HFDAC Left"},
+ {"Handsfree Left Playback", "Line-In amp", "AFMAmpL"},
- {"HF Right Playback", "HF DAC", "HFDAC Right"},
- {"HF Right Playback", "Line-In amp", "AFMAmpR"},
+ {"Handsfree Right Playback", "HF DAC", "HFDAC Right"},
+ {"Handsfree Right Playback", "Line-In amp", "AFMAmpR"},
- {"HFDAC Left PGA", NULL, "HF Left Playback"},
- {"HFDAC Right PGA", NULL, "HF Right Playback"},
+ {"HF Left PGA", NULL, "Handsfree Left Playback"},
+ {"HF Right PGA", NULL, "Handsfree Right Playback"},
- {"Handsfree Left Driver", "Switch", "HFDAC Left PGA"},
- {"Handsfree Right Driver", "Switch", "HFDAC Right PGA"},
+ {"HF Left Driver", NULL, "HF Left PGA"},
+ {"HF Right Driver", NULL, "HF Right PGA"},
- {"HFL", NULL, "Handsfree Left Driver"},
- {"HFR", NULL, "Handsfree Right Driver"},
-};
+ {"HFL", NULL, "HF Left Driver"},
+ {"HFR", NULL, "HF Right Driver"},
-static int twl6040_add_widgets(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ {"AUXL Playback", "Switch", "HF Left PGA"},
+ {"AUXR Playback", "Switch", "HF Right PGA"},
- snd_soc_dapm_new_controls(dapm, twl6040_dapm_widgets,
- ARRAY_SIZE(twl6040_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
- snd_soc_dapm_new_widgets(dapm);
+ {"AUXL", NULL, "AUXL Playback"},
+ {"AUXR", NULL, "AUXR Playback"},
- return 0;
-}
+ /* Vibrator paths */
+ {"Vibra Left Playback", "Audio PDM", "VIBRA DAC"},
+ {"Vibra Right Playback", "Audio PDM", "VIBRA DAC"},
+
+ {"Vibra Left Driver", NULL, "Vibra Left Playback"},
+ {"Vibra Right Driver", NULL, "Vibra Right Playback"},
+ {"Vibra Left Driver", NULL, "Vibra Left Control"},
+ {"Vibra Right Driver", NULL, "Vibra Right Control"},
+
+ {"VIBRAL", NULL, "Vibra Left Driver"},
+ {"VIBRAR", NULL, "Vibra Right Driver"},
+};
static int twl6040_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
@@ -1325,8 +1282,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
priv->codec_powered = 1;
- /* initialize vdd/vss registers with reg_cache */
- twl6040_init_vdd_regs(codec);
+ twl6040_restore_regs(codec);
/* Set external boost GPO */
twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);
@@ -1380,13 +1336,6 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
rate);
return -EINVAL;
}
- /* Capture is not supported with 17.64MHz sysclk */
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- dev_err(codec->dev,
- "capture mode is not supported at %dHz\n",
- rate);
- return -EINVAL;
- }
priv->sysclk = 17640000;
break;
case 8000:
@@ -1419,13 +1368,6 @@ static int twl6040_prepare(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if ((priv->sysclk == 17640000) && priv->non_lp) {
- dev_err(codec->dev,
- "some enabled paths aren't supported at %dHz\n",
- priv->sysclk);
- return -EPERM;
- }
-
ret = twl6040_set_pll(twl6040, priv->pll, priv->clk_in, priv->sysclk);
if (ret) {
dev_err(codec->dev, "Can not set PLL (%d)\n", ret);
@@ -1464,11 +1406,11 @@ static struct snd_soc_dai_ops twl6040_dai_ops = {
static struct snd_soc_dai_driver twl6040_dai[] = {
{
- .name = "twl6040-hifi",
+ .name = "twl6040-legacy",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 5,
.rates = TWL6040_RATES,
.formats = TWL6040_FORMATS,
},
@@ -1518,8 +1460,8 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
.name = "twl6040-vib",
.playback = {
.stream_name = "Vibra Playback",
- .channels_min = 2,
- .channels_max = 2,
+ .channels_min = 1,
+ .channels_max = 1,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.formats = TWL6040_FORMATS,
},
@@ -1562,6 +1504,7 @@ static int twl6040_probe(struct snd_soc_codec *codec)
priv->codec = codec;
codec->control_data = dev_get_drvdata(codec->dev->parent);
+ codec->ignore_pmdown_time = 1;
if (pdata && pdata->hs_left_step && pdata->hs_right_step) {
priv->hs_left_step = pdata->hs_left_step;
@@ -1586,33 +1529,21 @@ static int twl6040_probe(struct snd_soc_codec *codec)
goto work_err;
}
- priv->workqueue = create_singlethread_workqueue("twl6040-codec");
+ priv->workqueue = alloc_workqueue("twl6040-codec", 0, 0);
if (!priv->workqueue) {
ret = -ENOMEM;
goto work_err;
}
- INIT_DELAYED_WORK(&priv->delayed_work, twl6040_accessory_work);
+ INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work);
+ INIT_DELAYED_WORK(&priv->headset.work, twl6040_pga_hs_work);
+ INIT_DELAYED_WORK(&priv->handsfree.work, twl6040_pga_hf_work);
mutex_init(&priv->mutex);
init_completion(&priv->headset.ramp_done);
init_completion(&priv->handsfree.ramp_done);
- priv->hf_workqueue = create_singlethread_workqueue("twl6040-hf");
- if (priv->hf_workqueue == NULL) {
- ret = -ENOMEM;
- goto hfwq_err;
- }
- priv->hs_workqueue = create_singlethread_workqueue("twl6040-hs");
- if (priv->hs_workqueue == NULL) {
- ret = -ENOMEM;
- goto hswq_err;
- }
-
- INIT_DELAYED_WORK(&priv->hs_delayed_work, twl6040_pga_hs_work);
- INIT_DELAYED_WORK(&priv->hf_delayed_work, twl6040_pga_hf_work);
-
ret = request_threaded_irq(priv->plug_irq, NULL, twl6040_audio_handler,
0, "twl6040_irq_plug", codec);
if (ret) {
@@ -1620,27 +1551,16 @@ static int twl6040_probe(struct snd_soc_codec *codec)
goto plugirq_err;
}
- /* init vio registers */
- twl6040_init_vio_regs(codec);
+ twl6040_init_chip(codec);
/* power on device */
ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- if (ret)
- goto bias_err;
-
- snd_soc_add_controls(codec, twl6040_snd_controls,
- ARRAY_SIZE(twl6040_snd_controls));
- twl6040_add_widgets(codec);
-
- return 0;
+ if (!ret)
+ return 0;
-bias_err:
+ /* Error path */
free_irq(priv->plug_irq, codec);
plugirq_err:
- destroy_workqueue(priv->hs_workqueue);
-hswq_err:
- destroy_workqueue(priv->hf_workqueue);
-hfwq_err:
destroy_workqueue(priv->workqueue);
work_err:
kfree(priv);
@@ -1654,8 +1574,6 @@ static int twl6040_remove(struct snd_soc_codec *codec)
twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
free_irq(priv->plug_irq, codec);
destroy_workqueue(priv->workqueue);
- destroy_workqueue(priv->hf_workqueue);
- destroy_workqueue(priv->hs_workqueue);
kfree(priv);
return 0;
@@ -1672,6 +1590,13 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
.reg_cache_size = ARRAY_SIZE(twl6040_reg),
.reg_word_size = sizeof(u8),
.reg_cache_default = twl6040_reg,
+
+ .controls = twl6040_snd_controls,
+ .num_controls = ARRAY_SIZE(twl6040_snd_controls),
+ .dapm_widgets = twl6040_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets),
+ .dapm_routes = intercon,
+ .num_dapm_routes = ARRAY_SIZE(intercon),
};
static int __devinit twl6040_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/twl6040.h b/sound/soc/codecs/twl6040.h
index d8de67869dd9..a83277bdb851 100644
--- a/sound/soc/codecs/twl6040.h
+++ b/sound/soc/codecs/twl6040.h
@@ -22,8 +22,21 @@
#ifndef __TWL6040_H__
#define __TWL6040_H__
+enum twl6040_trim {
+ TWL6040_TRIM_TRIM1 = 0,
+ TWL6040_TRIM_TRIM2,
+ TWL6040_TRIM_TRIM3,
+ TWL6040_TRIM_HSOTRIM,
+ TWL6040_TRIM_HFOTRIM,
+ TWL6040_TRIM_INVAL,
+};
+
+#define TWL6040_HSF_TRIM_LEFT(x) (x & 0x0f)
+#define TWL6040_HSF_TRIM_RIGHT(x) ((x >> 4) & 0x0f)
+
void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *jack, int report);
int twl6040_get_clk_id(struct snd_soc_codec *codec);
+int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim);
#endif /* End of __TWL6040_H__ */
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index 5836201834d9..a85498982991 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -23,6 +23,7 @@
#include <linux/mfd/wl1273-core.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -462,7 +463,6 @@ static int wl1273_probe(struct snd_soc_codec *codec)
wl1273->core = *core;
snd_soc_codec_set_drvdata(codec, wl1273);
- mutex_init(&codec->mutex);
r = snd_soc_add_controls(codec, wl1273_controls,
ARRAY_SIZE(wl1273_controls));
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
index bcc208967917..cd0ec0fd1dba 100644
--- a/sound/soc/codecs/wm1250-ev1.c
+++ b/sound/soc/codecs/wm1250-ev1.c
@@ -12,10 +12,59 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/gpio.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <sound/wm1250-ev1.h>
+
+static const char *wm1250_gpio_names[WM1250_EV1_NUM_GPIOS] = {
+ "WM1250 CLK_ENA",
+ "WM1250 CLK_SEL0",
+ "WM1250 CLK_SEL1",
+ "WM1250 OSR",
+ "WM1250 MASTER",
+};
+
+struct wm1250_priv {
+ struct gpio gpios[WM1250_EV1_NUM_GPIOS];
+};
+
+static int wm1250_ev1_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct wm1250_priv *wm1250 = dev_get_drvdata(codec->dev);
+ int ena;
+
+ if (wm1250)
+ ena = wm1250->gpios[WM1250_EV1_GPIO_CLK_ENA].gpio;
+ else
+ ena = -1;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (ena >= 0)
+ gpio_set_value_cansleep(ena, 1);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ if (ena >= 0)
+ gpio_set_value_cansleep(ena, 0);
+ break;
+ }
+
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
static const struct snd_soc_dapm_widget wm1250_ev1_dapm_widgets[] = {
SND_SOC_DAPM_ADC("ADC", "wm1250-ev1 Capture", SND_SOC_NOPM, 0, 0),
@@ -53,18 +102,103 @@ static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
.num_dapm_widgets = ARRAY_SIZE(wm1250_ev1_dapm_widgets),
.dapm_routes = wm1250_ev1_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm1250_ev1_dapm_routes),
+
+ .set_bias_level = wm1250_ev1_set_bias_level,
+ .idle_bias_off = true,
};
+static int __devinit wm1250_ev1_pdata(struct i2c_client *i2c)
+{
+ struct wm1250_ev1_pdata *pdata = dev_get_platdata(&i2c->dev);
+ struct wm1250_priv *wm1250;
+ int i, ret;
+
+ if (!pdata)
+ return 0;
+
+ wm1250 = kzalloc(sizeof(*wm1250), GFP_KERNEL);
+ if (!wm1250) {
+ dev_err(&i2c->dev, "Unable to allocate private data\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm1250->gpios); i++) {
+ wm1250->gpios[i].gpio = pdata->gpios[i];
+ wm1250->gpios[i].label = wm1250_gpio_names[i];
+ wm1250->gpios[i].flags = GPIOF_OUT_INIT_LOW;
+ }
+ wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].flags = GPIOF_OUT_INIT_HIGH;
+ wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].flags = GPIOF_OUT_INIT_HIGH;
+
+ ret = gpio_request_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios));
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to get GPIOs: %d\n", ret);
+ goto err_alloc;
+ }
+
+ dev_set_drvdata(&i2c->dev, wm1250);
+
+ return ret;
+
+err_alloc:
+ kfree(wm1250);
+err:
+ return ret;
+}
+
+static void wm1250_ev1_free(struct i2c_client *i2c)
+{
+ struct wm1250_priv *wm1250 = dev_get_drvdata(&i2c->dev);
+
+ if (wm1250) {
+ gpio_free_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios));
+ kfree(wm1250);
+ }
+}
+
static int __devinit wm1250_ev1_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *i2c_id)
{
- return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1,
- &wm1250_ev1_dai, 1);
+ int id, board, rev, ret;
+
+ dev_set_drvdata(&i2c->dev, NULL);
+
+ board = i2c_smbus_read_byte_data(i2c, 0);
+ if (board < 0) {
+ dev_err(&i2c->dev, "Failed to read ID: %d\n", board);
+ return board;
+ }
+
+ id = (board & 0xfe) >> 2;
+ rev = board & 0x3;
+
+ if (id != 1) {
+ dev_err(&i2c->dev, "Unknown board ID %d\n", id);
+ return -ENODEV;
+ }
+
+ dev_info(&i2c->dev, "revision %d\n", rev + 1);
+
+ ret = wm1250_ev1_pdata(i2c);
+ if (ret != 0)
+ return ret;
+
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1,
+ &wm1250_ev1_dai, 1);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+ wm1250_ev1_free(i2c);
+ return ret;
+ }
+
+ return 0;
}
static int __devexit wm1250_ev1_remove(struct i2c_client *i2c)
{
snd_soc_unregister_codec(&i2c->dev);
+ wm1250_ev1_free(i2c);
return 0;
}
diff --git a/sound/soc/codecs/wm5100-tables.c b/sound/soc/codecs/wm5100-tables.c
new file mode 100644
index 000000000000..e9ce81a57b85
--- /dev/null
+++ b/sound/soc/codecs/wm5100-tables.c
@@ -0,0 +1,1531 @@
+/*
+ * wm5100-tables.c -- WM5100 ALSA SoC Audio driver data
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "wm5100.h"
+
+int wm5100_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
+{
+ switch (reg) {
+ case WM5100_SOFTWARE_RESET:
+ case WM5100_DEVICE_REVISION:
+ case WM5100_FX_CTRL:
+ case WM5100_INTERRUPT_STATUS_1:
+ case WM5100_INTERRUPT_STATUS_2:
+ case WM5100_INTERRUPT_STATUS_3:
+ case WM5100_INTERRUPT_STATUS_4:
+ case WM5100_INTERRUPT_RAW_STATUS_2:
+ case WM5100_INTERRUPT_RAW_STATUS_3:
+ case WM5100_INTERRUPT_RAW_STATUS_4:
+ case WM5100_OUTPUT_STATUS_1:
+ case WM5100_OUTPUT_STATUS_2:
+ case WM5100_INPUT_ENABLES_STATUS:
+ case WM5100_MIC_DETECT_3:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int wm5100_readable_register(struct snd_soc_codec *codec, unsigned int reg)
+{
+ switch (reg) {
+ case WM5100_SOFTWARE_RESET:
+ case WM5100_DEVICE_REVISION:
+ case WM5100_CTRL_IF_1:
+ case WM5100_TONE_GENERATOR_1:
+ case WM5100_PWM_DRIVE_1:
+ case WM5100_PWM_DRIVE_2:
+ case WM5100_PWM_DRIVE_3:
+ case WM5100_CLOCKING_1:
+ case WM5100_CLOCKING_3:
+ case WM5100_CLOCKING_4:
+ case WM5100_CLOCKING_5:
+ case WM5100_CLOCKING_6:
+ case WM5100_CLOCKING_7:
+ case WM5100_CLOCKING_8:
+ case WM5100_ASRC_ENABLE:
+ case WM5100_ASRC_STATUS:
+ case WM5100_ASRC_RATE1:
+ case WM5100_ISRC_1_CTRL_1:
+ case WM5100_ISRC_1_CTRL_2:
+ case WM5100_ISRC_2_CTRL1:
+ case WM5100_ISRC_2_CTRL_2:
+ case WM5100_FLL1_CONTROL_1:
+ case WM5100_FLL1_CONTROL_2:
+ case WM5100_FLL1_CONTROL_3:
+ case WM5100_FLL1_CONTROL_5:
+ case WM5100_FLL1_CONTROL_6:
+ case WM5100_FLL1_EFS_1:
+ case WM5100_FLL2_CONTROL_1:
+ case WM5100_FLL2_CONTROL_2:
+ case WM5100_FLL2_CONTROL_3:
+ case WM5100_FLL2_CONTROL_5:
+ case WM5100_FLL2_CONTROL_6:
+ case WM5100_FLL2_EFS_1:
+ case WM5100_MIC_CHARGE_PUMP_1:
+ case WM5100_MIC_CHARGE_PUMP_2:
+ case WM5100_HP_CHARGE_PUMP_1:
+ case WM5100_LDO1_CONTROL:
+ case WM5100_MIC_BIAS_CTRL_1:
+ case WM5100_MIC_BIAS_CTRL_2:
+ case WM5100_MIC_BIAS_CTRL_3:
+ case WM5100_ACCESSORY_DETECT_MODE_1:
+ case WM5100_HEADPHONE_DETECT_1:
+ case WM5100_HEADPHONE_DETECT_2:
+ case WM5100_MIC_DETECT_1:
+ case WM5100_MIC_DETECT_2:
+ case WM5100_MIC_DETECT_3:
+ case WM5100_INPUT_ENABLES:
+ case WM5100_INPUT_ENABLES_STATUS:
+ case WM5100_IN1L_CONTROL:
+ case WM5100_IN1R_CONTROL:
+ case WM5100_IN2L_CONTROL:
+ case WM5100_IN2R_CONTROL:
+ case WM5100_IN3L_CONTROL:
+ case WM5100_IN3R_CONTROL:
+ case WM5100_IN4L_CONTROL:
+ case WM5100_IN4R_CONTROL:
+ case WM5100_RXANC_SRC:
+ case WM5100_INPUT_VOLUME_RAMP:
+ case WM5100_ADC_DIGITAL_VOLUME_1L:
+ case WM5100_ADC_DIGITAL_VOLUME_1R:
+ case WM5100_ADC_DIGITAL_VOLUME_2L:
+ case WM5100_ADC_DIGITAL_VOLUME_2R:
+ case WM5100_ADC_DIGITAL_VOLUME_3L:
+ case WM5100_ADC_DIGITAL_VOLUME_3R:
+ case WM5100_ADC_DIGITAL_VOLUME_4L:
+ case WM5100_ADC_DIGITAL_VOLUME_4R:
+ case WM5100_OUTPUT_ENABLES_2:
+ case WM5100_OUTPUT_STATUS_1:
+ case WM5100_OUTPUT_STATUS_2:
+ case WM5100_CHANNEL_ENABLES_1:
+ case WM5100_OUT_VOLUME_1L:
+ case WM5100_OUT_VOLUME_1R:
+ case WM5100_DAC_VOLUME_LIMIT_1L:
+ case WM5100_DAC_VOLUME_LIMIT_1R:
+ case WM5100_OUT_VOLUME_2L:
+ case WM5100_OUT_VOLUME_2R:
+ case WM5100_DAC_VOLUME_LIMIT_2L:
+ case WM5100_DAC_VOLUME_LIMIT_2R:
+ case WM5100_OUT_VOLUME_3L:
+ case WM5100_OUT_VOLUME_3R:
+ case WM5100_DAC_VOLUME_LIMIT_3L:
+ case WM5100_DAC_VOLUME_LIMIT_3R:
+ case WM5100_OUT_VOLUME_4L:
+ case WM5100_OUT_VOLUME_4R:
+ case WM5100_DAC_VOLUME_LIMIT_5L:
+ case WM5100_DAC_VOLUME_LIMIT_5R:
+ case WM5100_DAC_VOLUME_LIMIT_6L:
+ case WM5100_DAC_VOLUME_LIMIT_6R:
+ case WM5100_DAC_AEC_CONTROL_1:
+ case WM5100_OUTPUT_VOLUME_RAMP:
+ case WM5100_DAC_DIGITAL_VOLUME_1L:
+ case WM5100_DAC_DIGITAL_VOLUME_1R:
+ case WM5100_DAC_DIGITAL_VOLUME_2L:
+ case WM5100_DAC_DIGITAL_VOLUME_2R:
+ case WM5100_DAC_DIGITAL_VOLUME_3L:
+ case WM5100_DAC_DIGITAL_VOLUME_3R:
+ case WM5100_DAC_DIGITAL_VOLUME_4L:
+ case WM5100_DAC_DIGITAL_VOLUME_4R:
+ case WM5100_DAC_DIGITAL_VOLUME_5L:
+ case WM5100_DAC_DIGITAL_VOLUME_5R:
+ case WM5100_DAC_DIGITAL_VOLUME_6L:
+ case WM5100_DAC_DIGITAL_VOLUME_6R:
+ case WM5100_PDM_SPK1_CTRL_1:
+ case WM5100_PDM_SPK1_CTRL_2:
+ case WM5100_PDM_SPK2_CTRL_1:
+ case WM5100_PDM_SPK2_CTRL_2:
+ case WM5100_AUDIO_IF_1_1:
+ case WM5100_AUDIO_IF_1_2:
+ case WM5100_AUDIO_IF_1_3:
+ case WM5100_AUDIO_IF_1_4:
+ case WM5100_AUDIO_IF_1_5:
+ case WM5100_AUDIO_IF_1_6:
+ case WM5100_AUDIO_IF_1_7:
+ case WM5100_AUDIO_IF_1_8:
+ case WM5100_AUDIO_IF_1_9:
+ case WM5100_AUDIO_IF_1_10:
+ case WM5100_AUDIO_IF_1_11:
+ case WM5100_AUDIO_IF_1_12:
+ case WM5100_AUDIO_IF_1_13:
+ case WM5100_AUDIO_IF_1_14:
+ case WM5100_AUDIO_IF_1_15:
+ case WM5100_AUDIO_IF_1_16:
+ case WM5100_AUDIO_IF_1_17:
+ case WM5100_AUDIO_IF_1_18:
+ case WM5100_AUDIO_IF_1_19:
+ case WM5100_AUDIO_IF_1_20:
+ case WM5100_AUDIO_IF_1_21:
+ case WM5100_AUDIO_IF_1_22:
+ case WM5100_AUDIO_IF_1_23:
+ case WM5100_AUDIO_IF_1_24:
+ case WM5100_AUDIO_IF_1_25:
+ case WM5100_AUDIO_IF_1_26:
+ case WM5100_AUDIO_IF_1_27:
+ case WM5100_AUDIO_IF_2_1:
+ case WM5100_AUDIO_IF_2_2:
+ case WM5100_AUDIO_IF_2_3:
+ case WM5100_AUDIO_IF_2_4:
+ case WM5100_AUDIO_IF_2_5:
+ case WM5100_AUDIO_IF_2_6:
+ case WM5100_AUDIO_IF_2_7:
+ case WM5100_AUDIO_IF_2_8:
+ case WM5100_AUDIO_IF_2_9:
+ case WM5100_AUDIO_IF_2_10:
+ case WM5100_AUDIO_IF_2_11:
+ case WM5100_AUDIO_IF_2_18:
+ case WM5100_AUDIO_IF_2_19:
+ case WM5100_AUDIO_IF_2_26:
+ case WM5100_AUDIO_IF_2_27:
+ case WM5100_AUDIO_IF_3_1:
+ case WM5100_AUDIO_IF_3_2:
+ case WM5100_AUDIO_IF_3_3:
+ case WM5100_AUDIO_IF_3_4:
+ case WM5100_AUDIO_IF_3_5:
+ case WM5100_AUDIO_IF_3_6:
+ case WM5100_AUDIO_IF_3_7:
+ case WM5100_AUDIO_IF_3_8:
+ case WM5100_AUDIO_IF_3_9:
+ case WM5100_AUDIO_IF_3_10:
+ case WM5100_AUDIO_IF_3_11:
+ case WM5100_AUDIO_IF_3_18:
+ case WM5100_AUDIO_IF_3_19:
+ case WM5100_AUDIO_IF_3_26:
+ case WM5100_AUDIO_IF_3_27:
+ case WM5100_PWM1MIX_INPUT_1_SOURCE:
+ case WM5100_PWM1MIX_INPUT_1_VOLUME:
+ case WM5100_PWM1MIX_INPUT_2_SOURCE:
+ case WM5100_PWM1MIX_INPUT_2_VOLUME:
+ case WM5100_PWM1MIX_INPUT_3_SOURCE:
+ case WM5100_PWM1MIX_INPUT_3_VOLUME:
+ case WM5100_PWM1MIX_INPUT_4_SOURCE:
+ case WM5100_PWM1MIX_INPUT_4_VOLUME:
+ case WM5100_PWM2MIX_INPUT_1_SOURCE:
+ case WM5100_PWM2MIX_INPUT_1_VOLUME:
+ case WM5100_PWM2MIX_INPUT_2_SOURCE:
+ case WM5100_PWM2MIX_INPUT_2_VOLUME:
+ case WM5100_PWM2MIX_INPUT_3_SOURCE:
+ case WM5100_PWM2MIX_INPUT_3_VOLUME:
+ case WM5100_PWM2MIX_INPUT_4_SOURCE:
+ case WM5100_PWM2MIX_INPUT_4_VOLUME:
+ case WM5100_OUT1LMIX_INPUT_1_SOURCE:
+ case WM5100_OUT1LMIX_INPUT_1_VOLUME:
+ case WM5100_OUT1LMIX_INPUT_2_SOURCE:
+ case WM5100_OUT1LMIX_INPUT_2_VOLUME:
+ case WM5100_OUT1LMIX_INPUT_3_SOURCE:
+ case WM5100_OUT1LMIX_INPUT_3_VOLUME:
+ case WM5100_OUT1LMIX_INPUT_4_SOURCE:
+ case WM5100_OUT1LMIX_INPUT_4_VOLUME:
+ case WM5100_OUT1RMIX_INPUT_1_SOURCE:
+ case WM5100_OUT1RMIX_INPUT_1_VOLUME:
+ case WM5100_OUT1RMIX_INPUT_2_SOURCE:
+ case WM5100_OUT1RMIX_INPUT_2_VOLUME:
+ case WM5100_OUT1RMIX_INPUT_3_SOURCE:
+ case WM5100_OUT1RMIX_INPUT_3_VOLUME:
+ case WM5100_OUT1RMIX_INPUT_4_SOURCE:
+ case WM5100_OUT1RMIX_INPUT_4_VOLUME:
+ case WM5100_OUT2LMIX_INPUT_1_SOURCE:
+ case WM5100_OUT2LMIX_INPUT_1_VOLUME:
+ case WM5100_OUT2LMIX_INPUT_2_SOURCE:
+ case WM5100_OUT2LMIX_INPUT_2_VOLUME:
+ case WM5100_OUT2LMIX_INPUT_3_SOURCE:
+ case WM5100_OUT2LMIX_INPUT_3_VOLUME:
+ case WM5100_OUT2LMIX_INPUT_4_SOURCE:
+ case WM5100_OUT2LMIX_INPUT_4_VOLUME:
+ case WM5100_OUT2RMIX_INPUT_1_SOURCE:
+ case WM5100_OUT2RMIX_INPUT_1_VOLUME:
+ case WM5100_OUT2RMIX_INPUT_2_SOURCE:
+ case WM5100_OUT2RMIX_INPUT_2_VOLUME:
+ case WM5100_OUT2RMIX_INPUT_3_SOURCE:
+ case WM5100_OUT2RMIX_INPUT_3_VOLUME:
+ case WM5100_OUT2RMIX_INPUT_4_SOURCE:
+ case WM5100_OUT2RMIX_INPUT_4_VOLUME:
+ case WM5100_OUT3LMIX_INPUT_1_SOURCE:
+ case WM5100_OUT3LMIX_INPUT_1_VOLUME:
+ case WM5100_OUT3LMIX_INPUT_2_SOURCE:
+ case WM5100_OUT3LMIX_INPUT_2_VOLUME:
+ case WM5100_OUT3LMIX_INPUT_3_SOURCE:
+ case WM5100_OUT3LMIX_INPUT_3_VOLUME:
+ case WM5100_OUT3LMIX_INPUT_4_SOURCE:
+ case WM5100_OUT3LMIX_INPUT_4_VOLUME:
+ case WM5100_OUT3RMIX_INPUT_1_SOURCE:
+ case WM5100_OUT3RMIX_INPUT_1_VOLUME:
+ case WM5100_OUT3RMIX_INPUT_2_SOURCE:
+ case WM5100_OUT3RMIX_INPUT_2_VOLUME:
+ case WM5100_OUT3RMIX_INPUT_3_SOURCE:
+ case WM5100_OUT3RMIX_INPUT_3_VOLUME:
+ case WM5100_OUT3RMIX_INPUT_4_SOURCE:
+ case WM5100_OUT3RMIX_INPUT_4_VOLUME:
+ case WM5100_OUT4LMIX_INPUT_1_SOURCE:
+ case WM5100_OUT4LMIX_INPUT_1_VOLUME:
+ case WM5100_OUT4LMIX_INPUT_2_SOURCE:
+ case WM5100_OUT4LMIX_INPUT_2_VOLUME:
+ case WM5100_OUT4LMIX_INPUT_3_SOURCE:
+ case WM5100_OUT4LMIX_INPUT_3_VOLUME:
+ case WM5100_OUT4LMIX_INPUT_4_SOURCE:
+ case WM5100_OUT4LMIX_INPUT_4_VOLUME:
+ case WM5100_OUT4RMIX_INPUT_1_SOURCE:
+ case WM5100_OUT4RMIX_INPUT_1_VOLUME:
+ case WM5100_OUT4RMIX_INPUT_2_SOURCE:
+ case WM5100_OUT4RMIX_INPUT_2_VOLUME:
+ case WM5100_OUT4RMIX_INPUT_3_SOURCE:
+ case WM5100_OUT4RMIX_INPUT_3_VOLUME:
+ case WM5100_OUT4RMIX_INPUT_4_SOURCE:
+ case WM5100_OUT4RMIX_INPUT_4_VOLUME:
+ case WM5100_OUT5LMIX_INPUT_1_SOURCE:
+ case WM5100_OUT5LMIX_INPUT_1_VOLUME:
+ case WM5100_OUT5LMIX_INPUT_2_SOURCE:
+ case WM5100_OUT5LMIX_INPUT_2_VOLUME:
+ case WM5100_OUT5LMIX_INPUT_3_SOURCE:
+ case WM5100_OUT5LMIX_INPUT_3_VOLUME:
+ case WM5100_OUT5LMIX_INPUT_4_SOURCE:
+ case WM5100_OUT5LMIX_INPUT_4_VOLUME:
+ case WM5100_OUT5RMIX_INPUT_1_SOURCE:
+ case WM5100_OUT5RMIX_INPUT_1_VOLUME:
+ case WM5100_OUT5RMIX_INPUT_2_SOURCE:
+ case WM5100_OUT5RMIX_INPUT_2_VOLUME:
+ case WM5100_OUT5RMIX_INPUT_3_SOURCE:
+ case WM5100_OUT5RMIX_INPUT_3_VOLUME:
+ case WM5100_OUT5RMIX_INPUT_4_SOURCE:
+ case WM5100_OUT5RMIX_INPUT_4_VOLUME:
+ case WM5100_OUT6LMIX_INPUT_1_SOURCE:
+ case WM5100_OUT6LMIX_INPUT_1_VOLUME:
+ case WM5100_OUT6LMIX_INPUT_2_SOURCE:
+ case WM5100_OUT6LMIX_INPUT_2_VOLUME:
+ case WM5100_OUT6LMIX_INPUT_3_SOURCE:
+ case WM5100_OUT6LMIX_INPUT_3_VOLUME:
+ case WM5100_OUT6LMIX_INPUT_4_SOURCE:
+ case WM5100_OUT6LMIX_INPUT_4_VOLUME:
+ case WM5100_OUT6RMIX_INPUT_1_SOURCE:
+ case WM5100_OUT6RMIX_INPUT_1_VOLUME:
+ case WM5100_OUT6RMIX_INPUT_2_SOURCE:
+ case WM5100_OUT6RMIX_INPUT_2_VOLUME:
+ case WM5100_OUT6RMIX_INPUT_3_SOURCE:
+ case WM5100_OUT6RMIX_INPUT_3_VOLUME:
+ case WM5100_OUT6RMIX_INPUT_4_SOURCE:
+ case WM5100_OUT6RMIX_INPUT_4_VOLUME:
+ case WM5100_AIF1TX1MIX_INPUT_1_SOURCE:
+ case WM5100_AIF1TX1MIX_INPUT_1_VOLUME:
+ case WM5100_AIF1TX1MIX_INPUT_2_SOURCE:
+ case WM5100_AIF1TX1MIX_INPUT_2_VOLUME:
+ case WM5100_AIF1TX1MIX_INPUT_3_SOURCE:
+ case WM5100_AIF1TX1MIX_INPUT_3_VOLUME:
+ case WM5100_AIF1TX1MIX_INPUT_4_SOURCE:
+ case WM5100_AIF1TX1MIX_INPUT_4_VOLUME:
+ case WM5100_AIF1TX2MIX_INPUT_1_SOURCE:
+ case WM5100_AIF1TX2MIX_INPUT_1_VOLUME:
+ case WM5100_AIF1TX2MIX_INPUT_2_SOURCE:
+ case WM5100_AIF1TX2MIX_INPUT_2_VOLUME:
+ case WM5100_AIF1TX2MIX_INPUT_3_SOURCE:
+ case WM5100_AIF1TX2MIX_INPUT_3_VOLUME:
+ case WM5100_AIF1TX2MIX_INPUT_4_SOURCE:
+ case WM5100_AIF1TX2MIX_INPUT_4_VOLUME:
+ case WM5100_AIF1TX3MIX_INPUT_1_SOURCE:
+ case WM5100_AIF1TX3MIX_INPUT_1_VOLUME:
+ case WM5100_AIF1TX3MIX_INPUT_2_SOURCE:
+ case WM5100_AIF1TX3MIX_INPUT_2_VOLUME:
+ case WM5100_AIF1TX3MIX_INPUT_3_SOURCE:
+ case WM5100_AIF1TX3MIX_INPUT_3_VOLUME:
+ case WM5100_AIF1TX3MIX_INPUT_4_SOURCE:
+ case WM5100_AIF1TX3MIX_INPUT_4_VOLUME:
+ case WM5100_AIF1TX4MIX_INPUT_1_SOURCE:
+ case WM5100_AIF1TX4MIX_INPUT_1_VOLUME:
+ case WM5100_AIF1TX4MIX_INPUT_2_SOURCE:
+ case WM5100_AIF1TX4MIX_INPUT_2_VOLUME:
+ case WM5100_AIF1TX4MIX_INPUT_3_SOURCE:
+ case WM5100_AIF1TX4MIX_INPUT_3_VOLUME:
+ case WM5100_AIF1TX4MIX_INPUT_4_SOURCE:
+ case WM5100_AIF1TX4MIX_INPUT_4_VOLUME:
+ case WM5100_AIF1TX5MIX_INPUT_1_SOURCE:
+ case WM5100_AIF1TX5MIX_INPUT_1_VOLUME:
+ case WM5100_AIF1TX5MIX_INPUT_2_SOURCE:
+ case WM5100_AIF1TX5MIX_INPUT_2_VOLUME:
+ case WM5100_AIF1TX5MIX_INPUT_3_SOURCE:
+ case WM5100_AIF1TX5MIX_INPUT_3_VOLUME:
+ case WM5100_AIF1TX5MIX_INPUT_4_SOURCE:
+ case WM5100_AIF1TX5MIX_INPUT_4_VOLUME:
+ case WM5100_AIF1TX6MIX_INPUT_1_SOURCE:
+ case WM5100_AIF1TX6MIX_INPUT_1_VOLUME:
+ case WM5100_AIF1TX6MIX_INPUT_2_SOURCE:
+ case WM5100_AIF1TX6MIX_INPUT_2_VOLUME:
+ case WM5100_AIF1TX6MIX_INPUT_3_SOURCE:
+ case WM5100_AIF1TX6MIX_INPUT_3_VOLUME:
+ case WM5100_AIF1TX6MIX_INPUT_4_SOURCE:
+ case WM5100_AIF1TX6MIX_INPUT_4_VOLUME:
+ case WM5100_AIF1TX7MIX_INPUT_1_SOURCE:
+ case WM5100_AIF1TX7MIX_INPUT_1_VOLUME:
+ case WM5100_AIF1TX7MIX_INPUT_2_SOURCE:
+ case WM5100_AIF1TX7MIX_INPUT_2_VOLUME:
+ case WM5100_AIF1TX7MIX_INPUT_3_SOURCE:
+ case WM5100_AIF1TX7MIX_INPUT_3_VOLUME:
+ case WM5100_AIF1TX7MIX_INPUT_4_SOURCE:
+ case WM5100_AIF1TX7MIX_INPUT_4_VOLUME:
+ case WM5100_AIF1TX8MIX_INPUT_1_SOURCE:
+ case WM5100_AIF1TX8MIX_INPUT_1_VOLUME:
+ case WM5100_AIF1TX8MIX_INPUT_2_SOURCE:
+ case WM5100_AIF1TX8MIX_INPUT_2_VOLUME:
+ case WM5100_AIF1TX8MIX_INPUT_3_SOURCE:
+ case WM5100_AIF1TX8MIX_INPUT_3_VOLUME:
+ case WM5100_AIF1TX8MIX_INPUT_4_SOURCE:
+ case WM5100_AIF1TX8MIX_INPUT_4_VOLUME:
+ case WM5100_AIF2TX1MIX_INPUT_1_SOURCE:
+ case WM5100_AIF2TX1MIX_INPUT_1_VOLUME:
+ case WM5100_AIF2TX1MIX_INPUT_2_SOURCE:
+ case WM5100_AIF2TX1MIX_INPUT_2_VOLUME:
+ case WM5100_AIF2TX1MIX_INPUT_3_SOURCE:
+ case WM5100_AIF2TX1MIX_INPUT_3_VOLUME:
+ case WM5100_AIF2TX1MIX_INPUT_4_SOURCE:
+ case WM5100_AIF2TX1MIX_INPUT_4_VOLUME:
+ case WM5100_AIF2TX2MIX_INPUT_1_SOURCE:
+ case WM5100_AIF2TX2MIX_INPUT_1_VOLUME:
+ case WM5100_AIF2TX2MIX_INPUT_2_SOURCE:
+ case WM5100_AIF2TX2MIX_INPUT_2_VOLUME:
+ case WM5100_AIF2TX2MIX_INPUT_3_SOURCE:
+ case WM5100_AIF2TX2MIX_INPUT_3_VOLUME:
+ case WM5100_AIF2TX2MIX_INPUT_4_SOURCE:
+ case WM5100_AIF2TX2MIX_INPUT_4_VOLUME:
+ case WM5100_AIF3TX1MIX_INPUT_1_SOURCE:
+ case WM5100_AIF3TX1MIX_INPUT_1_VOLUME:
+ case WM5100_AIF3TX1MIX_INPUT_2_SOURCE:
+ case WM5100_AIF3TX1MIX_INPUT_2_VOLUME:
+ case WM5100_AIF3TX1MIX_INPUT_3_SOURCE:
+ case WM5100_AIF3TX1MIX_INPUT_3_VOLUME:
+ case WM5100_AIF3TX1MIX_INPUT_4_SOURCE:
+ case WM5100_AIF3TX1MIX_INPUT_4_VOLUME:
+ case WM5100_AIF3TX2MIX_INPUT_1_SOURCE:
+ case WM5100_AIF3TX2MIX_INPUT_1_VOLUME:
+ case WM5100_AIF3TX2MIX_INPUT_2_SOURCE:
+ case WM5100_AIF3TX2MIX_INPUT_2_VOLUME:
+ case WM5100_AIF3TX2MIX_INPUT_3_SOURCE:
+ case WM5100_AIF3TX2MIX_INPUT_3_VOLUME:
+ case WM5100_AIF3TX2MIX_INPUT_4_SOURCE:
+ case WM5100_AIF3TX2MIX_INPUT_4_VOLUME:
+ case WM5100_EQ1MIX_INPUT_1_SOURCE:
+ case WM5100_EQ1MIX_INPUT_1_VOLUME:
+ case WM5100_EQ1MIX_INPUT_2_SOURCE:
+ case WM5100_EQ1MIX_INPUT_2_VOLUME:
+ case WM5100_EQ1MIX_INPUT_3_SOURCE:
+ case WM5100_EQ1MIX_INPUT_3_VOLUME:
+ case WM5100_EQ1MIX_INPUT_4_SOURCE:
+ case WM5100_EQ1MIX_INPUT_4_VOLUME:
+ case WM5100_EQ2MIX_INPUT_1_SOURCE:
+ case WM5100_EQ2MIX_INPUT_1_VOLUME:
+ case WM5100_EQ2MIX_INPUT_2_SOURCE:
+ case WM5100_EQ2MIX_INPUT_2_VOLUME:
+ case WM5100_EQ2MIX_INPUT_3_SOURCE:
+ case WM5100_EQ2MIX_INPUT_3_VOLUME:
+ case WM5100_EQ2MIX_INPUT_4_SOURCE:
+ case WM5100_EQ2MIX_INPUT_4_VOLUME:
+ case WM5100_EQ3MIX_INPUT_1_SOURCE:
+ case WM5100_EQ3MIX_INPUT_1_VOLUME:
+ case WM5100_EQ3MIX_INPUT_2_SOURCE:
+ case WM5100_EQ3MIX_INPUT_2_VOLUME:
+ case WM5100_EQ3MIX_INPUT_3_SOURCE:
+ case WM5100_EQ3MIX_INPUT_3_VOLUME:
+ case WM5100_EQ3MIX_INPUT_4_SOURCE:
+ case WM5100_EQ3MIX_INPUT_4_VOLUME:
+ case WM5100_EQ4MIX_INPUT_1_SOURCE:
+ case WM5100_EQ4MIX_INPUT_1_VOLUME:
+ case WM5100_EQ4MIX_INPUT_2_SOURCE:
+ case WM5100_EQ4MIX_INPUT_2_VOLUME:
+ case WM5100_EQ4MIX_INPUT_3_SOURCE:
+ case WM5100_EQ4MIX_INPUT_3_VOLUME:
+ case WM5100_EQ4MIX_INPUT_4_SOURCE:
+ case WM5100_EQ4MIX_INPUT_4_VOLUME:
+ case WM5100_DRC1LMIX_INPUT_1_SOURCE:
+ case WM5100_DRC1LMIX_INPUT_1_VOLUME:
+ case WM5100_DRC1LMIX_INPUT_2_SOURCE:
+ case WM5100_DRC1LMIX_INPUT_2_VOLUME:
+ case WM5100_DRC1LMIX_INPUT_3_SOURCE:
+ case WM5100_DRC1LMIX_INPUT_3_VOLUME:
+ case WM5100_DRC1LMIX_INPUT_4_SOURCE:
+ case WM5100_DRC1LMIX_INPUT_4_VOLUME:
+ case WM5100_DRC1RMIX_INPUT_1_SOURCE:
+ case WM5100_DRC1RMIX_INPUT_1_VOLUME:
+ case WM5100_DRC1RMIX_INPUT_2_SOURCE:
+ case WM5100_DRC1RMIX_INPUT_2_VOLUME:
+ case WM5100_DRC1RMIX_INPUT_3_SOURCE:
+ case WM5100_DRC1RMIX_INPUT_3_VOLUME:
+ case WM5100_DRC1RMIX_INPUT_4_SOURCE:
+ case WM5100_DRC1RMIX_INPUT_4_VOLUME:
+ case WM5100_HPLP1MIX_INPUT_1_SOURCE:
+ case WM5100_HPLP1MIX_INPUT_1_VOLUME:
+ case WM5100_HPLP1MIX_INPUT_2_SOURCE:
+ case WM5100_HPLP1MIX_INPUT_2_VOLUME:
+ case WM5100_HPLP1MIX_INPUT_3_SOURCE:
+ case WM5100_HPLP1MIX_INPUT_3_VOLUME:
+ case WM5100_HPLP1MIX_INPUT_4_SOURCE:
+ case WM5100_HPLP1MIX_INPUT_4_VOLUME:
+ case WM5100_HPLP2MIX_INPUT_1_SOURCE:
+ case WM5100_HPLP2MIX_INPUT_1_VOLUME:
+ case WM5100_HPLP2MIX_INPUT_2_SOURCE:
+ case WM5100_HPLP2MIX_INPUT_2_VOLUME:
+ case WM5100_HPLP2MIX_INPUT_3_SOURCE:
+ case WM5100_HPLP2MIX_INPUT_3_VOLUME:
+ case WM5100_HPLP2MIX_INPUT_4_SOURCE:
+ case WM5100_HPLP2MIX_INPUT_4_VOLUME:
+ case WM5100_HPLP3MIX_INPUT_1_SOURCE:
+ case WM5100_HPLP3MIX_INPUT_1_VOLUME:
+ case WM5100_HPLP3MIX_INPUT_2_SOURCE:
+ case WM5100_HPLP3MIX_INPUT_2_VOLUME:
+ case WM5100_HPLP3MIX_INPUT_3_SOURCE:
+ case WM5100_HPLP3MIX_INPUT_3_VOLUME:
+ case WM5100_HPLP3MIX_INPUT_4_SOURCE:
+ case WM5100_HPLP3MIX_INPUT_4_VOLUME:
+ case WM5100_HPLP4MIX_INPUT_1_SOURCE:
+ case WM5100_HPLP4MIX_INPUT_1_VOLUME:
+ case WM5100_HPLP4MIX_INPUT_2_SOURCE:
+ case WM5100_HPLP4MIX_INPUT_2_VOLUME:
+ case WM5100_HPLP4MIX_INPUT_3_SOURCE:
+ case WM5100_HPLP4MIX_INPUT_3_VOLUME:
+ case WM5100_HPLP4MIX_INPUT_4_SOURCE:
+ case WM5100_HPLP4MIX_INPUT_4_VOLUME:
+ case WM5100_DSP1LMIX_INPUT_1_SOURCE:
+ case WM5100_DSP1LMIX_INPUT_1_VOLUME:
+ case WM5100_DSP1LMIX_INPUT_2_SOURCE:
+ case WM5100_DSP1LMIX_INPUT_2_VOLUME:
+ case WM5100_DSP1LMIX_INPUT_3_SOURCE:
+ case WM5100_DSP1LMIX_INPUT_3_VOLUME:
+ case WM5100_DSP1LMIX_INPUT_4_SOURCE:
+ case WM5100_DSP1LMIX_INPUT_4_VOLUME:
+ case WM5100_DSP1RMIX_INPUT_1_SOURCE:
+ case WM5100_DSP1RMIX_INPUT_1_VOLUME:
+ case WM5100_DSP1RMIX_INPUT_2_SOURCE:
+ case WM5100_DSP1RMIX_INPUT_2_VOLUME:
+ case WM5100_DSP1RMIX_INPUT_3_SOURCE:
+ case WM5100_DSP1RMIX_INPUT_3_VOLUME:
+ case WM5100_DSP1RMIX_INPUT_4_SOURCE:
+ case WM5100_DSP1RMIX_INPUT_4_VOLUME:
+ case WM5100_DSP1AUX1MIX_INPUT_1_SOURCE:
+ case WM5100_DSP1AUX2MIX_INPUT_1_SOURCE:
+ case WM5100_DSP1AUX3MIX_INPUT_1_SOURCE:
+ case WM5100_DSP1AUX4MIX_INPUT_1_SOURCE:
+ case WM5100_DSP1AUX5MIX_INPUT_1_SOURCE:
+ case WM5100_DSP1AUX6MIX_INPUT_1_SOURCE:
+ case WM5100_DSP2LMIX_INPUT_1_SOURCE:
+ case WM5100_DSP2LMIX_INPUT_1_VOLUME:
+ case WM5100_DSP2LMIX_INPUT_2_SOURCE:
+ case WM5100_DSP2LMIX_INPUT_2_VOLUME:
+ case WM5100_DSP2LMIX_INPUT_3_SOURCE:
+ case WM5100_DSP2LMIX_INPUT_3_VOLUME:
+ case WM5100_DSP2LMIX_INPUT_4_SOURCE:
+ case WM5100_DSP2LMIX_INPUT_4_VOLUME:
+ case WM5100_DSP2RMIX_INPUT_1_SOURCE:
+ case WM5100_DSP2RMIX_INPUT_1_VOLUME:
+ case WM5100_DSP2RMIX_INPUT_2_SOURCE:
+ case WM5100_DSP2RMIX_INPUT_2_VOLUME:
+ case WM5100_DSP2RMIX_INPUT_3_SOURCE:
+ case WM5100_DSP2RMIX_INPUT_3_VOLUME:
+ case WM5100_DSP2RMIX_INPUT_4_SOURCE:
+ case WM5100_DSP2RMIX_INPUT_4_VOLUME:
+ case WM5100_DSP2AUX1MIX_INPUT_1_SOURCE:
+ case WM5100_DSP2AUX2MIX_INPUT_1_SOURCE:
+ case WM5100_DSP2AUX3MIX_INPUT_1_SOURCE:
+ case WM5100_DSP2AUX4MIX_INPUT_1_SOURCE:
+ case WM5100_DSP2AUX5MIX_INPUT_1_SOURCE:
+ case WM5100_DSP2AUX6MIX_INPUT_1_SOURCE:
+ case WM5100_DSP3LMIX_INPUT_1_SOURCE:
+ case WM5100_DSP3LMIX_INPUT_1_VOLUME:
+ case WM5100_DSP3LMIX_INPUT_2_SOURCE:
+ case WM5100_DSP3LMIX_INPUT_2_VOLUME:
+ case WM5100_DSP3LMIX_INPUT_3_SOURCE:
+ case WM5100_DSP3LMIX_INPUT_3_VOLUME:
+ case WM5100_DSP3LMIX_INPUT_4_SOURCE:
+ case WM5100_DSP3LMIX_INPUT_4_VOLUME:
+ case WM5100_DSP3RMIX_INPUT_1_SOURCE:
+ case WM5100_DSP3RMIX_INPUT_1_VOLUME:
+ case WM5100_DSP3RMIX_INPUT_2_SOURCE:
+ case WM5100_DSP3RMIX_INPUT_2_VOLUME:
+ case WM5100_DSP3RMIX_INPUT_3_SOURCE:
+ case WM5100_DSP3RMIX_INPUT_3_VOLUME:
+ case WM5100_DSP3RMIX_INPUT_4_SOURCE:
+ case WM5100_DSP3RMIX_INPUT_4_VOLUME:
+ case WM5100_DSP3AUX1MIX_INPUT_1_SOURCE:
+ case WM5100_DSP3AUX2MIX_INPUT_1_SOURCE:
+ case WM5100_DSP3AUX3MIX_INPUT_1_SOURCE:
+ case WM5100_DSP3AUX4MIX_INPUT_1_SOURCE:
+ case WM5100_DSP3AUX5MIX_INPUT_1_SOURCE:
+ case WM5100_DSP3AUX6MIX_INPUT_1_SOURCE:
+ case WM5100_ASRC1LMIX_INPUT_1_SOURCE:
+ case WM5100_ASRC1RMIX_INPUT_1_SOURCE:
+ case WM5100_ASRC2LMIX_INPUT_1_SOURCE:
+ case WM5100_ASRC2RMIX_INPUT_1_SOURCE:
+ case WM5100_ISRC1DEC1MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC1DEC2MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC1DEC3MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC1DEC4MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC1INT1MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC1INT2MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC1INT3MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC1INT4MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC2DEC1MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC2DEC2MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC2DEC3MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC2DEC4MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC2INT1MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC2INT2MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC2INT3MIX_INPUT_1_SOURCE:
+ case WM5100_ISRC2INT4MIX_INPUT_1_SOURCE:
+ case WM5100_GPIO_CTRL_1:
+ case WM5100_GPIO_CTRL_2:
+ case WM5100_GPIO_CTRL_3:
+ case WM5100_GPIO_CTRL_4:
+ case WM5100_GPIO_CTRL_5:
+ case WM5100_GPIO_CTRL_6:
+ case WM5100_MISC_PAD_CTRL_1:
+ case WM5100_MISC_PAD_CTRL_2:
+ case WM5100_MISC_PAD_CTRL_3:
+ case WM5100_MISC_PAD_CTRL_4:
+ case WM5100_MISC_PAD_CTRL_5:
+ case WM5100_MISC_GPIO_1:
+ case WM5100_INTERRUPT_STATUS_1:
+ case WM5100_INTERRUPT_STATUS_2:
+ case WM5100_INTERRUPT_STATUS_3:
+ case WM5100_INTERRUPT_STATUS_4:
+ case WM5100_INTERRUPT_RAW_STATUS_2:
+ case WM5100_INTERRUPT_RAW_STATUS_3:
+ case WM5100_INTERRUPT_RAW_STATUS_4:
+ case WM5100_INTERRUPT_STATUS_1_MASK:
+ case WM5100_INTERRUPT_STATUS_2_MASK:
+ case WM5100_INTERRUPT_STATUS_3_MASK:
+ case WM5100_INTERRUPT_STATUS_4_MASK:
+ case WM5100_INTERRUPT_CONTROL:
+ case WM5100_IRQ_DEBOUNCE_1:
+ case WM5100_IRQ_DEBOUNCE_2:
+ case WM5100_FX_CTRL:
+ case WM5100_EQ1_1:
+ case WM5100_EQ1_2:
+ case WM5100_EQ1_3:
+ case WM5100_EQ1_4:
+ case WM5100_EQ1_5:
+ case WM5100_EQ1_6:
+ case WM5100_EQ1_7:
+ case WM5100_EQ1_8:
+ case WM5100_EQ1_9:
+ case WM5100_EQ1_10:
+ case WM5100_EQ1_11:
+ case WM5100_EQ1_12:
+ case WM5100_EQ1_13:
+ case WM5100_EQ1_14:
+ case WM5100_EQ1_15:
+ case WM5100_EQ1_16:
+ case WM5100_EQ1_17:
+ case WM5100_EQ1_18:
+ case WM5100_EQ1_19:
+ case WM5100_EQ1_20:
+ case WM5100_EQ2_1:
+ case WM5100_EQ2_2:
+ case WM5100_EQ2_3:
+ case WM5100_EQ2_4:
+ case WM5100_EQ2_5:
+ case WM5100_EQ2_6:
+ case WM5100_EQ2_7:
+ case WM5100_EQ2_8:
+ case WM5100_EQ2_9:
+ case WM5100_EQ2_10:
+ case WM5100_EQ2_11:
+ case WM5100_EQ2_12:
+ case WM5100_EQ2_13:
+ case WM5100_EQ2_14:
+ case WM5100_EQ2_15:
+ case WM5100_EQ2_16:
+ case WM5100_EQ2_17:
+ case WM5100_EQ2_18:
+ case WM5100_EQ2_19:
+ case WM5100_EQ2_20:
+ case WM5100_EQ3_1:
+ case WM5100_EQ3_2:
+ case WM5100_EQ3_3:
+ case WM5100_EQ3_4:
+ case WM5100_EQ3_5:
+ case WM5100_EQ3_6:
+ case WM5100_EQ3_7:
+ case WM5100_EQ3_8:
+ case WM5100_EQ3_9:
+ case WM5100_EQ3_10:
+ case WM5100_EQ3_11:
+ case WM5100_EQ3_12:
+ case WM5100_EQ3_13:
+ case WM5100_EQ3_14:
+ case WM5100_EQ3_15:
+ case WM5100_EQ3_16:
+ case WM5100_EQ3_17:
+ case WM5100_EQ3_18:
+ case WM5100_EQ3_19:
+ case WM5100_EQ3_20:
+ case WM5100_EQ4_1:
+ case WM5100_EQ4_2:
+ case WM5100_EQ4_3:
+ case WM5100_EQ4_4:
+ case WM5100_EQ4_5:
+ case WM5100_EQ4_6:
+ case WM5100_EQ4_7:
+ case WM5100_EQ4_8:
+ case WM5100_EQ4_9:
+ case WM5100_EQ4_10:
+ case WM5100_EQ4_11:
+ case WM5100_EQ4_12:
+ case WM5100_EQ4_13:
+ case WM5100_EQ4_14:
+ case WM5100_EQ4_15:
+ case WM5100_EQ4_16:
+ case WM5100_EQ4_17:
+ case WM5100_EQ4_18:
+ case WM5100_EQ4_19:
+ case WM5100_EQ4_20:
+ case WM5100_DRC1_CTRL1:
+ case WM5100_DRC1_CTRL2:
+ case WM5100_DRC1_CTRL3:
+ case WM5100_DRC1_CTRL4:
+ case WM5100_DRC1_CTRL5:
+ case WM5100_HPLPF1_1:
+ case WM5100_HPLPF1_2:
+ case WM5100_HPLPF2_1:
+ case WM5100_HPLPF2_2:
+ case WM5100_HPLPF3_1:
+ case WM5100_HPLPF3_2:
+ case WM5100_HPLPF4_1:
+ case WM5100_HPLPF4_2:
+ case WM5100_DSP1_DM_0:
+ case WM5100_DSP1_DM_1:
+ case WM5100_DSP1_DM_2:
+ case WM5100_DSP1_DM_3:
+ case WM5100_DSP1_DM_508:
+ case WM5100_DSP1_DM_509:
+ case WM5100_DSP1_DM_510:
+ case WM5100_DSP1_DM_511:
+ case WM5100_DSP1_PM_0:
+ case WM5100_DSP1_PM_1:
+ case WM5100_DSP1_PM_2:
+ case WM5100_DSP1_PM_3:
+ case WM5100_DSP1_PM_4:
+ case WM5100_DSP1_PM_5:
+ case WM5100_DSP1_PM_1530:
+ case WM5100_DSP1_PM_1531:
+ case WM5100_DSP1_PM_1532:
+ case WM5100_DSP1_PM_1533:
+ case WM5100_DSP1_PM_1534:
+ case WM5100_DSP1_PM_1535:
+ case WM5100_DSP1_ZM_0:
+ case WM5100_DSP1_ZM_1:
+ case WM5100_DSP1_ZM_2:
+ case WM5100_DSP1_ZM_3:
+ case WM5100_DSP1_ZM_2044:
+ case WM5100_DSP1_ZM_2045:
+ case WM5100_DSP1_ZM_2046:
+ case WM5100_DSP1_ZM_2047:
+ case WM5100_DSP2_DM_0:
+ case WM5100_DSP2_DM_1:
+ case WM5100_DSP2_DM_2:
+ case WM5100_DSP2_DM_3:
+ case WM5100_DSP2_DM_508:
+ case WM5100_DSP2_DM_509:
+ case WM5100_DSP2_DM_510:
+ case WM5100_DSP2_DM_511:
+ case WM5100_DSP2_PM_0:
+ case WM5100_DSP2_PM_1:
+ case WM5100_DSP2_PM_2:
+ case WM5100_DSP2_PM_3:
+ case WM5100_DSP2_PM_4:
+ case WM5100_DSP2_PM_5:
+ case WM5100_DSP2_PM_1530:
+ case WM5100_DSP2_PM_1531:
+ case WM5100_DSP2_PM_1532:
+ case WM5100_DSP2_PM_1533:
+ case WM5100_DSP2_PM_1534:
+ case WM5100_DSP2_PM_1535:
+ case WM5100_DSP2_ZM_0:
+ case WM5100_DSP2_ZM_1:
+ case WM5100_DSP2_ZM_2:
+ case WM5100_DSP2_ZM_3:
+ case WM5100_DSP2_ZM_2044:
+ case WM5100_DSP2_ZM_2045:
+ case WM5100_DSP2_ZM_2046:
+ case WM5100_DSP2_ZM_2047:
+ case WM5100_DSP3_DM_0:
+ case WM5100_DSP3_DM_1:
+ case WM5100_DSP3_DM_2:
+ case WM5100_DSP3_DM_3:
+ case WM5100_DSP3_DM_508:
+ case WM5100_DSP3_DM_509:
+ case WM5100_DSP3_DM_510:
+ case WM5100_DSP3_DM_511:
+ case WM5100_DSP3_PM_0:
+ case WM5100_DSP3_PM_1:
+ case WM5100_DSP3_PM_2:
+ case WM5100_DSP3_PM_3:
+ case WM5100_DSP3_PM_4:
+ case WM5100_DSP3_PM_5:
+ case WM5100_DSP3_PM_1530:
+ case WM5100_DSP3_PM_1531:
+ case WM5100_DSP3_PM_1532:
+ case WM5100_DSP3_PM_1533:
+ case WM5100_DSP3_PM_1534:
+ case WM5100_DSP3_PM_1535:
+ case WM5100_DSP3_ZM_0:
+ case WM5100_DSP3_ZM_1:
+ case WM5100_DSP3_ZM_2:
+ case WM5100_DSP3_ZM_3:
+ case WM5100_DSP3_ZM_2044:
+ case WM5100_DSP3_ZM_2045:
+ case WM5100_DSP3_ZM_2046:
+ case WM5100_DSP3_ZM_2047:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+u16 wm5100_reg_defaults[WM5100_MAX_REGISTER + 1] = {
+ [0x0000] = 0x0000, /* R0 - software reset */
+ [0x0001] = 0x0000, /* R1 - Device Revision */
+ [0x0010] = 0x0801, /* R16 - Ctrl IF 1 */
+ [0x0020] = 0x0000, /* R32 - Tone Generator 1 */
+ [0x0030] = 0x0000, /* R48 - PWM Drive 1 */
+ [0x0031] = 0x0100, /* R49 - PWM Drive 2 */
+ [0x0032] = 0x0100, /* R50 - PWM Drive 3 */
+ [0x0100] = 0x0002, /* R256 - Clocking 1 */
+ [0x0101] = 0x0000, /* R257 - Clocking 3 */
+ [0x0102] = 0x0011, /* R258 - Clocking 4 */
+ [0x0103] = 0x0011, /* R259 - Clocking 5 */
+ [0x0104] = 0x0011, /* R260 - Clocking 6 */
+ [0x0107] = 0x0000, /* R263 - Clocking 7 */
+ [0x0108] = 0x0000, /* R264 - Clocking 8 */
+ [0x0120] = 0x0000, /* R288 - ASRC_ENABLE */
+ [0x0121] = 0x0000, /* R289 - ASRC_STATUS */
+ [0x0122] = 0x0000, /* R290 - ASRC_RATE1 */
+ [0x0141] = 0x8000, /* R321 - ISRC 1 CTRL 1 */
+ [0x0142] = 0x0000, /* R322 - ISRC 1 CTRL 2 */
+ [0x0143] = 0x8000, /* R323 - ISRC 2 CTRL1 */
+ [0x0144] = 0x0000, /* R324 - ISRC 2 CTRL 2 */
+ [0x0182] = 0x0000, /* R386 - FLL1 Control 1 */
+ [0x0183] = 0x0000, /* R387 - FLL1 Control 2 */
+ [0x0184] = 0x0000, /* R388 - FLL1 Control 3 */
+ [0x0186] = 0x0177, /* R390 - FLL1 Control 5 */
+ [0x0187] = 0x0001, /* R391 - FLL1 Control 6 */
+ [0x0188] = 0x0000, /* R392 - FLL1 EFS 1 */
+ [0x01A2] = 0x0000, /* R418 - FLL2 Control 1 */
+ [0x01A3] = 0x0000, /* R419 - FLL2 Control 2 */
+ [0x01A4] = 0x0000, /* R420 - FLL2 Control 3 */
+ [0x01A6] = 0x0177, /* R422 - FLL2 Control 5 */
+ [0x01A7] = 0x0001, /* R423 - FLL2 Control 6 */
+ [0x01A8] = 0x0000, /* R424 - FLL2 EFS 1 */
+ [0x0200] = 0x0020, /* R512 - Mic Charge Pump 1 */
+ [0x0201] = 0xB084, /* R513 - Mic Charge Pump 2 */
+ [0x0202] = 0xBBDE, /* R514 - HP Charge Pump 1 */
+ [0x0211] = 0x20D4, /* R529 - LDO1 Control */
+ [0x0215] = 0x0062, /* R533 - Mic Bias Ctrl 1 */
+ [0x0216] = 0x0062, /* R534 - Mic Bias Ctrl 2 */
+ [0x0217] = 0x0062, /* R535 - Mic Bias Ctrl 3 */
+ [0x0280] = 0x0004, /* R640 - Accessory Detect Mode 1 */
+ [0x0288] = 0x0020, /* R648 - Headphone Detect 1 */
+ [0x0289] = 0x0000, /* R649 - Headphone Detect 2 */
+ [0x0290] = 0x1100, /* R656 - Mic Detect 1 */
+ [0x0291] = 0x009F, /* R657 - Mic Detect 2 */
+ [0x0292] = 0x0000, /* R658 - Mic Detect 3 */
+ [0x0301] = 0x0000, /* R769 - Input Enables */
+ [0x0302] = 0x0000, /* R770 - Input Enables Status */
+ [0x0310] = 0x2280, /* R784 - Status */
+ [0x0311] = 0x0080, /* R785 - IN1R Control */
+ [0x0312] = 0x2280, /* R786 - IN2L Control */
+ [0x0313] = 0x0080, /* R787 - IN2R Control */
+ [0x0314] = 0x2280, /* R788 - IN3L Control */
+ [0x0315] = 0x0080, /* R789 - IN3R Control */
+ [0x0316] = 0x2280, /* R790 - IN4L Control */
+ [0x0317] = 0x0080, /* R791 - IN4R Control */
+ [0x0318] = 0x0000, /* R792 - RXANC_SRC */
+ [0x0319] = 0x0022, /* R793 - Input Volume Ramp */
+ [0x0320] = 0x0180, /* R800 - ADC Digital Volume 1L */
+ [0x0321] = 0x0180, /* R801 - ADC Digital Volume 1R */
+ [0x0322] = 0x0180, /* R802 - ADC Digital Volume 2L */
+ [0x0323] = 0x0180, /* R803 - ADC Digital Volume 2R */
+ [0x0324] = 0x0180, /* R804 - ADC Digital Volume 3L */
+ [0x0325] = 0x0180, /* R805 - ADC Digital Volume 3R */
+ [0x0326] = 0x0180, /* R806 - ADC Digital Volume 4L */
+ [0x0327] = 0x0180, /* R807 - ADC Digital Volume 4R */
+ [0x0401] = 0x0000, /* R1025 - Output Enables 2 */
+ [0x0402] = 0x0000, /* R1026 - Output Status 1 */
+ [0x0403] = 0x0000, /* R1027 - Output Status 2 */
+ [0x0408] = 0x0000, /* R1032 - Channel Enables 1 */
+ [0x0410] = 0x0080, /* R1040 - Out Volume 1L */
+ [0x0411] = 0x0080, /* R1041 - Out Volume 1R */
+ [0x0412] = 0x0080, /* R1042 - DAC Volume Limit 1L */
+ [0x0413] = 0x0080, /* R1043 - DAC Volume Limit 1R */
+ [0x0414] = 0x0080, /* R1044 - Out Volume 2L */
+ [0x0415] = 0x0080, /* R1045 - Out Volume 2R */
+ [0x0416] = 0x0080, /* R1046 - DAC Volume Limit 2L */
+ [0x0417] = 0x0080, /* R1047 - DAC Volume Limit 2R */
+ [0x0418] = 0x0080, /* R1048 - Out Volume 3L */
+ [0x0419] = 0x0080, /* R1049 - Out Volume 3R */
+ [0x041A] = 0x0080, /* R1050 - DAC Volume Limit 3L */
+ [0x041B] = 0x0080, /* R1051 - DAC Volume Limit 3R */
+ [0x041C] = 0x0080, /* R1052 - Out Volume 4L */
+ [0x041D] = 0x0080, /* R1053 - Out Volume 4R */
+ [0x041E] = 0x0080, /* R1054 - DAC Volume Limit 5L */
+ [0x041F] = 0x0080, /* R1055 - DAC Volume Limit 5R */
+ [0x0420] = 0x0080, /* R1056 - DAC Volume Limit 6L */
+ [0x0421] = 0x0080, /* R1057 - DAC Volume Limit 6R */
+ [0x0440] = 0x0000, /* R1088 - DAC AEC Control 1 */
+ [0x0441] = 0x0022, /* R1089 - Output Volume Ramp */
+ [0x0480] = 0x0180, /* R1152 - DAC Digital Volume 1L */
+ [0x0481] = 0x0180, /* R1153 - DAC Digital Volume 1R */
+ [0x0482] = 0x0180, /* R1154 - DAC Digital Volume 2L */
+ [0x0483] = 0x0180, /* R1155 - DAC Digital Volume 2R */
+ [0x0484] = 0x0180, /* R1156 - DAC Digital Volume 3L */
+ [0x0485] = 0x0180, /* R1157 - DAC Digital Volume 3R */
+ [0x0486] = 0x0180, /* R1158 - DAC Digital Volume 4L */
+ [0x0487] = 0x0180, /* R1159 - DAC Digital Volume 4R */
+ [0x0488] = 0x0180, /* R1160 - DAC Digital Volume 5L */
+ [0x0489] = 0x0180, /* R1161 - DAC Digital Volume 5R */
+ [0x048A] = 0x0180, /* R1162 - DAC Digital Volume 6L */
+ [0x048B] = 0x0180, /* R1163 - DAC Digital Volume 6R */
+ [0x04C0] = 0x0069, /* R1216 - PDM SPK1 CTRL 1 */
+ [0x04C1] = 0x0000, /* R1217 - PDM SPK1 CTRL 2 */
+ [0x04C2] = 0x0069, /* R1218 - PDM SPK2 CTRL 1 */
+ [0x04C3] = 0x0000, /* R1219 - PDM SPK2 CTRL 2 */
+ [0x0500] = 0x000C, /* R1280 - Audio IF 1_1 */
+ [0x0501] = 0x0008, /* R1281 - Audio IF 1_2 */
+ [0x0502] = 0x0000, /* R1282 - Audio IF 1_3 */
+ [0x0503] = 0x0000, /* R1283 - Audio IF 1_4 */
+ [0x0504] = 0x0000, /* R1284 - Audio IF 1_5 */
+ [0x0505] = 0x0300, /* R1285 - Audio IF 1_6 */
+ [0x0506] = 0x0300, /* R1286 - Audio IF 1_7 */
+ [0x0507] = 0x1820, /* R1287 - Audio IF 1_8 */
+ [0x0508] = 0x1820, /* R1288 - Audio IF 1_9 */
+ [0x0509] = 0x0000, /* R1289 - Audio IF 1_10 */
+ [0x050A] = 0x0001, /* R1290 - Audio IF 1_11 */
+ [0x050B] = 0x0002, /* R1291 - Audio IF 1_12 */
+ [0x050C] = 0x0003, /* R1292 - Audio IF 1_13 */
+ [0x050D] = 0x0004, /* R1293 - Audio IF 1_14 */
+ [0x050E] = 0x0005, /* R1294 - Audio IF 1_15 */
+ [0x050F] = 0x0006, /* R1295 - Audio IF 1_16 */
+ [0x0510] = 0x0007, /* R1296 - Audio IF 1_17 */
+ [0x0511] = 0x0000, /* R1297 - Audio IF 1_18 */
+ [0x0512] = 0x0001, /* R1298 - Audio IF 1_19 */
+ [0x0513] = 0x0002, /* R1299 - Audio IF 1_20 */
+ [0x0514] = 0x0003, /* R1300 - Audio IF 1_21 */
+ [0x0515] = 0x0004, /* R1301 - Audio IF 1_22 */
+ [0x0516] = 0x0005, /* R1302 - Audio IF 1_23 */
+ [0x0517] = 0x0006, /* R1303 - Audio IF 1_24 */
+ [0x0518] = 0x0007, /* R1304 - Audio IF 1_25 */
+ [0x0519] = 0x0000, /* R1305 - Audio IF 1_26 */
+ [0x051A] = 0x0000, /* R1306 - Audio IF 1_27 */
+ [0x0540] = 0x000C, /* R1344 - Audio IF 2_1 */
+ [0x0541] = 0x0008, /* R1345 - Audio IF 2_2 */
+ [0x0542] = 0x0000, /* R1346 - Audio IF 2_3 */
+ [0x0543] = 0x0000, /* R1347 - Audio IF 2_4 */
+ [0x0544] = 0x0000, /* R1348 - Audio IF 2_5 */
+ [0x0545] = 0x0300, /* R1349 - Audio IF 2_6 */
+ [0x0546] = 0x0300, /* R1350 - Audio IF 2_7 */
+ [0x0547] = 0x1820, /* R1351 - Audio IF 2_8 */
+ [0x0548] = 0x1820, /* R1352 - Audio IF 2_9 */
+ [0x0549] = 0x0000, /* R1353 - Audio IF 2_10 */
+ [0x054A] = 0x0001, /* R1354 - Audio IF 2_11 */
+ [0x0551] = 0x0000, /* R1361 - Audio IF 2_18 */
+ [0x0552] = 0x0001, /* R1362 - Audio IF 2_19 */
+ [0x0559] = 0x0000, /* R1369 - Audio IF 2_26 */
+ [0x055A] = 0x0000, /* R1370 - Audio IF 2_27 */
+ [0x0580] = 0x000C, /* R1408 - Audio IF 3_1 */
+ [0x0581] = 0x0008, /* R1409 - Audio IF 3_2 */
+ [0x0582] = 0x0000, /* R1410 - Audio IF 3_3 */
+ [0x0583] = 0x0000, /* R1411 - Audio IF 3_4 */
+ [0x0584] = 0x0000, /* R1412 - Audio IF 3_5 */
+ [0x0585] = 0x0300, /* R1413 - Audio IF 3_6 */
+ [0x0586] = 0x0300, /* R1414 - Audio IF 3_7 */
+ [0x0587] = 0x1820, /* R1415 - Audio IF 3_8 */
+ [0x0588] = 0x1820, /* R1416 - Audio IF 3_9 */
+ [0x0589] = 0x0000, /* R1417 - Audio IF 3_10 */
+ [0x058A] = 0x0001, /* R1418 - Audio IF 3_11 */
+ [0x0591] = 0x0000, /* R1425 - Audio IF 3_18 */
+ [0x0592] = 0x0001, /* R1426 - Audio IF 3_19 */
+ [0x0599] = 0x0000, /* R1433 - Audio IF 3_26 */
+ [0x059A] = 0x0000, /* R1434 - Audio IF 3_27 */
+ [0x0640] = 0x0000, /* R1600 - PWM1MIX Input 1 Source */
+ [0x0641] = 0x0080, /* R1601 - PWM1MIX Input 1 Volume */
+ [0x0642] = 0x0000, /* R1602 - PWM1MIX Input 2 Source */
+ [0x0643] = 0x0080, /* R1603 - PWM1MIX Input 2 Volume */
+ [0x0644] = 0x0000, /* R1604 - PWM1MIX Input 3 Source */
+ [0x0645] = 0x0080, /* R1605 - PWM1MIX Input 3 Volume */
+ [0x0646] = 0x0000, /* R1606 - PWM1MIX Input 4 Source */
+ [0x0647] = 0x0080, /* R1607 - PWM1MIX Input 4 Volume */
+ [0x0648] = 0x0000, /* R1608 - PWM2MIX Input 1 Source */
+ [0x0649] = 0x0080, /* R1609 - PWM2MIX Input 1 Volume */
+ [0x064A] = 0x0000, /* R1610 - PWM2MIX Input 2 Source */
+ [0x064B] = 0x0080, /* R1611 - PWM2MIX Input 2 Volume */
+ [0x064C] = 0x0000, /* R1612 - PWM2MIX Input 3 Source */
+ [0x064D] = 0x0080, /* R1613 - PWM2MIX Input 3 Volume */
+ [0x064E] = 0x0000, /* R1614 - PWM2MIX Input 4 Source */
+ [0x064F] = 0x0080, /* R1615 - PWM2MIX Input 4 Volume */
+ [0x0680] = 0x0000, /* R1664 - OUT1LMIX Input 1 Source */
+ [0x0681] = 0x0080, /* R1665 - OUT1LMIX Input 1 Volume */
+ [0x0682] = 0x0000, /* R1666 - OUT1LMIX Input 2 Source */
+ [0x0683] = 0x0080, /* R1667 - OUT1LMIX Input 2 Volume */
+ [0x0684] = 0x0000, /* R1668 - OUT1LMIX Input 3 Source */
+ [0x0685] = 0x0080, /* R1669 - OUT1LMIX Input 3 Volume */
+ [0x0686] = 0x0000, /* R1670 - OUT1LMIX Input 4 Source */
+ [0x0687] = 0x0080, /* R1671 - OUT1LMIX Input 4 Volume */
+ [0x0688] = 0x0000, /* R1672 - OUT1RMIX Input 1 Source */
+ [0x0689] = 0x0080, /* R1673 - OUT1RMIX Input 1 Volume */
+ [0x068A] = 0x0000, /* R1674 - OUT1RMIX Input 2 Source */
+ [0x068B] = 0x0080, /* R1675 - OUT1RMIX Input 2 Volume */
+ [0x068C] = 0x0000, /* R1676 - OUT1RMIX Input 3 Source */
+ [0x068D] = 0x0080, /* R1677 - OUT1RMIX Input 3 Volume */
+ [0x068E] = 0x0000, /* R1678 - OUT1RMIX Input 4 Source */
+ [0x068F] = 0x0080, /* R1679 - OUT1RMIX Input 4 Volume */
+ [0x0690] = 0x0000, /* R1680 - OUT2LMIX Input 1 Source */
+ [0x0691] = 0x0080, /* R1681 - OUT2LMIX Input 1 Volume */
+ [0x0692] = 0x0000, /* R1682 - OUT2LMIX Input 2 Source */
+ [0x0693] = 0x0080, /* R1683 - OUT2LMIX Input 2 Volume */
+ [0x0694] = 0x0000, /* R1684 - OUT2LMIX Input 3 Source */
+ [0x0695] = 0x0080, /* R1685 - OUT2LMIX Input 3 Volume */
+ [0x0696] = 0x0000, /* R1686 - OUT2LMIX Input 4 Source */
+ [0x0697] = 0x0080, /* R1687 - OUT2LMIX Input 4 Volume */
+ [0x0698] = 0x0000, /* R1688 - OUT2RMIX Input 1 Source */
+ [0x0699] = 0x0080, /* R1689 - OUT2RMIX Input 1 Volume */
+ [0x069A] = 0x0000, /* R1690 - OUT2RMIX Input 2 Source */
+ [0x069B] = 0x0080, /* R1691 - OUT2RMIX Input 2 Volume */
+ [0x069C] = 0x0000, /* R1692 - OUT2RMIX Input 3 Source */
+ [0x069D] = 0x0080, /* R1693 - OUT2RMIX Input 3 Volume */
+ [0x069E] = 0x0000, /* R1694 - OUT2RMIX Input 4 Source */
+ [0x069F] = 0x0080, /* R1695 - OUT2RMIX Input 4 Volume */
+ [0x06A0] = 0x0000, /* R1696 - OUT3LMIX Input 1 Source */
+ [0x06A1] = 0x0080, /* R1697 - OUT3LMIX Input 1 Volume */
+ [0x06A2] = 0x0000, /* R1698 - OUT3LMIX Input 2 Source */
+ [0x06A3] = 0x0080, /* R1699 - OUT3LMIX Input 2 Volume */
+ [0x06A4] = 0x0000, /* R1700 - OUT3LMIX Input 3 Source */
+ [0x06A5] = 0x0080, /* R1701 - OUT3LMIX Input 3 Volume */
+ [0x06A6] = 0x0000, /* R1702 - OUT3LMIX Input 4 Source */
+ [0x06A7] = 0x0080, /* R1703 - OUT3LMIX Input 4 Volume */
+ [0x06A8] = 0x0000, /* R1704 - OUT3RMIX Input 1 Source */
+ [0x06A9] = 0x0080, /* R1705 - OUT3RMIX Input 1 Volume */
+ [0x06AA] = 0x0000, /* R1706 - OUT3RMIX Input 2 Source */
+ [0x06AB] = 0x0080, /* R1707 - OUT3RMIX Input 2 Volume */
+ [0x06AC] = 0x0000, /* R1708 - OUT3RMIX Input 3 Source */
+ [0x06AD] = 0x0080, /* R1709 - OUT3RMIX Input 3 Volume */
+ [0x06AE] = 0x0000, /* R1710 - OUT3RMIX Input 4 Source */
+ [0x06AF] = 0x0080, /* R1711 - OUT3RMIX Input 4 Volume */
+ [0x06B0] = 0x0000, /* R1712 - OUT4LMIX Input 1 Source */
+ [0x06B1] = 0x0080, /* R1713 - OUT4LMIX Input 1 Volume */
+ [0x06B2] = 0x0000, /* R1714 - OUT4LMIX Input 2 Source */
+ [0x06B3] = 0x0080, /* R1715 - OUT4LMIX Input 2 Volume */
+ [0x06B4] = 0x0000, /* R1716 - OUT4LMIX Input 3 Source */
+ [0x06B5] = 0x0080, /* R1717 - OUT4LMIX Input 3 Volume */
+ [0x06B6] = 0x0000, /* R1718 - OUT4LMIX Input 4 Source */
+ [0x06B7] = 0x0080, /* R1719 - OUT4LMIX Input 4 Volume */
+ [0x06B8] = 0x0000, /* R1720 - OUT4RMIX Input 1 Source */
+ [0x06B9] = 0x0080, /* R1721 - OUT4RMIX Input 1 Volume */
+ [0x06BA] = 0x0000, /* R1722 - OUT4RMIX Input 2 Source */
+ [0x06BB] = 0x0080, /* R1723 - OUT4RMIX Input 2 Volume */
+ [0x06BC] = 0x0000, /* R1724 - OUT4RMIX Input 3 Source */
+ [0x06BD] = 0x0080, /* R1725 - OUT4RMIX Input 3 Volume */
+ [0x06BE] = 0x0000, /* R1726 - OUT4RMIX Input 4 Source */
+ [0x06BF] = 0x0080, /* R1727 - OUT4RMIX Input 4 Volume */
+ [0x06C0] = 0x0000, /* R1728 - OUT5LMIX Input 1 Source */
+ [0x06C1] = 0x0080, /* R1729 - OUT5LMIX Input 1 Volume */
+ [0x06C2] = 0x0000, /* R1730 - OUT5LMIX Input 2 Source */
+ [0x06C3] = 0x0080, /* R1731 - OUT5LMIX Input 2 Volume */
+ [0x06C4] = 0x0000, /* R1732 - OUT5LMIX Input 3 Source */
+ [0x06C5] = 0x0080, /* R1733 - OUT5LMIX Input 3 Volume */
+ [0x06C6] = 0x0000, /* R1734 - OUT5LMIX Input 4 Source */
+ [0x06C7] = 0x0080, /* R1735 - OUT5LMIX Input 4 Volume */
+ [0x06C8] = 0x0000, /* R1736 - OUT5RMIX Input 1 Source */
+ [0x06C9] = 0x0080, /* R1737 - OUT5RMIX Input 1 Volume */
+ [0x06CA] = 0x0000, /* R1738 - OUT5RMIX Input 2 Source */
+ [0x06CB] = 0x0080, /* R1739 - OUT5RMIX Input 2 Volume */
+ [0x06CC] = 0x0000, /* R1740 - OUT5RMIX Input 3 Source */
+ [0x06CD] = 0x0080, /* R1741 - OUT5RMIX Input 3 Volume */
+ [0x06CE] = 0x0000, /* R1742 - OUT5RMIX Input 4 Source */
+ [0x06CF] = 0x0080, /* R1743 - OUT5RMIX Input 4 Volume */
+ [0x06D0] = 0x0000, /* R1744 - OUT6LMIX Input 1 Source */
+ [0x06D1] = 0x0080, /* R1745 - OUT6LMIX Input 1 Volume */
+ [0x06D2] = 0x0000, /* R1746 - OUT6LMIX Input 2 Source */
+ [0x06D3] = 0x0080, /* R1747 - OUT6LMIX Input 2 Volume */
+ [0x06D4] = 0x0000, /* R1748 - OUT6LMIX Input 3 Source */
+ [0x06D5] = 0x0080, /* R1749 - OUT6LMIX Input 3 Volume */
+ [0x06D6] = 0x0000, /* R1750 - OUT6LMIX Input 4 Source */
+ [0x06D7] = 0x0080, /* R1751 - OUT6LMIX Input 4 Volume */
+ [0x06D8] = 0x0000, /* R1752 - OUT6RMIX Input 1 Source */
+ [0x06D9] = 0x0080, /* R1753 - OUT6RMIX Input 1 Volume */
+ [0x06DA] = 0x0000, /* R1754 - OUT6RMIX Input 2 Source */
+ [0x06DB] = 0x0080, /* R1755 - OUT6RMIX Input 2 Volume */
+ [0x06DC] = 0x0000, /* R1756 - OUT6RMIX Input 3 Source */
+ [0x06DD] = 0x0080, /* R1757 - OUT6RMIX Input 3 Volume */
+ [0x06DE] = 0x0000, /* R1758 - OUT6RMIX Input 4 Source */
+ [0x06DF] = 0x0080, /* R1759 - OUT6RMIX Input 4 Volume */
+ [0x0700] = 0x0000, /* R1792 - AIF1TX1MIX Input 1 Source */
+ [0x0701] = 0x0080, /* R1793 - AIF1TX1MIX Input 1 Volume */
+ [0x0702] = 0x0000, /* R1794 - AIF1TX1MIX Input 2 Source */
+ [0x0703] = 0x0080, /* R1795 - AIF1TX1MIX Input 2 Volume */
+ [0x0704] = 0x0000, /* R1796 - AIF1TX1MIX Input 3 Source */
+ [0x0705] = 0x0080, /* R1797 - AIF1TX1MIX Input 3 Volume */
+ [0x0706] = 0x0000, /* R1798 - AIF1TX1MIX Input 4 Source */
+ [0x0707] = 0x0080, /* R1799 - AIF1TX1MIX Input 4 Volume */
+ [0x0708] = 0x0000, /* R1800 - AIF1TX2MIX Input 1 Source */
+ [0x0709] = 0x0080, /* R1801 - AIF1TX2MIX Input 1 Volume */
+ [0x070A] = 0x0000, /* R1802 - AIF1TX2MIX Input 2 Source */
+ [0x070B] = 0x0080, /* R1803 - AIF1TX2MIX Input 2 Volume */
+ [0x070C] = 0x0000, /* R1804 - AIF1TX2MIX Input 3 Source */
+ [0x070D] = 0x0080, /* R1805 - AIF1TX2MIX Input 3 Volume */
+ [0x070E] = 0x0000, /* R1806 - AIF1TX2MIX Input 4 Source */
+ [0x070F] = 0x0080, /* R1807 - AIF1TX2MIX Input 4 Volume */
+ [0x0710] = 0x0000, /* R1808 - AIF1TX3MIX Input 1 Source */
+ [0x0711] = 0x0080, /* R1809 - AIF1TX3MIX Input 1 Volume */
+ [0x0712] = 0x0000, /* R1810 - AIF1TX3MIX Input 2 Source */
+ [0x0713] = 0x0080, /* R1811 - AIF1TX3MIX Input 2 Volume */
+ [0x0714] = 0x0000, /* R1812 - AIF1TX3MIX Input 3 Source */
+ [0x0715] = 0x0080, /* R1813 - AIF1TX3MIX Input 3 Volume */
+ [0x0716] = 0x0000, /* R1814 - AIF1TX3MIX Input 4 Source */
+ [0x0717] = 0x0080, /* R1815 - AIF1TX3MIX Input 4 Volume */
+ [0x0718] = 0x0000, /* R1816 - AIF1TX4MIX Input 1 Source */
+ [0x0719] = 0x0080, /* R1817 - AIF1TX4MIX Input 1 Volume */
+ [0x071A] = 0x0000, /* R1818 - AIF1TX4MIX Input 2 Source */
+ [0x071B] = 0x0080, /* R1819 - AIF1TX4MIX Input 2 Volume */
+ [0x071C] = 0x0000, /* R1820 - AIF1TX4MIX Input 3 Source */
+ [0x071D] = 0x0080, /* R1821 - AIF1TX4MIX Input 3 Volume */
+ [0x071E] = 0x0000, /* R1822 - AIF1TX4MIX Input 4 Source */
+ [0x071F] = 0x0080, /* R1823 - AIF1TX4MIX Input 4 Volume */
+ [0x0720] = 0x0000, /* R1824 - AIF1TX5MIX Input 1 Source */
+ [0x0721] = 0x0080, /* R1825 - AIF1TX5MIX Input 1 Volume */
+ [0x0722] = 0x0000, /* R1826 - AIF1TX5MIX Input 2 Source */
+ [0x0723] = 0x0080, /* R1827 - AIF1TX5MIX Input 2 Volume */
+ [0x0724] = 0x0000, /* R1828 - AIF1TX5MIX Input 3 Source */
+ [0x0725] = 0x0080, /* R1829 - AIF1TX5MIX Input 3 Volume */
+ [0x0726] = 0x0000, /* R1830 - AIF1TX5MIX Input 4 Source */
+ [0x0727] = 0x0080, /* R1831 - AIF1TX5MIX Input 4 Volume */
+ [0x0728] = 0x0000, /* R1832 - AIF1TX6MIX Input 1 Source */
+ [0x0729] = 0x0080, /* R1833 - AIF1TX6MIX Input 1 Volume */
+ [0x072A] = 0x0000, /* R1834 - AIF1TX6MIX Input 2 Source */
+ [0x072B] = 0x0080, /* R1835 - AIF1TX6MIX Input 2 Volume */
+ [0x072C] = 0x0000, /* R1836 - AIF1TX6MIX Input 3 Source */
+ [0x072D] = 0x0080, /* R1837 - AIF1TX6MIX Input 3 Volume */
+ [0x072E] = 0x0000, /* R1838 - AIF1TX6MIX Input 4 Source */
+ [0x072F] = 0x0080, /* R1839 - AIF1TX6MIX Input 4 Volume */
+ [0x0730] = 0x0000, /* R1840 - AIF1TX7MIX Input 1 Source */
+ [0x0731] = 0x0080, /* R1841 - AIF1TX7MIX Input 1 Volume */
+ [0x0732] = 0x0000, /* R1842 - AIF1TX7MIX Input 2 Source */
+ [0x0733] = 0x0080, /* R1843 - AIF1TX7MIX Input 2 Volume */
+ [0x0734] = 0x0000, /* R1844 - AIF1TX7MIX Input 3 Source */
+ [0x0735] = 0x0080, /* R1845 - AIF1TX7MIX Input 3 Volume */
+ [0x0736] = 0x0000, /* R1846 - AIF1TX7MIX Input 4 Source */
+ [0x0737] = 0x0080, /* R1847 - AIF1TX7MIX Input 4 Volume */
+ [0x0738] = 0x0000, /* R1848 - AIF1TX8MIX Input 1 Source */
+ [0x0739] = 0x0080, /* R1849 - AIF1TX8MIX Input 1 Volume */
+ [0x073A] = 0x0000, /* R1850 - AIF1TX8MIX Input 2 Source */
+ [0x073B] = 0x0080, /* R1851 - AIF1TX8MIX Input 2 Volume */
+ [0x073C] = 0x0000, /* R1852 - AIF1TX8MIX Input 3 Source */
+ [0x073D] = 0x0080, /* R1853 - AIF1TX8MIX Input 3 Volume */
+ [0x073E] = 0x0000, /* R1854 - AIF1TX8MIX Input 4 Source */
+ [0x073F] = 0x0080, /* R1855 - AIF1TX8MIX Input 4 Volume */
+ [0x0740] = 0x0000, /* R1856 - AIF2TX1MIX Input 1 Source */
+ [0x0741] = 0x0080, /* R1857 - AIF2TX1MIX Input 1 Volume */
+ [0x0742] = 0x0000, /* R1858 - AIF2TX1MIX Input 2 Source */
+ [0x0743] = 0x0080, /* R1859 - AIF2TX1MIX Input 2 Volume */
+ [0x0744] = 0x0000, /* R1860 - AIF2TX1MIX Input 3 Source */
+ [0x0745] = 0x0080, /* R1861 - AIF2TX1MIX Input 3 Volume */
+ [0x0746] = 0x0000, /* R1862 - AIF2TX1MIX Input 4 Source */
+ [0x0747] = 0x0080, /* R1863 - AIF2TX1MIX Input 4 Volume */
+ [0x0748] = 0x0000, /* R1864 - AIF2TX2MIX Input 1 Source */
+ [0x0749] = 0x0080, /* R1865 - AIF2TX2MIX Input 1 Volume */
+ [0x074A] = 0x0000, /* R1866 - AIF2TX2MIX Input 2 Source */
+ [0x074B] = 0x0080, /* R1867 - AIF2TX2MIX Input 2 Volume */
+ [0x074C] = 0x0000, /* R1868 - AIF2TX2MIX Input 3 Source */
+ [0x074D] = 0x0080, /* R1869 - AIF2TX2MIX Input 3 Volume */
+ [0x074E] = 0x0000, /* R1870 - AIF2TX2MIX Input 4 Source */
+ [0x074F] = 0x0080, /* R1871 - AIF2TX2MIX Input 4 Volume */
+ [0x0780] = 0x0000, /* R1920 - AIF3TX1MIX Input 1 Source */
+ [0x0781] = 0x0080, /* R1921 - AIF3TX1MIX Input 1 Volume */
+ [0x0782] = 0x0000, /* R1922 - AIF3TX1MIX Input 2 Source */
+ [0x0783] = 0x0080, /* R1923 - AIF3TX1MIX Input 2 Volume */
+ [0x0784] = 0x0000, /* R1924 - AIF3TX1MIX Input 3 Source */
+ [0x0785] = 0x0080, /* R1925 - AIF3TX1MIX Input 3 Volume */
+ [0x0786] = 0x0000, /* R1926 - AIF3TX1MIX Input 4 Source */
+ [0x0787] = 0x0080, /* R1927 - AIF3TX1MIX Input 4 Volume */
+ [0x0788] = 0x0000, /* R1928 - AIF3TX2MIX Input 1 Source */
+ [0x0789] = 0x0080, /* R1929 - AIF3TX2MIX Input 1 Volume */
+ [0x078A] = 0x0000, /* R1930 - AIF3TX2MIX Input 2 Source */
+ [0x078B] = 0x0080, /* R1931 - AIF3TX2MIX Input 2 Volume */
+ [0x078C] = 0x0000, /* R1932 - AIF3TX2MIX Input 3 Source */
+ [0x078D] = 0x0080, /* R1933 - AIF3TX2MIX Input 3 Volume */
+ [0x078E] = 0x0000, /* R1934 - AIF3TX2MIX Input 4 Source */
+ [0x078F] = 0x0080, /* R1935 - AIF3TX2MIX Input 4 Volume */
+ [0x0880] = 0x0000, /* R2176 - EQ1MIX Input 1 Source */
+ [0x0881] = 0x0080, /* R2177 - EQ1MIX Input 1 Volume */
+ [0x0882] = 0x0000, /* R2178 - EQ1MIX Input 2 Source */
+ [0x0883] = 0x0080, /* R2179 - EQ1MIX Input 2 Volume */
+ [0x0884] = 0x0000, /* R2180 - EQ1MIX Input 3 Source */
+ [0x0885] = 0x0080, /* R2181 - EQ1MIX Input 3 Volume */
+ [0x0886] = 0x0000, /* R2182 - EQ1MIX Input 4 Source */
+ [0x0887] = 0x0080, /* R2183 - EQ1MIX Input 4 Volume */
+ [0x0888] = 0x0000, /* R2184 - EQ2MIX Input 1 Source */
+ [0x0889] = 0x0080, /* R2185 - EQ2MIX Input 1 Volume */
+ [0x088A] = 0x0000, /* R2186 - EQ2MIX Input 2 Source */
+ [0x088B] = 0x0080, /* R2187 - EQ2MIX Input 2 Volume */
+ [0x088C] = 0x0000, /* R2188 - EQ2MIX Input 3 Source */
+ [0x088D] = 0x0080, /* R2189 - EQ2MIX Input 3 Volume */
+ [0x088E] = 0x0000, /* R2190 - EQ2MIX Input 4 Source */
+ [0x088F] = 0x0080, /* R2191 - EQ2MIX Input 4 Volume */
+ [0x0890] = 0x0000, /* R2192 - EQ3MIX Input 1 Source */
+ [0x0891] = 0x0080, /* R2193 - EQ3MIX Input 1 Volume */
+ [0x0892] = 0x0000, /* R2194 - EQ3MIX Input 2 Source */
+ [0x0893] = 0x0080, /* R2195 - EQ3MIX Input 2 Volume */
+ [0x0894] = 0x0000, /* R2196 - EQ3MIX Input 3 Source */
+ [0x0895] = 0x0080, /* R2197 - EQ3MIX Input 3 Volume */
+ [0x0896] = 0x0000, /* R2198 - EQ3MIX Input 4 Source */
+ [0x0897] = 0x0080, /* R2199 - EQ3MIX Input 4 Volume */
+ [0x0898] = 0x0000, /* R2200 - EQ4MIX Input 1 Source */
+ [0x0899] = 0x0080, /* R2201 - EQ4MIX Input 1 Volume */
+ [0x089A] = 0x0000, /* R2202 - EQ4MIX Input 2 Source */
+ [0x089B] = 0x0080, /* R2203 - EQ4MIX Input 2 Volume */
+ [0x089C] = 0x0000, /* R2204 - EQ4MIX Input 3 Source */
+ [0x089D] = 0x0080, /* R2205 - EQ4MIX Input 3 Volume */
+ [0x089E] = 0x0000, /* R2206 - EQ4MIX Input 4 Source */
+ [0x089F] = 0x0080, /* R2207 - EQ4MIX Input 4 Volume */
+ [0x08C0] = 0x0000, /* R2240 - DRC1LMIX Input 1 Source */
+ [0x08C1] = 0x0080, /* R2241 - DRC1LMIX Input 1 Volume */
+ [0x08C2] = 0x0000, /* R2242 - DRC1LMIX Input 2 Source */
+ [0x08C3] = 0x0080, /* R2243 - DRC1LMIX Input 2 Volume */
+ [0x08C4] = 0x0000, /* R2244 - DRC1LMIX Input 3 Source */
+ [0x08C5] = 0x0080, /* R2245 - DRC1LMIX Input 3 Volume */
+ [0x08C6] = 0x0000, /* R2246 - DRC1LMIX Input 4 Source */
+ [0x08C7] = 0x0080, /* R2247 - DRC1LMIX Input 4 Volume */
+ [0x08C8] = 0x0000, /* R2248 - DRC1RMIX Input 1 Source */
+ [0x08C9] = 0x0080, /* R2249 - DRC1RMIX Input 1 Volume */
+ [0x08CA] = 0x0000, /* R2250 - DRC1RMIX Input 2 Source */
+ [0x08CB] = 0x0080, /* R2251 - DRC1RMIX Input 2 Volume */
+ [0x08CC] = 0x0000, /* R2252 - DRC1RMIX Input 3 Source */
+ [0x08CD] = 0x0080, /* R2253 - DRC1RMIX Input 3 Volume */
+ [0x08CE] = 0x0000, /* R2254 - DRC1RMIX Input 4 Source */
+ [0x08CF] = 0x0080, /* R2255 - DRC1RMIX Input 4 Volume */
+ [0x0900] = 0x0000, /* R2304 - HPLP1MIX Input 1 Source */
+ [0x0901] = 0x0080, /* R2305 - HPLP1MIX Input 1 Volume */
+ [0x0902] = 0x0000, /* R2306 - HPLP1MIX Input 2 Source */
+ [0x0903] = 0x0080, /* R2307 - HPLP1MIX Input 2 Volume */
+ [0x0904] = 0x0000, /* R2308 - HPLP1MIX Input 3 Source */
+ [0x0905] = 0x0080, /* R2309 - HPLP1MIX Input 3 Volume */
+ [0x0906] = 0x0000, /* R2310 - HPLP1MIX Input 4 Source */
+ [0x0907] = 0x0080, /* R2311 - HPLP1MIX Input 4 Volume */
+ [0x0908] = 0x0000, /* R2312 - HPLP2MIX Input 1 Source */
+ [0x0909] = 0x0080, /* R2313 - HPLP2MIX Input 1 Volume */
+ [0x090A] = 0x0000, /* R2314 - HPLP2MIX Input 2 Source */
+ [0x090B] = 0x0080, /* R2315 - HPLP2MIX Input 2 Volume */
+ [0x090C] = 0x0000, /* R2316 - HPLP2MIX Input 3 Source */
+ [0x090D] = 0x0080, /* R2317 - HPLP2MIX Input 3 Volume */
+ [0x090E] = 0x0000, /* R2318 - HPLP2MIX Input 4 Source */
+ [0x090F] = 0x0080, /* R2319 - HPLP2MIX Input 4 Volume */
+ [0x0910] = 0x0000, /* R2320 - HPLP3MIX Input 1 Source */
+ [0x0911] = 0x0080, /* R2321 - HPLP3MIX Input 1 Volume */
+ [0x0912] = 0x0000, /* R2322 - HPLP3MIX Input 2 Source */
+ [0x0913] = 0x0080, /* R2323 - HPLP3MIX Input 2 Volume */
+ [0x0914] = 0x0000, /* R2324 - HPLP3MIX Input 3 Source */
+ [0x0915] = 0x0080, /* R2325 - HPLP3MIX Input 3 Volume */
+ [0x0916] = 0x0000, /* R2326 - HPLP3MIX Input 4 Source */
+ [0x0917] = 0x0080, /* R2327 - HPLP3MIX Input 4 Volume */
+ [0x0918] = 0x0000, /* R2328 - HPLP4MIX Input 1 Source */
+ [0x0919] = 0x0080, /* R2329 - HPLP4MIX Input 1 Volume */
+ [0x091A] = 0x0000, /* R2330 - HPLP4MIX Input 2 Source */
+ [0x091B] = 0x0080, /* R2331 - HPLP4MIX Input 2 Volume */
+ [0x091C] = 0x0000, /* R2332 - HPLP4MIX Input 3 Source */
+ [0x091D] = 0x0080, /* R2333 - HPLP4MIX Input 3 Volume */
+ [0x091E] = 0x0000, /* R2334 - HPLP4MIX Input 4 Source */
+ [0x091F] = 0x0080, /* R2335 - HPLP4MIX Input 4 Volume */
+ [0x0940] = 0x0000, /* R2368 - DSP1LMIX Input 1 Source */
+ [0x0941] = 0x0080, /* R2369 - DSP1LMIX Input 1 Volume */
+ [0x0942] = 0x0000, /* R2370 - DSP1LMIX Input 2 Source */
+ [0x0943] = 0x0080, /* R2371 - DSP1LMIX Input 2 Volume */
+ [0x0944] = 0x0000, /* R2372 - DSP1LMIX Input 3 Source */
+ [0x0945] = 0x0080, /* R2373 - DSP1LMIX Input 3 Volume */
+ [0x0946] = 0x0000, /* R2374 - DSP1LMIX Input 4 Source */
+ [0x0947] = 0x0080, /* R2375 - DSP1LMIX Input 4 Volume */
+ [0x0948] = 0x0000, /* R2376 - DSP1RMIX Input 1 Source */
+ [0x0949] = 0x0080, /* R2377 - DSP1RMIX Input 1 Volume */
+ [0x094A] = 0x0000, /* R2378 - DSP1RMIX Input 2 Source */
+ [0x094B] = 0x0080, /* R2379 - DSP1RMIX Input 2 Volume */
+ [0x094C] = 0x0000, /* R2380 - DSP1RMIX Input 3 Source */
+ [0x094D] = 0x0080, /* R2381 - DSP1RMIX Input 3 Volume */
+ [0x094E] = 0x0000, /* R2382 - DSP1RMIX Input 4 Source */
+ [0x094F] = 0x0080, /* R2383 - DSP1RMIX Input 4 Volume */
+ [0x0950] = 0x0000, /* R2384 - DSP1AUX1MIX Input 1 Source */
+ [0x0958] = 0x0000, /* R2392 - DSP1AUX2MIX Input 1 Source */
+ [0x0960] = 0x0000, /* R2400 - DSP1AUX3MIX Input 1 Source */
+ [0x0968] = 0x0000, /* R2408 - DSP1AUX4MIX Input 1 Source */
+ [0x0970] = 0x0000, /* R2416 - DSP1AUX5MIX Input 1 Source */
+ [0x0978] = 0x0000, /* R2424 - DSP1AUX6MIX Input 1 Source */
+ [0x0980] = 0x0000, /* R2432 - DSP2LMIX Input 1 Source */
+ [0x0981] = 0x0080, /* R2433 - DSP2LMIX Input 1 Volume */
+ [0x0982] = 0x0000, /* R2434 - DSP2LMIX Input 2 Source */
+ [0x0983] = 0x0080, /* R2435 - DSP2LMIX Input 2 Volume */
+ [0x0984] = 0x0000, /* R2436 - DSP2LMIX Input 3 Source */
+ [0x0985] = 0x0080, /* R2437 - DSP2LMIX Input 3 Volume */
+ [0x0986] = 0x0000, /* R2438 - DSP2LMIX Input 4 Source */
+ [0x0987] = 0x0080, /* R2439 - DSP2LMIX Input 4 Volume */
+ [0x0988] = 0x0000, /* R2440 - DSP2RMIX Input 1 Source */
+ [0x0989] = 0x0080, /* R2441 - DSP2RMIX Input 1 Volume */
+ [0x098A] = 0x0000, /* R2442 - DSP2RMIX Input 2 Source */
+ [0x098B] = 0x0080, /* R2443 - DSP2RMIX Input 2 Volume */
+ [0x098C] = 0x0000, /* R2444 - DSP2RMIX Input 3 Source */
+ [0x098D] = 0x0080, /* R2445 - DSP2RMIX Input 3 Volume */
+ [0x098E] = 0x0000, /* R2446 - DSP2RMIX Input 4 Source */
+ [0x098F] = 0x0080, /* R2447 - DSP2RMIX Input 4 Volume */
+ [0x0990] = 0x0000, /* R2448 - DSP2AUX1MIX Input 1 Source */
+ [0x0998] = 0x0000, /* R2456 - DSP2AUX2MIX Input 1 Source */
+ [0x09A0] = 0x0000, /* R2464 - DSP2AUX3MIX Input 1 Source */
+ [0x09A8] = 0x0000, /* R2472 - DSP2AUX4MIX Input 1 Source */
+ [0x09B0] = 0x0000, /* R2480 - DSP2AUX5MIX Input 1 Source */
+ [0x09B8] = 0x0000, /* R2488 - DSP2AUX6MIX Input 1 Source */
+ [0x09C0] = 0x0000, /* R2496 - DSP3LMIX Input 1 Source */
+ [0x09C1] = 0x0080, /* R2497 - DSP3LMIX Input 1 Volume */
+ [0x09C2] = 0x0000, /* R2498 - DSP3LMIX Input 2 Source */
+ [0x09C3] = 0x0080, /* R2499 - DSP3LMIX Input 2 Volume */
+ [0x09C4] = 0x0000, /* R2500 - DSP3LMIX Input 3 Source */
+ [0x09C5] = 0x0080, /* R2501 - DSP3LMIX Input 3 Volume */
+ [0x09C6] = 0x0000, /* R2502 - DSP3LMIX Input 4 Source */
+ [0x09C7] = 0x0080, /* R2503 - DSP3LMIX Input 4 Volume */
+ [0x09C8] = 0x0000, /* R2504 - DSP3RMIX Input 1 Source */
+ [0x09C9] = 0x0080, /* R2505 - DSP3RMIX Input 1 Volume */
+ [0x09CA] = 0x0000, /* R2506 - DSP3RMIX Input 2 Source */
+ [0x09CB] = 0x0080, /* R2507 - DSP3RMIX Input 2 Volume */
+ [0x09CC] = 0x0000, /* R2508 - DSP3RMIX Input 3 Source */
+ [0x09CD] = 0x0080, /* R2509 - DSP3RMIX Input 3 Volume */
+ [0x09CE] = 0x0000, /* R2510 - DSP3RMIX Input 4 Source */
+ [0x09CF] = 0x0080, /* R2511 - DSP3RMIX Input 4 Volume */
+ [0x09D0] = 0x0000, /* R2512 - DSP3AUX1MIX Input 1 Source */
+ [0x09D8] = 0x0000, /* R2520 - DSP3AUX2MIX Input 1 Source */
+ [0x09E0] = 0x0000, /* R2528 - DSP3AUX3MIX Input 1 Source */
+ [0x09E8] = 0x0000, /* R2536 - DSP3AUX4MIX Input 1 Source */
+ [0x09F0] = 0x0000, /* R2544 - DSP3AUX5MIX Input 1 Source */
+ [0x09F8] = 0x0000, /* R2552 - DSP3AUX6MIX Input 1 Source */
+ [0x0A80] = 0x0000, /* R2688 - ASRC1LMIX Input 1 Source */
+ [0x0A88] = 0x0000, /* R2696 - ASRC1RMIX Input 1 Source */
+ [0x0A90] = 0x0000, /* R2704 - ASRC2LMIX Input 1 Source */
+ [0x0A98] = 0x0000, /* R2712 - ASRC2RMIX Input 1 Source */
+ [0x0B00] = 0x0000, /* R2816 - ISRC1DEC1MIX Input 1 Source */
+ [0x0B08] = 0x0000, /* R2824 - ISRC1DEC2MIX Input 1 Source */
+ [0x0B10] = 0x0000, /* R2832 - ISRC1DEC3MIX Input 1 Source */
+ [0x0B18] = 0x0000, /* R2840 - ISRC1DEC4MIX Input 1 Source */
+ [0x0B20] = 0x0000, /* R2848 - ISRC1INT1MIX Input 1 Source */
+ [0x0B28] = 0x0000, /* R2856 - ISRC1INT2MIX Input 1 Source */
+ [0x0B30] = 0x0000, /* R2864 - ISRC1INT3MIX Input 1 Source */
+ [0x0B38] = 0x0000, /* R2872 - ISRC1INT4MIX Input 1 Source */
+ [0x0B40] = 0x0000, /* R2880 - ISRC2DEC1MIX Input 1 Source */
+ [0x0B48] = 0x0000, /* R2888 - ISRC2DEC2MIX Input 1 Source */
+ [0x0B50] = 0x0000, /* R2896 - ISRC2DEC3MIX Input 1 Source */
+ [0x0B58] = 0x0000, /* R2904 - ISRC2DEC4MIX Input 1 Source */
+ [0x0B60] = 0x0000, /* R2912 - ISRC2INT1MIX Input 1 Source */
+ [0x0B68] = 0x0000, /* R2920 - ISRC2INT2MIX Input 1 Source */
+ [0x0B70] = 0x0000, /* R2928 - ISRC2INT3MIX Input 1 Source */
+ [0x0B78] = 0x0000, /* R2936 - ISRC2INT4MIX Input 1 Source */
+ [0x0C00] = 0xA001, /* R3072 - GPIO CTRL 1 */
+ [0x0C01] = 0xA001, /* R3073 - GPIO CTRL 2 */
+ [0x0C02] = 0xA001, /* R3074 - GPIO CTRL 3 */
+ [0x0C03] = 0xA001, /* R3075 - GPIO CTRL 4 */
+ [0x0C04] = 0xA001, /* R3076 - GPIO CTRL 5 */
+ [0x0C05] = 0xA001, /* R3077 - GPIO CTRL 6 */
+ [0x0C23] = 0x4003, /* R3107 - Misc Pad Ctrl 1 */
+ [0x0C24] = 0x0000, /* R3108 - Misc Pad Ctrl 2 */
+ [0x0C25] = 0x0000, /* R3109 - Misc Pad Ctrl 3 */
+ [0x0C26] = 0x0000, /* R3110 - Misc Pad Ctrl 4 */
+ [0x0C27] = 0x0000, /* R3111 - Misc Pad Ctrl 5 */
+ [0x0C28] = 0x0000, /* R3112 - Misc GPIO 1 */
+ [0x0D00] = 0x0000, /* R3328 - Interrupt Status 1 */
+ [0x0D01] = 0x0000, /* R3329 - Interrupt Status 2 */
+ [0x0D02] = 0x0000, /* R3330 - Interrupt Status 3 */
+ [0x0D03] = 0x0000, /* R3331 - Interrupt Status 4 */
+ [0x0D04] = 0x0000, /* R3332 - Interrupt Raw Status 2 */
+ [0x0D05] = 0x0000, /* R3333 - Interrupt Raw Status 3 */
+ [0x0D06] = 0x0000, /* R3334 - Interrupt Raw Status 4 */
+ [0x0D07] = 0xFFFF, /* R3335 - Interrupt Status 1 Mask */
+ [0x0D08] = 0xFFFF, /* R3336 - Interrupt Status 2 Mask */
+ [0x0D09] = 0xFFFF, /* R3337 - Interrupt Status 3 Mask */
+ [0x0D0A] = 0xFFFF, /* R3338 - Interrupt Status 4 Mask */
+ [0x0D1F] = 0x0000, /* R3359 - Interrupt Control */
+ [0x0D20] = 0xFFFF, /* R3360 - IRQ Debounce 1 */
+ [0x0D21] = 0xFFFF, /* R3361 - IRQ Debounce 2 */
+ [0x0E00] = 0x0000, /* R3584 - FX_Ctrl */
+ [0x0E10] = 0x6318, /* R3600 - EQ1_1 */
+ [0x0E11] = 0x6300, /* R3601 - EQ1_2 */
+ [0x0E12] = 0x0FC8, /* R3602 - EQ1_3 */
+ [0x0E13] = 0x03FE, /* R3603 - EQ1_4 */
+ [0x0E14] = 0x00E0, /* R3604 - EQ1_5 */
+ [0x0E15] = 0x1EC4, /* R3605 - EQ1_6 */
+ [0x0E16] = 0xF136, /* R3606 - EQ1_7 */
+ [0x0E17] = 0x0409, /* R3607 - EQ1_8 */
+ [0x0E18] = 0x04CC, /* R3608 - EQ1_9 */
+ [0x0E19] = 0x1C9B, /* R3609 - EQ1_10 */
+ [0x0E1A] = 0xF337, /* R3610 - EQ1_11 */
+ [0x0E1B] = 0x040B, /* R3611 - EQ1_12 */
+ [0x0E1C] = 0x0CBB, /* R3612 - EQ1_13 */
+ [0x0E1D] = 0x16F8, /* R3613 - EQ1_14 */
+ [0x0E1E] = 0xF7D9, /* R3614 - EQ1_15 */
+ [0x0E1F] = 0x040A, /* R3615 - EQ1_16 */
+ [0x0E20] = 0x1F14, /* R3616 - EQ1_17 */
+ [0x0E21] = 0x058C, /* R3617 - EQ1_18 */
+ [0x0E22] = 0x0563, /* R3618 - EQ1_19 */
+ [0x0E23] = 0x4000, /* R3619 - EQ1_20 */
+ [0x0E26] = 0x6318, /* R3622 - EQ2_1 */
+ [0x0E27] = 0x6300, /* R3623 - EQ2_2 */
+ [0x0E28] = 0x0FC8, /* R3624 - EQ2_3 */
+ [0x0E29] = 0x03FE, /* R3625 - EQ2_4 */
+ [0x0E2A] = 0x00E0, /* R3626 - EQ2_5 */
+ [0x0E2B] = 0x1EC4, /* R3627 - EQ2_6 */
+ [0x0E2C] = 0xF136, /* R3628 - EQ2_7 */
+ [0x0E2D] = 0x0409, /* R3629 - EQ2_8 */
+ [0x0E2E] = 0x04CC, /* R3630 - EQ2_9 */
+ [0x0E2F] = 0x1C9B, /* R3631 - EQ2_10 */
+ [0x0E30] = 0xF337, /* R3632 - EQ2_11 */
+ [0x0E31] = 0x040B, /* R3633 - EQ2_12 */
+ [0x0E32] = 0x0CBB, /* R3634 - EQ2_13 */
+ [0x0E33] = 0x16F8, /* R3635 - EQ2_14 */
+ [0x0E34] = 0xF7D9, /* R3636 - EQ2_15 */
+ [0x0E35] = 0x040A, /* R3637 - EQ2_16 */
+ [0x0E36] = 0x1F14, /* R3638 - EQ2_17 */
+ [0x0E37] = 0x058C, /* R3639 - EQ2_18 */
+ [0x0E38] = 0x0563, /* R3640 - EQ2_19 */
+ [0x0E39] = 0x4000, /* R3641 - EQ2_20 */
+ [0x0E3C] = 0x6318, /* R3644 - EQ3_1 */
+ [0x0E3D] = 0x6300, /* R3645 - EQ3_2 */
+ [0x0E3E] = 0x0FC8, /* R3646 - EQ3_3 */
+ [0x0E3F] = 0x03FE, /* R3647 - EQ3_4 */
+ [0x0E40] = 0x00E0, /* R3648 - EQ3_5 */
+ [0x0E41] = 0x1EC4, /* R3649 - EQ3_6 */
+ [0x0E42] = 0xF136, /* R3650 - EQ3_7 */
+ [0x0E43] = 0x0409, /* R3651 - EQ3_8 */
+ [0x0E44] = 0x04CC, /* R3652 - EQ3_9 */
+ [0x0E45] = 0x1C9B, /* R3653 - EQ3_10 */
+ [0x0E46] = 0xF337, /* R3654 - EQ3_11 */
+ [0x0E47] = 0x040B, /* R3655 - EQ3_12 */
+ [0x0E48] = 0x0CBB, /* R3656 - EQ3_13 */
+ [0x0E49] = 0x16F8, /* R3657 - EQ3_14 */
+ [0x0E4A] = 0xF7D9, /* R3658 - EQ3_15 */
+ [0x0E4B] = 0x040A, /* R3659 - EQ3_16 */
+ [0x0E4C] = 0x1F14, /* R3660 - EQ3_17 */
+ [0x0E4D] = 0x058C, /* R3661 - EQ3_18 */
+ [0x0E4E] = 0x0563, /* R3662 - EQ3_19 */
+ [0x0E4F] = 0x4000, /* R3663 - EQ3_20 */
+ [0x0E52] = 0x6318, /* R3666 - EQ4_1 */
+ [0x0E53] = 0x6300, /* R3667 - EQ4_2 */
+ [0x0E54] = 0x0FC8, /* R3668 - EQ4_3 */
+ [0x0E55] = 0x03FE, /* R3669 - EQ4_4 */
+ [0x0E56] = 0x00E0, /* R3670 - EQ4_5 */
+ [0x0E57] = 0x1EC4, /* R3671 - EQ4_6 */
+ [0x0E58] = 0xF136, /* R3672 - EQ4_7 */
+ [0x0E59] = 0x0409, /* R3673 - EQ4_8 */
+ [0x0E5A] = 0x04CC, /* R3674 - EQ4_9 */
+ [0x0E5B] = 0x1C9B, /* R3675 - EQ4_10 */
+ [0x0E5C] = 0xF337, /* R3676 - EQ4_11 */
+ [0x0E5D] = 0x040B, /* R3677 - EQ4_12 */
+ [0x0E5E] = 0x0CBB, /* R3678 - EQ4_13 */
+ [0x0E5F] = 0x16F8, /* R3679 - EQ4_14 */
+ [0x0E60] = 0xF7D9, /* R3680 - EQ4_15 */
+ [0x0E61] = 0x040A, /* R3681 - EQ4_16 */
+ [0x0E62] = 0x1F14, /* R3682 - EQ4_17 */
+ [0x0E63] = 0x058C, /* R3683 - EQ4_18 */
+ [0x0E64] = 0x0563, /* R3684 - EQ4_19 */
+ [0x0E65] = 0x4000, /* R3685 - EQ4_20 */
+ [0x0E80] = 0x0018, /* R3712 - DRC1 ctrl1 */
+ [0x0E81] = 0x0933, /* R3713 - DRC1 ctrl2 */
+ [0x0E82] = 0x0018, /* R3714 - DRC1 ctrl3 */
+ [0x0E83] = 0x0000, /* R3715 - DRC1 ctrl4 */
+ [0x0E84] = 0x0000, /* R3716 - DRC1 ctrl5 */
+ [0x0EC0] = 0x0000, /* R3776 - HPLPF1_1 */
+ [0x0EC1] = 0x0000, /* R3777 - HPLPF1_2 */
+ [0x0EC4] = 0x0000, /* R3780 - HPLPF2_1 */
+ [0x0EC5] = 0x0000, /* R3781 - HPLPF2_2 */
+ [0x0EC8] = 0x0000, /* R3784 - HPLPF3_1 */
+ [0x0EC9] = 0x0000, /* R3785 - HPLPF3_2 */
+ [0x0ECC] = 0x0000, /* R3788 - HPLPF4_1 */
+ [0x0ECD] = 0x0000, /* R3789 - HPLPF4_2 */
+ [0x4000] = 0x0000, /* R16384 - DSP1 DM 0 */
+ [0x4001] = 0x0000, /* R16385 - DSP1 DM 1 */
+ [0x4002] = 0x0000, /* R16386 - DSP1 DM 2 */
+ [0x4003] = 0x0000, /* R16387 - DSP1 DM 3 */
+ [0x41FC] = 0x0000, /* R16892 - DSP1 DM 508 */
+ [0x41FD] = 0x0000, /* R16893 - DSP1 DM 509 */
+ [0x41FE] = 0x0000, /* R16894 - DSP1 DM 510 */
+ [0x41FF] = 0x0000, /* R16895 - DSP1 DM 511 */
+ [0x4800] = 0x0000, /* R18432 - DSP1 PM 0 */
+ [0x4801] = 0x0000, /* R18433 - DSP1 PM 1 */
+ [0x4802] = 0x0000, /* R18434 - DSP1 PM 2 */
+ [0x4803] = 0x0000, /* R18435 - DSP1 PM 3 */
+ [0x4804] = 0x0000, /* R18436 - DSP1 PM 4 */
+ [0x4805] = 0x0000, /* R18437 - DSP1 PM 5 */
+ [0x4DFA] = 0x0000, /* R19962 - DSP1 PM 1530 */
+ [0x4DFB] = 0x0000, /* R19963 - DSP1 PM 1531 */
+ [0x4DFC] = 0x0000, /* R19964 - DSP1 PM 1532 */
+ [0x4DFD] = 0x0000, /* R19965 - DSP1 PM 1533 */
+ [0x4DFE] = 0x0000, /* R19966 - DSP1 PM 1534 */
+ [0x4DFF] = 0x0000, /* R19967 - DSP1 PM 1535 */
+ [0x5000] = 0x0000, /* R20480 - DSP1 ZM 0 */
+ [0x5001] = 0x0000, /* R20481 - DSP1 ZM 1 */
+ [0x5002] = 0x0000, /* R20482 - DSP1 ZM 2 */
+ [0x5003] = 0x0000, /* R20483 - DSP1 ZM 3 */
+ [0x57FC] = 0x0000, /* R22524 - DSP1 ZM 2044 */
+ [0x57FD] = 0x0000, /* R22525 - DSP1 ZM 2045 */
+ [0x57FE] = 0x0000, /* R22526 - DSP1 ZM 2046 */
+ [0x57FF] = 0x0000, /* R22527 - DSP1 ZM 2047 */
+ [0x6000] = 0x0000, /* R24576 - DSP2 DM 0 */
+ [0x6001] = 0x0000, /* R24577 - DSP2 DM 1 */
+ [0x6002] = 0x0000, /* R24578 - DSP2 DM 2 */
+ [0x6003] = 0x0000, /* R24579 - DSP2 DM 3 */
+ [0x61FC] = 0x0000, /* R25084 - DSP2 DM 508 */
+ [0x61FD] = 0x0000, /* R25085 - DSP2 DM 509 */
+ [0x61FE] = 0x0000, /* R25086 - DSP2 DM 510 */
+ [0x61FF] = 0x0000, /* R25087 - DSP2 DM 511 */
+ [0x6800] = 0x0000, /* R26624 - DSP2 PM 0 */
+ [0x6801] = 0x0000, /* R26625 - DSP2 PM 1 */
+ [0x6802] = 0x0000, /* R26626 - DSP2 PM 2 */
+ [0x6803] = 0x0000, /* R26627 - DSP2 PM 3 */
+ [0x6804] = 0x0000, /* R26628 - DSP2 PM 4 */
+ [0x6805] = 0x0000, /* R26629 - DSP2 PM 5 */
+ [0x6DFA] = 0x0000, /* R28154 - DSP2 PM 1530 */
+ [0x6DFB] = 0x0000, /* R28155 - DSP2 PM 1531 */
+ [0x6DFC] = 0x0000, /* R28156 - DSP2 PM 1532 */
+ [0x6DFD] = 0x0000, /* R28157 - DSP2 PM 1533 */
+ [0x6DFE] = 0x0000, /* R28158 - DSP2 PM 1534 */
+ [0x6DFF] = 0x0000, /* R28159 - DSP2 PM 1535 */
+ [0x7000] = 0x0000, /* R28672 - DSP2 ZM 0 */
+ [0x7001] = 0x0000, /* R28673 - DSP2 ZM 1 */
+ [0x7002] = 0x0000, /* R28674 - DSP2 ZM 2 */
+ [0x7003] = 0x0000, /* R28675 - DSP2 ZM 3 */
+ [0x77FC] = 0x0000, /* R30716 - DSP2 ZM 2044 */
+ [0x77FD] = 0x0000, /* R30717 - DSP2 ZM 2045 */
+ [0x77FE] = 0x0000, /* R30718 - DSP2 ZM 2046 */
+ [0x77FF] = 0x0000, /* R30719 - DSP2 ZM 2047 */
+ [0x8000] = 0x0000, /* R32768 - DSP3 DM 0 */
+ [0x8001] = 0x0000, /* R32769 - DSP3 DM 1 */
+ [0x8002] = 0x0000, /* R32770 - DSP3 DM 2 */
+ [0x8003] = 0x0000, /* R32771 - DSP3 DM 3 */
+ [0x81FC] = 0x0000, /* R33276 - DSP3 DM 508 */
+ [0x81FD] = 0x0000, /* R33277 - DSP3 DM 509 */
+ [0x81FE] = 0x0000, /* R33278 - DSP3 DM 510 */
+ [0x81FF] = 0x0000, /* R33279 - DSP3 DM 511 */
+ [0x8800] = 0x0000, /* R34816 - DSP3 PM 0 */
+ [0x8801] = 0x0000, /* R34817 - DSP3 PM 1 */
+ [0x8802] = 0x0000, /* R34818 - DSP3 PM 2 */
+ [0x8803] = 0x0000, /* R34819 - DSP3 PM 3 */
+ [0x8804] = 0x0000, /* R34820 - DSP3 PM 4 */
+ [0x8805] = 0x0000, /* R34821 - DSP3 PM 5 */
+ [0x8DFA] = 0x0000, /* R36346 - DSP3 PM 1530 */
+ [0x8DFB] = 0x0000, /* R36347 - DSP3 PM 1531 */
+ [0x8DFC] = 0x0000, /* R36348 - DSP3 PM 1532 */
+ [0x8DFD] = 0x0000, /* R36349 - DSP3 PM 1533 */
+ [0x8DFE] = 0x0000, /* R36350 - DSP3 PM 1534 */
+ [0x8DFF] = 0x0000, /* R36351 - DSP3 PM 1535 */
+ [0x9000] = 0x0000, /* R36864 - DSP3 ZM 0 */
+ [0x9001] = 0x0000, /* R36865 - DSP3 ZM 1 */
+ [0x9002] = 0x0000, /* R36866 - DSP3 ZM 2 */
+ [0x9003] = 0x0000, /* R36867 - DSP3 ZM 3 */
+ [0x97FC] = 0x0000, /* R38908 - DSP3 ZM 2044 */
+ [0x97FD] = 0x0000, /* R38909 - DSP3 ZM 2045 */
+ [0x97FE] = 0x0000, /* R38910 - DSP3 ZM 2046 */
+ [0x97FF] = 0x0000 /* R38911 - DSP3 ZM 2047 */
+};
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
new file mode 100644
index 000000000000..42d9039a49e9
--- /dev/null
+++ b/sound/soc/codecs/wm5100.c
@@ -0,0 +1,2813 @@
+/*
+ * wm5100.c -- WM5100 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/fixed.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm5100.h>
+
+#include "wm5100.h"
+
+#define WM5100_NUM_CORE_SUPPLIES 2
+static const char *wm5100_core_supply_names[WM5100_NUM_CORE_SUPPLIES] = {
+ "DBVDD1",
+ "LDOVDD", /* If DCVDD is supplied externally specify as LDOVDD */
+};
+
+#define WM5100_AIFS 3
+#define WM5100_SYNC_SRS 3
+
+struct wm5100_fll {
+ int fref;
+ int fout;
+ int src;
+ struct completion lock;
+};
+
+/* codec private data */
+struct wm5100_priv {
+ struct snd_soc_codec *codec;
+
+ struct regulator_bulk_data core_supplies[WM5100_NUM_CORE_SUPPLIES];
+ struct regulator *cpvdd;
+ struct regulator *dbvdd2;
+ struct regulator *dbvdd3;
+
+ int rev;
+
+ int sysclk;
+ int asyncclk;
+
+ bool aif_async[WM5100_AIFS];
+ bool aif_symmetric[WM5100_AIFS];
+ int sr_ref[WM5100_SYNC_SRS];
+
+ bool out_ena[2];
+
+ struct snd_soc_jack *jack;
+ bool jack_detecting;
+ bool jack_mic;
+ int jack_mode;
+
+ struct wm5100_fll fll[2];
+
+ struct wm5100_pdata pdata;
+
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gpio_chip;
+#endif
+};
+
+static int wm5100_sr_code[] = {
+ 0,
+ 12000,
+ 24000,
+ 48000,
+ 96000,
+ 192000,
+ 384000,
+ 768000,
+ 0,
+ 11025,
+ 22050,
+ 44100,
+ 88200,
+ 176400,
+ 352800,
+ 705600,
+ 4000,
+ 8000,
+ 16000,
+ 32000,
+ 64000,
+ 128000,
+ 256000,
+ 512000,
+};
+
+static int wm5100_sr_regs[WM5100_SYNC_SRS] = {
+ WM5100_CLOCKING_4,
+ WM5100_CLOCKING_5,
+ WM5100_CLOCKING_6,
+};
+
+static int wm5100_alloc_sr(struct snd_soc_codec *codec, int rate)
+{
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ int sr_code, sr_free, i;
+
+ for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
+ if (wm5100_sr_code[i] == rate)
+ break;
+ if (i == ARRAY_SIZE(wm5100_sr_code)) {
+ dev_err(codec->dev, "Unsupported sample rate: %dHz\n", rate);
+ return -EINVAL;
+ }
+ sr_code = i;
+
+ if ((wm5100->sysclk % rate) == 0) {
+ /* Is this rate already in use? */
+ sr_free = -1;
+ for (i = 0; i < ARRAY_SIZE(wm5100_sr_regs); i++) {
+ if (!wm5100->sr_ref[i] && sr_free == -1) {
+ sr_free = i;
+ continue;
+ }
+ if ((snd_soc_read(codec, wm5100_sr_regs[i]) &
+ WM5100_SAMPLE_RATE_1_MASK) == sr_code)
+ break;
+ }
+
+ if (i < ARRAY_SIZE(wm5100_sr_regs)) {
+ wm5100->sr_ref[i]++;
+ dev_dbg(codec->dev, "SR %dHz, slot %d, ref %d\n",
+ rate, i, wm5100->sr_ref[i]);
+ return i;
+ }
+
+ if (sr_free == -1) {
+ dev_err(codec->dev, "All SR slots already in use\n");
+ return -EBUSY;
+ }
+
+ dev_dbg(codec->dev, "Allocating SR slot %d for %dHz\n",
+ sr_free, rate);
+ wm5100->sr_ref[sr_free]++;
+ snd_soc_update_bits(codec, wm5100_sr_regs[sr_free],
+ WM5100_SAMPLE_RATE_1_MASK,
+ sr_code);
+
+ return sr_free;
+
+ } else {
+ dev_err(codec->dev,
+ "SR %dHz incompatible with %dHz SYSCLK and %dHz ASYNCCLK\n",
+ rate, wm5100->sysclk, wm5100->asyncclk);
+ return -EINVAL;
+ }
+}
+
+static void wm5100_free_sr(struct snd_soc_codec *codec, int rate)
+{
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ int i, sr_code;
+
+ for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
+ if (wm5100_sr_code[i] == rate)
+ break;
+ if (i == ARRAY_SIZE(wm5100_sr_code)) {
+ dev_err(codec->dev, "Unsupported sample rate: %dHz\n", rate);
+ return;
+ }
+ sr_code = wm5100_sr_code[i];
+
+ for (i = 0; i < ARRAY_SIZE(wm5100_sr_regs); i++) {
+ if (!wm5100->sr_ref[i])
+ continue;
+
+ if ((snd_soc_read(codec, wm5100_sr_regs[i]) &
+ WM5100_SAMPLE_RATE_1_MASK) == sr_code)
+ break;
+ }
+ if (i < ARRAY_SIZE(wm5100_sr_regs)) {
+ wm5100->sr_ref[i]--;
+ dev_dbg(codec->dev, "Dereference SR %dHz, count now %d\n",
+ rate, wm5100->sr_ref[i]);
+ } else {
+ dev_warn(codec->dev, "Freeing unreferenced sample rate %dHz\n",
+ rate);
+ }
+}
+
+static int wm5100_reset(struct snd_soc_codec *codec)
+{
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+
+ if (wm5100->pdata.reset) {
+ gpio_set_value_cansleep(wm5100->pdata.reset, 0);
+ gpio_set_value_cansleep(wm5100->pdata.reset, 1);
+
+ return 0;
+ } else {
+ return snd_soc_write(codec, WM5100_SOFTWARE_RESET, 0);
+ }
+}
+
+static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0);
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(mixer_tlv, -3200, 100, 0);
+static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+
+static const char *wm5100_mixer_texts[] = {
+ "None",
+ "Tone Generator 1",
+ "Tone Generator 2",
+ "AEC loopback",
+ "IN1L",
+ "IN1R",
+ "IN2L",
+ "IN2R",
+ "IN3L",
+ "IN3R",
+ "IN4L",
+ "IN4R",
+ "AIF1RX1",
+ "AIF1RX2",
+ "AIF1RX3",
+ "AIF1RX4",
+ "AIF1RX5",
+ "AIF1RX6",
+ "AIF1RX7",
+ "AIF1RX8",
+ "AIF2RX1",
+ "AIF2RX2",
+ "AIF3RX1",
+ "AIF3RX2",
+ "EQ1",
+ "EQ2",
+ "EQ3",
+ "EQ4",
+ "DRC1L",
+ "DRC1R",
+ "LHPF1",
+ "LHPF2",
+ "LHPF3",
+ "LHPF4",
+ "DSP1.1",
+ "DSP1.2",
+ "DSP1.3",
+ "DSP1.4",
+ "DSP1.5",
+ "DSP1.6",
+ "DSP2.1",
+ "DSP2.2",
+ "DSP2.3",
+ "DSP2.4",
+ "DSP2.5",
+ "DSP2.6",
+ "DSP3.1",
+ "DSP3.2",
+ "DSP3.3",
+ "DSP3.4",
+ "DSP3.5",
+ "DSP3.6",
+ "ASRC1L",
+ "ASRC1R",
+ "ASRC2L",
+ "ASRC2R",
+ "ISRC1INT1",
+ "ISRC1INT2",
+ "ISRC1INT3",
+ "ISRC1INT4",
+ "ISRC2INT1",
+ "ISRC2INT2",
+ "ISRC2INT3",
+ "ISRC2INT4",
+ "ISRC1DEC1",
+ "ISRC1DEC2",
+ "ISRC1DEC3",
+ "ISRC1DEC4",
+ "ISRC2DEC1",
+ "ISRC2DEC2",
+ "ISRC2DEC3",
+ "ISRC2DEC4",
+};
+
+static int wm5100_mixer_values[] = {
+ 0x00,
+ 0x04, /* Tone */
+ 0x05,
+ 0x08, /* AEC */
+ 0x10, /* Input */
+ 0x11,
+ 0x12,
+ 0x13,
+ 0x14,
+ 0x15,
+ 0x16,
+ 0x17,
+ 0x20, /* AIF */
+ 0x21,
+ 0x22,
+ 0x23,
+ 0x24,
+ 0x25,
+ 0x26,
+ 0x27,
+ 0x28,
+ 0x29,
+ 0x30, /* AIF3 - check */
+ 0x31,
+ 0x50, /* EQ */
+ 0x51,
+ 0x52,
+ 0x53,
+ 0x54,
+ 0x58, /* DRC */
+ 0x59,
+ 0x60, /* LHPF1 */
+ 0x61, /* LHPF2 */
+ 0x62, /* LHPF3 */
+ 0x63, /* LHPF4 */
+ 0x68, /* DSP1 */
+ 0x69,
+ 0x6a,
+ 0x6b,
+ 0x6c,
+ 0x6d,
+ 0x70, /* DSP2 */
+ 0x71,
+ 0x72,
+ 0x73,
+ 0x74,
+ 0x75,
+ 0x78, /* DSP3 */
+ 0x79,
+ 0x7a,
+ 0x7b,
+ 0x7c,
+ 0x7d,
+ 0x90, /* ASRC1 */
+ 0x91,
+ 0x92, /* ASRC2 */
+ 0x93,
+ 0xa0, /* ISRC1DEC1 */
+ 0xa1,
+ 0xa2,
+ 0xa3,
+ 0xa4, /* ISRC1INT1 */
+ 0xa5,
+ 0xa6,
+ 0xa7,
+ 0xa8, /* ISRC2DEC1 */
+ 0xa9,
+ 0xaa,
+ 0xab,
+ 0xac, /* ISRC2INT1 */
+ 0xad,
+ 0xae,
+ 0xaf,
+};
+
+#define WM5100_MIXER_CONTROLS(name, base) \
+ SOC_SINGLE_TLV(name " Input 1 Volume", base + 1 , \
+ WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+ SOC_SINGLE_TLV(name " Input 2 Volume", base + 3 , \
+ WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+ SOC_SINGLE_TLV(name " Input 3 Volume", base + 5 , \
+ WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+ SOC_SINGLE_TLV(name " Input 4 Volume", base + 7 , \
+ WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv)
+
+#define WM5100_MUX_ENUM_DECL(name, reg) \
+ SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, \
+ wm5100_mixer_texts, wm5100_mixer_values)
+
+#define WM5100_MUX_CTL_DECL(name) \
+ const struct snd_kcontrol_new name##_mux = \
+ SOC_DAPM_VALUE_ENUM("Route", name##_enum)
+
+#define WM5100_MIXER_ENUMS(name, base_reg) \
+ static WM5100_MUX_ENUM_DECL(name##_in1_enum, base_reg); \
+ static WM5100_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2); \
+ static WM5100_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4); \
+ static WM5100_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6); \
+ static WM5100_MUX_CTL_DECL(name##_in1); \
+ static WM5100_MUX_CTL_DECL(name##_in2); \
+ static WM5100_MUX_CTL_DECL(name##_in3); \
+ static WM5100_MUX_CTL_DECL(name##_in4)
+
+WM5100_MIXER_ENUMS(HPOUT1L, WM5100_OUT1LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(HPOUT1R, WM5100_OUT1RMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(HPOUT2L, WM5100_OUT2LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(HPOUT2R, WM5100_OUT2RMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(HPOUT3L, WM5100_OUT3LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(HPOUT3R, WM5100_OUT3RMIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(SPKOUTL, WM5100_OUT4LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(SPKOUTR, WM5100_OUT4RMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(SPKDAT1L, WM5100_OUT5LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(SPKDAT1R, WM5100_OUT5RMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(SPKDAT2L, WM5100_OUT6LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(SPKDAT2R, WM5100_OUT6RMIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(PWM1, WM5100_PWM1MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(PWM2, WM5100_PWM1MIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(AIF1TX1, WM5100_AIF1TX1MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX2, WM5100_AIF1TX2MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX3, WM5100_AIF1TX3MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX4, WM5100_AIF1TX4MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX5, WM5100_AIF1TX5MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX6, WM5100_AIF1TX6MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX7, WM5100_AIF1TX7MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX8, WM5100_AIF1TX8MIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(AIF2TX1, WM5100_AIF2TX1MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF2TX2, WM5100_AIF2TX2MIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(AIF3TX1, WM5100_AIF1TX1MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF3TX2, WM5100_AIF1TX2MIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(EQ1, WM5100_EQ1MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(EQ2, WM5100_EQ2MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(EQ3, WM5100_EQ3MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(EQ4, WM5100_EQ4MIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(DRC1L, WM5100_DRC1LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(DRC1R, WM5100_DRC1RMIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(LHPF1, WM5100_HPLP1MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(LHPF2, WM5100_HPLP2MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(LHPF3, WM5100_HPLP3MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(LHPF4, WM5100_HPLP4MIX_INPUT_1_SOURCE);
+
+#define WM5100_MUX(name, ctrl) \
+ SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+
+#define WM5100_MIXER_WIDGETS(name, name_str) \
+ WM5100_MUX(name_str " Input 1", &name##_in1_mux), \
+ WM5100_MUX(name_str " Input 2", &name##_in2_mux), \
+ WM5100_MUX(name_str " Input 3", &name##_in3_mux), \
+ WM5100_MUX(name_str " Input 4", &name##_in4_mux), \
+ SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
+
+#define WM5100_MIXER_INPUT_ROUTES(name) \
+ { name, "Tone Generator 1", "Tone Generator 1" }, \
+ { name, "Tone Generator 2", "Tone Generator 2" }, \
+ { name, "IN1L", "IN1L PGA" }, \
+ { name, "IN1R", "IN1R PGA" }, \
+ { name, "IN2L", "IN2L PGA" }, \
+ { name, "IN2R", "IN2R PGA" }, \
+ { name, "IN3L", "IN3L PGA" }, \
+ { name, "IN3R", "IN3R PGA" }, \
+ { name, "IN4L", "IN4L PGA" }, \
+ { name, "IN4R", "IN4R PGA" }, \
+ { name, "AIF1RX1", "AIF1RX1" }, \
+ { name, "AIF1RX2", "AIF1RX2" }, \
+ { name, "AIF1RX3", "AIF1RX3" }, \
+ { name, "AIF1RX4", "AIF1RX4" }, \
+ { name, "AIF1RX5", "AIF1RX5" }, \
+ { name, "AIF1RX6", "AIF1RX6" }, \
+ { name, "AIF1RX7", "AIF1RX7" }, \
+ { name, "AIF1RX8", "AIF1RX8" }, \
+ { name, "AIF2RX1", "AIF2RX1" }, \
+ { name, "AIF2RX2", "AIF2RX2" }, \
+ { name, "AIF3RX1", "AIF3RX1" }, \
+ { name, "AIF3RX2", "AIF3RX2" }, \
+ { name, "EQ1", "EQ1" }, \
+ { name, "EQ2", "EQ2" }, \
+ { name, "EQ3", "EQ3" }, \
+ { name, "EQ4", "EQ4" }, \
+ { name, "DRC1L", "DRC1L" }, \
+ { name, "DRC1R", "DRC1R" }, \
+ { name, "LHPF1", "LHPF1" }, \
+ { name, "LHPF2", "LHPF2" }, \
+ { name, "LHPF3", "LHPF3" }, \
+ { name, "LHPF4", "LHPF4" }
+
+#define WM5100_MIXER_ROUTES(widget, name) \
+ { widget, NULL, name " Mixer" }, \
+ { name " Mixer", NULL, name " Input 1" }, \
+ { name " Mixer", NULL, name " Input 2" }, \
+ { name " Mixer", NULL, name " Input 3" }, \
+ { name " Mixer", NULL, name " Input 4" }, \
+ WM5100_MIXER_INPUT_ROUTES(name " Input 1"), \
+ WM5100_MIXER_INPUT_ROUTES(name " Input 2"), \
+ WM5100_MIXER_INPUT_ROUTES(name " Input 3"), \
+ WM5100_MIXER_INPUT_ROUTES(name " Input 4")
+
+static const char *wm5100_lhpf_mode_text[] = {
+ "Low-pass", "High-pass"
+};
+
+static const struct soc_enum wm5100_lhpf1_mode =
+ SOC_ENUM_SINGLE(WM5100_HPLPF1_1, WM5100_LHPF1_MODE_SHIFT, 2,
+ wm5100_lhpf_mode_text);
+
+static const struct soc_enum wm5100_lhpf2_mode =
+ SOC_ENUM_SINGLE(WM5100_HPLPF2_1, WM5100_LHPF2_MODE_SHIFT, 2,
+ wm5100_lhpf_mode_text);
+
+static const struct soc_enum wm5100_lhpf3_mode =
+ SOC_ENUM_SINGLE(WM5100_HPLPF3_1, WM5100_LHPF3_MODE_SHIFT, 2,
+ wm5100_lhpf_mode_text);
+
+static const struct soc_enum wm5100_lhpf4_mode =
+ SOC_ENUM_SINGLE(WM5100_HPLPF4_1, WM5100_LHPF4_MODE_SHIFT, 2,
+ wm5100_lhpf_mode_text);
+
+static const struct snd_kcontrol_new wm5100_snd_controls[] = {
+SOC_SINGLE("IN1 High Performance Switch", WM5100_IN1L_CONTROL,
+ WM5100_IN1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN2 High Performance Switch", WM5100_IN2L_CONTROL,
+ WM5100_IN2_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN3 High Performance Switch", WM5100_IN3L_CONTROL,
+ WM5100_IN3_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN4 High Performance Switch", WM5100_IN4L_CONTROL,
+ WM5100_IN4_OSR_SHIFT, 1, 0),
+
+/* Only applicable for analogue inputs */
+SOC_DOUBLE_R_TLV("IN1 Volume", WM5100_IN1L_CONTROL, WM5100_IN1R_CONTROL,
+ WM5100_IN1L_PGA_VOL_SHIFT, 94, 0, in_tlv),
+SOC_DOUBLE_R_TLV("IN2 Volume", WM5100_IN2L_CONTROL, WM5100_IN2R_CONTROL,
+ WM5100_IN2L_PGA_VOL_SHIFT, 94, 0, in_tlv),
+SOC_DOUBLE_R_TLV("IN3 Volume", WM5100_IN3L_CONTROL, WM5100_IN3R_CONTROL,
+ WM5100_IN3L_PGA_VOL_SHIFT, 94, 0, in_tlv),
+SOC_DOUBLE_R_TLV("IN4 Volume", WM5100_IN4L_CONTROL, WM5100_IN4R_CONTROL,
+ WM5100_IN4L_PGA_VOL_SHIFT, 94, 0, in_tlv),
+
+SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_1L,
+ WM5100_ADC_DIGITAL_VOLUME_1R, WM5100_IN1L_VOL_SHIFT, 191,
+ 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN2 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_2L,
+ WM5100_ADC_DIGITAL_VOLUME_2R, WM5100_IN2L_VOL_SHIFT, 191,
+ 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_3L,
+ WM5100_ADC_DIGITAL_VOLUME_3R, WM5100_IN3L_VOL_SHIFT, 191,
+ 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN4 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_4L,
+ WM5100_ADC_DIGITAL_VOLUME_4R, WM5100_IN4L_VOL_SHIFT, 191,
+ 0, digital_tlv),
+
+SOC_DOUBLE_R("IN1 Switch", WM5100_ADC_DIGITAL_VOLUME_1L,
+ WM5100_ADC_DIGITAL_VOLUME_1R, WM5100_IN1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN2 Switch", WM5100_ADC_DIGITAL_VOLUME_2L,
+ WM5100_ADC_DIGITAL_VOLUME_2R, WM5100_IN2L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN3 Switch", WM5100_ADC_DIGITAL_VOLUME_3L,
+ WM5100_ADC_DIGITAL_VOLUME_3R, WM5100_IN3L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN4 Switch", WM5100_ADC_DIGITAL_VOLUME_4L,
+ WM5100_ADC_DIGITAL_VOLUME_4R, WM5100_IN4L_MUTE_SHIFT, 1, 1),
+
+SOC_SINGLE("HPOUT1 High Performance Switch", WM5100_OUT_VOLUME_1L,
+ WM5100_OUT1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("HPOUT2 High Performance Switch", WM5100_OUT_VOLUME_2L,
+ WM5100_OUT2_OSR_SHIFT, 1, 0),
+SOC_SINGLE("HPOUT3 High Performance Switch", WM5100_OUT_VOLUME_3L,
+ WM5100_OUT3_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKOUT High Performance Switch", WM5100_OUT_VOLUME_4L,
+ WM5100_OUT4_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT1 High Performance Switch", WM5100_DAC_VOLUME_LIMIT_5L,
+ WM5100_OUT5_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT2 High Performance Switch", WM5100_DAC_VOLUME_LIMIT_6L,
+ WM5100_OUT6_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_1L,
+ WM5100_DAC_DIGITAL_VOLUME_1R, WM5100_OUT1L_VOL_SHIFT, 159, 0,
+ digital_tlv),
+SOC_DOUBLE_R_TLV("HPOUT2 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_2L,
+ WM5100_DAC_DIGITAL_VOLUME_2R, WM5100_OUT2L_VOL_SHIFT, 159, 0,
+ digital_tlv),
+SOC_DOUBLE_R_TLV("HPOUT3 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_3L,
+ WM5100_DAC_DIGITAL_VOLUME_3R, WM5100_OUT3L_VOL_SHIFT, 159, 0,
+ digital_tlv),
+SOC_DOUBLE_R_TLV("SPKOUT Digital Volume", WM5100_DAC_DIGITAL_VOLUME_4L,
+ WM5100_DAC_DIGITAL_VOLUME_4R, WM5100_OUT4L_VOL_SHIFT, 159, 0,
+ digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_5L,
+ WM5100_DAC_DIGITAL_VOLUME_5R, WM5100_OUT5L_VOL_SHIFT, 159, 0,
+ digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT2 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_6L,
+ WM5100_DAC_DIGITAL_VOLUME_6R, WM5100_OUT6L_VOL_SHIFT, 159, 0,
+ digital_tlv),
+
+SOC_DOUBLE_R("HPOUT1 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_1L,
+ WM5100_DAC_DIGITAL_VOLUME_1R, WM5100_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("HPOUT2 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_2L,
+ WM5100_DAC_DIGITAL_VOLUME_2R, WM5100_OUT2L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("HPOUT3 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_3L,
+ WM5100_DAC_DIGITAL_VOLUME_3R, WM5100_OUT3L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKOUT Digital Switch", WM5100_DAC_DIGITAL_VOLUME_4L,
+ WM5100_DAC_DIGITAL_VOLUME_4R, WM5100_OUT4L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT1 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_5L,
+ WM5100_DAC_DIGITAL_VOLUME_5R, WM5100_OUT5L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT2 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_6L,
+ WM5100_DAC_DIGITAL_VOLUME_6R, WM5100_OUT6L_MUTE_SHIFT, 1, 1),
+
+/* FIXME: Only valid from -12dB to 0dB (52-64) */
+SOC_DOUBLE_R_TLV("HPOUT1 Volume", WM5100_OUT_VOLUME_1L, WM5100_OUT_VOLUME_1R,
+ WM5100_OUT1L_PGA_VOL_SHIFT, 64, 0, out_tlv),
+SOC_DOUBLE_R_TLV("HPOUT2 Volume", WM5100_OUT_VOLUME_2L, WM5100_OUT_VOLUME_2R,
+ WM5100_OUT2L_PGA_VOL_SHIFT, 64, 0, out_tlv),
+SOC_DOUBLE_R_TLV("HPOUT3 Volume", WM5100_OUT_VOLUME_3L, WM5100_OUT_VOLUME_3R,
+ WM5100_OUT2L_PGA_VOL_SHIFT, 64, 0, out_tlv),
+
+SOC_DOUBLE("SPKDAT1 Switch", WM5100_PDM_SPK1_CTRL_1, WM5100_SPK1L_MUTE_SHIFT,
+ WM5100_SPK1R_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE("SPKDAT2 Switch", WM5100_PDM_SPK2_CTRL_1, WM5100_SPK2L_MUTE_SHIFT,
+ WM5100_SPK2R_MUTE_SHIFT, 1, 1),
+
+SOC_SINGLE_TLV("EQ1 Band 1 Volume", WM5100_EQ1_1, WM5100_EQ1_B1_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 Band 2 Volume", WM5100_EQ1_1, WM5100_EQ1_B2_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 Band 3 Volume", WM5100_EQ1_1, WM5100_EQ1_B3_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 Band 4 Volume", WM5100_EQ1_2, WM5100_EQ1_B4_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 Band 5 Volume", WM5100_EQ1_2, WM5100_EQ1_B5_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ2 Band 1 Volume", WM5100_EQ2_1, WM5100_EQ2_B1_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Band 2 Volume", WM5100_EQ2_1, WM5100_EQ2_B2_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Band 3 Volume", WM5100_EQ2_1, WM5100_EQ2_B3_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Band 4 Volume", WM5100_EQ2_2, WM5100_EQ2_B4_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Band 5 Volume", WM5100_EQ2_2, WM5100_EQ2_B5_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ3 Band 1 Volume", WM5100_EQ1_1, WM5100_EQ3_B1_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Band 2 Volume", WM5100_EQ3_1, WM5100_EQ3_B2_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Band 3 Volume", WM5100_EQ3_1, WM5100_EQ3_B3_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Band 4 Volume", WM5100_EQ3_2, WM5100_EQ3_B4_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Band 5 Volume", WM5100_EQ3_2, WM5100_EQ3_B5_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ4 Band 1 Volume", WM5100_EQ4_1, WM5100_EQ4_B1_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Band 2 Volume", WM5100_EQ4_1, WM5100_EQ4_B2_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Band 3 Volume", WM5100_EQ4_1, WM5100_EQ4_B3_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Band 4 Volume", WM5100_EQ4_2, WM5100_EQ4_B4_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Band 5 Volume", WM5100_EQ4_2, WM5100_EQ4_B5_GAIN_SHIFT,
+ 24, 0, eq_tlv),
+
+SOC_ENUM("LHPF1 Mode", wm5100_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", wm5100_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", wm5100_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", wm5100_lhpf4_mode),
+
+WM5100_MIXER_CONTROLS("HPOUT1L", WM5100_OUT1LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("HPOUT1R", WM5100_OUT1RMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("HPOUT2L", WM5100_OUT2LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("HPOUT2R", WM5100_OUT2RMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("HPOUT3L", WM5100_OUT3LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("HPOUT3R", WM5100_OUT3RMIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("SPKOUTL", WM5100_OUT4LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("SPKOUTR", WM5100_OUT4RMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("SPKDAT1L", WM5100_OUT5LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("SPKDAT1R", WM5100_OUT5RMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("SPKDAT2L", WM5100_OUT6LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("SPKDAT2R", WM5100_OUT6RMIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("PWM1", WM5100_PWM1MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("PWM2", WM5100_PWM2MIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("AIF1TX1", WM5100_AIF1TX1MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX2", WM5100_AIF1TX2MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX3", WM5100_AIF1TX3MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX4", WM5100_AIF1TX4MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX5", WM5100_AIF1TX5MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX6", WM5100_AIF1TX6MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX7", WM5100_AIF1TX7MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX8", WM5100_AIF1TX8MIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("AIF2TX1", WM5100_AIF2TX1MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF2TX2", WM5100_AIF2TX2MIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("AIF3TX1", WM5100_AIF3TX1MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF3TX2", WM5100_AIF3TX2MIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("EQ1", WM5100_EQ1MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("EQ2", WM5100_EQ2MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("EQ3", WM5100_EQ3MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("EQ4", WM5100_EQ4MIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("DRC1L", WM5100_DRC1LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("DRC1R", WM5100_DRC1RMIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("LHPF1", WM5100_HPLP1MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("LHPF2", WM5100_HPLP2MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("LHPF3", WM5100_HPLP3MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("LHPF4", WM5100_HPLP4MIX_INPUT_1_SOURCE),
+};
+
+static void wm5100_seq_notifier(struct snd_soc_dapm_context *dapm,
+ enum snd_soc_dapm_type event, int subseq)
+{
+ struct snd_soc_codec *codec = container_of(dapm,
+ struct snd_soc_codec, dapm);
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ u16 val, expect, i;
+
+ /* Wait for the outputs to flag themselves as enabled */
+ if (wm5100->out_ena[0]) {
+ expect = snd_soc_read(codec, WM5100_CHANNEL_ENABLES_1);
+ for (i = 0; i < 200; i++) {
+ val = snd_soc_read(codec, WM5100_OUTPUT_STATUS_1);
+ if (val == expect) {
+ wm5100->out_ena[0] = false;
+ break;
+ }
+ }
+ if (i == 200) {
+ dev_err(codec->dev, "Timeout waiting for OUTPUT1 %x\n",
+ expect);
+ }
+ }
+
+ if (wm5100->out_ena[1]) {
+ expect = snd_soc_read(codec, WM5100_OUTPUT_ENABLES_2);
+ for (i = 0; i < 200; i++) {
+ val = snd_soc_read(codec, WM5100_OUTPUT_STATUS_2);
+ if (val == expect) {
+ wm5100->out_ena[1] = false;
+ break;
+ }
+ }
+ if (i == 200) {
+ dev_err(codec->dev, "Timeout waiting for OUTPUT2 %x\n",
+ expect);
+ }
+ }
+}
+
+static int wm5100_out_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(w->codec);
+
+ switch (w->reg) {
+ case WM5100_CHANNEL_ENABLES_1:
+ wm5100->out_ena[0] = true;
+ break;
+ case WM5100_OUTPUT_ENABLES_2:
+ wm5100->out_ena[0] = true;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int wm5100_cp_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = regulator_enable(wm5100->cpvdd);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to enable CPVDD: %d\n",
+ ret);
+ return ret;
+ }
+ return ret;
+
+ case SND_SOC_DAPM_POST_PMD:
+ ret = regulator_disable_deferred(wm5100->cpvdd, 20);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to disable CPVDD: %d\n",
+ ret);
+ return ret;
+ }
+ return ret;
+
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static int wm5100_dbvdd_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ struct regulator *regulator;
+ int ret;
+
+ switch (w->shift) {
+ case 2:
+ regulator = wm5100->dbvdd2;
+ break;
+ case 3:
+ regulator = wm5100->dbvdd3;
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = regulator_enable(regulator);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to enable DBVDD%d: %d\n",
+ w->shift, ret);
+ return ret;
+ }
+ return ret;
+
+ case SND_SOC_DAPM_POST_PMD:
+ ret = regulator_disable(regulator);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to enable DBVDD%d: %d\n",
+ w->shift, ret);
+ return ret;
+ }
+ return ret;
+
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static void wm5100_log_status3(struct snd_soc_codec *codec, int val)
+{
+ if (val & WM5100_SPK_SHUTDOWN_WARN_EINT)
+ dev_crit(codec->dev, "Speaker shutdown warning\n");
+ if (val & WM5100_SPK_SHUTDOWN_EINT)
+ dev_crit(codec->dev, "Speaker shutdown\n");
+ if (val & WM5100_CLKGEN_ERR_EINT)
+ dev_crit(codec->dev, "SYSCLK underclocked\n");
+ if (val & WM5100_CLKGEN_ERR_ASYNC_EINT)
+ dev_crit(codec->dev, "ASYNCCLK underclocked\n");
+}
+
+static void wm5100_log_status4(struct snd_soc_codec *codec, int val)
+{
+ if (val & WM5100_AIF3_ERR_EINT)
+ dev_err(codec->dev, "AIF3 configuration error\n");
+ if (val & WM5100_AIF2_ERR_EINT)
+ dev_err(codec->dev, "AIF2 configuration error\n");
+ if (val & WM5100_AIF1_ERR_EINT)
+ dev_err(codec->dev, "AIF1 configuration error\n");
+ if (val & WM5100_CTRLIF_ERR_EINT)
+ dev_err(codec->dev, "Control interface error\n");
+ if (val & WM5100_ISRC2_UNDERCLOCKED_EINT)
+ dev_err(codec->dev, "ISRC2 underclocked\n");
+ if (val & WM5100_ISRC1_UNDERCLOCKED_EINT)
+ dev_err(codec->dev, "ISRC1 underclocked\n");
+ if (val & WM5100_FX_UNDERCLOCKED_EINT)
+ dev_err(codec->dev, "FX underclocked\n");
+ if (val & WM5100_AIF3_UNDERCLOCKED_EINT)
+ dev_err(codec->dev, "AIF3 underclocked\n");
+ if (val & WM5100_AIF2_UNDERCLOCKED_EINT)
+ dev_err(codec->dev, "AIF2 underclocked\n");
+ if (val & WM5100_AIF1_UNDERCLOCKED_EINT)
+ dev_err(codec->dev, "AIF1 underclocked\n");
+ if (val & WM5100_ASRC_UNDERCLOCKED_EINT)
+ dev_err(codec->dev, "ASRC underclocked\n");
+ if (val & WM5100_DAC_UNDERCLOCKED_EINT)
+ dev_err(codec->dev, "DAC underclocked\n");
+ if (val & WM5100_ADC_UNDERCLOCKED_EINT)
+ dev_err(codec->dev, "ADC underclocked\n");
+ if (val & WM5100_MIXER_UNDERCLOCKED_EINT)
+ dev_err(codec->dev, "Mixer underclocked\n");
+}
+
+static int wm5100_post_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ int ret;
+
+ ret = snd_soc_read(codec, WM5100_INTERRUPT_RAW_STATUS_3);
+ ret &= WM5100_SPK_SHUTDOWN_WARN_STS |
+ WM5100_SPK_SHUTDOWN_STS | WM5100_CLKGEN_ERR_STS |
+ WM5100_CLKGEN_ERR_ASYNC_STS;
+ wm5100_log_status3(codec, ret);
+
+ ret = snd_soc_read(codec, WM5100_INTERRUPT_RAW_STATUS_4);
+ wm5100_log_status4(codec, ret);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget wm5100_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM5100_CLOCKING_3, WM5100_SYSCLK_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", WM5100_CLOCKING_6, WM5100_ASYNC_CLK_ENA_SHIFT,
+ 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("CP1", WM5100_HP_CHARGE_PUMP_1, WM5100_CP1_ENA_SHIFT, 0,
+ wm5100_cp_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("CP2", WM5100_MIC_CHARGE_PUMP_1, WM5100_CP2_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_SUPPLY("CP2 Active", WM5100_MIC_CHARGE_PUMP_1,
+ WM5100_CP2_BYPASS_SHIFT, 1, wm5100_cp_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("DBVDD2", SND_SOC_NOPM, 2, 0, wm5100_dbvdd_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("DBVDD3", SND_SOC_NOPM, 3, 0, wm5100_dbvdd_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", WM5100_MIC_BIAS_CTRL_1, WM5100_MICB1_ENA_SHIFT,
+ 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", WM5100_MIC_BIAS_CTRL_2, WM5100_MICB2_ENA_SHIFT,
+ 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS3", WM5100_MIC_BIAS_CTRL_3, WM5100_MICB3_ENA_SHIFT,
+ 0, NULL, 0),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("IN4L"),
+SND_SOC_DAPM_INPUT("IN4R"),
+SND_SOC_DAPM_INPUT("TONE"),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", WM5100_INPUT_ENABLES, WM5100_IN1L_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", WM5100_INPUT_ENABLES, WM5100_IN1R_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", WM5100_INPUT_ENABLES, WM5100_IN2L_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", WM5100_INPUT_ENABLES, WM5100_IN2R_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN3L PGA", WM5100_INPUT_ENABLES, WM5100_IN3L_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN3R PGA", WM5100_INPUT_ENABLES, WM5100_IN3R_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN4L PGA", WM5100_INPUT_ENABLES, WM5100_IN4L_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN4R PGA", WM5100_INPUT_ENABLES, WM5100_IN4R_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", WM5100_TONE_GENERATOR_1,
+ WM5100_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", WM5100_TONE_GENERATOR_1,
+ WM5100_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 0,
+ WM5100_AUDIO_IF_1_27, WM5100_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 1,
+ WM5100_AUDIO_IF_1_27, WM5100_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 2,
+ WM5100_AUDIO_IF_1_27, WM5100_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 3,
+ WM5100_AUDIO_IF_1_27, WM5100_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 4,
+ WM5100_AUDIO_IF_1_27, WM5100_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", "AIF1 Playback", 5,
+ WM5100_AUDIO_IF_1_27, WM5100_AIF1RX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX7", "AIF1 Playback", 6,
+ WM5100_AUDIO_IF_1_27, WM5100_AIF1RX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX8", "AIF1 Playback", 7,
+ WM5100_AUDIO_IF_1_27, WM5100_AIF1RX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 0,
+ WM5100_AUDIO_IF_2_27, WM5100_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", "AIF2 Playback", 1,
+ WM5100_AUDIO_IF_2_27, WM5100_AIF2RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF3RX1", "AIF3 Playback", 0,
+ WM5100_AUDIO_IF_3_27, WM5100_AIF3RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF3RX2", "AIF3 Playback", 1,
+ WM5100_AUDIO_IF_3_27, WM5100_AIF3RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 0,
+ WM5100_AUDIO_IF_1_26, WM5100_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 1,
+ WM5100_AUDIO_IF_1_26, WM5100_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 2,
+ WM5100_AUDIO_IF_1_26, WM5100_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 3,
+ WM5100_AUDIO_IF_1_26, WM5100_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 4,
+ WM5100_AUDIO_IF_1_26, WM5100_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", "AIF1 Capture", 5,
+ WM5100_AUDIO_IF_1_26, WM5100_AIF1TX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX7", "AIF1 Capture", 6,
+ WM5100_AUDIO_IF_1_26, WM5100_AIF1TX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX8", "AIF1 Capture", 7,
+ WM5100_AUDIO_IF_1_26, WM5100_AIF1TX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", "AIF2 Capture", 0,
+ WM5100_AUDIO_IF_2_26, WM5100_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", "AIF2 Capture", 1,
+ WM5100_AUDIO_IF_2_26, WM5100_AIF2TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF3TX1", "AIF3 Capture", 0,
+ WM5100_AUDIO_IF_3_26, WM5100_AIF3TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3TX2", "AIF3 Capture", 1,
+ WM5100_AUDIO_IF_3_26, WM5100_AIF3TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA_E("OUT6L", WM5100_OUTPUT_ENABLES_2, WM5100_OUT6L_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT6R", WM5100_OUTPUT_ENABLES_2, WM5100_OUT6R_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5L", WM5100_OUTPUT_ENABLES_2, WM5100_OUT5L_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5R", WM5100_OUTPUT_ENABLES_2, WM5100_OUT5R_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT4L", WM5100_OUTPUT_ENABLES_2, WM5100_OUT4L_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT4R", WM5100_OUTPUT_ENABLES_2, WM5100_OUT4R_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3L", WM5100_CHANNEL_ENABLES_1, WM5100_HP3L_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3R", WM5100_CHANNEL_ENABLES_1, WM5100_HP3R_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2L", WM5100_CHANNEL_ENABLES_1, WM5100_HP2L_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2R", WM5100_CHANNEL_ENABLES_1, WM5100_HP2R_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1L", WM5100_CHANNEL_ENABLES_1, WM5100_HP1L_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", WM5100_CHANNEL_ENABLES_1, WM5100_HP1R_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("PWM1 Driver", WM5100_PWM_DRIVE_1, WM5100_PWM1_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("PWM2 Driver", WM5100_PWM_DRIVE_1, WM5100_PWM2_ENA_SHIFT, 0,
+ NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("EQ1", WM5100_EQ1_1, WM5100_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", WM5100_EQ2_1, WM5100_EQ2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ3", WM5100_EQ3_1, WM5100_EQ3_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ4", WM5100_EQ4_1, WM5100_EQ4_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", WM5100_DRC1_CTRL1, WM5100_DRCL_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", WM5100_DRC1_CTRL1, WM5100_DRCR_ENA_SHIFT, 0,
+ NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", WM5100_HPLPF1_1, WM5100_LHPF1_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", WM5100_HPLPF2_1, WM5100_LHPF2_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", WM5100_HPLPF3_1, WM5100_LHPF3_ENA_SHIFT, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", WM5100_HPLPF4_1, WM5100_LHPF4_ENA_SHIFT, 0,
+ NULL, 0),
+
+WM5100_MIXER_WIDGETS(EQ1, "EQ1"),
+WM5100_MIXER_WIDGETS(EQ2, "EQ2"),
+WM5100_MIXER_WIDGETS(EQ3, "EQ3"),
+WM5100_MIXER_WIDGETS(EQ4, "EQ4"),
+
+WM5100_MIXER_WIDGETS(DRC1L, "DRC1L"),
+WM5100_MIXER_WIDGETS(DRC1R, "DRC1R"),
+
+WM5100_MIXER_WIDGETS(LHPF1, "LHPF1"),
+WM5100_MIXER_WIDGETS(LHPF2, "LHPF2"),
+WM5100_MIXER_WIDGETS(LHPF3, "LHPF3"),
+WM5100_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+WM5100_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+WM5100_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+WM5100_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+WM5100_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+WM5100_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+WM5100_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+WM5100_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
+WM5100_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
+
+WM5100_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+WM5100_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+
+WM5100_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
+WM5100_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
+
+WM5100_MIXER_WIDGETS(HPOUT1L, "HPOUT1L"),
+WM5100_MIXER_WIDGETS(HPOUT1R, "HPOUT1R"),
+WM5100_MIXER_WIDGETS(HPOUT2L, "HPOUT2L"),
+WM5100_MIXER_WIDGETS(HPOUT2R, "HPOUT2R"),
+WM5100_MIXER_WIDGETS(HPOUT3L, "HPOUT3L"),
+WM5100_MIXER_WIDGETS(HPOUT3R, "HPOUT3R"),
+
+WM5100_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
+WM5100_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
+WM5100_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
+WM5100_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"),
+WM5100_MIXER_WIDGETS(SPKDAT2L, "SPKDAT2L"),
+WM5100_MIXER_WIDGETS(SPKDAT2R, "SPKDAT2R"),
+
+WM5100_MIXER_WIDGETS(PWM1, "PWM1"),
+WM5100_MIXER_WIDGETS(PWM2, "PWM2"),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2L"),
+SND_SOC_DAPM_OUTPUT("HPOUT2R"),
+SND_SOC_DAPM_OUTPUT("HPOUT3L"),
+SND_SOC_DAPM_OUTPUT("HPOUT3R"),
+SND_SOC_DAPM_OUTPUT("SPKOUTL"),
+SND_SOC_DAPM_OUTPUT("SPKOUTR"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1"),
+SND_SOC_DAPM_OUTPUT("SPKDAT2"),
+SND_SOC_DAPM_OUTPUT("PWM1"),
+SND_SOC_DAPM_OUTPUT("PWM2"),
+};
+
+/* We register a _POST event if we don't have IRQ support so we can
+ * look at the error status from the CODEC - if we've got the IRQ
+ * hooked up then we will get prompted to look by an interrupt.
+ */
+static const struct snd_soc_dapm_widget wm5100_dapm_widgets_noirq[] = {
+SND_SOC_DAPM_POST("Post", wm5100_post_ev),
+};
+
+static const struct snd_soc_dapm_route wm5100_dapm_routes[] = {
+ { "IN1L", NULL, "SYSCLK" },
+ { "IN1R", NULL, "SYSCLK" },
+ { "IN2L", NULL, "SYSCLK" },
+ { "IN2R", NULL, "SYSCLK" },
+ { "IN3L", NULL, "SYSCLK" },
+ { "IN3R", NULL, "SYSCLK" },
+ { "IN4L", NULL, "SYSCLK" },
+ { "IN4R", NULL, "SYSCLK" },
+
+ { "OUT1L", NULL, "SYSCLK" },
+ { "OUT1R", NULL, "SYSCLK" },
+ { "OUT2L", NULL, "SYSCLK" },
+ { "OUT2R", NULL, "SYSCLK" },
+ { "OUT3L", NULL, "SYSCLK" },
+ { "OUT3R", NULL, "SYSCLK" },
+ { "OUT4L", NULL, "SYSCLK" },
+ { "OUT4R", NULL, "SYSCLK" },
+ { "OUT5L", NULL, "SYSCLK" },
+ { "OUT5R", NULL, "SYSCLK" },
+ { "OUT6L", NULL, "SYSCLK" },
+ { "OUT6R", NULL, "SYSCLK" },
+
+ { "AIF1RX1", NULL, "SYSCLK" },
+ { "AIF1RX2", NULL, "SYSCLK" },
+ { "AIF1RX3", NULL, "SYSCLK" },
+ { "AIF1RX4", NULL, "SYSCLK" },
+ { "AIF1RX5", NULL, "SYSCLK" },
+ { "AIF1RX6", NULL, "SYSCLK" },
+ { "AIF1RX7", NULL, "SYSCLK" },
+ { "AIF1RX8", NULL, "SYSCLK" },
+
+ { "AIF2RX1", NULL, "SYSCLK" },
+ { "AIF2RX1", NULL, "DBVDD2" },
+ { "AIF2RX2", NULL, "SYSCLK" },
+ { "AIF2RX2", NULL, "DBVDD2" },
+
+ { "AIF3RX1", NULL, "SYSCLK" },
+ { "AIF3RX1", NULL, "DBVDD3" },
+ { "AIF3RX2", NULL, "SYSCLK" },
+ { "AIF3RX2", NULL, "DBVDD3" },
+
+ { "AIF1TX1", NULL, "SYSCLK" },
+ { "AIF1TX2", NULL, "SYSCLK" },
+ { "AIF1TX3", NULL, "SYSCLK" },
+ { "AIF1TX4", NULL, "SYSCLK" },
+ { "AIF1TX5", NULL, "SYSCLK" },
+ { "AIF1TX6", NULL, "SYSCLK" },
+ { "AIF1TX7", NULL, "SYSCLK" },
+ { "AIF1TX8", NULL, "SYSCLK" },
+
+ { "AIF2TX1", NULL, "SYSCLK" },
+ { "AIF2TX1", NULL, "DBVDD2" },
+ { "AIF2TX2", NULL, "SYSCLK" },
+ { "AIF2TX2", NULL, "DBVDD2" },
+
+ { "AIF3TX1", NULL, "SYSCLK" },
+ { "AIF3TX1", NULL, "DBVDD3" },
+ { "AIF3TX2", NULL, "SYSCLK" },
+ { "AIF3TX2", NULL, "DBVDD3" },
+
+ { "MICBIAS1", NULL, "CP2" },
+ { "MICBIAS2", NULL, "CP2" },
+ { "MICBIAS3", NULL, "CP2" },
+
+ { "IN1L PGA", NULL, "CP2" },
+ { "IN1R PGA", NULL, "CP2" },
+ { "IN2L PGA", NULL, "CP2" },
+ { "IN2R PGA", NULL, "CP2" },
+ { "IN3L PGA", NULL, "CP2" },
+ { "IN3R PGA", NULL, "CP2" },
+ { "IN4L PGA", NULL, "CP2" },
+ { "IN4R PGA", NULL, "CP2" },
+
+ { "IN1L PGA", NULL, "CP2 Active" },
+ { "IN1R PGA", NULL, "CP2 Active" },
+ { "IN2L PGA", NULL, "CP2 Active" },
+ { "IN2R PGA", NULL, "CP2 Active" },
+ { "IN3L PGA", NULL, "CP2 Active" },
+ { "IN3R PGA", NULL, "CP2 Active" },
+ { "IN4L PGA", NULL, "CP2 Active" },
+ { "IN4R PGA", NULL, "CP2 Active" },
+
+ { "OUT1L", NULL, "CP1" },
+ { "OUT1R", NULL, "CP1" },
+ { "OUT2L", NULL, "CP1" },
+ { "OUT2R", NULL, "CP1" },
+ { "OUT3L", NULL, "CP1" },
+ { "OUT3R", NULL, "CP1" },
+
+ { "Tone Generator 1", NULL, "TONE" },
+ { "Tone Generator 2", NULL, "TONE" },
+
+ { "IN1L PGA", NULL, "IN1L" },
+ { "IN1R PGA", NULL, "IN1R" },
+ { "IN2L PGA", NULL, "IN2L" },
+ { "IN2R PGA", NULL, "IN2R" },
+ { "IN3L PGA", NULL, "IN3L" },
+ { "IN3R PGA", NULL, "IN3R" },
+ { "IN4L PGA", NULL, "IN4L" },
+ { "IN4R PGA", NULL, "IN4R" },
+
+ WM5100_MIXER_ROUTES("OUT1L", "HPOUT1L"),
+ WM5100_MIXER_ROUTES("OUT1R", "HPOUT1R"),
+ WM5100_MIXER_ROUTES("OUT2L", "HPOUT2L"),
+ WM5100_MIXER_ROUTES("OUT2R", "HPOUT2R"),
+ WM5100_MIXER_ROUTES("OUT3L", "HPOUT3L"),
+ WM5100_MIXER_ROUTES("OUT3R", "HPOUT3R"),
+
+ WM5100_MIXER_ROUTES("OUT4L", "SPKOUTL"),
+ WM5100_MIXER_ROUTES("OUT4R", "SPKOUTR"),
+ WM5100_MIXER_ROUTES("OUT5L", "SPKDAT1L"),
+ WM5100_MIXER_ROUTES("OUT5R", "SPKDAT1R"),
+ WM5100_MIXER_ROUTES("OUT6L", "SPKDAT2L"),
+ WM5100_MIXER_ROUTES("OUT6R", "SPKDAT2R"),
+
+ WM5100_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+ WM5100_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+ WM5100_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+ WM5100_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+ WM5100_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+ WM5100_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+ WM5100_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+ WM5100_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+ WM5100_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
+ WM5100_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
+
+ WM5100_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+ WM5100_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+
+ WM5100_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
+ WM5100_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
+
+ WM5100_MIXER_ROUTES("EQ1", "EQ1"),
+ WM5100_MIXER_ROUTES("EQ2", "EQ2"),
+ WM5100_MIXER_ROUTES("EQ3", "EQ3"),
+ WM5100_MIXER_ROUTES("EQ4", "EQ4"),
+
+ WM5100_MIXER_ROUTES("DRC1L", "DRC1L"),
+ WM5100_MIXER_ROUTES("DRC1R", "DRC1R"),
+
+ WM5100_MIXER_ROUTES("LHPF1", "LHPF1"),
+ WM5100_MIXER_ROUTES("LHPF2", "LHPF2"),
+ WM5100_MIXER_ROUTES("LHPF3", "LHPF3"),
+ WM5100_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+ { "HPOUT1L", NULL, "OUT1L" },
+ { "HPOUT1R", NULL, "OUT1R" },
+ { "HPOUT2L", NULL, "OUT2L" },
+ { "HPOUT2R", NULL, "OUT2R" },
+ { "HPOUT3L", NULL, "OUT3L" },
+ { "HPOUT3R", NULL, "OUT3R" },
+ { "SPKOUTL", NULL, "OUT4L" },
+ { "SPKOUTR", NULL, "OUT4R" },
+ { "SPKDAT1", NULL, "OUT5L" },
+ { "SPKDAT1", NULL, "OUT5R" },
+ { "SPKDAT2", NULL, "OUT6L" },
+ { "SPKDAT2", NULL, "OUT6R" },
+ { "PWM1", NULL, "PWM1 Driver" },
+ { "PWM2", NULL, "PWM2 Driver" },
+};
+
+static struct {
+ int reg;
+ int val;
+} wm5100_reva_patches[] = {
+ { WM5100_AUDIO_IF_1_10, 0 },
+ { WM5100_AUDIO_IF_1_11, 1 },
+ { WM5100_AUDIO_IF_1_12, 2 },
+ { WM5100_AUDIO_IF_1_13, 3 },
+ { WM5100_AUDIO_IF_1_14, 4 },
+ { WM5100_AUDIO_IF_1_15, 5 },
+ { WM5100_AUDIO_IF_1_16, 6 },
+ { WM5100_AUDIO_IF_1_17, 7 },
+
+ { WM5100_AUDIO_IF_1_18, 0 },
+ { WM5100_AUDIO_IF_1_19, 1 },
+ { WM5100_AUDIO_IF_1_20, 2 },
+ { WM5100_AUDIO_IF_1_21, 3 },
+ { WM5100_AUDIO_IF_1_22, 4 },
+ { WM5100_AUDIO_IF_1_23, 5 },
+ { WM5100_AUDIO_IF_1_24, 6 },
+ { WM5100_AUDIO_IF_1_25, 7 },
+
+ { WM5100_AUDIO_IF_2_10, 0 },
+ { WM5100_AUDIO_IF_2_11, 1 },
+
+ { WM5100_AUDIO_IF_2_18, 0 },
+ { WM5100_AUDIO_IF_2_19, 1 },
+
+ { WM5100_AUDIO_IF_3_10, 0 },
+ { WM5100_AUDIO_IF_3_11, 1 },
+
+ { WM5100_AUDIO_IF_3_18, 0 },
+ { WM5100_AUDIO_IF_3_19, 1 },
+};
+
+static int wm5100_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ int ret, i;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
+ wm5100->core_supplies);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to enable supplies: %d\n",
+ ret);
+ return ret;
+ }
+
+ if (wm5100->pdata.ldo_ena) {
+ gpio_set_value_cansleep(wm5100->pdata.ldo_ena,
+ 1);
+ msleep(2);
+ }
+
+ codec->cache_only = false;
+
+ switch (wm5100->rev) {
+ case 0:
+ snd_soc_write(codec, 0x11, 0x3);
+ snd_soc_write(codec, 0x203, 0xc);
+ snd_soc_write(codec, 0x206, 0);
+ snd_soc_write(codec, 0x207, 0xf0);
+ snd_soc_write(codec, 0x208, 0x3c);
+ snd_soc_write(codec, 0x209, 0);
+ snd_soc_write(codec, 0x211, 0x20d8);
+ snd_soc_write(codec, 0x11, 0);
+
+ for (i = 0;
+ i < ARRAY_SIZE(wm5100_reva_patches);
+ i++)
+ snd_soc_write(codec,
+ wm5100_reva_patches[i].reg,
+ wm5100_reva_patches[i].val);
+ break;
+ default:
+ break;
+ }
+
+ snd_soc_cache_sync(codec);
+ }
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ if (wm5100->pdata.ldo_ena)
+ gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
+ regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
+ wm5100->core_supplies);
+ break;
+ }
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+static int wm5100_dai_to_base(struct snd_soc_dai *dai)
+{
+ switch (dai->id) {
+ case 0:
+ return WM5100_AUDIO_IF_1_1 - 1;
+ case 1:
+ return WM5100_AUDIO_IF_2_1 - 1;
+ case 2:
+ return WM5100_AUDIO_IF_3_1 - 1;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+}
+
+static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int lrclk, bclk, mask, base;
+
+ base = wm5100_dai_to_base(dai);
+ if (base < 0)
+ return base;
+
+ lrclk = 0;
+ bclk = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ mask = 0;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ mask = 1;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ mask = 2;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ mask = 3;
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported DAI format %d\n",
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ lrclk |= WM5100_AIF1TX_LRCLK_MSTR;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ bclk |= WM5100_AIF1_BCLK_MSTR;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ lrclk |= WM5100_AIF1TX_LRCLK_MSTR;
+ bclk |= WM5100_AIF1_BCLK_MSTR;
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported master mode %d\n",
+ fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ bclk |= WM5100_AIF1_BCLK_INV;
+ lrclk |= WM5100_AIF1TX_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ bclk |= WM5100_AIF1_BCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ lrclk |= WM5100_AIF1TX_LRCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, base + 1, WM5100_AIF1_BCLK_MSTR |
+ WM5100_AIF1_BCLK_INV, bclk);
+ snd_soc_update_bits(codec, base + 2, WM5100_AIF1TX_LRCLK_MSTR |
+ WM5100_AIF1TX_LRCLK_INV, lrclk);
+ snd_soc_update_bits(codec, base + 3, WM5100_AIF1TX_LRCLK_MSTR |
+ WM5100_AIF1TX_LRCLK_INV, lrclk);
+ snd_soc_update_bits(codec, base + 5, WM5100_AIF1_FMT_MASK, mask);
+
+ return 0;
+}
+
+#define WM5100_NUM_BCLK_RATES 19
+
+static int wm5100_bclk_rates_dat[WM5100_NUM_BCLK_RATES] = {
+ 32000,
+ 48000,
+ 64000,
+ 96000,
+ 128000,
+ 192000,
+ 256000,
+ 384000,
+ 512000,
+ 768000,
+ 1024000,
+ 1536000,
+ 2048000,
+ 3072000,
+ 4096000,
+ 6144000,
+ 8192000,
+ 12288000,
+ 24576000,
+};
+
+static int wm5100_bclk_rates_cd[WM5100_NUM_BCLK_RATES] = {
+ 29400,
+ 44100,
+ 58800,
+ 88200,
+ 117600,
+ 176400,
+ 235200,
+ 352800,
+ 470400,
+ 705600,
+ 940800,
+ 1411200,
+ 1881600,
+ 2882400,
+ 3763200,
+ 5644800,
+ 7526400,
+ 11289600,
+ 22579600,
+};
+
+static int wm5100_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ bool async = wm5100->aif_async[dai->id];
+ int i, base, bclk, aif_rate, lrclk, wl, fl, sr;
+ int *bclk_rates;
+
+ base = wm5100_dai_to_base(dai);
+ if (base < 0)
+ return base;
+
+ /* Data sizes if not using TDM */
+ wl = snd_pcm_format_width(params_format(params));
+ if (wl < 0)
+ return wl;
+ fl = snd_soc_params_to_frame_size(params);
+ if (fl < 0)
+ return fl;
+
+ dev_dbg(codec->dev, "Word length %d bits, frame length %d bits\n",
+ wl, fl);
+
+ /* Target BCLK rate */
+ bclk = snd_soc_params_to_bclk(params);
+ if (bclk < 0)
+ return bclk;
+
+ /* Root for BCLK depends on SYS/ASYNCCLK */
+ if (!async) {
+ aif_rate = wm5100->sysclk;
+ sr = wm5100_alloc_sr(codec, params_rate(params));
+ if (sr < 0)
+ return sr;
+ } else {
+ /* If we're in ASYNCCLK set the ASYNC sample rate */
+ aif_rate = wm5100->asyncclk;
+ sr = 3;
+
+ for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
+ if (params_rate(params) == wm5100_sr_code[i])
+ break;
+ if (i == ARRAY_SIZE(wm5100_sr_code)) {
+ dev_err(codec->dev, "Invalid rate %dHzn",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ /* TODO: We should really check for symmetry */
+ snd_soc_update_bits(codec, WM5100_CLOCKING_8,
+ WM5100_ASYNC_SAMPLE_RATE_MASK, i);
+ }
+
+ if (!aif_rate) {
+ dev_err(codec->dev, "%s has no rate set\n",
+ async ? "ASYNCCLK" : "SYSCLK");
+ return -EINVAL;
+ }
+
+ dev_dbg(codec->dev, "Target BCLK is %dHz, using %dHz %s\n",
+ bclk, aif_rate, async ? "ASYNCCLK" : "SYSCLK");
+
+ if (aif_rate % 4000)
+ bclk_rates = wm5100_bclk_rates_cd;
+ else
+ bclk_rates = wm5100_bclk_rates_dat;
+
+ for (i = 0; i < WM5100_NUM_BCLK_RATES; i++)
+ if (bclk_rates[i] >= bclk && (bclk_rates[i] % bclk == 0))
+ break;
+ if (i == WM5100_NUM_BCLK_RATES) {
+ dev_err(codec->dev,
+ "No valid BCLK for %dHz found from %dHz %s\n",
+ bclk, aif_rate, async ? "ASYNCCLK" : "SYSCLK");
+ return -EINVAL;
+ }
+
+ bclk = i;
+ dev_dbg(codec->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
+ snd_soc_update_bits(codec, base + 1, WM5100_AIF1_BCLK_FREQ_MASK, bclk);
+
+ lrclk = bclk_rates[bclk] / params_rate(params);
+ dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+ wm5100->aif_symmetric[dai->id])
+ snd_soc_update_bits(codec, base + 7,
+ WM5100_AIF1RX_BCPF_MASK, lrclk);
+ else
+ snd_soc_update_bits(codec, base + 6,
+ WM5100_AIF1TX_BCPF_MASK, lrclk);
+
+ i = (wl << WM5100_AIF1TX_WL_SHIFT) | fl;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_update_bits(codec, base + 9,
+ WM5100_AIF1RX_WL_MASK |
+ WM5100_AIF1RX_SLOT_LEN_MASK, i);
+ else
+ snd_soc_update_bits(codec, base + 8,
+ WM5100_AIF1TX_WL_MASK |
+ WM5100_AIF1TX_SLOT_LEN_MASK, i);
+
+ snd_soc_update_bits(codec, base + 4, WM5100_AIF1_RATE_MASK, sr);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops wm5100_dai_ops = {
+ .set_fmt = wm5100_set_fmt,
+ .hw_params = wm5100_hw_params,
+};
+
+static int wm5100_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+ int source, unsigned int freq, int dir)
+{
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ int *rate_store;
+ int fval, audio_rate, ret, reg;
+
+ switch (clk_id) {
+ case WM5100_CLK_SYSCLK:
+ reg = WM5100_CLOCKING_3;
+ rate_store = &wm5100->sysclk;
+ break;
+ case WM5100_CLK_ASYNCCLK:
+ reg = WM5100_CLOCKING_7;
+ rate_store = &wm5100->asyncclk;
+ break;
+ case WM5100_CLK_32KHZ:
+ /* The 32kHz clock is slightly different to the others */
+ switch (source) {
+ case WM5100_CLKSRC_MCLK1:
+ case WM5100_CLKSRC_MCLK2:
+ case WM5100_CLKSRC_SYSCLK:
+ snd_soc_update_bits(codec, WM5100_CLOCKING_1,
+ WM5100_CLK_32K_SRC_MASK,
+ source);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+
+ case WM5100_CLK_AIF1:
+ case WM5100_CLK_AIF2:
+ case WM5100_CLK_AIF3:
+ /* Not real clocks, record which clock domain they're in */
+ switch (source) {
+ case WM5100_CLKSRC_SYSCLK:
+ wm5100->aif_async[clk_id - 1] = false;
+ break;
+ case WM5100_CLKSRC_ASYNCCLK:
+ wm5100->aif_async[clk_id - 1] = true;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid source %d\n", source);
+ return -EINVAL;
+ }
+ return 0;
+
+ case WM5100_CLK_OPCLK:
+ switch (freq) {
+ case 5644800:
+ case 6144000:
+ snd_soc_update_bits(codec, WM5100_MISC_GPIO_1,
+ WM5100_OPCLK_SEL_MASK, 0);
+ break;
+ case 11289600:
+ case 12288000:
+ snd_soc_update_bits(codec, WM5100_MISC_GPIO_1,
+ WM5100_OPCLK_SEL_MASK, 0);
+ break;
+ case 22579200:
+ case 24576000:
+ snd_soc_update_bits(codec, WM5100_MISC_GPIO_1,
+ WM5100_OPCLK_SEL_MASK, 0);
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported OPCLK %dHz\n",
+ freq);
+ return -EINVAL;
+ }
+ return 0;
+
+ default:
+ dev_err(codec->dev, "Unknown clock %d\n", clk_id);
+ return -EINVAL;
+ }
+
+ switch (source) {
+ case WM5100_CLKSRC_SYSCLK:
+ case WM5100_CLKSRC_ASYNCCLK:
+ dev_err(codec->dev, "Invalid source %d\n", source);
+ return -EINVAL;
+ }
+
+ switch (freq) {
+ case 5644800:
+ case 6144000:
+ fval = 0;
+ break;
+ case 11289600:
+ case 12288000:
+ fval = 1;
+ break;
+ case 22579200:
+ case 24576000:
+ fval = 2;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid clock rate: %d\n", freq);
+ return -EINVAL;
+ }
+
+ switch (freq) {
+ case 5644800:
+ case 11289600:
+ case 22579200:
+ audio_rate = 44100;
+ break;
+
+ case 6144000:
+ case 12288000:
+ case 24576000:
+ audio_rate = 48000;
+ break;
+
+ default:
+ BUG();
+ audio_rate = 0;
+ break;
+ }
+
+ /* TODO: Check if MCLKs are in use and enable/disable pulls to
+ * match.
+ */
+
+ snd_soc_update_bits(codec, reg, WM5100_SYSCLK_FREQ_MASK |
+ WM5100_SYSCLK_SRC_MASK,
+ fval << WM5100_SYSCLK_FREQ_SHIFT | source);
+
+ /* If this is SYSCLK then configure the clock rate for the
+ * internal audio functions to the natural sample rate for
+ * this clock rate.
+ */
+ if (clk_id == WM5100_CLK_SYSCLK) {
+ dev_dbg(codec->dev, "Setting primary audio rate to %dHz",
+ audio_rate);
+ if (0 && *rate_store)
+ wm5100_free_sr(codec, audio_rate);
+ ret = wm5100_alloc_sr(codec, audio_rate);
+ if (ret != 0)
+ dev_warn(codec->dev, "Primary audio slot is %d\n",
+ ret);
+ }
+
+ *rate_store = freq;
+
+ return 0;
+}
+
+struct _fll_div {
+ u16 fll_fratio;
+ u16 fll_outdiv;
+ u16 fll_refclk_div;
+ u16 n;
+ u16 theta;
+ u16 lambda;
+};
+
+static struct {
+ unsigned int min;
+ unsigned int max;
+ u16 fll_fratio;
+ int ratio;
+} fll_fratios[] = {
+ { 0, 64000, 4, 16 },
+ { 64000, 128000, 3, 8 },
+ { 128000, 256000, 2, 4 },
+ { 256000, 1000000, 1, 2 },
+ { 1000000, 13500000, 0, 1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+ unsigned int Fout)
+{
+ unsigned int target;
+ unsigned int div;
+ unsigned int fratio, gcd_fll;
+ int i;
+
+ /* Fref must be <=13.5MHz */
+ div = 1;
+ fll_div->fll_refclk_div = 0;
+ while ((Fref / div) > 13500000) {
+ div *= 2;
+ fll_div->fll_refclk_div++;
+
+ if (div > 8) {
+ pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+ Fref);
+ return -EINVAL;
+ }
+ }
+
+ pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+ /* Apply the division for our remaining calculations */
+ Fref /= div;
+
+ /* Fvco should be 90-100MHz; don't check the upper bound */
+ div = 2;
+ while (Fout * div < 90000000) {
+ div++;
+ if (div > 64) {
+ pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+ Fout);
+ return -EINVAL;
+ }
+ }
+ target = Fout * div;
+ fll_div->fll_outdiv = div - 1;
+
+ pr_debug("FLL Fvco=%dHz\n", target);
+
+ /* Find an appropraite FLL_FRATIO and factor it out of the target */
+ for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+ if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+ fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+ fratio = fll_fratios[i].ratio;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(fll_fratios)) {
+ pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+ return -EINVAL;
+ }
+
+ fll_div->n = target / (fratio * Fref);
+
+ if (target % Fref == 0) {
+ fll_div->theta = 0;
+ fll_div->lambda = 0;
+ } else {
+ gcd_fll = gcd(target, fratio * Fref);
+
+ fll_div->theta = (target - (fll_div->n * fratio * Fref))
+ / gcd_fll;
+ fll_div->lambda = (fratio * Fref) / gcd_fll;
+ }
+
+ pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+ fll_div->n, fll_div->theta, fll_div->lambda);
+ pr_debug("FLL_FRATIO=%x(%d) FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+ fll_div->fll_fratio, fratio, fll_div->fll_outdiv,
+ fll_div->fll_refclk_div);
+
+ return 0;
+}
+
+static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+ unsigned int Fref, unsigned int Fout)
+{
+ struct i2c_client *i2c = to_i2c_client(codec->dev);
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ struct _fll_div factors;
+ struct wm5100_fll *fll;
+ int ret, base, lock, i, timeout;
+
+ switch (fll_id) {
+ case WM5100_FLL1:
+ fll = &wm5100->fll[0];
+ base = WM5100_FLL1_CONTROL_1 - 1;
+ lock = WM5100_FLL1_LOCK_STS;
+ break;
+ case WM5100_FLL2:
+ fll = &wm5100->fll[1];
+ base = WM5100_FLL2_CONTROL_2 - 1;
+ lock = WM5100_FLL2_LOCK_STS;
+ break;
+ default:
+ dev_err(codec->dev, "Unknown FLL %d\n",fll_id);
+ return -EINVAL;
+ }
+
+ if (!Fout) {
+ dev_dbg(codec->dev, "FLL%d disabled", fll_id);
+ fll->fout = 0;
+ snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, 0);
+ return 0;
+ }
+
+ switch (source) {
+ case WM5100_FLL_SRC_MCLK1:
+ case WM5100_FLL_SRC_MCLK2:
+ case WM5100_FLL_SRC_FLL1:
+ case WM5100_FLL_SRC_FLL2:
+ case WM5100_FLL_SRC_AIF1BCLK:
+ case WM5100_FLL_SRC_AIF2BCLK:
+ case WM5100_FLL_SRC_AIF3BCLK:
+ break;
+ default:
+ dev_err(codec->dev, "Invalid FLL source %d\n", source);
+ return -EINVAL;
+ }
+
+ ret = fll_factors(&factors, Fref, Fout);
+ if (ret < 0)
+ return ret;
+
+ /* Disable the FLL while we reconfigure */
+ snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, 0);
+
+ snd_soc_update_bits(codec, base + 2,
+ WM5100_FLL1_OUTDIV_MASK | WM5100_FLL1_FRATIO_MASK,
+ (factors.fll_outdiv << WM5100_FLL1_OUTDIV_SHIFT) |
+ factors.fll_fratio);
+ snd_soc_update_bits(codec, base + 3, WM5100_FLL1_THETA_MASK,
+ factors.theta);
+ snd_soc_update_bits(codec, base + 5, WM5100_FLL1_N_MASK, factors.n);
+ snd_soc_update_bits(codec, base + 6,
+ WM5100_FLL1_REFCLK_DIV_MASK |
+ WM5100_FLL1_REFCLK_SRC_MASK,
+ (factors.fll_refclk_div
+ << WM5100_FLL1_REFCLK_DIV_SHIFT) | source);
+ snd_soc_update_bits(codec, base + 7, WM5100_FLL1_LAMBDA_MASK,
+ factors.lambda);
+
+ /* Clear any pending completions */
+ try_wait_for_completion(&fll->lock);
+
+ snd_soc_update_bits(codec, base + 1, WM5100_FLL1_ENA, WM5100_FLL1_ENA);
+
+ if (i2c->irq)
+ timeout = 2;
+ else
+ timeout = 50;
+
+ /* Poll for the lock; will use interrupt when we can test */
+ for (i = 0; i < timeout; i++) {
+ if (i2c->irq) {
+ ret = wait_for_completion_timeout(&fll->lock,
+ msecs_to_jiffies(25));
+ if (ret > 0)
+ break;
+ } else {
+ msleep(1);
+ }
+
+ ret = snd_soc_read(codec,
+ WM5100_INTERRUPT_RAW_STATUS_3);
+ if (ret < 0) {
+ dev_err(codec->dev,
+ "Failed to read FLL status: %d\n",
+ ret);
+ continue;
+ }
+ if (ret & lock)
+ break;
+ }
+ if (i == timeout) {
+ dev_err(codec->dev, "FLL%d lock timed out\n", fll_id);
+ return -ETIMEDOUT;
+ }
+
+ fll->src = source;
+ fll->fref = Fref;
+ fll->fout = Fout;
+
+ dev_dbg(codec->dev, "FLL%d running %dHz->%dHz\n", fll_id,
+ Fref, Fout);
+
+ return 0;
+}
+
+/* Actually go much higher */
+#define WM5100_RATES SNDRV_PCM_RATE_8000_192000
+
+#define WM5100_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm5100_dai[] = {
+ {
+ .name = "wm5100-aif1",
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = WM5100_RATES,
+ .formats = WM5100_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = WM5100_RATES,
+ .formats = WM5100_FORMATS,
+ },
+ .ops = &wm5100_dai_ops,
+ },
+ {
+ .name = "wm5100-aif2",
+ .id = 1,
+ .playback = {
+ .stream_name = "AIF2 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = WM5100_RATES,
+ .formats = WM5100_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF2 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = WM5100_RATES,
+ .formats = WM5100_FORMATS,
+ },
+ .ops = &wm5100_dai_ops,
+ },
+ {
+ .name = "wm5100-aif3",
+ .id = 2,
+ .playback = {
+ .stream_name = "AIF3 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = WM5100_RATES,
+ .formats = WM5100_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF3 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = WM5100_RATES,
+ .formats = WM5100_FORMATS,
+ },
+ .ops = &wm5100_dai_ops,
+ },
+};
+
+static int wm5100_dig_vu[] = {
+ WM5100_ADC_DIGITAL_VOLUME_1L,
+ WM5100_ADC_DIGITAL_VOLUME_1R,
+ WM5100_ADC_DIGITAL_VOLUME_2L,
+ WM5100_ADC_DIGITAL_VOLUME_2R,
+ WM5100_ADC_DIGITAL_VOLUME_3L,
+ WM5100_ADC_DIGITAL_VOLUME_3R,
+ WM5100_ADC_DIGITAL_VOLUME_4L,
+ WM5100_ADC_DIGITAL_VOLUME_4R,
+
+ WM5100_DAC_DIGITAL_VOLUME_1L,
+ WM5100_DAC_DIGITAL_VOLUME_1R,
+ WM5100_DAC_DIGITAL_VOLUME_2L,
+ WM5100_DAC_DIGITAL_VOLUME_2R,
+ WM5100_DAC_DIGITAL_VOLUME_3L,
+ WM5100_DAC_DIGITAL_VOLUME_3R,
+ WM5100_DAC_DIGITAL_VOLUME_4L,
+ WM5100_DAC_DIGITAL_VOLUME_4R,
+ WM5100_DAC_DIGITAL_VOLUME_5L,
+ WM5100_DAC_DIGITAL_VOLUME_5R,
+ WM5100_DAC_DIGITAL_VOLUME_6L,
+ WM5100_DAC_DIGITAL_VOLUME_6R,
+};
+
+static void wm5100_set_detect_mode(struct snd_soc_codec *codec, int the_mode)
+{
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ struct wm5100_jack_mode *mode = &wm5100->pdata.jack_modes[the_mode];
+
+ BUG_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes));
+
+ gpio_set_value_cansleep(wm5100->pdata.hp_pol, mode->hp_pol);
+ snd_soc_update_bits(codec, WM5100_ACCESSORY_DETECT_MODE_1,
+ WM5100_ACCDET_BIAS_SRC_MASK |
+ WM5100_ACCDET_SRC,
+ (mode->bias << WM5100_ACCDET_BIAS_SRC_SHIFT) |
+ mode->micd_src << WM5100_ACCDET_SRC_SHIFT);
+ snd_soc_update_bits(codec, WM5100_MISC_CONTROL,
+ WM5100_HPCOM_SRC,
+ mode->micd_src << WM5100_HPCOM_SRC_SHIFT);
+
+ wm5100->jack_mode = the_mode;
+
+ dev_dbg(codec->dev, "Set microphone polarity to %d\n",
+ wm5100->jack_mode);
+}
+
+static void wm5100_micd_irq(struct snd_soc_codec *codec)
+{
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ int val;
+
+ val = snd_soc_read(codec, WM5100_MIC_DETECT_3);
+
+ dev_dbg(codec->dev, "Microphone event: %x\n", val);
+
+ if (!(val & WM5100_ACCDET_VALID)) {
+ dev_warn(codec->dev, "Microphone detection state invalid\n");
+ return;
+ }
+
+ /* No accessory, reset everything and report removal */
+ if (!(val & WM5100_ACCDET_STS)) {
+ dev_dbg(codec->dev, "Jack removal detected\n");
+ wm5100->jack_mic = false;
+ wm5100->jack_detecting = true;
+ snd_soc_jack_report(wm5100->jack, 0,
+ SND_JACK_LINEOUT | SND_JACK_HEADSET |
+ SND_JACK_BTN_0);
+
+ snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
+ WM5100_ACCDET_RATE_MASK,
+ WM5100_ACCDET_RATE_MASK);
+ return;
+ }
+
+ /* If the measurement is very high we've got a microphone,
+ * either we just detected one or if we already reported then
+ * we've got a button release event.
+ */
+ if (val & 0x400) {
+ if (wm5100->jack_detecting) {
+ dev_dbg(codec->dev, "Microphone detected\n");
+ wm5100->jack_mic = true;
+ snd_soc_jack_report(wm5100->jack,
+ SND_JACK_HEADSET,
+ SND_JACK_HEADSET | SND_JACK_BTN_0);
+
+ /* Increase poll rate to give better responsiveness
+ * for buttons */
+ snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
+ WM5100_ACCDET_RATE_MASK,
+ 5 << WM5100_ACCDET_RATE_SHIFT);
+ } else {
+ dev_dbg(codec->dev, "Mic button up\n");
+ snd_soc_jack_report(wm5100->jack, 0, SND_JACK_BTN_0);
+ }
+
+ return;
+ }
+
+ /* If we detected a lower impedence during initial startup
+ * then we probably have the wrong polarity, flip it. Don't
+ * do this for the lowest impedences to speed up detection of
+ * plain headphones.
+ */
+ if (wm5100->jack_detecting && (val & 0x3f8)) {
+ wm5100_set_detect_mode(codec, !wm5100->jack_mode);
+
+ return;
+ }
+
+ /* Don't distinguish between buttons, just report any low
+ * impedence as BTN_0.
+ */
+ if (val & 0x3fc) {
+ if (wm5100->jack_mic) {
+ dev_dbg(codec->dev, "Mic button detected\n");
+ snd_soc_jack_report(wm5100->jack, SND_JACK_BTN_0,
+ SND_JACK_BTN_0);
+ } else if (wm5100->jack_detecting) {
+ dev_dbg(codec->dev, "Headphone detected\n");
+ snd_soc_jack_report(wm5100->jack, SND_JACK_HEADPHONE,
+ SND_JACK_HEADPHONE);
+
+ /* Increase the detection rate a bit for
+ * responsiveness.
+ */
+ snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
+ WM5100_ACCDET_RATE_MASK,
+ 7 << WM5100_ACCDET_RATE_SHIFT);
+ }
+ }
+}
+
+int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+{
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+
+ if (jack) {
+ wm5100->jack = jack;
+ wm5100->jack_detecting = true;
+
+ wm5100_set_detect_mode(codec, 0);
+
+ /* Slowest detection rate, gives debounce for initial
+ * detection */
+ snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
+ WM5100_ACCDET_BIAS_STARTTIME_MASK |
+ WM5100_ACCDET_RATE_MASK,
+ (7 << WM5100_ACCDET_BIAS_STARTTIME_SHIFT) |
+ WM5100_ACCDET_RATE_MASK);
+
+ /* We need the charge pump to power MICBIAS */
+ snd_soc_dapm_force_enable_pin(&codec->dapm, "CP2");
+ snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
+ snd_soc_dapm_sync(&codec->dapm);
+
+ /* We start off just enabling microphone detection - even a
+ * plain headphone will trigger detection.
+ */
+ snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
+ WM5100_ACCDET_ENA, WM5100_ACCDET_ENA);
+
+ snd_soc_update_bits(codec, WM5100_INTERRUPT_STATUS_3_MASK,
+ WM5100_IM_ACCDET_EINT, 0);
+ } else {
+ snd_soc_update_bits(codec, WM5100_INTERRUPT_STATUS_3_MASK,
+ WM5100_IM_HPDET_EINT |
+ WM5100_IM_ACCDET_EINT,
+ WM5100_IM_HPDET_EINT |
+ WM5100_IM_ACCDET_EINT);
+ snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
+ WM5100_ACCDET_ENA, 0);
+ wm5100->jack = NULL;
+ }
+
+ return 0;
+}
+
+static irqreturn_t wm5100_irq(int irq, void *data)
+{
+ struct snd_soc_codec *codec = data;
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ irqreturn_t status = IRQ_NONE;
+ int irq_val;
+
+ irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_3);
+ if (irq_val < 0) {
+ dev_err(codec->dev, "Failed to read IRQ status 3: %d\n",
+ irq_val);
+ irq_val = 0;
+ }
+ irq_val &= ~snd_soc_read(codec, WM5100_INTERRUPT_STATUS_3_MASK);
+
+ snd_soc_write(codec, WM5100_INTERRUPT_STATUS_3, irq_val);
+
+ if (irq_val)
+ status = IRQ_HANDLED;
+
+ wm5100_log_status3(codec, irq_val);
+
+ if (irq_val & WM5100_FLL1_LOCK_EINT) {
+ dev_dbg(codec->dev, "FLL1 locked\n");
+ complete(&wm5100->fll[0].lock);
+ }
+ if (irq_val & WM5100_FLL2_LOCK_EINT) {
+ dev_dbg(codec->dev, "FLL2 locked\n");
+ complete(&wm5100->fll[1].lock);
+ }
+
+ if (irq_val & WM5100_ACCDET_EINT)
+ wm5100_micd_irq(codec);
+
+ irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4);
+ if (irq_val < 0) {
+ dev_err(codec->dev, "Failed to read IRQ status 4: %d\n",
+ irq_val);
+ irq_val = 0;
+ }
+ irq_val &= ~snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4_MASK);
+
+ if (irq_val)
+ status = IRQ_HANDLED;
+
+ snd_soc_write(codec, WM5100_INTERRUPT_STATUS_4, irq_val);
+
+ wm5100_log_status4(codec, irq_val);
+
+ return status;
+}
+
+static irqreturn_t wm5100_edge_irq(int irq, void *data)
+{
+ irqreturn_t ret = IRQ_NONE;
+ irqreturn_t val;
+
+ do {
+ val = wm5100_irq(irq, data);
+ if (val != IRQ_NONE)
+ ret = val;
+ } while (val != IRQ_NONE);
+
+ return ret;
+}
+
+#ifdef CONFIG_GPIOLIB
+static inline struct wm5100_priv *gpio_to_wm5100(struct gpio_chip *chip)
+{
+ return container_of(chip, struct wm5100_priv, gpio_chip);
+}
+
+static void wm5100_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
+ struct snd_soc_codec *codec = wm5100->codec;
+
+ snd_soc_update_bits(codec, WM5100_GPIO_CTRL_1 + offset,
+ WM5100_GP1_LVL, !!value << WM5100_GP1_LVL_SHIFT);
+}
+
+static int wm5100_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
+ struct snd_soc_codec *codec = wm5100->codec;
+ int val, ret;
+
+ val = (1 << WM5100_GP1_FN_SHIFT) | (!!value << WM5100_GP1_LVL_SHIFT);
+
+ ret = snd_soc_update_bits(codec, WM5100_GPIO_CTRL_1 + offset,
+ WM5100_GP1_FN_MASK | WM5100_GP1_DIR |
+ WM5100_GP1_LVL, val);
+ if (ret < 0)
+ return ret;
+ else
+ return 0;
+}
+
+static int wm5100_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
+ struct snd_soc_codec *codec = wm5100->codec;
+ int ret;
+
+ ret = snd_soc_read(codec, WM5100_GPIO_CTRL_1 + offset);
+ if (ret < 0)
+ return ret;
+
+ return (ret & WM5100_GP1_LVL) != 0;
+}
+
+static int wm5100_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+ struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
+ struct snd_soc_codec *codec = wm5100->codec;
+
+ return snd_soc_update_bits(codec, WM5100_GPIO_CTRL_1 + offset,
+ WM5100_GP1_FN_MASK | WM5100_GP1_DIR,
+ (1 << WM5100_GP1_FN_SHIFT) |
+ (1 << WM5100_GP1_DIR_SHIFT));
+}
+
+static struct gpio_chip wm5100_template_chip = {
+ .label = "wm5100",
+ .owner = THIS_MODULE,
+ .direction_output = wm5100_gpio_direction_out,
+ .set = wm5100_gpio_set,
+ .direction_input = wm5100_gpio_direction_in,
+ .get = wm5100_gpio_get,
+ .can_sleep = 1,
+};
+
+static void wm5100_init_gpio(struct snd_soc_codec *codec)
+{
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ wm5100->gpio_chip = wm5100_template_chip;
+ wm5100->gpio_chip.ngpio = 6;
+ wm5100->gpio_chip.dev = codec->dev;
+
+ if (wm5100->pdata.gpio_base)
+ wm5100->gpio_chip.base = wm5100->pdata.gpio_base;
+ else
+ wm5100->gpio_chip.base = -1;
+
+ ret = gpiochip_add(&wm5100->gpio_chip);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm5100_free_gpio(struct snd_soc_codec *codec)
+{
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = gpiochip_remove(&wm5100->gpio_chip);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+}
+#else
+static void wm5100_init_gpio(struct snd_soc_codec *codec)
+{
+}
+
+static void wm5100_free_gpio(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+static int wm5100_probe(struct snd_soc_codec *codec)
+{
+ struct i2c_client *i2c = to_i2c_client(codec->dev);
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ int ret, i, irq_flags;
+
+ wm5100->codec = codec;
+
+ ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm5100->core_supplies); i++)
+ wm5100->core_supplies[i].supply = wm5100_core_supply_names[i];
+
+ ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm5100->core_supplies),
+ wm5100->core_supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request core supplies: %d\n",
+ ret);
+ return ret;
+ }
+
+ wm5100->cpvdd = regulator_get(&i2c->dev, "CPVDD");
+ if (IS_ERR(wm5100->cpvdd)) {
+ ret = PTR_ERR(wm5100->cpvdd);
+ dev_err(&i2c->dev, "Failed to get CPVDD: %d\n", ret);
+ goto err_core;
+ }
+
+ wm5100->dbvdd2 = regulator_get(&i2c->dev, "DBVDD2");
+ if (IS_ERR(wm5100->dbvdd2)) {
+ ret = PTR_ERR(wm5100->dbvdd2);
+ dev_err(&i2c->dev, "Failed to get DBVDD2: %d\n", ret);
+ goto err_cpvdd;
+ }
+
+ wm5100->dbvdd3 = regulator_get(&i2c->dev, "DBVDD3");
+ if (IS_ERR(wm5100->dbvdd3)) {
+ ret = PTR_ERR(wm5100->dbvdd3);
+ dev_err(&i2c->dev, "Failed to get DBVDD2: %d\n", ret);
+ goto err_dbvdd2;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
+ wm5100->core_supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to enable core supplies: %d\n",
+ ret);
+ goto err_dbvdd3;
+ }
+
+ if (wm5100->pdata.ldo_ena) {
+ ret = gpio_request_one(wm5100->pdata.ldo_ena,
+ GPIOF_OUT_INIT_HIGH, "WM5100 LDOENA");
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
+ wm5100->pdata.ldo_ena, ret);
+ goto err_enable;
+ }
+ msleep(2);
+ }
+
+ if (wm5100->pdata.reset) {
+ ret = gpio_request_one(wm5100->pdata.reset,
+ GPIOF_OUT_INIT_HIGH, "WM5100 /RESET");
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
+ wm5100->pdata.reset, ret);
+ goto err_ldo;
+ }
+ }
+
+ ret = snd_soc_read(codec, WM5100_SOFTWARE_RESET);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read ID register\n");
+ goto err_reset;
+ }
+ switch (ret) {
+ case 0x8997:
+ case 0x5100:
+ break;
+
+ default:
+ dev_err(codec->dev, "Device is not a WM5100, ID is %x\n", ret);
+ ret = -EINVAL;
+ goto err_reset;
+ }
+
+ ret = snd_soc_read(codec, WM5100_DEVICE_REVISION);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to read revision register\n");
+ goto err_reset;
+ }
+ wm5100->rev = ret & WM5100_DEVICE_REVISION_MASK;
+
+ dev_info(codec->dev, "revision %c\n", wm5100->rev + 'A');
+
+ ret = wm5100_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ goto err_reset;
+ }
+
+ codec->cache_only = true;
+
+ wm5100_init_gpio(codec);
+
+ for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++)
+ snd_soc_update_bits(codec, wm5100_dig_vu[i], WM5100_OUT_VU,
+ WM5100_OUT_VU);
+
+ for (i = 0; i < ARRAY_SIZE(wm5100->pdata.in_mode); i++) {
+ snd_soc_update_bits(codec, WM5100_IN1L_CONTROL,
+ WM5100_IN1_MODE_MASK |
+ WM5100_IN1_DMIC_SUP_MASK,
+ (wm5100->pdata.in_mode[i] <<
+ WM5100_IN1_MODE_SHIFT) |
+ (wm5100->pdata.dmic_sup[i] <<
+ WM5100_IN1_DMIC_SUP_SHIFT));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm5100->pdata.gpio_defaults); i++) {
+ if (!wm5100->pdata.gpio_defaults[i])
+ continue;
+
+ snd_soc_write(codec, WM5100_GPIO_CTRL_1 + i,
+ wm5100->pdata.gpio_defaults[i]);
+ }
+
+ /* Don't debounce interrupts to support use of SYSCLK only */
+ snd_soc_write(codec, WM5100_IRQ_DEBOUNCE_1, 0);
+ snd_soc_write(codec, WM5100_IRQ_DEBOUNCE_2, 0);
+
+ /* TODO: check if we're symmetric */
+
+ if (i2c->irq) {
+ if (wm5100->pdata.irq_flags)
+ irq_flags = wm5100->pdata.irq_flags;
+ else
+ irq_flags = IRQF_TRIGGER_LOW;
+
+ irq_flags |= IRQF_ONESHOT;
+
+ if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+ ret = request_threaded_irq(i2c->irq, NULL,
+ wm5100_edge_irq,
+ irq_flags, "wm5100", codec);
+ else
+ ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq,
+ irq_flags, "wm5100", codec);
+
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
+ i2c->irq, ret);
+ } else {
+ /* Enable default interrupts */
+ snd_soc_update_bits(codec,
+ WM5100_INTERRUPT_STATUS_3_MASK,
+ WM5100_IM_SPK_SHUTDOWN_WARN_EINT |
+ WM5100_IM_SPK_SHUTDOWN_EINT |
+ WM5100_IM_ASRC2_LOCK_EINT |
+ WM5100_IM_ASRC1_LOCK_EINT |
+ WM5100_IM_FLL2_LOCK_EINT |
+ WM5100_IM_FLL1_LOCK_EINT |
+ WM5100_CLKGEN_ERR_EINT |
+ WM5100_CLKGEN_ERR_ASYNC_EINT, 0);
+
+ snd_soc_update_bits(codec,
+ WM5100_INTERRUPT_STATUS_4_MASK,
+ WM5100_AIF3_ERR_EINT |
+ WM5100_AIF2_ERR_EINT |
+ WM5100_AIF1_ERR_EINT |
+ WM5100_CTRLIF_ERR_EINT |
+ WM5100_ISRC2_UNDERCLOCKED_EINT |
+ WM5100_ISRC1_UNDERCLOCKED_EINT |
+ WM5100_FX_UNDERCLOCKED_EINT |
+ WM5100_AIF3_UNDERCLOCKED_EINT |
+ WM5100_AIF2_UNDERCLOCKED_EINT |
+ WM5100_AIF1_UNDERCLOCKED_EINT |
+ WM5100_ASRC_UNDERCLOCKED_EINT |
+ WM5100_DAC_UNDERCLOCKED_EINT |
+ WM5100_ADC_UNDERCLOCKED_EINT |
+ WM5100_MIXER_UNDERCLOCKED_EINT, 0);
+ }
+ } else {
+ snd_soc_dapm_new_controls(&codec->dapm,
+ wm5100_dapm_widgets_noirq,
+ ARRAY_SIZE(wm5100_dapm_widgets_noirq));
+ }
+
+ if (wm5100->pdata.hp_pol) {
+ ret = gpio_request_one(wm5100->pdata.hp_pol,
+ GPIOF_OUT_INIT_HIGH, "WM5100 HP_POL");
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to request HP_POL %d: %d\n",
+ wm5100->pdata.hp_pol, ret);
+ goto err_gpio;
+ }
+ }
+
+ /* We'll get woken up again when the system has something useful
+ * for us to do.
+ */
+ if (wm5100->pdata.ldo_ena)
+ gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
+ regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
+ wm5100->core_supplies);
+
+ return 0;
+
+err_gpio:
+ if (i2c->irq)
+ free_irq(i2c->irq, codec);
+ wm5100_free_gpio(codec);
+err_reset:
+ if (wm5100->pdata.reset) {
+ gpio_set_value_cansleep(wm5100->pdata.reset, 1);
+ gpio_free(wm5100->pdata.reset);
+ }
+err_ldo:
+ if (wm5100->pdata.ldo_ena) {
+ gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
+ gpio_free(wm5100->pdata.ldo_ena);
+ }
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
+ wm5100->core_supplies);
+err_dbvdd3:
+ regulator_put(wm5100->dbvdd3);
+err_dbvdd2:
+ regulator_put(wm5100->dbvdd2);
+err_cpvdd:
+ regulator_put(wm5100->cpvdd);
+err_core:
+ regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies),
+ wm5100->core_supplies);
+
+ return ret;
+}
+
+static int wm5100_remove(struct snd_soc_codec *codec)
+{
+ struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ struct i2c_client *i2c = to_i2c_client(codec->dev);
+
+ wm5100_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ if (wm5100->pdata.hp_pol) {
+ gpio_free(wm5100->pdata.hp_pol);
+ }
+ if (i2c->irq)
+ free_irq(i2c->irq, codec);
+ wm5100_free_gpio(codec);
+ if (wm5100->pdata.reset) {
+ gpio_set_value_cansleep(wm5100->pdata.reset, 1);
+ gpio_free(wm5100->pdata.reset);
+ }
+ if (wm5100->pdata.ldo_ena) {
+ gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
+ gpio_free(wm5100->pdata.ldo_ena);
+ }
+ regulator_put(wm5100->dbvdd3);
+ regulator_put(wm5100->dbvdd2);
+ regulator_put(wm5100->cpvdd);
+ regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies),
+ wm5100->core_supplies);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
+ .probe = wm5100_probe,
+ .remove = wm5100_remove,
+
+ .set_sysclk = wm5100_set_sysclk,
+ .set_pll = wm5100_set_fll,
+ .set_bias_level = wm5100_set_bias_level,
+ .idle_bias_off = 1,
+
+ .seq_notifier = wm5100_seq_notifier,
+ .controls = wm5100_snd_controls,
+ .num_controls = ARRAY_SIZE(wm5100_snd_controls),
+ .dapm_widgets = wm5100_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm5100_dapm_widgets),
+ .dapm_routes = wm5100_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(wm5100_dapm_routes),
+
+ .reg_cache_size = ARRAY_SIZE(wm5100_reg_defaults),
+ .reg_word_size = sizeof(u16),
+ .compress_type = SND_SOC_RBTREE_COMPRESSION,
+ .reg_cache_default = wm5100_reg_defaults,
+
+ .volatile_register = wm5100_volatile_register,
+ .readable_register = wm5100_readable_register,
+};
+
+static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm5100_pdata *pdata = dev_get_platdata(&i2c->dev);
+ struct wm5100_priv *wm5100;
+ int ret, i;
+
+ wm5100 = kzalloc(sizeof(struct wm5100_priv), GFP_KERNEL);
+ if (wm5100 == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(wm5100->fll); i++)
+ init_completion(&wm5100->fll[i].lock);
+
+ if (pdata)
+ wm5100->pdata = *pdata;
+
+ i2c_set_clientdata(i2c, wm5100);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm5100, wm5100_dai,
+ ARRAY_SIZE(wm5100_dai));
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to register WM5100: %d\n", ret);
+ kfree(wm5100);
+ }
+
+ return ret;
+}
+
+static __devexit int wm5100_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id wm5100_i2c_id[] = {
+ { "wm5100", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm5100_i2c_id);
+
+static struct i2c_driver wm5100_i2c_driver = {
+ .driver = {
+ .name = "wm5100",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm5100_i2c_probe,
+ .remove = __devexit_p(wm5100_i2c_remove),
+ .id_table = wm5100_i2c_id,
+};
+
+static int __init wm5100_modinit(void)
+{
+ return i2c_add_driver(&wm5100_i2c_driver);
+}
+module_init(wm5100_modinit);
+
+static void __exit wm5100_exit(void)
+{
+ i2c_del_driver(&wm5100_i2c_driver);
+}
+module_exit(wm5100_exit);
+
+MODULE_DESCRIPTION("ASoC WM5100 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm5100.h b/sound/soc/codecs/wm5100.h
new file mode 100644
index 000000000000..970759636bdc
--- /dev/null
+++ b/sound/soc/codecs/wm5100.h
@@ -0,0 +1,5155 @@
+/*
+ * wm5100.h -- WM5100 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef WM5100_ASOC_H
+#define WM5100_ASOC_H
+
+#include <sound/soc.h>
+
+int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+
+#define WM5100_CLK_AIF1 1
+#define WM5100_CLK_AIF2 2
+#define WM5100_CLK_AIF3 3
+#define WM5100_CLK_SYSCLK 4
+#define WM5100_CLK_ASYNCCLK 5
+#define WM5100_CLK_32KHZ 6
+#define WM5100_CLK_OPCLK 7
+
+#define WM5100_CLKSRC_MCLK1 0
+#define WM5100_CLKSRC_MCLK2 1
+#define WM5100_CLKSRC_SYSCLK 2
+#define WM5100_CLKSRC_FLL1 4
+#define WM5100_CLKSRC_FLL2 5
+#define WM5100_CLKSRC_AIF1BCLK 8
+#define WM5100_CLKSRC_AIF2BCLK 9
+#define WM5100_CLKSRC_AIF3BCLK 10
+#define WM5100_CLKSRC_ASYNCCLK 0x100
+
+#define WM5100_FLL1 1
+#define WM5100_FLL2 2
+
+#define WM5100_FLL_SRC_MCLK1 0x0
+#define WM5100_FLL_SRC_MCLK2 0x1
+#define WM5100_FLL_SRC_FLL1 0x4
+#define WM5100_FLL_SRC_FLL2 0x5
+#define WM5100_FLL_SRC_AIF1BCLK 0x8
+#define WM5100_FLL_SRC_AIF2BCLK 0x9
+#define WM5100_FLL_SRC_AIF3BCLK 0xa
+
+/*
+ * Register values.
+ */
+#define WM5100_SOFTWARE_RESET 0x00
+#define WM5100_DEVICE_REVISION 0x01
+#define WM5100_CTRL_IF_1 0x10
+#define WM5100_TONE_GENERATOR_1 0x20
+#define WM5100_PWM_DRIVE_1 0x30
+#define WM5100_PWM_DRIVE_2 0x31
+#define WM5100_PWM_DRIVE_3 0x32
+#define WM5100_CLOCKING_1 0x100
+#define WM5100_CLOCKING_3 0x101
+#define WM5100_CLOCKING_4 0x102
+#define WM5100_CLOCKING_5 0x103
+#define WM5100_CLOCKING_6 0x104
+#define WM5100_CLOCKING_7 0x107
+#define WM5100_CLOCKING_8 0x108
+#define WM5100_ASRC_ENABLE 0x120
+#define WM5100_ASRC_STATUS 0x121
+#define WM5100_ASRC_RATE1 0x122
+#define WM5100_ISRC_1_CTRL_1 0x141
+#define WM5100_ISRC_1_CTRL_2 0x142
+#define WM5100_ISRC_2_CTRL1 0x143
+#define WM5100_ISRC_2_CTRL_2 0x144
+#define WM5100_FLL1_CONTROL_1 0x182
+#define WM5100_FLL1_CONTROL_2 0x183
+#define WM5100_FLL1_CONTROL_3 0x184
+#define WM5100_FLL1_CONTROL_5 0x186
+#define WM5100_FLL1_CONTROL_6 0x187
+#define WM5100_FLL1_EFS_1 0x188
+#define WM5100_FLL2_CONTROL_1 0x1A2
+#define WM5100_FLL2_CONTROL_2 0x1A3
+#define WM5100_FLL2_CONTROL_3 0x1A4
+#define WM5100_FLL2_CONTROL_5 0x1A6
+#define WM5100_FLL2_CONTROL_6 0x1A7
+#define WM5100_FLL2_EFS_1 0x1A8
+#define WM5100_MIC_CHARGE_PUMP_1 0x200
+#define WM5100_MIC_CHARGE_PUMP_2 0x201
+#define WM5100_HP_CHARGE_PUMP_1 0x202
+#define WM5100_LDO1_CONTROL 0x211
+#define WM5100_MIC_BIAS_CTRL_1 0x215
+#define WM5100_MIC_BIAS_CTRL_2 0x216
+#define WM5100_MIC_BIAS_CTRL_3 0x217
+#define WM5100_ACCESSORY_DETECT_MODE_1 0x280
+#define WM5100_HEADPHONE_DETECT_1 0x288
+#define WM5100_HEADPHONE_DETECT_2 0x289
+#define WM5100_MIC_DETECT_1 0x290
+#define WM5100_MIC_DETECT_2 0x291
+#define WM5100_MIC_DETECT_3 0x292
+#define WM5100_MISC_CONTROL 0x2BB
+#define WM5100_INPUT_ENABLES 0x301
+#define WM5100_INPUT_ENABLES_STATUS 0x302
+#define WM5100_IN1L_CONTROL 0x310
+#define WM5100_IN1R_CONTROL 0x311
+#define WM5100_IN2L_CONTROL 0x312
+#define WM5100_IN2R_CONTROL 0x313
+#define WM5100_IN3L_CONTROL 0x314
+#define WM5100_IN3R_CONTROL 0x315
+#define WM5100_IN4L_CONTROL 0x316
+#define WM5100_IN4R_CONTROL 0x317
+#define WM5100_RXANC_SRC 0x318
+#define WM5100_INPUT_VOLUME_RAMP 0x319
+#define WM5100_ADC_DIGITAL_VOLUME_1L 0x320
+#define WM5100_ADC_DIGITAL_VOLUME_1R 0x321
+#define WM5100_ADC_DIGITAL_VOLUME_2L 0x322
+#define WM5100_ADC_DIGITAL_VOLUME_2R 0x323
+#define WM5100_ADC_DIGITAL_VOLUME_3L 0x324
+#define WM5100_ADC_DIGITAL_VOLUME_3R 0x325
+#define WM5100_ADC_DIGITAL_VOLUME_4L 0x326
+#define WM5100_ADC_DIGITAL_VOLUME_4R 0x327
+#define WM5100_OUTPUT_ENABLES_2 0x401
+#define WM5100_OUTPUT_STATUS_1 0x402
+#define WM5100_OUTPUT_STATUS_2 0x403
+#define WM5100_CHANNEL_ENABLES_1 0x408
+#define WM5100_OUT_VOLUME_1L 0x410
+#define WM5100_OUT_VOLUME_1R 0x411
+#define WM5100_DAC_VOLUME_LIMIT_1L 0x412
+#define WM5100_DAC_VOLUME_LIMIT_1R 0x413
+#define WM5100_OUT_VOLUME_2L 0x414
+#define WM5100_OUT_VOLUME_2R 0x415
+#define WM5100_DAC_VOLUME_LIMIT_2L 0x416
+#define WM5100_DAC_VOLUME_LIMIT_2R 0x417
+#define WM5100_OUT_VOLUME_3L 0x418
+#define WM5100_OUT_VOLUME_3R 0x419
+#define WM5100_DAC_VOLUME_LIMIT_3L 0x41A
+#define WM5100_DAC_VOLUME_LIMIT_3R 0x41B
+#define WM5100_OUT_VOLUME_4L 0x41C
+#define WM5100_OUT_VOLUME_4R 0x41D
+#define WM5100_DAC_VOLUME_LIMIT_5L 0x41E
+#define WM5100_DAC_VOLUME_LIMIT_5R 0x41F
+#define WM5100_DAC_VOLUME_LIMIT_6L 0x420
+#define WM5100_DAC_VOLUME_LIMIT_6R 0x421
+#define WM5100_DAC_AEC_CONTROL_1 0x440
+#define WM5100_OUTPUT_VOLUME_RAMP 0x441
+#define WM5100_DAC_DIGITAL_VOLUME_1L 0x480
+#define WM5100_DAC_DIGITAL_VOLUME_1R 0x481
+#define WM5100_DAC_DIGITAL_VOLUME_2L 0x482
+#define WM5100_DAC_DIGITAL_VOLUME_2R 0x483
+#define WM5100_DAC_DIGITAL_VOLUME_3L 0x484
+#define WM5100_DAC_DIGITAL_VOLUME_3R 0x485
+#define WM5100_DAC_DIGITAL_VOLUME_4L 0x486
+#define WM5100_DAC_DIGITAL_VOLUME_4R 0x487
+#define WM5100_DAC_DIGITAL_VOLUME_5L 0x488
+#define WM5100_DAC_DIGITAL_VOLUME_5R 0x489
+#define WM5100_DAC_DIGITAL_VOLUME_6L 0x48A
+#define WM5100_DAC_DIGITAL_VOLUME_6R 0x48B
+#define WM5100_PDM_SPK1_CTRL_1 0x4C0
+#define WM5100_PDM_SPK1_CTRL_2 0x4C1
+#define WM5100_PDM_SPK2_CTRL_1 0x4C2
+#define WM5100_PDM_SPK2_CTRL_2 0x4C3
+#define WM5100_AUDIO_IF_1_1 0x500
+#define WM5100_AUDIO_IF_1_2 0x501
+#define WM5100_AUDIO_IF_1_3 0x502
+#define WM5100_AUDIO_IF_1_4 0x503
+#define WM5100_AUDIO_IF_1_5 0x504
+#define WM5100_AUDIO_IF_1_6 0x505
+#define WM5100_AUDIO_IF_1_7 0x506
+#define WM5100_AUDIO_IF_1_8 0x507
+#define WM5100_AUDIO_IF_1_9 0x508
+#define WM5100_AUDIO_IF_1_10 0x509
+#define WM5100_AUDIO_IF_1_11 0x50A
+#define WM5100_AUDIO_IF_1_12 0x50B
+#define WM5100_AUDIO_IF_1_13 0x50C
+#define WM5100_AUDIO_IF_1_14 0x50D
+#define WM5100_AUDIO_IF_1_15 0x50E
+#define WM5100_AUDIO_IF_1_16 0x50F
+#define WM5100_AUDIO_IF_1_17 0x510
+#define WM5100_AUDIO_IF_1_18 0x511
+#define WM5100_AUDIO_IF_1_19 0x512
+#define WM5100_AUDIO_IF_1_20 0x513
+#define WM5100_AUDIO_IF_1_21 0x514
+#define WM5100_AUDIO_IF_1_22 0x515
+#define WM5100_AUDIO_IF_1_23 0x516
+#define WM5100_AUDIO_IF_1_24 0x517
+#define WM5100_AUDIO_IF_1_25 0x518
+#define WM5100_AUDIO_IF_1_26 0x519
+#define WM5100_AUDIO_IF_1_27 0x51A
+#define WM5100_AUDIO_IF_2_1 0x540
+#define WM5100_AUDIO_IF_2_2 0x541
+#define WM5100_AUDIO_IF_2_3 0x542
+#define WM5100_AUDIO_IF_2_4 0x543
+#define WM5100_AUDIO_IF_2_5 0x544
+#define WM5100_AUDIO_IF_2_6 0x545
+#define WM5100_AUDIO_IF_2_7 0x546
+#define WM5100_AUDIO_IF_2_8 0x547
+#define WM5100_AUDIO_IF_2_9 0x548
+#define WM5100_AUDIO_IF_2_10 0x549
+#define WM5100_AUDIO_IF_2_11 0x54A
+#define WM5100_AUDIO_IF_2_18 0x551
+#define WM5100_AUDIO_IF_2_19 0x552
+#define WM5100_AUDIO_IF_2_26 0x559
+#define WM5100_AUDIO_IF_2_27 0x55A
+#define WM5100_AUDIO_IF_3_1 0x580
+#define WM5100_AUDIO_IF_3_2 0x581
+#define WM5100_AUDIO_IF_3_3 0x582
+#define WM5100_AUDIO_IF_3_4 0x583
+#define WM5100_AUDIO_IF_3_5 0x584
+#define WM5100_AUDIO_IF_3_6 0x585
+#define WM5100_AUDIO_IF_3_7 0x586
+#define WM5100_AUDIO_IF_3_8 0x587
+#define WM5100_AUDIO_IF_3_9 0x588
+#define WM5100_AUDIO_IF_3_10 0x589
+#define WM5100_AUDIO_IF_3_11 0x58A
+#define WM5100_AUDIO_IF_3_18 0x591
+#define WM5100_AUDIO_IF_3_19 0x592
+#define WM5100_AUDIO_IF_3_26 0x599
+#define WM5100_AUDIO_IF_3_27 0x59A
+#define WM5100_PWM1MIX_INPUT_1_SOURCE 0x640
+#define WM5100_PWM1MIX_INPUT_1_VOLUME 0x641
+#define WM5100_PWM1MIX_INPUT_2_SOURCE 0x642
+#define WM5100_PWM1MIX_INPUT_2_VOLUME 0x643
+#define WM5100_PWM1MIX_INPUT_3_SOURCE 0x644
+#define WM5100_PWM1MIX_INPUT_3_VOLUME 0x645
+#define WM5100_PWM1MIX_INPUT_4_SOURCE 0x646
+#define WM5100_PWM1MIX_INPUT_4_VOLUME 0x647
+#define WM5100_PWM2MIX_INPUT_1_SOURCE 0x648
+#define WM5100_PWM2MIX_INPUT_1_VOLUME 0x649
+#define WM5100_PWM2MIX_INPUT_2_SOURCE 0x64A
+#define WM5100_PWM2MIX_INPUT_2_VOLUME 0x64B
+#define WM5100_PWM2MIX_INPUT_3_SOURCE 0x64C
+#define WM5100_PWM2MIX_INPUT_3_VOLUME 0x64D
+#define WM5100_PWM2MIX_INPUT_4_SOURCE 0x64E
+#define WM5100_PWM2MIX_INPUT_4_VOLUME 0x64F
+#define WM5100_OUT1LMIX_INPUT_1_SOURCE 0x680
+#define WM5100_OUT1LMIX_INPUT_1_VOLUME 0x681
+#define WM5100_OUT1LMIX_INPUT_2_SOURCE 0x682
+#define WM5100_OUT1LMIX_INPUT_2_VOLUME 0x683
+#define WM5100_OUT1LMIX_INPUT_3_SOURCE 0x684
+#define WM5100_OUT1LMIX_INPUT_3_VOLUME 0x685
+#define WM5100_OUT1LMIX_INPUT_4_SOURCE 0x686
+#define WM5100_OUT1LMIX_INPUT_4_VOLUME 0x687
+#define WM5100_OUT1RMIX_INPUT_1_SOURCE 0x688
+#define WM5100_OUT1RMIX_INPUT_1_VOLUME 0x689
+#define WM5100_OUT1RMIX_INPUT_2_SOURCE 0x68A
+#define WM5100_OUT1RMIX_INPUT_2_VOLUME 0x68B
+#define WM5100_OUT1RMIX_INPUT_3_SOURCE 0x68C
+#define WM5100_OUT1RMIX_INPUT_3_VOLUME 0x68D
+#define WM5100_OUT1RMIX_INPUT_4_SOURCE 0x68E
+#define WM5100_OUT1RMIX_INPUT_4_VOLUME 0x68F
+#define WM5100_OUT2LMIX_INPUT_1_SOURCE 0x690
+#define WM5100_OUT2LMIX_INPUT_1_VOLUME 0x691
+#define WM5100_OUT2LMIX_INPUT_2_SOURCE 0x692
+#define WM5100_OUT2LMIX_INPUT_2_VOLUME 0x693
+#define WM5100_OUT2LMIX_INPUT_3_SOURCE 0x694
+#define WM5100_OUT2LMIX_INPUT_3_VOLUME 0x695
+#define WM5100_OUT2LMIX_INPUT_4_SOURCE 0x696
+#define WM5100_OUT2LMIX_INPUT_4_VOLUME 0x697
+#define WM5100_OUT2RMIX_INPUT_1_SOURCE 0x698
+#define WM5100_OUT2RMIX_INPUT_1_VOLUME 0x699
+#define WM5100_OUT2RMIX_INPUT_2_SOURCE 0x69A
+#define WM5100_OUT2RMIX_INPUT_2_VOLUME 0x69B
+#define WM5100_OUT2RMIX_INPUT_3_SOURCE 0x69C
+#define WM5100_OUT2RMIX_INPUT_3_VOLUME 0x69D
+#define WM5100_OUT2RMIX_INPUT_4_SOURCE 0x69E
+#define WM5100_OUT2RMIX_INPUT_4_VOLUME 0x69F
+#define WM5100_OUT3LMIX_INPUT_1_SOURCE 0x6A0
+#define WM5100_OUT3LMIX_INPUT_1_VOLUME 0x6A1
+#define WM5100_OUT3LMIX_INPUT_2_SOURCE 0x6A2
+#define WM5100_OUT3LMIX_INPUT_2_VOLUME 0x6A3
+#define WM5100_OUT3LMIX_INPUT_3_SOURCE 0x6A4
+#define WM5100_OUT3LMIX_INPUT_3_VOLUME 0x6A5
+#define WM5100_OUT3LMIX_INPUT_4_SOURCE 0x6A6
+#define WM5100_OUT3LMIX_INPUT_4_VOLUME 0x6A7
+#define WM5100_OUT3RMIX_INPUT_1_SOURCE 0x6A8
+#define WM5100_OUT3RMIX_INPUT_1_VOLUME 0x6A9
+#define WM5100_OUT3RMIX_INPUT_2_SOURCE 0x6AA
+#define WM5100_OUT3RMIX_INPUT_2_VOLUME 0x6AB
+#define WM5100_OUT3RMIX_INPUT_3_SOURCE 0x6AC
+#define WM5100_OUT3RMIX_INPUT_3_VOLUME 0x6AD
+#define WM5100_OUT3RMIX_INPUT_4_SOURCE 0x6AE
+#define WM5100_OUT3RMIX_INPUT_4_VOLUME 0x6AF
+#define WM5100_OUT4LMIX_INPUT_1_SOURCE 0x6B0
+#define WM5100_OUT4LMIX_INPUT_1_VOLUME 0x6B1
+#define WM5100_OUT4LMIX_INPUT_2_SOURCE 0x6B2
+#define WM5100_OUT4LMIX_INPUT_2_VOLUME 0x6B3
+#define WM5100_OUT4LMIX_INPUT_3_SOURCE 0x6B4
+#define WM5100_OUT4LMIX_INPUT_3_VOLUME 0x6B5
+#define WM5100_OUT4LMIX_INPUT_4_SOURCE 0x6B6
+#define WM5100_OUT4LMIX_INPUT_4_VOLUME 0x6B7
+#define WM5100_OUT4RMIX_INPUT_1_SOURCE 0x6B8
+#define WM5100_OUT4RMIX_INPUT_1_VOLUME 0x6B9
+#define WM5100_OUT4RMIX_INPUT_2_SOURCE 0x6BA
+#define WM5100_OUT4RMIX_INPUT_2_VOLUME 0x6BB
+#define WM5100_OUT4RMIX_INPUT_3_SOURCE 0x6BC
+#define WM5100_OUT4RMIX_INPUT_3_VOLUME 0x6BD
+#define WM5100_OUT4RMIX_INPUT_4_SOURCE 0x6BE
+#define WM5100_OUT4RMIX_INPUT_4_VOLUME 0x6BF
+#define WM5100_OUT5LMIX_INPUT_1_SOURCE 0x6C0
+#define WM5100_OUT5LMIX_INPUT_1_VOLUME 0x6C1
+#define WM5100_OUT5LMIX_INPUT_2_SOURCE 0x6C2
+#define WM5100_OUT5LMIX_INPUT_2_VOLUME 0x6C3
+#define WM5100_OUT5LMIX_INPUT_3_SOURCE 0x6C4
+#define WM5100_OUT5LMIX_INPUT_3_VOLUME 0x6C5
+#define WM5100_OUT5LMIX_INPUT_4_SOURCE 0x6C6
+#define WM5100_OUT5LMIX_INPUT_4_VOLUME 0x6C7
+#define WM5100_OUT5RMIX_INPUT_1_SOURCE 0x6C8
+#define WM5100_OUT5RMIX_INPUT_1_VOLUME 0x6C9
+#define WM5100_OUT5RMIX_INPUT_2_SOURCE 0x6CA
+#define WM5100_OUT5RMIX_INPUT_2_VOLUME 0x6CB
+#define WM5100_OUT5RMIX_INPUT_3_SOURCE 0x6CC
+#define WM5100_OUT5RMIX_INPUT_3_VOLUME 0x6CD
+#define WM5100_OUT5RMIX_INPUT_4_SOURCE 0x6CE
+#define WM5100_OUT5RMIX_INPUT_4_VOLUME 0x6CF
+#define WM5100_OUT6LMIX_INPUT_1_SOURCE 0x6D0
+#define WM5100_OUT6LMIX_INPUT_1_VOLUME 0x6D1
+#define WM5100_OUT6LMIX_INPUT_2_SOURCE 0x6D2
+#define WM5100_OUT6LMIX_INPUT_2_VOLUME 0x6D3
+#define WM5100_OUT6LMIX_INPUT_3_SOURCE 0x6D4
+#define WM5100_OUT6LMIX_INPUT_3_VOLUME 0x6D5
+#define WM5100_OUT6LMIX_INPUT_4_SOURCE 0x6D6
+#define WM5100_OUT6LMIX_INPUT_4_VOLUME 0x6D7
+#define WM5100_OUT6RMIX_INPUT_1_SOURCE 0x6D8
+#define WM5100_OUT6RMIX_INPUT_1_VOLUME 0x6D9
+#define WM5100_OUT6RMIX_INPUT_2_SOURCE 0x6DA
+#define WM5100_OUT6RMIX_INPUT_2_VOLUME 0x6DB
+#define WM5100_OUT6RMIX_INPUT_3_SOURCE 0x6DC
+#define WM5100_OUT6RMIX_INPUT_3_VOLUME 0x6DD
+#define WM5100_OUT6RMIX_INPUT_4_SOURCE 0x6DE
+#define WM5100_OUT6RMIX_INPUT_4_VOLUME 0x6DF
+#define WM5100_AIF1TX1MIX_INPUT_1_SOURCE 0x700
+#define WM5100_AIF1TX1MIX_INPUT_1_VOLUME 0x701
+#define WM5100_AIF1TX1MIX_INPUT_2_SOURCE 0x702
+#define WM5100_AIF1TX1MIX_INPUT_2_VOLUME 0x703
+#define WM5100_AIF1TX1MIX_INPUT_3_SOURCE 0x704
+#define WM5100_AIF1TX1MIX_INPUT_3_VOLUME 0x705
+#define WM5100_AIF1TX1MIX_INPUT_4_SOURCE 0x706
+#define WM5100_AIF1TX1MIX_INPUT_4_VOLUME 0x707
+#define WM5100_AIF1TX2MIX_INPUT_1_SOURCE 0x708
+#define WM5100_AIF1TX2MIX_INPUT_1_VOLUME 0x709
+#define WM5100_AIF1TX2MIX_INPUT_2_SOURCE 0x70A
+#define WM5100_AIF1TX2MIX_INPUT_2_VOLUME 0x70B
+#define WM5100_AIF1TX2MIX_INPUT_3_SOURCE 0x70C
+#define WM5100_AIF1TX2MIX_INPUT_3_VOLUME 0x70D
+#define WM5100_AIF1TX2MIX_INPUT_4_SOURCE 0x70E
+#define WM5100_AIF1TX2MIX_INPUT_4_VOLUME 0x70F
+#define WM5100_AIF1TX3MIX_INPUT_1_SOURCE 0x710
+#define WM5100_AIF1TX3MIX_INPUT_1_VOLUME 0x711
+#define WM5100_AIF1TX3MIX_INPUT_2_SOURCE 0x712
+#define WM5100_AIF1TX3MIX_INPUT_2_VOLUME 0x713
+#define WM5100_AIF1TX3MIX_INPUT_3_SOURCE 0x714
+#define WM5100_AIF1TX3MIX_INPUT_3_VOLUME 0x715
+#define WM5100_AIF1TX3MIX_INPUT_4_SOURCE 0x716
+#define WM5100_AIF1TX3MIX_INPUT_4_VOLUME 0x717
+#define WM5100_AIF1TX4MIX_INPUT_1_SOURCE 0x718
+#define WM5100_AIF1TX4MIX_INPUT_1_VOLUME 0x719
+#define WM5100_AIF1TX4MIX_INPUT_2_SOURCE 0x71A
+#define WM5100_AIF1TX4MIX_INPUT_2_VOLUME 0x71B
+#define WM5100_AIF1TX4MIX_INPUT_3_SOURCE 0x71C
+#define WM5100_AIF1TX4MIX_INPUT_3_VOLUME 0x71D
+#define WM5100_AIF1TX4MIX_INPUT_4_SOURCE 0x71E
+#define WM5100_AIF1TX4MIX_INPUT_4_VOLUME 0x71F
+#define WM5100_AIF1TX5MIX_INPUT_1_SOURCE 0x720
+#define WM5100_AIF1TX5MIX_INPUT_1_VOLUME 0x721
+#define WM5100_AIF1TX5MIX_INPUT_2_SOURCE 0x722
+#define WM5100_AIF1TX5MIX_INPUT_2_VOLUME 0x723
+#define WM5100_AIF1TX5MIX_INPUT_3_SOURCE 0x724
+#define WM5100_AIF1TX5MIX_INPUT_3_VOLUME 0x725
+#define WM5100_AIF1TX5MIX_INPUT_4_SOURCE 0x726
+#define WM5100_AIF1TX5MIX_INPUT_4_VOLUME 0x727
+#define WM5100_AIF1TX6MIX_INPUT_1_SOURCE 0x728
+#define WM5100_AIF1TX6MIX_INPUT_1_VOLUME 0x729
+#define WM5100_AIF1TX6MIX_INPUT_2_SOURCE 0x72A
+#define WM5100_AIF1TX6MIX_INPUT_2_VOLUME 0x72B
+#define WM5100_AIF1TX6MIX_INPUT_3_SOURCE 0x72C
+#define WM5100_AIF1TX6MIX_INPUT_3_VOLUME 0x72D
+#define WM5100_AIF1TX6MIX_INPUT_4_SOURCE 0x72E
+#define WM5100_AIF1TX6MIX_INPUT_4_VOLUME 0x72F
+#define WM5100_AIF1TX7MIX_INPUT_1_SOURCE 0x730
+#define WM5100_AIF1TX7MIX_INPUT_1_VOLUME 0x731
+#define WM5100_AIF1TX7MIX_INPUT_2_SOURCE 0x732
+#define WM5100_AIF1TX7MIX_INPUT_2_VOLUME 0x733
+#define WM5100_AIF1TX7MIX_INPUT_3_SOURCE 0x734
+#define WM5100_AIF1TX7MIX_INPUT_3_VOLUME 0x735
+#define WM5100_AIF1TX7MIX_INPUT_4_SOURCE 0x736
+#define WM5100_AIF1TX7MIX_INPUT_4_VOLUME 0x737
+#define WM5100_AIF1TX8MIX_INPUT_1_SOURCE 0x738
+#define WM5100_AIF1TX8MIX_INPUT_1_VOLUME 0x739
+#define WM5100_AIF1TX8MIX_INPUT_2_SOURCE 0x73A
+#define WM5100_AIF1TX8MIX_INPUT_2_VOLUME 0x73B
+#define WM5100_AIF1TX8MIX_INPUT_3_SOURCE 0x73C
+#define WM5100_AIF1TX8MIX_INPUT_3_VOLUME 0x73D
+#define WM5100_AIF1TX8MIX_INPUT_4_SOURCE 0x73E
+#define WM5100_AIF1TX8MIX_INPUT_4_VOLUME 0x73F
+#define WM5100_AIF2TX1MIX_INPUT_1_SOURCE 0x740
+#define WM5100_AIF2TX1MIX_INPUT_1_VOLUME 0x741
+#define WM5100_AIF2TX1MIX_INPUT_2_SOURCE 0x742
+#define WM5100_AIF2TX1MIX_INPUT_2_VOLUME 0x743
+#define WM5100_AIF2TX1MIX_INPUT_3_SOURCE 0x744
+#define WM5100_AIF2TX1MIX_INPUT_3_VOLUME 0x745
+#define WM5100_AIF2TX1MIX_INPUT_4_SOURCE 0x746
+#define WM5100_AIF2TX1MIX_INPUT_4_VOLUME 0x747
+#define WM5100_AIF2TX2MIX_INPUT_1_SOURCE 0x748
+#define WM5100_AIF2TX2MIX_INPUT_1_VOLUME 0x749
+#define WM5100_AIF2TX2MIX_INPUT_2_SOURCE 0x74A
+#define WM5100_AIF2TX2MIX_INPUT_2_VOLUME 0x74B
+#define WM5100_AIF2TX2MIX_INPUT_3_SOURCE 0x74C
+#define WM5100_AIF2TX2MIX_INPUT_3_VOLUME 0x74D
+#define WM5100_AIF2TX2MIX_INPUT_4_SOURCE 0x74E
+#define WM5100_AIF2TX2MIX_INPUT_4_VOLUME 0x74F
+#define WM5100_AIF3TX1MIX_INPUT_1_SOURCE 0x780
+#define WM5100_AIF3TX1MIX_INPUT_1_VOLUME 0x781
+#define WM5100_AIF3TX1MIX_INPUT_2_SOURCE 0x782
+#define WM5100_AIF3TX1MIX_INPUT_2_VOLUME 0x783
+#define WM5100_AIF3TX1MIX_INPUT_3_SOURCE 0x784
+#define WM5100_AIF3TX1MIX_INPUT_3_VOLUME 0x785
+#define WM5100_AIF3TX1MIX_INPUT_4_SOURCE 0x786
+#define WM5100_AIF3TX1MIX_INPUT_4_VOLUME 0x787
+#define WM5100_AIF3TX2MIX_INPUT_1_SOURCE 0x788
+#define WM5100_AIF3TX2MIX_INPUT_1_VOLUME 0x789
+#define WM5100_AIF3TX2MIX_INPUT_2_SOURCE 0x78A
+#define WM5100_AIF3TX2MIX_INPUT_2_VOLUME 0x78B
+#define WM5100_AIF3TX2MIX_INPUT_3_SOURCE 0x78C
+#define WM5100_AIF3TX2MIX_INPUT_3_VOLUME 0x78D
+#define WM5100_AIF3TX2MIX_INPUT_4_SOURCE 0x78E
+#define WM5100_AIF3TX2MIX_INPUT_4_VOLUME 0x78F
+#define WM5100_EQ1MIX_INPUT_1_SOURCE 0x880
+#define WM5100_EQ1MIX_INPUT_1_VOLUME 0x881
+#define WM5100_EQ1MIX_INPUT_2_SOURCE 0x882
+#define WM5100_EQ1MIX_INPUT_2_VOLUME 0x883
+#define WM5100_EQ1MIX_INPUT_3_SOURCE 0x884
+#define WM5100_EQ1MIX_INPUT_3_VOLUME 0x885
+#define WM5100_EQ1MIX_INPUT_4_SOURCE 0x886
+#define WM5100_EQ1MIX_INPUT_4_VOLUME 0x887
+#define WM5100_EQ2MIX_INPUT_1_SOURCE 0x888
+#define WM5100_EQ2MIX_INPUT_1_VOLUME 0x889
+#define WM5100_EQ2MIX_INPUT_2_SOURCE 0x88A
+#define WM5100_EQ2MIX_INPUT_2_VOLUME 0x88B
+#define WM5100_EQ2MIX_INPUT_3_SOURCE 0x88C
+#define WM5100_EQ2MIX_INPUT_3_VOLUME 0x88D
+#define WM5100_EQ2MIX_INPUT_4_SOURCE 0x88E
+#define WM5100_EQ2MIX_INPUT_4_VOLUME 0x88F
+#define WM5100_EQ3MIX_INPUT_1_SOURCE 0x890
+#define WM5100_EQ3MIX_INPUT_1_VOLUME 0x891
+#define WM5100_EQ3MIX_INPUT_2_SOURCE 0x892
+#define WM5100_EQ3MIX_INPUT_2_VOLUME 0x893
+#define WM5100_EQ3MIX_INPUT_3_SOURCE 0x894
+#define WM5100_EQ3MIX_INPUT_3_VOLUME 0x895
+#define WM5100_EQ3MIX_INPUT_4_SOURCE 0x896
+#define WM5100_EQ3MIX_INPUT_4_VOLUME 0x897
+#define WM5100_EQ4MIX_INPUT_1_SOURCE 0x898
+#define WM5100_EQ4MIX_INPUT_1_VOLUME 0x899
+#define WM5100_EQ4MIX_INPUT_2_SOURCE 0x89A
+#define WM5100_EQ4MIX_INPUT_2_VOLUME 0x89B
+#define WM5100_EQ4MIX_INPUT_3_SOURCE 0x89C
+#define WM5100_EQ4MIX_INPUT_3_VOLUME 0x89D
+#define WM5100_EQ4MIX_INPUT_4_SOURCE 0x89E
+#define WM5100_EQ4MIX_INPUT_4_VOLUME 0x89F
+#define WM5100_DRC1LMIX_INPUT_1_SOURCE 0x8C0
+#define WM5100_DRC1LMIX_INPUT_1_VOLUME 0x8C1
+#define WM5100_DRC1LMIX_INPUT_2_SOURCE 0x8C2
+#define WM5100_DRC1LMIX_INPUT_2_VOLUME 0x8C3
+#define WM5100_DRC1LMIX_INPUT_3_SOURCE 0x8C4
+#define WM5100_DRC1LMIX_INPUT_3_VOLUME 0x8C5
+#define WM5100_DRC1LMIX_INPUT_4_SOURCE 0x8C6
+#define WM5100_DRC1LMIX_INPUT_4_VOLUME 0x8C7
+#define WM5100_DRC1RMIX_INPUT_1_SOURCE 0x8C8
+#define WM5100_DRC1RMIX_INPUT_1_VOLUME 0x8C9
+#define WM5100_DRC1RMIX_INPUT_2_SOURCE 0x8CA
+#define WM5100_DRC1RMIX_INPUT_2_VOLUME 0x8CB
+#define WM5100_DRC1RMIX_INPUT_3_SOURCE 0x8CC
+#define WM5100_DRC1RMIX_INPUT_3_VOLUME 0x8CD
+#define WM5100_DRC1RMIX_INPUT_4_SOURCE 0x8CE
+#define WM5100_DRC1RMIX_INPUT_4_VOLUME 0x8CF
+#define WM5100_HPLP1MIX_INPUT_1_SOURCE 0x900
+#define WM5100_HPLP1MIX_INPUT_1_VOLUME 0x901
+#define WM5100_HPLP1MIX_INPUT_2_SOURCE 0x902
+#define WM5100_HPLP1MIX_INPUT_2_VOLUME 0x903
+#define WM5100_HPLP1MIX_INPUT_3_SOURCE 0x904
+#define WM5100_HPLP1MIX_INPUT_3_VOLUME 0x905
+#define WM5100_HPLP1MIX_INPUT_4_SOURCE 0x906
+#define WM5100_HPLP1MIX_INPUT_4_VOLUME 0x907
+#define WM5100_HPLP2MIX_INPUT_1_SOURCE 0x908
+#define WM5100_HPLP2MIX_INPUT_1_VOLUME 0x909
+#define WM5100_HPLP2MIX_INPUT_2_SOURCE 0x90A
+#define WM5100_HPLP2MIX_INPUT_2_VOLUME 0x90B
+#define WM5100_HPLP2MIX_INPUT_3_SOURCE 0x90C
+#define WM5100_HPLP2MIX_INPUT_3_VOLUME 0x90D
+#define WM5100_HPLP2MIX_INPUT_4_SOURCE 0x90E
+#define WM5100_HPLP2MIX_INPUT_4_VOLUME 0x90F
+#define WM5100_HPLP3MIX_INPUT_1_SOURCE 0x910
+#define WM5100_HPLP3MIX_INPUT_1_VOLUME 0x911
+#define WM5100_HPLP3MIX_INPUT_2_SOURCE 0x912
+#define WM5100_HPLP3MIX_INPUT_2_VOLUME 0x913
+#define WM5100_HPLP3MIX_INPUT_3_SOURCE 0x914
+#define WM5100_HPLP3MIX_INPUT_3_VOLUME 0x915
+#define WM5100_HPLP3MIX_INPUT_4_SOURCE 0x916
+#define WM5100_HPLP3MIX_INPUT_4_VOLUME 0x917
+#define WM5100_HPLP4MIX_INPUT_1_SOURCE 0x918
+#define WM5100_HPLP4MIX_INPUT_1_VOLUME 0x919
+#define WM5100_HPLP4MIX_INPUT_2_SOURCE 0x91A
+#define WM5100_HPLP4MIX_INPUT_2_VOLUME 0x91B
+#define WM5100_HPLP4MIX_INPUT_3_SOURCE 0x91C
+#define WM5100_HPLP4MIX_INPUT_3_VOLUME 0x91D
+#define WM5100_HPLP4MIX_INPUT_4_SOURCE 0x91E
+#define WM5100_HPLP4MIX_INPUT_4_VOLUME 0x91F
+#define WM5100_DSP1LMIX_INPUT_1_SOURCE 0x940
+#define WM5100_DSP1LMIX_INPUT_1_VOLUME 0x941
+#define WM5100_DSP1LMIX_INPUT_2_SOURCE 0x942
+#define WM5100_DSP1LMIX_INPUT_2_VOLUME 0x943
+#define WM5100_DSP1LMIX_INPUT_3_SOURCE 0x944
+#define WM5100_DSP1LMIX_INPUT_3_VOLUME 0x945
+#define WM5100_DSP1LMIX_INPUT_4_SOURCE 0x946
+#define WM5100_DSP1LMIX_INPUT_4_VOLUME 0x947
+#define WM5100_DSP1RMIX_INPUT_1_SOURCE 0x948
+#define WM5100_DSP1RMIX_INPUT_1_VOLUME 0x949
+#define WM5100_DSP1RMIX_INPUT_2_SOURCE 0x94A
+#define WM5100_DSP1RMIX_INPUT_2_VOLUME 0x94B
+#define WM5100_DSP1RMIX_INPUT_3_SOURCE 0x94C
+#define WM5100_DSP1RMIX_INPUT_3_VOLUME 0x94D
+#define WM5100_DSP1RMIX_INPUT_4_SOURCE 0x94E
+#define WM5100_DSP1RMIX_INPUT_4_VOLUME 0x94F
+#define WM5100_DSP1AUX1MIX_INPUT_1_SOURCE 0x950
+#define WM5100_DSP1AUX2MIX_INPUT_1_SOURCE 0x958
+#define WM5100_DSP1AUX3MIX_INPUT_1_SOURCE 0x960
+#define WM5100_DSP1AUX4MIX_INPUT_1_SOURCE 0x968
+#define WM5100_DSP1AUX5MIX_INPUT_1_SOURCE 0x970
+#define WM5100_DSP1AUX6MIX_INPUT_1_SOURCE 0x978
+#define WM5100_DSP2LMIX_INPUT_1_SOURCE 0x980
+#define WM5100_DSP2LMIX_INPUT_1_VOLUME 0x981
+#define WM5100_DSP2LMIX_INPUT_2_SOURCE 0x982
+#define WM5100_DSP2LMIX_INPUT_2_VOLUME 0x983
+#define WM5100_DSP2LMIX_INPUT_3_SOURCE 0x984
+#define WM5100_DSP2LMIX_INPUT_3_VOLUME 0x985
+#define WM5100_DSP2LMIX_INPUT_4_SOURCE 0x986
+#define WM5100_DSP2LMIX_INPUT_4_VOLUME 0x987
+#define WM5100_DSP2RMIX_INPUT_1_SOURCE 0x988
+#define WM5100_DSP2RMIX_INPUT_1_VOLUME 0x989
+#define WM5100_DSP2RMIX_INPUT_2_SOURCE 0x98A
+#define WM5100_DSP2RMIX_INPUT_2_VOLUME 0x98B
+#define WM5100_DSP2RMIX_INPUT_3_SOURCE 0x98C
+#define WM5100_DSP2RMIX_INPUT_3_VOLUME 0x98D
+#define WM5100_DSP2RMIX_INPUT_4_SOURCE 0x98E
+#define WM5100_DSP2RMIX_INPUT_4_VOLUME 0x98F
+#define WM5100_DSP2AUX1MIX_INPUT_1_SOURCE 0x990
+#define WM5100_DSP2AUX2MIX_INPUT_1_SOURCE 0x998
+#define WM5100_DSP2AUX3MIX_INPUT_1_SOURCE 0x9A0
+#define WM5100_DSP2AUX4MIX_INPUT_1_SOURCE 0x9A8
+#define WM5100_DSP2AUX5MIX_INPUT_1_SOURCE 0x9B0
+#define WM5100_DSP2AUX6MIX_INPUT_1_SOURCE 0x9B8
+#define WM5100_DSP3LMIX_INPUT_1_SOURCE 0x9C0
+#define WM5100_DSP3LMIX_INPUT_1_VOLUME 0x9C1
+#define WM5100_DSP3LMIX_INPUT_2_SOURCE 0x9C2
+#define WM5100_DSP3LMIX_INPUT_2_VOLUME 0x9C3
+#define WM5100_DSP3LMIX_INPUT_3_SOURCE 0x9C4
+#define WM5100_DSP3LMIX_INPUT_3_VOLUME 0x9C5
+#define WM5100_DSP3LMIX_INPUT_4_SOURCE 0x9C6
+#define WM5100_DSP3LMIX_INPUT_4_VOLUME 0x9C7
+#define WM5100_DSP3RMIX_INPUT_1_SOURCE 0x9C8
+#define WM5100_DSP3RMIX_INPUT_1_VOLUME 0x9C9
+#define WM5100_DSP3RMIX_INPUT_2_SOURCE 0x9CA
+#define WM5100_DSP3RMIX_INPUT_2_VOLUME 0x9CB
+#define WM5100_DSP3RMIX_INPUT_3_SOURCE 0x9CC
+#define WM5100_DSP3RMIX_INPUT_3_VOLUME 0x9CD
+#define WM5100_DSP3RMIX_INPUT_4_SOURCE 0x9CE
+#define WM5100_DSP3RMIX_INPUT_4_VOLUME 0x9CF
+#define WM5100_DSP3AUX1MIX_INPUT_1_SOURCE 0x9D0
+#define WM5100_DSP3AUX2MIX_INPUT_1_SOURCE 0x9D8
+#define WM5100_DSP3AUX3MIX_INPUT_1_SOURCE 0x9E0
+#define WM5100_DSP3AUX4MIX_INPUT_1_SOURCE 0x9E8
+#define WM5100_DSP3AUX5MIX_INPUT_1_SOURCE 0x9F0
+#define WM5100_DSP3AUX6MIX_INPUT_1_SOURCE 0x9F8
+#define WM5100_ASRC1LMIX_INPUT_1_SOURCE 0xA80
+#define WM5100_ASRC1RMIX_INPUT_1_SOURCE 0xA88
+#define WM5100_ASRC2LMIX_INPUT_1_SOURCE 0xA90
+#define WM5100_ASRC2RMIX_INPUT_1_SOURCE 0xA98
+#define WM5100_ISRC1DEC1MIX_INPUT_1_SOURCE 0xB00
+#define WM5100_ISRC1DEC2MIX_INPUT_1_SOURCE 0xB08
+#define WM5100_ISRC1DEC3MIX_INPUT_1_SOURCE 0xB10
+#define WM5100_ISRC1DEC4MIX_INPUT_1_SOURCE 0xB18
+#define WM5100_ISRC1INT1MIX_INPUT_1_SOURCE 0xB20
+#define WM5100_ISRC1INT2MIX_INPUT_1_SOURCE 0xB28
+#define WM5100_ISRC1INT3MIX_INPUT_1_SOURCE 0xB30
+#define WM5100_ISRC1INT4MIX_INPUT_1_SOURCE 0xB38
+#define WM5100_ISRC2DEC1MIX_INPUT_1_SOURCE 0xB40
+#define WM5100_ISRC2DEC2MIX_INPUT_1_SOURCE 0xB48
+#define WM5100_ISRC2DEC3MIX_INPUT_1_SOURCE 0xB50
+#define WM5100_ISRC2DEC4MIX_INPUT_1_SOURCE 0xB58
+#define WM5100_ISRC2INT1MIX_INPUT_1_SOURCE 0xB60
+#define WM5100_ISRC2INT2MIX_INPUT_1_SOURCE 0xB68
+#define WM5100_ISRC2INT3MIX_INPUT_1_SOURCE 0xB70
+#define WM5100_ISRC2INT4MIX_INPUT_1_SOURCE 0xB78
+#define WM5100_GPIO_CTRL_1 0xC00
+#define WM5100_GPIO_CTRL_2 0xC01
+#define WM5100_GPIO_CTRL_3 0xC02
+#define WM5100_GPIO_CTRL_4 0xC03
+#define WM5100_GPIO_CTRL_5 0xC04
+#define WM5100_GPIO_CTRL_6 0xC05
+#define WM5100_MISC_PAD_CTRL_1 0xC23
+#define WM5100_MISC_PAD_CTRL_2 0xC24
+#define WM5100_MISC_PAD_CTRL_3 0xC25
+#define WM5100_MISC_PAD_CTRL_4 0xC26
+#define WM5100_MISC_PAD_CTRL_5 0xC27
+#define WM5100_MISC_GPIO_1 0xC28
+#define WM5100_INTERRUPT_STATUS_1 0xD00
+#define WM5100_INTERRUPT_STATUS_2 0xD01
+#define WM5100_INTERRUPT_STATUS_3 0xD02
+#define WM5100_INTERRUPT_STATUS_4 0xD03
+#define WM5100_INTERRUPT_RAW_STATUS_2 0xD04
+#define WM5100_INTERRUPT_RAW_STATUS_3 0xD05
+#define WM5100_INTERRUPT_RAW_STATUS_4 0xD06
+#define WM5100_INTERRUPT_STATUS_1_MASK 0xD07
+#define WM5100_INTERRUPT_STATUS_2_MASK 0xD08
+#define WM5100_INTERRUPT_STATUS_3_MASK 0xD09
+#define WM5100_INTERRUPT_STATUS_4_MASK 0xD0A
+#define WM5100_INTERRUPT_CONTROL 0xD1F
+#define WM5100_IRQ_DEBOUNCE_1 0xD20
+#define WM5100_IRQ_DEBOUNCE_2 0xD21
+#define WM5100_FX_CTRL 0xE00
+#define WM5100_EQ1_1 0xE10
+#define WM5100_EQ1_2 0xE11
+#define WM5100_EQ1_3 0xE12
+#define WM5100_EQ1_4 0xE13
+#define WM5100_EQ1_5 0xE14
+#define WM5100_EQ1_6 0xE15
+#define WM5100_EQ1_7 0xE16
+#define WM5100_EQ1_8 0xE17
+#define WM5100_EQ1_9 0xE18
+#define WM5100_EQ1_10 0xE19
+#define WM5100_EQ1_11 0xE1A
+#define WM5100_EQ1_12 0xE1B
+#define WM5100_EQ1_13 0xE1C
+#define WM5100_EQ1_14 0xE1D
+#define WM5100_EQ1_15 0xE1E
+#define WM5100_EQ1_16 0xE1F
+#define WM5100_EQ1_17 0xE20
+#define WM5100_EQ1_18 0xE21
+#define WM5100_EQ1_19 0xE22
+#define WM5100_EQ1_20 0xE23
+#define WM5100_EQ2_1 0xE26
+#define WM5100_EQ2_2 0xE27
+#define WM5100_EQ2_3 0xE28
+#define WM5100_EQ2_4 0xE29
+#define WM5100_EQ2_5 0xE2A
+#define WM5100_EQ2_6 0xE2B
+#define WM5100_EQ2_7 0xE2C
+#define WM5100_EQ2_8 0xE2D
+#define WM5100_EQ2_9 0xE2E
+#define WM5100_EQ2_10 0xE2F
+#define WM5100_EQ2_11 0xE30
+#define WM5100_EQ2_12 0xE31
+#define WM5100_EQ2_13 0xE32
+#define WM5100_EQ2_14 0xE33
+#define WM5100_EQ2_15 0xE34
+#define WM5100_EQ2_16 0xE35
+#define WM5100_EQ2_17 0xE36
+#define WM5100_EQ2_18 0xE37
+#define WM5100_EQ2_19 0xE38
+#define WM5100_EQ2_20 0xE39
+#define WM5100_EQ3_1 0xE3C
+#define WM5100_EQ3_2 0xE3D
+#define WM5100_EQ3_3 0xE3E
+#define WM5100_EQ3_4 0xE3F
+#define WM5100_EQ3_5 0xE40
+#define WM5100_EQ3_6 0xE41
+#define WM5100_EQ3_7 0xE42
+#define WM5100_EQ3_8 0xE43
+#define WM5100_EQ3_9 0xE44
+#define WM5100_EQ3_10 0xE45
+#define WM5100_EQ3_11 0xE46
+#define WM5100_EQ3_12 0xE47
+#define WM5100_EQ3_13 0xE48
+#define WM5100_EQ3_14 0xE49
+#define WM5100_EQ3_15 0xE4A
+#define WM5100_EQ3_16 0xE4B
+#define WM5100_EQ3_17 0xE4C
+#define WM5100_EQ3_18 0xE4D
+#define WM5100_EQ3_19 0xE4E
+#define WM5100_EQ3_20 0xE4F
+#define WM5100_EQ4_1 0xE52
+#define WM5100_EQ4_2 0xE53
+#define WM5100_EQ4_3 0xE54
+#define WM5100_EQ4_4 0xE55
+#define WM5100_EQ4_5 0xE56
+#define WM5100_EQ4_6 0xE57
+#define WM5100_EQ4_7 0xE58
+#define WM5100_EQ4_8 0xE59
+#define WM5100_EQ4_9 0xE5A
+#define WM5100_EQ4_10 0xE5B
+#define WM5100_EQ4_11 0xE5C
+#define WM5100_EQ4_12 0xE5D
+#define WM5100_EQ4_13 0xE5E
+#define WM5100_EQ4_14 0xE5F
+#define WM5100_EQ4_15 0xE60
+#define WM5100_EQ4_16 0xE61
+#define WM5100_EQ4_17 0xE62
+#define WM5100_EQ4_18 0xE63
+#define WM5100_EQ4_19 0xE64
+#define WM5100_EQ4_20 0xE65
+#define WM5100_DRC1_CTRL1 0xE80
+#define WM5100_DRC1_CTRL2 0xE81
+#define WM5100_DRC1_CTRL3 0xE82
+#define WM5100_DRC1_CTRL4 0xE83
+#define WM5100_DRC1_CTRL5 0xE84
+#define WM5100_HPLPF1_1 0xEC0
+#define WM5100_HPLPF1_2 0xEC1
+#define WM5100_HPLPF2_1 0xEC4
+#define WM5100_HPLPF2_2 0xEC5
+#define WM5100_HPLPF3_1 0xEC8
+#define WM5100_HPLPF3_2 0xEC9
+#define WM5100_HPLPF4_1 0xECC
+#define WM5100_HPLPF4_2 0xECD
+#define WM5100_DSP1_DM_0 0x4000
+#define WM5100_DSP1_DM_1 0x4001
+#define WM5100_DSP1_DM_2 0x4002
+#define WM5100_DSP1_DM_3 0x4003
+#define WM5100_DSP1_DM_508 0x41FC
+#define WM5100_DSP1_DM_509 0x41FD
+#define WM5100_DSP1_DM_510 0x41FE
+#define WM5100_DSP1_DM_511 0x41FF
+#define WM5100_DSP1_PM_0 0x4800
+#define WM5100_DSP1_PM_1 0x4801
+#define WM5100_DSP1_PM_2 0x4802
+#define WM5100_DSP1_PM_3 0x4803
+#define WM5100_DSP1_PM_4 0x4804
+#define WM5100_DSP1_PM_5 0x4805
+#define WM5100_DSP1_PM_1530 0x4DFA
+#define WM5100_DSP1_PM_1531 0x4DFB
+#define WM5100_DSP1_PM_1532 0x4DFC
+#define WM5100_DSP1_PM_1533 0x4DFD
+#define WM5100_DSP1_PM_1534 0x4DFE
+#define WM5100_DSP1_PM_1535 0x4DFF
+#define WM5100_DSP1_ZM_0 0x5000
+#define WM5100_DSP1_ZM_1 0x5001
+#define WM5100_DSP1_ZM_2 0x5002
+#define WM5100_DSP1_ZM_3 0x5003
+#define WM5100_DSP1_ZM_2044 0x57FC
+#define WM5100_DSP1_ZM_2045 0x57FD
+#define WM5100_DSP1_ZM_2046 0x57FE
+#define WM5100_DSP1_ZM_2047 0x57FF
+#define WM5100_DSP2_DM_0 0x6000
+#define WM5100_DSP2_DM_1 0x6001
+#define WM5100_DSP2_DM_2 0x6002
+#define WM5100_DSP2_DM_3 0x6003
+#define WM5100_DSP2_DM_508 0x61FC
+#define WM5100_DSP2_DM_509 0x61FD
+#define WM5100_DSP2_DM_510 0x61FE
+#define WM5100_DSP2_DM_511 0x61FF
+#define WM5100_DSP2_PM_0 0x6800
+#define WM5100_DSP2_PM_1 0x6801
+#define WM5100_DSP2_PM_2 0x6802
+#define WM5100_DSP2_PM_3 0x6803
+#define WM5100_DSP2_PM_4 0x6804
+#define WM5100_DSP2_PM_5 0x6805
+#define WM5100_DSP2_PM_1530 0x6DFA
+#define WM5100_DSP2_PM_1531 0x6DFB
+#define WM5100_DSP2_PM_1532 0x6DFC
+#define WM5100_DSP2_PM_1533 0x6DFD
+#define WM5100_DSP2_PM_1534 0x6DFE
+#define WM5100_DSP2_PM_1535 0x6DFF
+#define WM5100_DSP2_ZM_0 0x7000
+#define WM5100_DSP2_ZM_1 0x7001
+#define WM5100_DSP2_ZM_2 0x7002
+#define WM5100_DSP2_ZM_3 0x7003
+#define WM5100_DSP2_ZM_2044 0x77FC
+#define WM5100_DSP2_ZM_2045 0x77FD
+#define WM5100_DSP2_ZM_2046 0x77FE
+#define WM5100_DSP2_ZM_2047 0x77FF
+#define WM5100_DSP3_DM_0 0x8000
+#define WM5100_DSP3_DM_1 0x8001
+#define WM5100_DSP3_DM_2 0x8002
+#define WM5100_DSP3_DM_3 0x8003
+#define WM5100_DSP3_DM_508 0x81FC
+#define WM5100_DSP3_DM_509 0x81FD
+#define WM5100_DSP3_DM_510 0x81FE
+#define WM5100_DSP3_DM_511 0x81FF
+#define WM5100_DSP3_PM_0 0x8800
+#define WM5100_DSP3_PM_1 0x8801
+#define WM5100_DSP3_PM_2 0x8802
+#define WM5100_DSP3_PM_3 0x8803
+#define WM5100_DSP3_PM_4 0x8804
+#define WM5100_DSP3_PM_5 0x8805
+#define WM5100_DSP3_PM_1530 0x8DFA
+#define WM5100_DSP3_PM_1531 0x8DFB
+#define WM5100_DSP3_PM_1532 0x8DFC
+#define WM5100_DSP3_PM_1533 0x8DFD
+#define WM5100_DSP3_PM_1534 0x8DFE
+#define WM5100_DSP3_PM_1535 0x8DFF
+#define WM5100_DSP3_ZM_0 0x9000
+#define WM5100_DSP3_ZM_1 0x9001
+#define WM5100_DSP3_ZM_2 0x9002
+#define WM5100_DSP3_ZM_3 0x9003
+#define WM5100_DSP3_ZM_2044 0x97FC
+#define WM5100_DSP3_ZM_2045 0x97FD
+#define WM5100_DSP3_ZM_2046 0x97FE
+#define WM5100_DSP3_ZM_2047 0x97FF
+
+#define WM5100_REGISTER_COUNT 1435
+#define WM5100_MAX_REGISTER 0x97FF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - software reset
+ */
+#define WM5100_SW_RST_DEV_ID1_MASK 0xFFFF /* SW_RST_DEV_ID1 - [15:0] */
+#define WM5100_SW_RST_DEV_ID1_SHIFT 0 /* SW_RST_DEV_ID1 - [15:0] */
+#define WM5100_SW_RST_DEV_ID1_WIDTH 16 /* SW_RST_DEV_ID1 - [15:0] */
+
+/*
+ * R1 (0x01) - Device Revision
+ */
+#define WM5100_DEVICE_REVISION_MASK 0x000F /* DEVICE_REVISION - [3:0] */
+#define WM5100_DEVICE_REVISION_SHIFT 0 /* DEVICE_REVISION - [3:0] */
+#define WM5100_DEVICE_REVISION_WIDTH 4 /* DEVICE_REVISION - [3:0] */
+
+/*
+ * R16 (0x10) - Ctrl IF 1
+ */
+#define WM5100_AUTO_INC 0x0001 /* AUTO_INC */
+#define WM5100_AUTO_INC_MASK 0x0001 /* AUTO_INC */
+#define WM5100_AUTO_INC_SHIFT 0 /* AUTO_INC */
+#define WM5100_AUTO_INC_WIDTH 1 /* AUTO_INC */
+
+/*
+ * R32 (0x20) - Tone Generator 1
+ */
+#define WM5100_TONE_RATE_MASK 0x3000 /* TONE_RATE - [13:12] */
+#define WM5100_TONE_RATE_SHIFT 12 /* TONE_RATE - [13:12] */
+#define WM5100_TONE_RATE_WIDTH 2 /* TONE_RATE - [13:12] */
+#define WM5100_TONE_OFFSET_MASK 0x0300 /* TONE_OFFSET - [9:8] */
+#define WM5100_TONE_OFFSET_SHIFT 8 /* TONE_OFFSET - [9:8] */
+#define WM5100_TONE_OFFSET_WIDTH 2 /* TONE_OFFSET - [9:8] */
+#define WM5100_TONE2_ENA 0x0002 /* TONE2_ENA */
+#define WM5100_TONE2_ENA_MASK 0x0002 /* TONE2_ENA */
+#define WM5100_TONE2_ENA_SHIFT 1 /* TONE2_ENA */
+#define WM5100_TONE2_ENA_WIDTH 1 /* TONE2_ENA */
+#define WM5100_TONE1_ENA 0x0001 /* TONE1_ENA */
+#define WM5100_TONE1_ENA_MASK 0x0001 /* TONE1_ENA */
+#define WM5100_TONE1_ENA_SHIFT 0 /* TONE1_ENA */
+#define WM5100_TONE1_ENA_WIDTH 1 /* TONE1_ENA */
+
+/*
+ * R48 (0x30) - PWM Drive 1
+ */
+#define WM5100_PWM_RATE_MASK 0x3000 /* PWM_RATE - [13:12] */
+#define WM5100_PWM_RATE_SHIFT 12 /* PWM_RATE - [13:12] */
+#define WM5100_PWM_RATE_WIDTH 2 /* PWM_RATE - [13:12] */
+#define WM5100_PWM_CLK_SEL_MASK 0x0300 /* PWM_CLK_SEL - [9:8] */
+#define WM5100_PWM_CLK_SEL_SHIFT 8 /* PWM_CLK_SEL - [9:8] */
+#define WM5100_PWM_CLK_SEL_WIDTH 2 /* PWM_CLK_SEL - [9:8] */
+#define WM5100_PWM2_OVD 0x0020 /* PWM2_OVD */
+#define WM5100_PWM2_OVD_MASK 0x0020 /* PWM2_OVD */
+#define WM5100_PWM2_OVD_SHIFT 5 /* PWM2_OVD */
+#define WM5100_PWM2_OVD_WIDTH 1 /* PWM2_OVD */
+#define WM5100_PWM1_OVD 0x0010 /* PWM1_OVD */
+#define WM5100_PWM1_OVD_MASK 0x0010 /* PWM1_OVD */
+#define WM5100_PWM1_OVD_SHIFT 4 /* PWM1_OVD */
+#define WM5100_PWM1_OVD_WIDTH 1 /* PWM1_OVD */
+#define WM5100_PWM2_ENA 0x0002 /* PWM2_ENA */
+#define WM5100_PWM2_ENA_MASK 0x0002 /* PWM2_ENA */
+#define WM5100_PWM2_ENA_SHIFT 1 /* PWM2_ENA */
+#define WM5100_PWM2_ENA_WIDTH 1 /* PWM2_ENA */
+#define WM5100_PWM1_ENA 0x0001 /* PWM1_ENA */
+#define WM5100_PWM1_ENA_MASK 0x0001 /* PWM1_ENA */
+#define WM5100_PWM1_ENA_SHIFT 0 /* PWM1_ENA */
+#define WM5100_PWM1_ENA_WIDTH 1 /* PWM1_ENA */
+
+/*
+ * R49 (0x31) - PWM Drive 2
+ */
+#define WM5100_PWM1_LVL_MASK 0x03FF /* PWM1_LVL - [9:0] */
+#define WM5100_PWM1_LVL_SHIFT 0 /* PWM1_LVL - [9:0] */
+#define WM5100_PWM1_LVL_WIDTH 10 /* PWM1_LVL - [9:0] */
+
+/*
+ * R50 (0x32) - PWM Drive 3
+ */
+#define WM5100_PWM2_LVL_MASK 0x03FF /* PWM2_LVL - [9:0] */
+#define WM5100_PWM2_LVL_SHIFT 0 /* PWM2_LVL - [9:0] */
+#define WM5100_PWM2_LVL_WIDTH 10 /* PWM2_LVL - [9:0] */
+
+/*
+ * R256 (0x100) - Clocking 1
+ */
+#define WM5100_CLK_32K_SRC_MASK 0x000F /* CLK_32K_SRC - [3:0] */
+#define WM5100_CLK_32K_SRC_SHIFT 0 /* CLK_32K_SRC - [3:0] */
+#define WM5100_CLK_32K_SRC_WIDTH 4 /* CLK_32K_SRC - [3:0] */
+
+/*
+ * R257 (0x101) - Clocking 3
+ */
+#define WM5100_SYSCLK_FREQ_MASK 0x0700 /* SYSCLK_FREQ - [10:8] */
+#define WM5100_SYSCLK_FREQ_SHIFT 8 /* SYSCLK_FREQ - [10:8] */
+#define WM5100_SYSCLK_FREQ_WIDTH 3 /* SYSCLK_FREQ - [10:8] */
+#define WM5100_SYSCLK_ENA 0x0040 /* SYSCLK_ENA */
+#define WM5100_SYSCLK_ENA_MASK 0x0040 /* SYSCLK_ENA */
+#define WM5100_SYSCLK_ENA_SHIFT 6 /* SYSCLK_ENA */
+#define WM5100_SYSCLK_ENA_WIDTH 1 /* SYSCLK_ENA */
+#define WM5100_SYSCLK_SRC_MASK 0x000F /* SYSCLK_SRC - [3:0] */
+#define WM5100_SYSCLK_SRC_SHIFT 0 /* SYSCLK_SRC - [3:0] */
+#define WM5100_SYSCLK_SRC_WIDTH 4 /* SYSCLK_SRC - [3:0] */
+
+/*
+ * R258 (0x102) - Clocking 4
+ */
+#define WM5100_SAMPLE_RATE_1_MASK 0x001F /* SAMPLE_RATE_1 - [4:0] */
+#define WM5100_SAMPLE_RATE_1_SHIFT 0 /* SAMPLE_RATE_1 - [4:0] */
+#define WM5100_SAMPLE_RATE_1_WIDTH 5 /* SAMPLE_RATE_1 - [4:0] */
+
+/*
+ * R259 (0x103) - Clocking 5
+ */
+#define WM5100_SAMPLE_RATE_2_MASK 0x001F /* SAMPLE_RATE_2 - [4:0] */
+#define WM5100_SAMPLE_RATE_2_SHIFT 0 /* SAMPLE_RATE_2 - [4:0] */
+#define WM5100_SAMPLE_RATE_2_WIDTH 5 /* SAMPLE_RATE_2 - [4:0] */
+
+/*
+ * R260 (0x104) - Clocking 6
+ */
+#define WM5100_SAMPLE_RATE_3_MASK 0x001F /* SAMPLE_RATE_3 - [4:0] */
+#define WM5100_SAMPLE_RATE_3_SHIFT 0 /* SAMPLE_RATE_3 - [4:0] */
+#define WM5100_SAMPLE_RATE_3_WIDTH 5 /* SAMPLE_RATE_3 - [4:0] */
+
+/*
+ * R263 (0x107) - Clocking 7
+ */
+#define WM5100_ASYNC_CLK_FREQ_MASK 0x0700 /* ASYNC_CLK_FREQ - [10:8] */
+#define WM5100_ASYNC_CLK_FREQ_SHIFT 8 /* ASYNC_CLK_FREQ - [10:8] */
+#define WM5100_ASYNC_CLK_FREQ_WIDTH 3 /* ASYNC_CLK_FREQ - [10:8] */
+#define WM5100_ASYNC_CLK_ENA 0x0040 /* ASYNC_CLK_ENA */
+#define WM5100_ASYNC_CLK_ENA_MASK 0x0040 /* ASYNC_CLK_ENA */
+#define WM5100_ASYNC_CLK_ENA_SHIFT 6 /* ASYNC_CLK_ENA */
+#define WM5100_ASYNC_CLK_ENA_WIDTH 1 /* ASYNC_CLK_ENA */
+#define WM5100_ASYNC_CLK_SRC_MASK 0x000F /* ASYNC_CLK_SRC - [3:0] */
+#define WM5100_ASYNC_CLK_SRC_SHIFT 0 /* ASYNC_CLK_SRC - [3:0] */
+#define WM5100_ASYNC_CLK_SRC_WIDTH 4 /* ASYNC_CLK_SRC - [3:0] */
+
+/*
+ * R264 (0x108) - Clocking 8
+ */
+#define WM5100_ASYNC_SAMPLE_RATE_MASK 0x001F /* ASYNC_SAMPLE_RATE - [4:0] */
+#define WM5100_ASYNC_SAMPLE_RATE_SHIFT 0 /* ASYNC_SAMPLE_RATE - [4:0] */
+#define WM5100_ASYNC_SAMPLE_RATE_WIDTH 5 /* ASYNC_SAMPLE_RATE - [4:0] */
+
+/*
+ * R288 (0x120) - ASRC_ENABLE
+ */
+#define WM5100_ASRC2L_ENA 0x0008 /* ASRC2L_ENA */
+#define WM5100_ASRC2L_ENA_MASK 0x0008 /* ASRC2L_ENA */
+#define WM5100_ASRC2L_ENA_SHIFT 3 /* ASRC2L_ENA */
+#define WM5100_ASRC2L_ENA_WIDTH 1 /* ASRC2L_ENA */
+#define WM5100_ASRC2R_ENA 0x0004 /* ASRC2R_ENA */
+#define WM5100_ASRC2R_ENA_MASK 0x0004 /* ASRC2R_ENA */
+#define WM5100_ASRC2R_ENA_SHIFT 2 /* ASRC2R_ENA */
+#define WM5100_ASRC2R_ENA_WIDTH 1 /* ASRC2R_ENA */
+#define WM5100_ASRC1L_ENA 0x0002 /* ASRC1L_ENA */
+#define WM5100_ASRC1L_ENA_MASK 0x0002 /* ASRC1L_ENA */
+#define WM5100_ASRC1L_ENA_SHIFT 1 /* ASRC1L_ENA */
+#define WM5100_ASRC1L_ENA_WIDTH 1 /* ASRC1L_ENA */
+#define WM5100_ASRC1R_ENA 0x0001 /* ASRC1R_ENA */
+#define WM5100_ASRC1R_ENA_MASK 0x0001 /* ASRC1R_ENA */
+#define WM5100_ASRC1R_ENA_SHIFT 0 /* ASRC1R_ENA */
+#define WM5100_ASRC1R_ENA_WIDTH 1 /* ASRC1R_ENA */
+
+/*
+ * R289 (0x121) - ASRC_STATUS
+ */
+#define WM5100_ASRC2L_ENA_STS 0x0008 /* ASRC2L_ENA_STS */
+#define WM5100_ASRC2L_ENA_STS_MASK 0x0008 /* ASRC2L_ENA_STS */
+#define WM5100_ASRC2L_ENA_STS_SHIFT 3 /* ASRC2L_ENA_STS */
+#define WM5100_ASRC2L_ENA_STS_WIDTH 1 /* ASRC2L_ENA_STS */
+#define WM5100_ASRC2R_ENA_STS 0x0004 /* ASRC2R_ENA_STS */
+#define WM5100_ASRC2R_ENA_STS_MASK 0x0004 /* ASRC2R_ENA_STS */
+#define WM5100_ASRC2R_ENA_STS_SHIFT 2 /* ASRC2R_ENA_STS */
+#define WM5100_ASRC2R_ENA_STS_WIDTH 1 /* ASRC2R_ENA_STS */
+#define WM5100_ASRC1L_ENA_STS 0x0002 /* ASRC1L_ENA_STS */
+#define WM5100_ASRC1L_ENA_STS_MASK 0x0002 /* ASRC1L_ENA_STS */
+#define WM5100_ASRC1L_ENA_STS_SHIFT 1 /* ASRC1L_ENA_STS */
+#define WM5100_ASRC1L_ENA_STS_WIDTH 1 /* ASRC1L_ENA_STS */
+#define WM5100_ASRC1R_ENA_STS 0x0001 /* ASRC1R_ENA_STS */
+#define WM5100_ASRC1R_ENA_STS_MASK 0x0001 /* ASRC1R_ENA_STS */
+#define WM5100_ASRC1R_ENA_STS_SHIFT 0 /* ASRC1R_ENA_STS */
+#define WM5100_ASRC1R_ENA_STS_WIDTH 1 /* ASRC1R_ENA_STS */
+
+/*
+ * R290 (0x122) - ASRC_RATE1
+ */
+#define WM5100_ASRC_RATE1_MASK 0x0006 /* ASRC_RATE1 - [2:1] */
+#define WM5100_ASRC_RATE1_SHIFT 1 /* ASRC_RATE1 - [2:1] */
+#define WM5100_ASRC_RATE1_WIDTH 2 /* ASRC_RATE1 - [2:1] */
+
+/*
+ * R321 (0x141) - ISRC 1 CTRL 1
+ */
+#define WM5100_ISRC1_DFS_ENA 0x2000 /* ISRC1_DFS_ENA */
+#define WM5100_ISRC1_DFS_ENA_MASK 0x2000 /* ISRC1_DFS_ENA */
+#define WM5100_ISRC1_DFS_ENA_SHIFT 13 /* ISRC1_DFS_ENA */
+#define WM5100_ISRC1_DFS_ENA_WIDTH 1 /* ISRC1_DFS_ENA */
+#define WM5100_ISRC1_CLK_SEL_MASK 0x0300 /* ISRC1_CLK_SEL - [9:8] */
+#define WM5100_ISRC1_CLK_SEL_SHIFT 8 /* ISRC1_CLK_SEL - [9:8] */
+#define WM5100_ISRC1_CLK_SEL_WIDTH 2 /* ISRC1_CLK_SEL - [9:8] */
+#define WM5100_ISRC1_FSH_MASK 0x000C /* ISRC1_FSH - [3:2] */
+#define WM5100_ISRC1_FSH_SHIFT 2 /* ISRC1_FSH - [3:2] */
+#define WM5100_ISRC1_FSH_WIDTH 2 /* ISRC1_FSH - [3:2] */
+#define WM5100_ISRC1_FSL_MASK 0x0003 /* ISRC1_FSL - [1:0] */
+#define WM5100_ISRC1_FSL_SHIFT 0 /* ISRC1_FSL - [1:0] */
+#define WM5100_ISRC1_FSL_WIDTH 2 /* ISRC1_FSL - [1:0] */
+
+/*
+ * R322 (0x142) - ISRC 1 CTRL 2
+ */
+#define WM5100_ISRC1_INT1_ENA 0x8000 /* ISRC1_INT1_ENA */
+#define WM5100_ISRC1_INT1_ENA_MASK 0x8000 /* ISRC1_INT1_ENA */
+#define WM5100_ISRC1_INT1_ENA_SHIFT 15 /* ISRC1_INT1_ENA */
+#define WM5100_ISRC1_INT1_ENA_WIDTH 1 /* ISRC1_INT1_ENA */
+#define WM5100_ISRC1_INT2_ENA 0x4000 /* ISRC1_INT2_ENA */
+#define WM5100_ISRC1_INT2_ENA_MASK 0x4000 /* ISRC1_INT2_ENA */
+#define WM5100_ISRC1_INT2_ENA_SHIFT 14 /* ISRC1_INT2_ENA */
+#define WM5100_ISRC1_INT2_ENA_WIDTH 1 /* ISRC1_INT2_ENA */
+#define WM5100_ISRC1_INT3_ENA 0x2000 /* ISRC1_INT3_ENA */
+#define WM5100_ISRC1_INT3_ENA_MASK 0x2000 /* ISRC1_INT3_ENA */
+#define WM5100_ISRC1_INT3_ENA_SHIFT 13 /* ISRC1_INT3_ENA */
+#define WM5100_ISRC1_INT3_ENA_WIDTH 1 /* ISRC1_INT3_ENA */
+#define WM5100_ISRC1_INT4_ENA 0x1000 /* ISRC1_INT4_ENA */
+#define WM5100_ISRC1_INT4_ENA_MASK 0x1000 /* ISRC1_INT4_ENA */
+#define WM5100_ISRC1_INT4_ENA_SHIFT 12 /* ISRC1_INT4_ENA */
+#define WM5100_ISRC1_INT4_ENA_WIDTH 1 /* ISRC1_INT4_ENA */
+#define WM5100_ISRC1_DEC1_ENA 0x0200 /* ISRC1_DEC1_ENA */
+#define WM5100_ISRC1_DEC1_ENA_MASK 0x0200 /* ISRC1_DEC1_ENA */
+#define WM5100_ISRC1_DEC1_ENA_SHIFT 9 /* ISRC1_DEC1_ENA */
+#define WM5100_ISRC1_DEC1_ENA_WIDTH 1 /* ISRC1_DEC1_ENA */
+#define WM5100_ISRC1_DEC2_ENA 0x0100 /* ISRC1_DEC2_ENA */
+#define WM5100_ISRC1_DEC2_ENA_MASK 0x0100 /* ISRC1_DEC2_ENA */
+#define WM5100_ISRC1_DEC2_ENA_SHIFT 8 /* ISRC1_DEC2_ENA */
+#define WM5100_ISRC1_DEC2_ENA_WIDTH 1 /* ISRC1_DEC2_ENA */
+#define WM5100_ISRC1_DEC3_ENA 0x0080 /* ISRC1_DEC3_ENA */
+#define WM5100_ISRC1_DEC3_ENA_MASK 0x0080 /* ISRC1_DEC3_ENA */
+#define WM5100_ISRC1_DEC3_ENA_SHIFT 7 /* ISRC1_DEC3_ENA */
+#define WM5100_ISRC1_DEC3_ENA_WIDTH 1 /* ISRC1_DEC3_ENA */
+#define WM5100_ISRC1_DEC4_ENA 0x0040 /* ISRC1_DEC4_ENA */
+#define WM5100_ISRC1_DEC4_ENA_MASK 0x0040 /* ISRC1_DEC4_ENA */
+#define WM5100_ISRC1_DEC4_ENA_SHIFT 6 /* ISRC1_DEC4_ENA */
+#define WM5100_ISRC1_DEC4_ENA_WIDTH 1 /* ISRC1_DEC4_ENA */
+#define WM5100_ISRC1_NOTCH_ENA 0x0001 /* ISRC1_NOTCH_ENA */
+#define WM5100_ISRC1_NOTCH_ENA_MASK 0x0001 /* ISRC1_NOTCH_ENA */
+#define WM5100_ISRC1_NOTCH_ENA_SHIFT 0 /* ISRC1_NOTCH_ENA */
+#define WM5100_ISRC1_NOTCH_ENA_WIDTH 1 /* ISRC1_NOTCH_ENA */
+
+/*
+ * R323 (0x143) - ISRC 2 CTRL1
+ */
+#define WM5100_ISRC2_DFS_ENA 0x2000 /* ISRC2_DFS_ENA */
+#define WM5100_ISRC2_DFS_ENA_MASK 0x2000 /* ISRC2_DFS_ENA */
+#define WM5100_ISRC2_DFS_ENA_SHIFT 13 /* ISRC2_DFS_ENA */
+#define WM5100_ISRC2_DFS_ENA_WIDTH 1 /* ISRC2_DFS_ENA */
+#define WM5100_ISRC2_CLK_SEL_MASK 0x0300 /* ISRC2_CLK_SEL - [9:8] */
+#define WM5100_ISRC2_CLK_SEL_SHIFT 8 /* ISRC2_CLK_SEL - [9:8] */
+#define WM5100_ISRC2_CLK_SEL_WIDTH 2 /* ISRC2_CLK_SEL - [9:8] */
+#define WM5100_ISRC2_FSH_MASK 0x000C /* ISRC2_FSH - [3:2] */
+#define WM5100_ISRC2_FSH_SHIFT 2 /* ISRC2_FSH - [3:2] */
+#define WM5100_ISRC2_FSH_WIDTH 2 /* ISRC2_FSH - [3:2] */
+#define WM5100_ISRC2_FSL_MASK 0x0003 /* ISRC2_FSL - [1:0] */
+#define WM5100_ISRC2_FSL_SHIFT 0 /* ISRC2_FSL - [1:0] */
+#define WM5100_ISRC2_FSL_WIDTH 2 /* ISRC2_FSL - [1:0] */
+
+/*
+ * R324 (0x144) - ISRC 2 CTRL 2
+ */
+#define WM5100_ISRC2_INT1_ENA 0x8000 /* ISRC2_INT1_ENA */
+#define WM5100_ISRC2_INT1_ENA_MASK 0x8000 /* ISRC2_INT1_ENA */
+#define WM5100_ISRC2_INT1_ENA_SHIFT 15 /* ISRC2_INT1_ENA */
+#define WM5100_ISRC2_INT1_ENA_WIDTH 1 /* ISRC2_INT1_ENA */
+#define WM5100_ISRC2_INT2_ENA 0x4000 /* ISRC2_INT2_ENA */
+#define WM5100_ISRC2_INT2_ENA_MASK 0x4000 /* ISRC2_INT2_ENA */
+#define WM5100_ISRC2_INT2_ENA_SHIFT 14 /* ISRC2_INT2_ENA */
+#define WM5100_ISRC2_INT2_ENA_WIDTH 1 /* ISRC2_INT2_ENA */
+#define WM5100_ISRC2_INT3_ENA 0x2000 /* ISRC2_INT3_ENA */
+#define WM5100_ISRC2_INT3_ENA_MASK 0x2000 /* ISRC2_INT3_ENA */
+#define WM5100_ISRC2_INT3_ENA_SHIFT 13 /* ISRC2_INT3_ENA */
+#define WM5100_ISRC2_INT3_ENA_WIDTH 1 /* ISRC2_INT3_ENA */
+#define WM5100_ISRC2_INT4_ENA 0x1000 /* ISRC2_INT4_ENA */
+#define WM5100_ISRC2_INT4_ENA_MASK 0x1000 /* ISRC2_INT4_ENA */
+#define WM5100_ISRC2_INT4_ENA_SHIFT 12 /* ISRC2_INT4_ENA */
+#define WM5100_ISRC2_INT4_ENA_WIDTH 1 /* ISRC2_INT4_ENA */
+#define WM5100_ISRC2_DEC1_ENA 0x0200 /* ISRC2_DEC1_ENA */
+#define WM5100_ISRC2_DEC1_ENA_MASK 0x0200 /* ISRC2_DEC1_ENA */
+#define WM5100_ISRC2_DEC1_ENA_SHIFT 9 /* ISRC2_DEC1_ENA */
+#define WM5100_ISRC2_DEC1_ENA_WIDTH 1 /* ISRC2_DEC1_ENA */
+#define WM5100_ISRC2_DEC2_ENA 0x0100 /* ISRC2_DEC2_ENA */
+#define WM5100_ISRC2_DEC2_ENA_MASK 0x0100 /* ISRC2_DEC2_ENA */
+#define WM5100_ISRC2_DEC2_ENA_SHIFT 8 /* ISRC2_DEC2_ENA */
+#define WM5100_ISRC2_DEC2_ENA_WIDTH 1 /* ISRC2_DEC2_ENA */
+#define WM5100_ISRC2_DEC3_ENA 0x0080 /* ISRC2_DEC3_ENA */
+#define WM5100_ISRC2_DEC3_ENA_MASK 0x0080 /* ISRC2_DEC3_ENA */
+#define WM5100_ISRC2_DEC3_ENA_SHIFT 7 /* ISRC2_DEC3_ENA */
+#define WM5100_ISRC2_DEC3_ENA_WIDTH 1 /* ISRC2_DEC3_ENA */
+#define WM5100_ISRC2_DEC4_ENA 0x0040 /* ISRC2_DEC4_ENA */
+#define WM5100_ISRC2_DEC4_ENA_MASK 0x0040 /* ISRC2_DEC4_ENA */
+#define WM5100_ISRC2_DEC4_ENA_SHIFT 6 /* ISRC2_DEC4_ENA */
+#define WM5100_ISRC2_DEC4_ENA_WIDTH 1 /* ISRC2_DEC4_ENA */
+#define WM5100_ISRC2_NOTCH_ENA 0x0001 /* ISRC2_NOTCH_ENA */
+#define WM5100_ISRC2_NOTCH_ENA_MASK 0x0001 /* ISRC2_NOTCH_ENA */
+#define WM5100_ISRC2_NOTCH_ENA_SHIFT 0 /* ISRC2_NOTCH_ENA */
+#define WM5100_ISRC2_NOTCH_ENA_WIDTH 1 /* ISRC2_NOTCH_ENA */
+
+/*
+ * R386 (0x182) - FLL1 Control 1
+ */
+#define WM5100_FLL1_ENA 0x0001 /* FLL1_ENA */
+#define WM5100_FLL1_ENA_MASK 0x0001 /* FLL1_ENA */
+#define WM5100_FLL1_ENA_SHIFT 0 /* FLL1_ENA */
+#define WM5100_FLL1_ENA_WIDTH 1 /* FLL1_ENA */
+
+/*
+ * R387 (0x183) - FLL1 Control 2
+ */
+#define WM5100_FLL1_OUTDIV_MASK 0x3F00 /* FLL1_OUTDIV - [13:8] */
+#define WM5100_FLL1_OUTDIV_SHIFT 8 /* FLL1_OUTDIV - [13:8] */
+#define WM5100_FLL1_OUTDIV_WIDTH 6 /* FLL1_OUTDIV - [13:8] */
+#define WM5100_FLL1_FRATIO_MASK 0x0007 /* FLL1_FRATIO - [2:0] */
+#define WM5100_FLL1_FRATIO_SHIFT 0 /* FLL1_FRATIO - [2:0] */
+#define WM5100_FLL1_FRATIO_WIDTH 3 /* FLL1_FRATIO - [2:0] */
+
+/*
+ * R388 (0x184) - FLL1 Control 3
+ */
+#define WM5100_FLL1_THETA_MASK 0xFFFF /* FLL1_THETA - [15:0] */
+#define WM5100_FLL1_THETA_SHIFT 0 /* FLL1_THETA - [15:0] */
+#define WM5100_FLL1_THETA_WIDTH 16 /* FLL1_THETA - [15:0] */
+
+/*
+ * R390 (0x186) - FLL1 Control 5
+ */
+#define WM5100_FLL1_N_MASK 0x03FF /* FLL1_N - [9:0] */
+#define WM5100_FLL1_N_SHIFT 0 /* FLL1_N - [9:0] */
+#define WM5100_FLL1_N_WIDTH 10 /* FLL1_N - [9:0] */
+
+/*
+ * R391 (0x187) - FLL1 Control 6
+ */
+#define WM5100_FLL1_REFCLK_DIV_MASK 0x00C0 /* FLL1_REFCLK_DIV - [7:6] */
+#define WM5100_FLL1_REFCLK_DIV_SHIFT 6 /* FLL1_REFCLK_DIV - [7:6] */
+#define WM5100_FLL1_REFCLK_DIV_WIDTH 2 /* FLL1_REFCLK_DIV - [7:6] */
+#define WM5100_FLL1_REFCLK_SRC_MASK 0x000F /* FLL1_REFCLK_SRC - [3:0] */
+#define WM5100_FLL1_REFCLK_SRC_SHIFT 0 /* FLL1_REFCLK_SRC - [3:0] */
+#define WM5100_FLL1_REFCLK_SRC_WIDTH 4 /* FLL1_REFCLK_SRC - [3:0] */
+
+/*
+ * R392 (0x188) - FLL1 EFS 1
+ */
+#define WM5100_FLL1_LAMBDA_MASK 0xFFFF /* FLL1_LAMBDA - [15:0] */
+#define WM5100_FLL1_LAMBDA_SHIFT 0 /* FLL1_LAMBDA - [15:0] */
+#define WM5100_FLL1_LAMBDA_WIDTH 16 /* FLL1_LAMBDA - [15:0] */
+
+/*
+ * R418 (0x1A2) - FLL2 Control 1
+ */
+#define WM5100_FLL2_ENA 0x0001 /* FLL2_ENA */
+#define WM5100_FLL2_ENA_MASK 0x0001 /* FLL2_ENA */
+#define WM5100_FLL2_ENA_SHIFT 0 /* FLL2_ENA */
+#define WM5100_FLL2_ENA_WIDTH 1 /* FLL2_ENA */
+
+/*
+ * R419 (0x1A3) - FLL2 Control 2
+ */
+#define WM5100_FLL2_OUTDIV_MASK 0x3F00 /* FLL2_OUTDIV - [13:8] */
+#define WM5100_FLL2_OUTDIV_SHIFT 8 /* FLL2_OUTDIV - [13:8] */
+#define WM5100_FLL2_OUTDIV_WIDTH 6 /* FLL2_OUTDIV - [13:8] */
+#define WM5100_FLL2_FRATIO_MASK 0x0007 /* FLL2_FRATIO - [2:0] */
+#define WM5100_FLL2_FRATIO_SHIFT 0 /* FLL2_FRATIO - [2:0] */
+#define WM5100_FLL2_FRATIO_WIDTH 3 /* FLL2_FRATIO - [2:0] */
+
+/*
+ * R420 (0x1A4) - FLL2 Control 3
+ */
+#define WM5100_FLL2_THETA_MASK 0xFFFF /* FLL2_THETA - [15:0] */
+#define WM5100_FLL2_THETA_SHIFT 0 /* FLL2_THETA - [15:0] */
+#define WM5100_FLL2_THETA_WIDTH 16 /* FLL2_THETA - [15:0] */
+
+/*
+ * R422 (0x1A6) - FLL2 Control 5
+ */
+#define WM5100_FLL2_N_MASK 0x03FF /* FLL2_N - [9:0] */
+#define WM5100_FLL2_N_SHIFT 0 /* FLL2_N - [9:0] */
+#define WM5100_FLL2_N_WIDTH 10 /* FLL2_N - [9:0] */
+
+/*
+ * R423 (0x1A7) - FLL2 Control 6
+ */
+#define WM5100_FLL2_REFCLK_DIV_MASK 0x00C0 /* FLL2_REFCLK_DIV - [7:6] */
+#define WM5100_FLL2_REFCLK_DIV_SHIFT 6 /* FLL2_REFCLK_DIV - [7:6] */
+#define WM5100_FLL2_REFCLK_DIV_WIDTH 2 /* FLL2_REFCLK_DIV - [7:6] */
+#define WM5100_FLL2_REFCLK_SRC_MASK 0x000F /* FLL2_REFCLK_SRC - [3:0] */
+#define WM5100_FLL2_REFCLK_SRC_SHIFT 0 /* FLL2_REFCLK_SRC - [3:0] */
+#define WM5100_FLL2_REFCLK_SRC_WIDTH 4 /* FLL2_REFCLK_SRC - [3:0] */
+
+/*
+ * R424 (0x1A8) - FLL2 EFS 1
+ */
+#define WM5100_FLL2_LAMBDA_MASK 0xFFFF /* FLL2_LAMBDA - [15:0] */
+#define WM5100_FLL2_LAMBDA_SHIFT 0 /* FLL2_LAMBDA - [15:0] */
+#define WM5100_FLL2_LAMBDA_WIDTH 16 /* FLL2_LAMBDA - [15:0] */
+
+/*
+ * R512 (0x200) - Mic Charge Pump 1
+ */
+#define WM5100_CP2_BYPASS 0x0020 /* CP2_BYPASS */
+#define WM5100_CP2_BYPASS_MASK 0x0020 /* CP2_BYPASS */
+#define WM5100_CP2_BYPASS_SHIFT 5 /* CP2_BYPASS */
+#define WM5100_CP2_BYPASS_WIDTH 1 /* CP2_BYPASS */
+#define WM5100_CP2_ENA 0x0001 /* CP2_ENA */
+#define WM5100_CP2_ENA_MASK 0x0001 /* CP2_ENA */
+#define WM5100_CP2_ENA_SHIFT 0 /* CP2_ENA */
+#define WM5100_CP2_ENA_WIDTH 1 /* CP2_ENA */
+
+/*
+ * R513 (0x201) - Mic Charge Pump 2
+ */
+#define WM5100_LDO2_VSEL_MASK 0xF800 /* LDO2_VSEL - [15:11] */
+#define WM5100_LDO2_VSEL_SHIFT 11 /* LDO2_VSEL - [15:11] */
+#define WM5100_LDO2_VSEL_WIDTH 5 /* LDO2_VSEL - [15:11] */
+
+/*
+ * R514 (0x202) - HP Charge Pump 1
+ */
+#define WM5100_CP1_ENA 0x0001 /* CP1_ENA */
+#define WM5100_CP1_ENA_MASK 0x0001 /* CP1_ENA */
+#define WM5100_CP1_ENA_SHIFT 0 /* CP1_ENA */
+#define WM5100_CP1_ENA_WIDTH 1 /* CP1_ENA */
+
+/*
+ * R529 (0x211) - LDO1 Control
+ */
+#define WM5100_LDO1_BYPASS 0x0002 /* LDO1_BYPASS */
+#define WM5100_LDO1_BYPASS_MASK 0x0002 /* LDO1_BYPASS */
+#define WM5100_LDO1_BYPASS_SHIFT 1 /* LDO1_BYPASS */
+#define WM5100_LDO1_BYPASS_WIDTH 1 /* LDO1_BYPASS */
+
+/*
+ * R533 (0x215) - Mic Bias Ctrl 1
+ */
+#define WM5100_MICB1_DISCH 0x0040 /* MICB1_DISCH */
+#define WM5100_MICB1_DISCH_MASK 0x0040 /* MICB1_DISCH */
+#define WM5100_MICB1_DISCH_SHIFT 6 /* MICB1_DISCH */
+#define WM5100_MICB1_DISCH_WIDTH 1 /* MICB1_DISCH */
+#define WM5100_MICB1_RATE 0x0020 /* MICB1_RATE */
+#define WM5100_MICB1_RATE_MASK 0x0020 /* MICB1_RATE */
+#define WM5100_MICB1_RATE_SHIFT 5 /* MICB1_RATE */
+#define WM5100_MICB1_RATE_WIDTH 1 /* MICB1_RATE */
+#define WM5100_MICB1_LVL_MASK 0x001C /* MICB1_LVL - [4:2] */
+#define WM5100_MICB1_LVL_SHIFT 2 /* MICB1_LVL - [4:2] */
+#define WM5100_MICB1_LVL_WIDTH 3 /* MICB1_LVL - [4:2] */
+#define WM5100_MICB1_BYPASS 0x0002 /* MICB1_BYPASS */
+#define WM5100_MICB1_BYPASS_MASK 0x0002 /* MICB1_BYPASS */
+#define WM5100_MICB1_BYPASS_SHIFT 1 /* MICB1_BYPASS */
+#define WM5100_MICB1_BYPASS_WIDTH 1 /* MICB1_BYPASS */
+#define WM5100_MICB1_ENA 0x0001 /* MICB1_ENA */
+#define WM5100_MICB1_ENA_MASK 0x0001 /* MICB1_ENA */
+#define WM5100_MICB1_ENA_SHIFT 0 /* MICB1_ENA */
+#define WM5100_MICB1_ENA_WIDTH 1 /* MICB1_ENA */
+
+/*
+ * R534 (0x216) - Mic Bias Ctrl 2
+ */
+#define WM5100_MICB2_DISCH 0x0040 /* MICB2_DISCH */
+#define WM5100_MICB2_DISCH_MASK 0x0040 /* MICB2_DISCH */
+#define WM5100_MICB2_DISCH_SHIFT 6 /* MICB2_DISCH */
+#define WM5100_MICB2_DISCH_WIDTH 1 /* MICB2_DISCH */
+#define WM5100_MICB2_RATE 0x0020 /* MICB2_RATE */
+#define WM5100_MICB2_RATE_MASK 0x0020 /* MICB2_RATE */
+#define WM5100_MICB2_RATE_SHIFT 5 /* MICB2_RATE */
+#define WM5100_MICB2_RATE_WIDTH 1 /* MICB2_RATE */
+#define WM5100_MICB2_LVL_MASK 0x001C /* MICB2_LVL - [4:2] */
+#define WM5100_MICB2_LVL_SHIFT 2 /* MICB2_LVL - [4:2] */
+#define WM5100_MICB2_LVL_WIDTH 3 /* MICB2_LVL - [4:2] */
+#define WM5100_MICB2_BYPASS 0x0002 /* MICB2_BYPASS */
+#define WM5100_MICB2_BYPASS_MASK 0x0002 /* MICB2_BYPASS */
+#define WM5100_MICB2_BYPASS_SHIFT 1 /* MICB2_BYPASS */
+#define WM5100_MICB2_BYPASS_WIDTH 1 /* MICB2_BYPASS */
+#define WM5100_MICB2_ENA 0x0001 /* MICB2_ENA */
+#define WM5100_MICB2_ENA_MASK 0x0001 /* MICB2_ENA */
+#define WM5100_MICB2_ENA_SHIFT 0 /* MICB2_ENA */
+#define WM5100_MICB2_ENA_WIDTH 1 /* MICB2_ENA */
+
+/*
+ * R535 (0x217) - Mic Bias Ctrl 3
+ */
+#define WM5100_MICB3_DISCH 0x0040 /* MICB3_DISCH */
+#define WM5100_MICB3_DISCH_MASK 0x0040 /* MICB3_DISCH */
+#define WM5100_MICB3_DISCH_SHIFT 6 /* MICB3_DISCH */
+#define WM5100_MICB3_DISCH_WIDTH 1 /* MICB3_DISCH */
+#define WM5100_MICB3_RATE 0x0020 /* MICB3_RATE */
+#define WM5100_MICB3_RATE_MASK 0x0020 /* MICB3_RATE */
+#define WM5100_MICB3_RATE_SHIFT 5 /* MICB3_RATE */
+#define WM5100_MICB3_RATE_WIDTH 1 /* MICB3_RATE */
+#define WM5100_MICB3_LVL_MASK 0x001C /* MICB3_LVL - [4:2] */
+#define WM5100_MICB3_LVL_SHIFT 2 /* MICB3_LVL - [4:2] */
+#define WM5100_MICB3_LVL_WIDTH 3 /* MICB3_LVL - [4:2] */
+#define WM5100_MICB3_BYPASS 0x0002 /* MICB3_BYPASS */
+#define WM5100_MICB3_BYPASS_MASK 0x0002 /* MICB3_BYPASS */
+#define WM5100_MICB3_BYPASS_SHIFT 1 /* MICB3_BYPASS */
+#define WM5100_MICB3_BYPASS_WIDTH 1 /* MICB3_BYPASS */
+#define WM5100_MICB3_ENA 0x0001 /* MICB3_ENA */
+#define WM5100_MICB3_ENA_MASK 0x0001 /* MICB3_ENA */
+#define WM5100_MICB3_ENA_SHIFT 0 /* MICB3_ENA */
+#define WM5100_MICB3_ENA_WIDTH 1 /* MICB3_ENA */
+
+/*
+ * R640 (0x280) - Accessory Detect Mode 1
+ */
+#define WM5100_ACCDET_BIAS_SRC_MASK 0xC000 /* ACCDET_BIAS_SRC - [15:14] */
+#define WM5100_ACCDET_BIAS_SRC_SHIFT 14 /* ACCDET_BIAS_SRC - [15:14] */
+#define WM5100_ACCDET_BIAS_SRC_WIDTH 2 /* ACCDET_BIAS_SRC - [15:14] */
+#define WM5100_ACCDET_SRC 0x2000 /* ACCDET_SRC */
+#define WM5100_ACCDET_SRC_MASK 0x2000 /* ACCDET_SRC */
+#define WM5100_ACCDET_SRC_SHIFT 13 /* ACCDET_SRC */
+#define WM5100_ACCDET_SRC_WIDTH 1 /* ACCDET_SRC */
+#define WM5100_ACCDET_MODE_MASK 0x0003 /* ACCDET_MODE - [1:0] */
+#define WM5100_ACCDET_MODE_SHIFT 0 /* ACCDET_MODE - [1:0] */
+#define WM5100_ACCDET_MODE_WIDTH 2 /* ACCDET_MODE - [1:0] */
+
+/*
+ * R648 (0x288) - Headphone Detect 1
+ */
+#define WM5100_HP_HOLDTIME_MASK 0x00E0 /* HP_HOLDTIME - [7:5] */
+#define WM5100_HP_HOLDTIME_SHIFT 5 /* HP_HOLDTIME - [7:5] */
+#define WM5100_HP_HOLDTIME_WIDTH 3 /* HP_HOLDTIME - [7:5] */
+#define WM5100_HP_CLK_DIV_MASK 0x0018 /* HP_CLK_DIV - [4:3] */
+#define WM5100_HP_CLK_DIV_SHIFT 3 /* HP_CLK_DIV - [4:3] */
+#define WM5100_HP_CLK_DIV_WIDTH 2 /* HP_CLK_DIV - [4:3] */
+#define WM5100_HP_STEP_SIZE 0x0002 /* HP_STEP_SIZE */
+#define WM5100_HP_STEP_SIZE_MASK 0x0002 /* HP_STEP_SIZE */
+#define WM5100_HP_STEP_SIZE_SHIFT 1 /* HP_STEP_SIZE */
+#define WM5100_HP_STEP_SIZE_WIDTH 1 /* HP_STEP_SIZE */
+#define WM5100_HP_POLL 0x0001 /* HP_POLL */
+#define WM5100_HP_POLL_MASK 0x0001 /* HP_POLL */
+#define WM5100_HP_POLL_SHIFT 0 /* HP_POLL */
+#define WM5100_HP_POLL_WIDTH 1 /* HP_POLL */
+
+/*
+ * R649 (0x289) - Headphone Detect 2
+ */
+#define WM5100_HP_DONE 0x0080 /* HP_DONE */
+#define WM5100_HP_DONE_MASK 0x0080 /* HP_DONE */
+#define WM5100_HP_DONE_SHIFT 7 /* HP_DONE */
+#define WM5100_HP_DONE_WIDTH 1 /* HP_DONE */
+#define WM5100_HP_LVL_MASK 0x007F /* HP_LVL - [6:0] */
+#define WM5100_HP_LVL_SHIFT 0 /* HP_LVL - [6:0] */
+#define WM5100_HP_LVL_WIDTH 7 /* HP_LVL - [6:0] */
+
+/*
+ * R656 (0x290) - Mic Detect 1
+ */
+#define WM5100_ACCDET_BIAS_STARTTIME_MASK 0xF000 /* ACCDET_BIAS_STARTTIME - [15:12] */
+#define WM5100_ACCDET_BIAS_STARTTIME_SHIFT 12 /* ACCDET_BIAS_STARTTIME - [15:12] */
+#define WM5100_ACCDET_BIAS_STARTTIME_WIDTH 4 /* ACCDET_BIAS_STARTTIME - [15:12] */
+#define WM5100_ACCDET_RATE_MASK 0x0F00 /* ACCDET_RATE - [11:8] */
+#define WM5100_ACCDET_RATE_SHIFT 8 /* ACCDET_RATE - [11:8] */
+#define WM5100_ACCDET_RATE_WIDTH 4 /* ACCDET_RATE - [11:8] */
+#define WM5100_ACCDET_DBTIME 0x0002 /* ACCDET_DBTIME */
+#define WM5100_ACCDET_DBTIME_MASK 0x0002 /* ACCDET_DBTIME */
+#define WM5100_ACCDET_DBTIME_SHIFT 1 /* ACCDET_DBTIME */
+#define WM5100_ACCDET_DBTIME_WIDTH 1 /* ACCDET_DBTIME */
+#define WM5100_ACCDET_ENA 0x0001 /* ACCDET_ENA */
+#define WM5100_ACCDET_ENA_MASK 0x0001 /* ACCDET_ENA */
+#define WM5100_ACCDET_ENA_SHIFT 0 /* ACCDET_ENA */
+#define WM5100_ACCDET_ENA_WIDTH 1 /* ACCDET_ENA */
+
+/*
+ * R657 (0x291) - Mic Detect 2
+ */
+#define WM5100_ACCDET_LVL_SEL_MASK 0x00FF /* ACCDET_LVL_SEL - [7:0] */
+#define WM5100_ACCDET_LVL_SEL_SHIFT 0 /* ACCDET_LVL_SEL - [7:0] */
+#define WM5100_ACCDET_LVL_SEL_WIDTH 8 /* ACCDET_LVL_SEL - [7:0] */
+
+/*
+ * R658 (0x292) - Mic Detect 3
+ */
+#define WM5100_ACCDET_LVL_MASK 0x07FC /* ACCDET_LVL - [10:2] */
+#define WM5100_ACCDET_LVL_SHIFT 2 /* ACCDET_LVL - [10:2] */
+#define WM5100_ACCDET_LVL_WIDTH 9 /* ACCDET_LVL - [10:2] */
+#define WM5100_ACCDET_VALID 0x0002 /* ACCDET_VALID */
+#define WM5100_ACCDET_VALID_MASK 0x0002 /* ACCDET_VALID */
+#define WM5100_ACCDET_VALID_SHIFT 1 /* ACCDET_VALID */
+#define WM5100_ACCDET_VALID_WIDTH 1 /* ACCDET_VALID */
+#define WM5100_ACCDET_STS 0x0001 /* ACCDET_STS */
+#define WM5100_ACCDET_STS_MASK 0x0001 /* ACCDET_STS */
+#define WM5100_ACCDET_STS_SHIFT 0 /* ACCDET_STS */
+#define WM5100_ACCDET_STS_WIDTH 1 /* ACCDET_STS */
+
+/*
+ * R699 (0x2BB) - Misc Control
+ */
+#define WM5100_HPCOM_SRC 0x200 /* HPCOM_SRC */
+#define WM5100_HPCOM_SRC_SHIFT 9 /* HPCOM_SRC */
+
+/*
+ * R769 (0x301) - Input Enables
+ */
+#define WM5100_IN4L_ENA 0x0080 /* IN4L_ENA */
+#define WM5100_IN4L_ENA_MASK 0x0080 /* IN4L_ENA */
+#define WM5100_IN4L_ENA_SHIFT 7 /* IN4L_ENA */
+#define WM5100_IN4L_ENA_WIDTH 1 /* IN4L_ENA */
+#define WM5100_IN4R_ENA 0x0040 /* IN4R_ENA */
+#define WM5100_IN4R_ENA_MASK 0x0040 /* IN4R_ENA */
+#define WM5100_IN4R_ENA_SHIFT 6 /* IN4R_ENA */
+#define WM5100_IN4R_ENA_WIDTH 1 /* IN4R_ENA */
+#define WM5100_IN3L_ENA 0x0020 /* IN3L_ENA */
+#define WM5100_IN3L_ENA_MASK 0x0020 /* IN3L_ENA */
+#define WM5100_IN3L_ENA_SHIFT 5 /* IN3L_ENA */
+#define WM5100_IN3L_ENA_WIDTH 1 /* IN3L_ENA */
+#define WM5100_IN3R_ENA 0x0010 /* IN3R_ENA */
+#define WM5100_IN3R_ENA_MASK 0x0010 /* IN3R_ENA */
+#define WM5100_IN3R_ENA_SHIFT 4 /* IN3R_ENA */
+#define WM5100_IN3R_ENA_WIDTH 1 /* IN3R_ENA */
+#define WM5100_IN2L_ENA 0x0008 /* IN2L_ENA */
+#define WM5100_IN2L_ENA_MASK 0x0008 /* IN2L_ENA */
+#define WM5100_IN2L_ENA_SHIFT 3 /* IN2L_ENA */
+#define WM5100_IN2L_ENA_WIDTH 1 /* IN2L_ENA */
+#define WM5100_IN2R_ENA 0x0004 /* IN2R_ENA */
+#define WM5100_IN2R_ENA_MASK 0x0004 /* IN2R_ENA */
+#define WM5100_IN2R_ENA_SHIFT 2 /* IN2R_ENA */
+#define WM5100_IN2R_ENA_WIDTH 1 /* IN2R_ENA */
+#define WM5100_IN1L_ENA 0x0002 /* IN1L_ENA */
+#define WM5100_IN1L_ENA_MASK 0x0002 /* IN1L_ENA */
+#define WM5100_IN1L_ENA_SHIFT 1 /* IN1L_ENA */
+#define WM5100_IN1L_ENA_WIDTH 1 /* IN1L_ENA */
+#define WM5100_IN1R_ENA 0x0001 /* IN1R_ENA */
+#define WM5100_IN1R_ENA_MASK 0x0001 /* IN1R_ENA */
+#define WM5100_IN1R_ENA_SHIFT 0 /* IN1R_ENA */
+#define WM5100_IN1R_ENA_WIDTH 1 /* IN1R_ENA */
+
+/*
+ * R770 (0x302) - Input Enables Status
+ */
+#define WM5100_IN4L_ENA_STS 0x0080 /* IN4L_ENA_STS */
+#define WM5100_IN4L_ENA_STS_MASK 0x0080 /* IN4L_ENA_STS */
+#define WM5100_IN4L_ENA_STS_SHIFT 7 /* IN4L_ENA_STS */
+#define WM5100_IN4L_ENA_STS_WIDTH 1 /* IN4L_ENA_STS */
+#define WM5100_IN4R_ENA_STS 0x0040 /* IN4R_ENA_STS */
+#define WM5100_IN4R_ENA_STS_MASK 0x0040 /* IN4R_ENA_STS */
+#define WM5100_IN4R_ENA_STS_SHIFT 6 /* IN4R_ENA_STS */
+#define WM5100_IN4R_ENA_STS_WIDTH 1 /* IN4R_ENA_STS */
+#define WM5100_IN3L_ENA_STS 0x0020 /* IN3L_ENA_STS */
+#define WM5100_IN3L_ENA_STS_MASK 0x0020 /* IN3L_ENA_STS */
+#define WM5100_IN3L_ENA_STS_SHIFT 5 /* IN3L_ENA_STS */
+#define WM5100_IN3L_ENA_STS_WIDTH 1 /* IN3L_ENA_STS */
+#define WM5100_IN3R_ENA_STS 0x0010 /* IN3R_ENA_STS */
+#define WM5100_IN3R_ENA_STS_MASK 0x0010 /* IN3R_ENA_STS */
+#define WM5100_IN3R_ENA_STS_SHIFT 4 /* IN3R_ENA_STS */
+#define WM5100_IN3R_ENA_STS_WIDTH 1 /* IN3R_ENA_STS */
+#define WM5100_IN2L_ENA_STS 0x0008 /* IN2L_ENA_STS */
+#define WM5100_IN2L_ENA_STS_MASK 0x0008 /* IN2L_ENA_STS */
+#define WM5100_IN2L_ENA_STS_SHIFT 3 /* IN2L_ENA_STS */
+#define WM5100_IN2L_ENA_STS_WIDTH 1 /* IN2L_ENA_STS */
+#define WM5100_IN2R_ENA_STS 0x0004 /* IN2R_ENA_STS */
+#define WM5100_IN2R_ENA_STS_MASK 0x0004 /* IN2R_ENA_STS */
+#define WM5100_IN2R_ENA_STS_SHIFT 2 /* IN2R_ENA_STS */
+#define WM5100_IN2R_ENA_STS_WIDTH 1 /* IN2R_ENA_STS */
+#define WM5100_IN1L_ENA_STS 0x0002 /* IN1L_ENA_STS */
+#define WM5100_IN1L_ENA_STS_MASK 0x0002 /* IN1L_ENA_STS */
+#define WM5100_IN1L_ENA_STS_SHIFT 1 /* IN1L_ENA_STS */
+#define WM5100_IN1L_ENA_STS_WIDTH 1 /* IN1L_ENA_STS */
+#define WM5100_IN1R_ENA_STS 0x0001 /* IN1R_ENA_STS */
+#define WM5100_IN1R_ENA_STS_MASK 0x0001 /* IN1R_ENA_STS */
+#define WM5100_IN1R_ENA_STS_SHIFT 0 /* IN1R_ENA_STS */
+#define WM5100_IN1R_ENA_STS_WIDTH 1 /* IN1R_ENA_STS */
+
+/*
+ * R784 (0x310) - IN1L Control
+ */
+#define WM5100_IN_RATE_MASK 0xC000 /* IN_RATE - [15:14] */
+#define WM5100_IN_RATE_SHIFT 14 /* IN_RATE - [15:14] */
+#define WM5100_IN_RATE_WIDTH 2 /* IN_RATE - [15:14] */
+#define WM5100_IN1_OSR 0x2000 /* IN1_OSR */
+#define WM5100_IN1_OSR_MASK 0x2000 /* IN1_OSR */
+#define WM5100_IN1_OSR_SHIFT 13 /* IN1_OSR */
+#define WM5100_IN1_OSR_WIDTH 1 /* IN1_OSR */
+#define WM5100_IN1_DMIC_SUP_MASK 0x1800 /* IN1_DMIC_SUP - [12:11] */
+#define WM5100_IN1_DMIC_SUP_SHIFT 11 /* IN1_DMIC_SUP - [12:11] */
+#define WM5100_IN1_DMIC_SUP_WIDTH 2 /* IN1_DMIC_SUP - [12:11] */
+#define WM5100_IN1_MODE_MASK 0x0600 /* IN1_MODE - [10:9] */
+#define WM5100_IN1_MODE_SHIFT 9 /* IN1_MODE - [10:9] */
+#define WM5100_IN1_MODE_WIDTH 2 /* IN1_MODE - [10:9] */
+#define WM5100_IN1L_PGA_VOL_MASK 0x00FE /* IN1L_PGA_VOL - [7:1] */
+#define WM5100_IN1L_PGA_VOL_SHIFT 1 /* IN1L_PGA_VOL - [7:1] */
+#define WM5100_IN1L_PGA_VOL_WIDTH 7 /* IN1L_PGA_VOL - [7:1] */
+
+/*
+ * R785 (0x311) - IN1R Control
+ */
+#define WM5100_IN1R_PGA_VOL_MASK 0x00FE /* IN1R_PGA_VOL - [7:1] */
+#define WM5100_IN1R_PGA_VOL_SHIFT 1 /* IN1R_PGA_VOL - [7:1] */
+#define WM5100_IN1R_PGA_VOL_WIDTH 7 /* IN1R_PGA_VOL - [7:1] */
+
+/*
+ * R786 (0x312) - IN2L Control
+ */
+#define WM5100_IN2_OSR 0x2000 /* IN2_OSR */
+#define WM5100_IN2_OSR_MASK 0x2000 /* IN2_OSR */
+#define WM5100_IN2_OSR_SHIFT 13 /* IN2_OSR */
+#define WM5100_IN2_OSR_WIDTH 1 /* IN2_OSR */
+#define WM5100_IN2_DMIC_SUP_MASK 0x1800 /* IN2_DMIC_SUP - [12:11] */
+#define WM5100_IN2_DMIC_SUP_SHIFT 11 /* IN2_DMIC_SUP - [12:11] */
+#define WM5100_IN2_DMIC_SUP_WIDTH 2 /* IN2_DMIC_SUP - [12:11] */
+#define WM5100_IN2_MODE_MASK 0x0600 /* IN2_MODE - [10:9] */
+#define WM5100_IN2_MODE_SHIFT 9 /* IN2_MODE - [10:9] */
+#define WM5100_IN2_MODE_WIDTH 2 /* IN2_MODE - [10:9] */
+#define WM5100_IN2L_PGA_VOL_MASK 0x00FE /* IN2L_PGA_VOL - [7:1] */
+#define WM5100_IN2L_PGA_VOL_SHIFT 1 /* IN2L_PGA_VOL - [7:1] */
+#define WM5100_IN2L_PGA_VOL_WIDTH 7 /* IN2L_PGA_VOL - [7:1] */
+
+/*
+ * R787 (0x313) - IN2R Control
+ */
+#define WM5100_IN2R_PGA_VOL_MASK 0x00FE /* IN2R_PGA_VOL - [7:1] */
+#define WM5100_IN2R_PGA_VOL_SHIFT 1 /* IN2R_PGA_VOL - [7:1] */
+#define WM5100_IN2R_PGA_VOL_WIDTH 7 /* IN2R_PGA_VOL - [7:1] */
+
+/*
+ * R788 (0x314) - IN3L Control
+ */
+#define WM5100_IN3_OSR 0x2000 /* IN3_OSR */
+#define WM5100_IN3_OSR_MASK 0x2000 /* IN3_OSR */
+#define WM5100_IN3_OSR_SHIFT 13 /* IN3_OSR */
+#define WM5100_IN3_OSR_WIDTH 1 /* IN3_OSR */
+#define WM5100_IN3_DMIC_SUP_MASK 0x1800 /* IN3_DMIC_SUP - [12:11] */
+#define WM5100_IN3_DMIC_SUP_SHIFT 11 /* IN3_DMIC_SUP - [12:11] */
+#define WM5100_IN3_DMIC_SUP_WIDTH 2 /* IN3_DMIC_SUP - [12:11] */
+#define WM5100_IN3_MODE_MASK 0x0600 /* IN3_MODE - [10:9] */
+#define WM5100_IN3_MODE_SHIFT 9 /* IN3_MODE - [10:9] */
+#define WM5100_IN3_MODE_WIDTH 2 /* IN3_MODE - [10:9] */
+#define WM5100_IN3L_PGA_VOL_MASK 0x00FE /* IN3L_PGA_VOL - [7:1] */
+#define WM5100_IN3L_PGA_VOL_SHIFT 1 /* IN3L_PGA_VOL - [7:1] */
+#define WM5100_IN3L_PGA_VOL_WIDTH 7 /* IN3L_PGA_VOL - [7:1] */
+
+/*
+ * R789 (0x315) - IN3R Control
+ */
+#define WM5100_IN3R_PGA_VOL_MASK 0x00FE /* IN3R_PGA_VOL - [7:1] */
+#define WM5100_IN3R_PGA_VOL_SHIFT 1 /* IN3R_PGA_VOL - [7:1] */
+#define WM5100_IN3R_PGA_VOL_WIDTH 7 /* IN3R_PGA_VOL - [7:1] */
+
+/*
+ * R790 (0x316) - IN4L Control
+ */
+#define WM5100_IN4_OSR 0x2000 /* IN4_OSR */
+#define WM5100_IN4_OSR_MASK 0x2000 /* IN4_OSR */
+#define WM5100_IN4_OSR_SHIFT 13 /* IN4_OSR */
+#define WM5100_IN4_OSR_WIDTH 1 /* IN4_OSR */
+#define WM5100_IN4_DMIC_SUP_MASK 0x1800 /* IN4_DMIC_SUP - [12:11] */
+#define WM5100_IN4_DMIC_SUP_SHIFT 11 /* IN4_DMIC_SUP - [12:11] */
+#define WM5100_IN4_DMIC_SUP_WIDTH 2 /* IN4_DMIC_SUP - [12:11] */
+#define WM5100_IN4_MODE_MASK 0x0600 /* IN4_MODE - [10:9] */
+#define WM5100_IN4_MODE_SHIFT 9 /* IN4_MODE - [10:9] */
+#define WM5100_IN4_MODE_WIDTH 2 /* IN4_MODE - [10:9] */
+#define WM5100_IN4L_PGA_VOL_MASK 0x00FE /* IN4L_PGA_VOL - [7:1] */
+#define WM5100_IN4L_PGA_VOL_SHIFT 1 /* IN4L_PGA_VOL - [7:1] */
+#define WM5100_IN4L_PGA_VOL_WIDTH 7 /* IN4L_PGA_VOL - [7:1] */
+
+/*
+ * R791 (0x317) - IN4R Control
+ */
+#define WM5100_IN4R_PGA_VOL_MASK 0x00FE /* IN4R_PGA_VOL - [7:1] */
+#define WM5100_IN4R_PGA_VOL_SHIFT 1 /* IN4R_PGA_VOL - [7:1] */
+#define WM5100_IN4R_PGA_VOL_WIDTH 7 /* IN4R_PGA_VOL - [7:1] */
+
+/*
+ * R792 (0x318) - RXANC_SRC
+ */
+#define WM5100_IN_RXANC_SEL_MASK 0x0007 /* IN_RXANC_SEL - [2:0] */
+#define WM5100_IN_RXANC_SEL_SHIFT 0 /* IN_RXANC_SEL - [2:0] */
+#define WM5100_IN_RXANC_SEL_WIDTH 3 /* IN_RXANC_SEL - [2:0] */
+
+/*
+ * R793 (0x319) - Input Volume Ramp
+ */
+#define WM5100_IN_VD_RAMP_MASK 0x0070 /* IN_VD_RAMP - [6:4] */
+#define WM5100_IN_VD_RAMP_SHIFT 4 /* IN_VD_RAMP - [6:4] */
+#define WM5100_IN_VD_RAMP_WIDTH 3 /* IN_VD_RAMP - [6:4] */
+#define WM5100_IN_VI_RAMP_MASK 0x0007 /* IN_VI_RAMP - [2:0] */
+#define WM5100_IN_VI_RAMP_SHIFT 0 /* IN_VI_RAMP - [2:0] */
+#define WM5100_IN_VI_RAMP_WIDTH 3 /* IN_VI_RAMP - [2:0] */
+
+/*
+ * R800 (0x320) - ADC Digital Volume 1L
+ */
+#define WM5100_IN_VU 0x0200 /* IN_VU */
+#define WM5100_IN_VU_MASK 0x0200 /* IN_VU */
+#define WM5100_IN_VU_SHIFT 9 /* IN_VU */
+#define WM5100_IN_VU_WIDTH 1 /* IN_VU */
+#define WM5100_IN1L_MUTE 0x0100 /* IN1L_MUTE */
+#define WM5100_IN1L_MUTE_MASK 0x0100 /* IN1L_MUTE */
+#define WM5100_IN1L_MUTE_SHIFT 8 /* IN1L_MUTE */
+#define WM5100_IN1L_MUTE_WIDTH 1 /* IN1L_MUTE */
+#define WM5100_IN1L_VOL_MASK 0x00FF /* IN1L_VOL - [7:0] */
+#define WM5100_IN1L_VOL_SHIFT 0 /* IN1L_VOL - [7:0] */
+#define WM5100_IN1L_VOL_WIDTH 8 /* IN1L_VOL - [7:0] */
+
+/*
+ * R801 (0x321) - ADC Digital Volume 1R
+ */
+#define WM5100_IN_VU 0x0200 /* IN_VU */
+#define WM5100_IN_VU_MASK 0x0200 /* IN_VU */
+#define WM5100_IN_VU_SHIFT 9 /* IN_VU */
+#define WM5100_IN_VU_WIDTH 1 /* IN_VU */
+#define WM5100_IN1R_MUTE 0x0100 /* IN1R_MUTE */
+#define WM5100_IN1R_MUTE_MASK 0x0100 /* IN1R_MUTE */
+#define WM5100_IN1R_MUTE_SHIFT 8 /* IN1R_MUTE */
+#define WM5100_IN1R_MUTE_WIDTH 1 /* IN1R_MUTE */
+#define WM5100_IN1R_VOL_MASK 0x00FF /* IN1R_VOL - [7:0] */
+#define WM5100_IN1R_VOL_SHIFT 0 /* IN1R_VOL - [7:0] */
+#define WM5100_IN1R_VOL_WIDTH 8 /* IN1R_VOL - [7:0] */
+
+/*
+ * R802 (0x322) - ADC Digital Volume 2L
+ */
+#define WM5100_IN_VU 0x0200 /* IN_VU */
+#define WM5100_IN_VU_MASK 0x0200 /* IN_VU */
+#define WM5100_IN_VU_SHIFT 9 /* IN_VU */
+#define WM5100_IN_VU_WIDTH 1 /* IN_VU */
+#define WM5100_IN2L_MUTE 0x0100 /* IN2L_MUTE */
+#define WM5100_IN2L_MUTE_MASK 0x0100 /* IN2L_MUTE */
+#define WM5100_IN2L_MUTE_SHIFT 8 /* IN2L_MUTE */
+#define WM5100_IN2L_MUTE_WIDTH 1 /* IN2L_MUTE */
+#define WM5100_IN2L_VOL_MASK 0x00FF /* IN2L_VOL - [7:0] */
+#define WM5100_IN2L_VOL_SHIFT 0 /* IN2L_VOL - [7:0] */
+#define WM5100_IN2L_VOL_WIDTH 8 /* IN2L_VOL - [7:0] */
+
+/*
+ * R803 (0x323) - ADC Digital Volume 2R
+ */
+#define WM5100_IN_VU 0x0200 /* IN_VU */
+#define WM5100_IN_VU_MASK 0x0200 /* IN_VU */
+#define WM5100_IN_VU_SHIFT 9 /* IN_VU */
+#define WM5100_IN_VU_WIDTH 1 /* IN_VU */
+#define WM5100_IN2R_MUTE 0x0100 /* IN2R_MUTE */
+#define WM5100_IN2R_MUTE_MASK 0x0100 /* IN2R_MUTE */
+#define WM5100_IN2R_MUTE_SHIFT 8 /* IN2R_MUTE */
+#define WM5100_IN2R_MUTE_WIDTH 1 /* IN2R_MUTE */
+#define WM5100_IN2R_VOL_MASK 0x00FF /* IN2R_VOL - [7:0] */
+#define WM5100_IN2R_VOL_SHIFT 0 /* IN2R_VOL - [7:0] */
+#define WM5100_IN2R_VOL_WIDTH 8 /* IN2R_VOL - [7:0] */
+
+/*
+ * R804 (0x324) - ADC Digital Volume 3L
+ */
+#define WM5100_IN_VU 0x0200 /* IN_VU */
+#define WM5100_IN_VU_MASK 0x0200 /* IN_VU */
+#define WM5100_IN_VU_SHIFT 9 /* IN_VU */
+#define WM5100_IN_VU_WIDTH 1 /* IN_VU */
+#define WM5100_IN3L_MUTE 0x0100 /* IN3L_MUTE */
+#define WM5100_IN3L_MUTE_MASK 0x0100 /* IN3L_MUTE */
+#define WM5100_IN3L_MUTE_SHIFT 8 /* IN3L_MUTE */
+#define WM5100_IN3L_MUTE_WIDTH 1 /* IN3L_MUTE */
+#define WM5100_IN3L_VOL_MASK 0x00FF /* IN3L_VOL - [7:0] */
+#define WM5100_IN3L_VOL_SHIFT 0 /* IN3L_VOL - [7:0] */
+#define WM5100_IN3L_VOL_WIDTH 8 /* IN3L_VOL - [7:0] */
+
+/*
+ * R805 (0x325) - ADC Digital Volume 3R
+ */
+#define WM5100_IN_VU 0x0200 /* IN_VU */
+#define WM5100_IN_VU_MASK 0x0200 /* IN_VU */
+#define WM5100_IN_VU_SHIFT 9 /* IN_VU */
+#define WM5100_IN_VU_WIDTH 1 /* IN_VU */
+#define WM5100_IN3R_MUTE 0x0100 /* IN3R_MUTE */
+#define WM5100_IN3R_MUTE_MASK 0x0100 /* IN3R_MUTE */
+#define WM5100_IN3R_MUTE_SHIFT 8 /* IN3R_MUTE */
+#define WM5100_IN3R_MUTE_WIDTH 1 /* IN3R_MUTE */
+#define WM5100_IN3R_VOL_MASK 0x00FF /* IN3R_VOL - [7:0] */
+#define WM5100_IN3R_VOL_SHIFT 0 /* IN3R_VOL - [7:0] */
+#define WM5100_IN3R_VOL_WIDTH 8 /* IN3R_VOL - [7:0] */
+
+/*
+ * R806 (0x326) - ADC Digital Volume 4L
+ */
+#define WM5100_IN_VU 0x0200 /* IN_VU */
+#define WM5100_IN_VU_MASK 0x0200 /* IN_VU */
+#define WM5100_IN_VU_SHIFT 9 /* IN_VU */
+#define WM5100_IN_VU_WIDTH 1 /* IN_VU */
+#define WM5100_IN4L_MUTE 0x0100 /* IN4L_MUTE */
+#define WM5100_IN4L_MUTE_MASK 0x0100 /* IN4L_MUTE */
+#define WM5100_IN4L_MUTE_SHIFT 8 /* IN4L_MUTE */
+#define WM5100_IN4L_MUTE_WIDTH 1 /* IN4L_MUTE */
+#define WM5100_IN4L_VOL_MASK 0x00FF /* IN4L_VOL - [7:0] */
+#define WM5100_IN4L_VOL_SHIFT 0 /* IN4L_VOL - [7:0] */
+#define WM5100_IN4L_VOL_WIDTH 8 /* IN4L_VOL - [7:0] */
+
+/*
+ * R807 (0x327) - ADC Digital Volume 4R
+ */
+#define WM5100_IN_VU 0x0200 /* IN_VU */
+#define WM5100_IN_VU_MASK 0x0200 /* IN_VU */
+#define WM5100_IN_VU_SHIFT 9 /* IN_VU */
+#define WM5100_IN_VU_WIDTH 1 /* IN_VU */
+#define WM5100_IN4R_MUTE 0x0100 /* IN4R_MUTE */
+#define WM5100_IN4R_MUTE_MASK 0x0100 /* IN4R_MUTE */
+#define WM5100_IN4R_MUTE_SHIFT 8 /* IN4R_MUTE */
+#define WM5100_IN4R_MUTE_WIDTH 1 /* IN4R_MUTE */
+#define WM5100_IN4R_VOL_MASK 0x00FF /* IN4R_VOL - [7:0] */
+#define WM5100_IN4R_VOL_SHIFT 0 /* IN4R_VOL - [7:0] */
+#define WM5100_IN4R_VOL_WIDTH 8 /* IN4R_VOL - [7:0] */
+
+/*
+ * R1025 (0x401) - Output Enables 2
+ */
+#define WM5100_OUT6L_ENA 0x0800 /* OUT6L_ENA */
+#define WM5100_OUT6L_ENA_MASK 0x0800 /* OUT6L_ENA */
+#define WM5100_OUT6L_ENA_SHIFT 11 /* OUT6L_ENA */
+#define WM5100_OUT6L_ENA_WIDTH 1 /* OUT6L_ENA */
+#define WM5100_OUT6R_ENA 0x0400 /* OUT6R_ENA */
+#define WM5100_OUT6R_ENA_MASK 0x0400 /* OUT6R_ENA */
+#define WM5100_OUT6R_ENA_SHIFT 10 /* OUT6R_ENA */
+#define WM5100_OUT6R_ENA_WIDTH 1 /* OUT6R_ENA */
+#define WM5100_OUT5L_ENA 0x0200 /* OUT5L_ENA */
+#define WM5100_OUT5L_ENA_MASK 0x0200 /* OUT5L_ENA */
+#define WM5100_OUT5L_ENA_SHIFT 9 /* OUT5L_ENA */
+#define WM5100_OUT5L_ENA_WIDTH 1 /* OUT5L_ENA */
+#define WM5100_OUT5R_ENA 0x0100 /* OUT5R_ENA */
+#define WM5100_OUT5R_ENA_MASK 0x0100 /* OUT5R_ENA */
+#define WM5100_OUT5R_ENA_SHIFT 8 /* OUT5R_ENA */
+#define WM5100_OUT5R_ENA_WIDTH 1 /* OUT5R_ENA */
+#define WM5100_OUT4L_ENA 0x0080 /* OUT4L_ENA */
+#define WM5100_OUT4L_ENA_MASK 0x0080 /* OUT4L_ENA */
+#define WM5100_OUT4L_ENA_SHIFT 7 /* OUT4L_ENA */
+#define WM5100_OUT4L_ENA_WIDTH 1 /* OUT4L_ENA */
+#define WM5100_OUT4R_ENA 0x0040 /* OUT4R_ENA */
+#define WM5100_OUT4R_ENA_MASK 0x0040 /* OUT4R_ENA */
+#define WM5100_OUT4R_ENA_SHIFT 6 /* OUT4R_ENA */
+#define WM5100_OUT4R_ENA_WIDTH 1 /* OUT4R_ENA */
+
+/*
+ * R1026 (0x402) - Output Status 1
+ */
+#define WM5100_OUT3L_ENA_STS 0x0020 /* OUT3L_ENA_STS */
+#define WM5100_OUT3L_ENA_STS_MASK 0x0020 /* OUT3L_ENA_STS */
+#define WM5100_OUT3L_ENA_STS_SHIFT 5 /* OUT3L_ENA_STS */
+#define WM5100_OUT3L_ENA_STS_WIDTH 1 /* OUT3L_ENA_STS */
+#define WM5100_OUT3R_ENA_STS 0x0010 /* OUT3R_ENA_STS */
+#define WM5100_OUT3R_ENA_STS_MASK 0x0010 /* OUT3R_ENA_STS */
+#define WM5100_OUT3R_ENA_STS_SHIFT 4 /* OUT3R_ENA_STS */
+#define WM5100_OUT3R_ENA_STS_WIDTH 1 /* OUT3R_ENA_STS */
+#define WM5100_OUT2L_ENA_STS 0x0008 /* OUT2L_ENA_STS */
+#define WM5100_OUT2L_ENA_STS_MASK 0x0008 /* OUT2L_ENA_STS */
+#define WM5100_OUT2L_ENA_STS_SHIFT 3 /* OUT2L_ENA_STS */
+#define WM5100_OUT2L_ENA_STS_WIDTH 1 /* OUT2L_ENA_STS */
+#define WM5100_OUT2R_ENA_STS 0x0004 /* OUT2R_ENA_STS */
+#define WM5100_OUT2R_ENA_STS_MASK 0x0004 /* OUT2R_ENA_STS */
+#define WM5100_OUT2R_ENA_STS_SHIFT 2 /* OUT2R_ENA_STS */
+#define WM5100_OUT2R_ENA_STS_WIDTH 1 /* OUT2R_ENA_STS */
+#define WM5100_OUT1L_ENA_STS 0x0002 /* OUT1L_ENA_STS */
+#define WM5100_OUT1L_ENA_STS_MASK 0x0002 /* OUT1L_ENA_STS */
+#define WM5100_OUT1L_ENA_STS_SHIFT 1 /* OUT1L_ENA_STS */
+#define WM5100_OUT1L_ENA_STS_WIDTH 1 /* OUT1L_ENA_STS */
+#define WM5100_OUT1R_ENA_STS 0x0001 /* OUT1R_ENA_STS */
+#define WM5100_OUT1R_ENA_STS_MASK 0x0001 /* OUT1R_ENA_STS */
+#define WM5100_OUT1R_ENA_STS_SHIFT 0 /* OUT1R_ENA_STS */
+#define WM5100_OUT1R_ENA_STS_WIDTH 1 /* OUT1R_ENA_STS */
+
+/*
+ * R1027 (0x403) - Output Status 2
+ */
+#define WM5100_OUT6L_ENA_STS 0x0800 /* OUT6L_ENA_STS */
+#define WM5100_OUT6L_ENA_STS_MASK 0x0800 /* OUT6L_ENA_STS */
+#define WM5100_OUT6L_ENA_STS_SHIFT 11 /* OUT6L_ENA_STS */
+#define WM5100_OUT6L_ENA_STS_WIDTH 1 /* OUT6L_ENA_STS */
+#define WM5100_OUT6R_ENA_STS 0x0400 /* OUT6R_ENA_STS */
+#define WM5100_OUT6R_ENA_STS_MASK 0x0400 /* OUT6R_ENA_STS */
+#define WM5100_OUT6R_ENA_STS_SHIFT 10 /* OUT6R_ENA_STS */
+#define WM5100_OUT6R_ENA_STS_WIDTH 1 /* OUT6R_ENA_STS */
+#define WM5100_OUT5L_ENA_STS 0x0200 /* OUT5L_ENA_STS */
+#define WM5100_OUT5L_ENA_STS_MASK 0x0200 /* OUT5L_ENA_STS */
+#define WM5100_OUT5L_ENA_STS_SHIFT 9 /* OUT5L_ENA_STS */
+#define WM5100_OUT5L_ENA_STS_WIDTH 1 /* OUT5L_ENA_STS */
+#define WM5100_OUT5R_ENA_STS 0x0100 /* OUT5R_ENA_STS */
+#define WM5100_OUT5R_ENA_STS_MASK 0x0100 /* OUT5R_ENA_STS */
+#define WM5100_OUT5R_ENA_STS_SHIFT 8 /* OUT5R_ENA_STS */
+#define WM5100_OUT5R_ENA_STS_WIDTH 1 /* OUT5R_ENA_STS */
+#define WM5100_OUT4L_ENA_STS 0x0080 /* OUT4L_ENA_STS */
+#define WM5100_OUT4L_ENA_STS_MASK 0x0080 /* OUT4L_ENA_STS */
+#define WM5100_OUT4L_ENA_STS_SHIFT 7 /* OUT4L_ENA_STS */
+#define WM5100_OUT4L_ENA_STS_WIDTH 1 /* OUT4L_ENA_STS */
+#define WM5100_OUT4R_ENA_STS 0x0040 /* OUT4R_ENA_STS */
+#define WM5100_OUT4R_ENA_STS_MASK 0x0040 /* OUT4R_ENA_STS */
+#define WM5100_OUT4R_ENA_STS_SHIFT 6 /* OUT4R_ENA_STS */
+#define WM5100_OUT4R_ENA_STS_WIDTH 1 /* OUT4R_ENA_STS */
+
+/*
+ * R1032 (0x408) - Channel Enables 1
+ */
+#define WM5100_HP3L_ENA 0x0020 /* HP3L_ENA */
+#define WM5100_HP3L_ENA_MASK 0x0020 /* HP3L_ENA */
+#define WM5100_HP3L_ENA_SHIFT 5 /* HP3L_ENA */
+#define WM5100_HP3L_ENA_WIDTH 1 /* HP3L_ENA */
+#define WM5100_HP3R_ENA 0x0010 /* HP3R_ENA */
+#define WM5100_HP3R_ENA_MASK 0x0010 /* HP3R_ENA */
+#define WM5100_HP3R_ENA_SHIFT 4 /* HP3R_ENA */
+#define WM5100_HP3R_ENA_WIDTH 1 /* HP3R_ENA */
+#define WM5100_HP2L_ENA 0x0008 /* HP2L_ENA */
+#define WM5100_HP2L_ENA_MASK 0x0008 /* HP2L_ENA */
+#define WM5100_HP2L_ENA_SHIFT 3 /* HP2L_ENA */
+#define WM5100_HP2L_ENA_WIDTH 1 /* HP2L_ENA */
+#define WM5100_HP2R_ENA 0x0004 /* HP2R_ENA */
+#define WM5100_HP2R_ENA_MASK 0x0004 /* HP2R_ENA */
+#define WM5100_HP2R_ENA_SHIFT 2 /* HP2R_ENA */
+#define WM5100_HP2R_ENA_WIDTH 1 /* HP2R_ENA */
+#define WM5100_HP1L_ENA 0x0002 /* HP1L_ENA */
+#define WM5100_HP1L_ENA_MASK 0x0002 /* HP1L_ENA */
+#define WM5100_HP1L_ENA_SHIFT 1 /* HP1L_ENA */
+#define WM5100_HP1L_ENA_WIDTH 1 /* HP1L_ENA */
+#define WM5100_HP1R_ENA 0x0001 /* HP1R_ENA */
+#define WM5100_HP1R_ENA_MASK 0x0001 /* HP1R_ENA */
+#define WM5100_HP1R_ENA_SHIFT 0 /* HP1R_ENA */
+#define WM5100_HP1R_ENA_WIDTH 1 /* HP1R_ENA */
+
+/*
+ * R1040 (0x410) - Out Volume 1L
+ */
+#define WM5100_OUT_RATE_MASK 0xC000 /* OUT_RATE - [15:14] */
+#define WM5100_OUT_RATE_SHIFT 14 /* OUT_RATE - [15:14] */
+#define WM5100_OUT_RATE_WIDTH 2 /* OUT_RATE - [15:14] */
+#define WM5100_OUT1_OSR 0x2000 /* OUT1_OSR */
+#define WM5100_OUT1_OSR_MASK 0x2000 /* OUT1_OSR */
+#define WM5100_OUT1_OSR_SHIFT 13 /* OUT1_OSR */
+#define WM5100_OUT1_OSR_WIDTH 1 /* OUT1_OSR */
+#define WM5100_OUT1_MONO 0x1000 /* OUT1_MONO */
+#define WM5100_OUT1_MONO_MASK 0x1000 /* OUT1_MONO */
+#define WM5100_OUT1_MONO_SHIFT 12 /* OUT1_MONO */
+#define WM5100_OUT1_MONO_WIDTH 1 /* OUT1_MONO */
+#define WM5100_OUT1L_ANC_SRC 0x0800 /* OUT1L_ANC_SRC */
+#define WM5100_OUT1L_ANC_SRC_MASK 0x0800 /* OUT1L_ANC_SRC */
+#define WM5100_OUT1L_ANC_SRC_SHIFT 11 /* OUT1L_ANC_SRC */
+#define WM5100_OUT1L_ANC_SRC_WIDTH 1 /* OUT1L_ANC_SRC */
+#define WM5100_OUT1L_PGA_VOL_MASK 0x00FE /* OUT1L_PGA_VOL - [7:1] */
+#define WM5100_OUT1L_PGA_VOL_SHIFT 1 /* OUT1L_PGA_VOL - [7:1] */
+#define WM5100_OUT1L_PGA_VOL_WIDTH 7 /* OUT1L_PGA_VOL - [7:1] */
+
+/*
+ * R1041 (0x411) - Out Volume 1R
+ */
+#define WM5100_OUT1R_ANC_SRC 0x0800 /* OUT1R_ANC_SRC */
+#define WM5100_OUT1R_ANC_SRC_MASK 0x0800 /* OUT1R_ANC_SRC */
+#define WM5100_OUT1R_ANC_SRC_SHIFT 11 /* OUT1R_ANC_SRC */
+#define WM5100_OUT1R_ANC_SRC_WIDTH 1 /* OUT1R_ANC_SRC */
+#define WM5100_OUT1R_PGA_VOL_MASK 0x00FE /* OUT1R_PGA_VOL - [7:1] */
+#define WM5100_OUT1R_PGA_VOL_SHIFT 1 /* OUT1R_PGA_VOL - [7:1] */
+#define WM5100_OUT1R_PGA_VOL_WIDTH 7 /* OUT1R_PGA_VOL - [7:1] */
+
+/*
+ * R1042 (0x412) - DAC Volume Limit 1L
+ */
+#define WM5100_OUT1L_VOL_LIM_MASK 0x00FF /* OUT1L_VOL_LIM - [7:0] */
+#define WM5100_OUT1L_VOL_LIM_SHIFT 0 /* OUT1L_VOL_LIM - [7:0] */
+#define WM5100_OUT1L_VOL_LIM_WIDTH 8 /* OUT1L_VOL_LIM - [7:0] */
+
+/*
+ * R1043 (0x413) - DAC Volume Limit 1R
+ */
+#define WM5100_OUT1R_VOL_LIM_MASK 0x00FF /* OUT1R_VOL_LIM - [7:0] */
+#define WM5100_OUT1R_VOL_LIM_SHIFT 0 /* OUT1R_VOL_LIM - [7:0] */
+#define WM5100_OUT1R_VOL_LIM_WIDTH 8 /* OUT1R_VOL_LIM - [7:0] */
+
+/*
+ * R1044 (0x414) - Out Volume 2L
+ */
+#define WM5100_OUT2_OSR 0x2000 /* OUT2_OSR */
+#define WM5100_OUT2_OSR_MASK 0x2000 /* OUT2_OSR */
+#define WM5100_OUT2_OSR_SHIFT 13 /* OUT2_OSR */
+#define WM5100_OUT2_OSR_WIDTH 1 /* OUT2_OSR */
+#define WM5100_OUT2_MONO 0x1000 /* OUT2_MONO */
+#define WM5100_OUT2_MONO_MASK 0x1000 /* OUT2_MONO */
+#define WM5100_OUT2_MONO_SHIFT 12 /* OUT2_MONO */
+#define WM5100_OUT2_MONO_WIDTH 1 /* OUT2_MONO */
+#define WM5100_OUT2L_ANC_SRC 0x0800 /* OUT2L_ANC_SRC */
+#define WM5100_OUT2L_ANC_SRC_MASK 0x0800 /* OUT2L_ANC_SRC */
+#define WM5100_OUT2L_ANC_SRC_SHIFT 11 /* OUT2L_ANC_SRC */
+#define WM5100_OUT2L_ANC_SRC_WIDTH 1 /* OUT2L_ANC_SRC */
+#define WM5100_OUT2L_PGA_VOL_MASK 0x00FE /* OUT2L_PGA_VOL - [7:1] */
+#define WM5100_OUT2L_PGA_VOL_SHIFT 1 /* OUT2L_PGA_VOL - [7:1] */
+#define WM5100_OUT2L_PGA_VOL_WIDTH 7 /* OUT2L_PGA_VOL - [7:1] */
+
+/*
+ * R1045 (0x415) - Out Volume 2R
+ */
+#define WM5100_OUT2R_ANC_SRC 0x0800 /* OUT2R_ANC_SRC */
+#define WM5100_OUT2R_ANC_SRC_MASK 0x0800 /* OUT2R_ANC_SRC */
+#define WM5100_OUT2R_ANC_SRC_SHIFT 11 /* OUT2R_ANC_SRC */
+#define WM5100_OUT2R_ANC_SRC_WIDTH 1 /* OUT2R_ANC_SRC */
+#define WM5100_OUT2R_PGA_VOL_MASK 0x00FE /* OUT2R_PGA_VOL - [7:1] */
+#define WM5100_OUT2R_PGA_VOL_SHIFT 1 /* OUT2R_PGA_VOL - [7:1] */
+#define WM5100_OUT2R_PGA_VOL_WIDTH 7 /* OUT2R_PGA_VOL - [7:1] */
+
+/*
+ * R1046 (0x416) - DAC Volume Limit 2L
+ */
+#define WM5100_OUT2L_VOL_LIM_MASK 0x00FF /* OUT2L_VOL_LIM - [7:0] */
+#define WM5100_OUT2L_VOL_LIM_SHIFT 0 /* OUT2L_VOL_LIM - [7:0] */
+#define WM5100_OUT2L_VOL_LIM_WIDTH 8 /* OUT2L_VOL_LIM - [7:0] */
+
+/*
+ * R1047 (0x417) - DAC Volume Limit 2R
+ */
+#define WM5100_OUT2R_VOL_LIM_MASK 0x00FF /* OUT2R_VOL_LIM - [7:0] */
+#define WM5100_OUT2R_VOL_LIM_SHIFT 0 /* OUT2R_VOL_LIM - [7:0] */
+#define WM5100_OUT2R_VOL_LIM_WIDTH 8 /* OUT2R_VOL_LIM - [7:0] */
+
+/*
+ * R1048 (0x418) - Out Volume 3L
+ */
+#define WM5100_OUT3_OSR 0x2000 /* OUT3_OSR */
+#define WM5100_OUT3_OSR_MASK 0x2000 /* OUT3_OSR */
+#define WM5100_OUT3_OSR_SHIFT 13 /* OUT3_OSR */
+#define WM5100_OUT3_OSR_WIDTH 1 /* OUT3_OSR */
+#define WM5100_OUT3_MONO 0x1000 /* OUT3_MONO */
+#define WM5100_OUT3_MONO_MASK 0x1000 /* OUT3_MONO */
+#define WM5100_OUT3_MONO_SHIFT 12 /* OUT3_MONO */
+#define WM5100_OUT3_MONO_WIDTH 1 /* OUT3_MONO */
+#define WM5100_OUT3L_ANC_SRC 0x0800 /* OUT3L_ANC_SRC */
+#define WM5100_OUT3L_ANC_SRC_MASK 0x0800 /* OUT3L_ANC_SRC */
+#define WM5100_OUT3L_ANC_SRC_SHIFT 11 /* OUT3L_ANC_SRC */
+#define WM5100_OUT3L_ANC_SRC_WIDTH 1 /* OUT3L_ANC_SRC */
+#define WM5100_OUT3L_PGA_VOL_MASK 0x00FE /* OUT3L_PGA_VOL - [7:1] */
+#define WM5100_OUT3L_PGA_VOL_SHIFT 1 /* OUT3L_PGA_VOL - [7:1] */
+#define WM5100_OUT3L_PGA_VOL_WIDTH 7 /* OUT3L_PGA_VOL - [7:1] */
+
+/*
+ * R1049 (0x419) - Out Volume 3R
+ */
+#define WM5100_OUT3R_ANC_SRC 0x0800 /* OUT3R_ANC_SRC */
+#define WM5100_OUT3R_ANC_SRC_MASK 0x0800 /* OUT3R_ANC_SRC */
+#define WM5100_OUT3R_ANC_SRC_SHIFT 11 /* OUT3R_ANC_SRC */
+#define WM5100_OUT3R_ANC_SRC_WIDTH 1 /* OUT3R_ANC_SRC */
+#define WM5100_OUT3R_PGA_VOL_MASK 0x00FE /* OUT3R_PGA_VOL - [7:1] */
+#define WM5100_OUT3R_PGA_VOL_SHIFT 1 /* OUT3R_PGA_VOL - [7:1] */
+#define WM5100_OUT3R_PGA_VOL_WIDTH 7 /* OUT3R_PGA_VOL - [7:1] */
+
+/*
+ * R1050 (0x41A) - DAC Volume Limit 3L
+ */
+#define WM5100_OUT3L_VOL_LIM_MASK 0x00FF /* OUT3L_VOL_LIM - [7:0] */
+#define WM5100_OUT3L_VOL_LIM_SHIFT 0 /* OUT3L_VOL_LIM - [7:0] */
+#define WM5100_OUT3L_VOL_LIM_WIDTH 8 /* OUT3L_VOL_LIM - [7:0] */
+
+/*
+ * R1051 (0x41B) - DAC Volume Limit 3R
+ */
+#define WM5100_OUT3R_VOL_LIM_MASK 0x00FF /* OUT3R_VOL_LIM - [7:0] */
+#define WM5100_OUT3R_VOL_LIM_SHIFT 0 /* OUT3R_VOL_LIM - [7:0] */
+#define WM5100_OUT3R_VOL_LIM_WIDTH 8 /* OUT3R_VOL_LIM - [7:0] */
+
+/*
+ * R1052 (0x41C) - Out Volume 4L
+ */
+#define WM5100_OUT4_OSR 0x2000 /* OUT4_OSR */
+#define WM5100_OUT4_OSR_MASK 0x2000 /* OUT4_OSR */
+#define WM5100_OUT4_OSR_SHIFT 13 /* OUT4_OSR */
+#define WM5100_OUT4_OSR_WIDTH 1 /* OUT4_OSR */
+#define WM5100_OUT4L_ANC_SRC 0x0800 /* OUT4L_ANC_SRC */
+#define WM5100_OUT4L_ANC_SRC_MASK 0x0800 /* OUT4L_ANC_SRC */
+#define WM5100_OUT4L_ANC_SRC_SHIFT 11 /* OUT4L_ANC_SRC */
+#define WM5100_OUT4L_ANC_SRC_WIDTH 1 /* OUT4L_ANC_SRC */
+#define WM5100_OUT4L_VOL_LIM_MASK 0x00FF /* OUT4L_VOL_LIM - [7:0] */
+#define WM5100_OUT4L_VOL_LIM_SHIFT 0 /* OUT4L_VOL_LIM - [7:0] */
+#define WM5100_OUT4L_VOL_LIM_WIDTH 8 /* OUT4L_VOL_LIM - [7:0] */
+
+/*
+ * R1053 (0x41D) - Out Volume 4R
+ */
+#define WM5100_OUT4R_ANC_SRC 0x0800 /* OUT4R_ANC_SRC */
+#define WM5100_OUT4R_ANC_SRC_MASK 0x0800 /* OUT4R_ANC_SRC */
+#define WM5100_OUT4R_ANC_SRC_SHIFT 11 /* OUT4R_ANC_SRC */
+#define WM5100_OUT4R_ANC_SRC_WIDTH 1 /* OUT4R_ANC_SRC */
+#define WM5100_OUT4R_VOL_LIM_MASK 0x00FF /* OUT4R_VOL_LIM - [7:0] */
+#define WM5100_OUT4R_VOL_LIM_SHIFT 0 /* OUT4R_VOL_LIM - [7:0] */
+#define WM5100_OUT4R_VOL_LIM_WIDTH 8 /* OUT4R_VOL_LIM - [7:0] */
+
+/*
+ * R1054 (0x41E) - DAC Volume Limit 5L
+ */
+#define WM5100_OUT5_OSR 0x2000 /* OUT5_OSR */
+#define WM5100_OUT5_OSR_MASK 0x2000 /* OUT5_OSR */
+#define WM5100_OUT5_OSR_SHIFT 13 /* OUT5_OSR */
+#define WM5100_OUT5_OSR_WIDTH 1 /* OUT5_OSR */
+#define WM5100_OUT5L_ANC_SRC 0x0800 /* OUT5L_ANC_SRC */
+#define WM5100_OUT5L_ANC_SRC_MASK 0x0800 /* OUT5L_ANC_SRC */
+#define WM5100_OUT5L_ANC_SRC_SHIFT 11 /* OUT5L_ANC_SRC */
+#define WM5100_OUT5L_ANC_SRC_WIDTH 1 /* OUT5L_ANC_SRC */
+#define WM5100_OUT5L_VOL_LIM_MASK 0x00FF /* OUT5L_VOL_LIM - [7:0] */
+#define WM5100_OUT5L_VOL_LIM_SHIFT 0 /* OUT5L_VOL_LIM - [7:0] */
+#define WM5100_OUT5L_VOL_LIM_WIDTH 8 /* OUT5L_VOL_LIM - [7:0] */
+
+/*
+ * R1055 (0x41F) - DAC Volume Limit 5R
+ */
+#define WM5100_OUT5R_ANC_SRC 0x0800 /* OUT5R_ANC_SRC */
+#define WM5100_OUT5R_ANC_SRC_MASK 0x0800 /* OUT5R_ANC_SRC */
+#define WM5100_OUT5R_ANC_SRC_SHIFT 11 /* OUT5R_ANC_SRC */
+#define WM5100_OUT5R_ANC_SRC_WIDTH 1 /* OUT5R_ANC_SRC */
+#define WM5100_OUT5R_VOL_LIM_MASK 0x00FF /* OUT5R_VOL_LIM - [7:0] */
+#define WM5100_OUT5R_VOL_LIM_SHIFT 0 /* OUT5R_VOL_LIM - [7:0] */
+#define WM5100_OUT5R_VOL_LIM_WIDTH 8 /* OUT5R_VOL_LIM - [7:0] */
+
+/*
+ * R1056 (0x420) - DAC Volume Limit 6L
+ */
+#define WM5100_OUT6_OSR 0x2000 /* OUT6_OSR */
+#define WM5100_OUT6_OSR_MASK 0x2000 /* OUT6_OSR */
+#define WM5100_OUT6_OSR_SHIFT 13 /* OUT6_OSR */
+#define WM5100_OUT6_OSR_WIDTH 1 /* OUT6_OSR */
+#define WM5100_OUT6L_ANC_SRC 0x0800 /* OUT6L_ANC_SRC */
+#define WM5100_OUT6L_ANC_SRC_MASK 0x0800 /* OUT6L_ANC_SRC */
+#define WM5100_OUT6L_ANC_SRC_SHIFT 11 /* OUT6L_ANC_SRC */
+#define WM5100_OUT6L_ANC_SRC_WIDTH 1 /* OUT6L_ANC_SRC */
+#define WM5100_OUT6L_VOL_LIM_MASK 0x00FF /* OUT6L_VOL_LIM - [7:0] */
+#define WM5100_OUT6L_VOL_LIM_SHIFT 0 /* OUT6L_VOL_LIM - [7:0] */
+#define WM5100_OUT6L_VOL_LIM_WIDTH 8 /* OUT6L_VOL_LIM - [7:0] */
+
+/*
+ * R1057 (0x421) - DAC Volume Limit 6R
+ */
+#define WM5100_OUT6R_ANC_SRC 0x0800 /* OUT6R_ANC_SRC */
+#define WM5100_OUT6R_ANC_SRC_MASK 0x0800 /* OUT6R_ANC_SRC */
+#define WM5100_OUT6R_ANC_SRC_SHIFT 11 /* OUT6R_ANC_SRC */
+#define WM5100_OUT6R_ANC_SRC_WIDTH 1 /* OUT6R_ANC_SRC */
+#define WM5100_OUT6R_VOL_LIM_MASK 0x00FF /* OUT6R_VOL_LIM - [7:0] */
+#define WM5100_OUT6R_VOL_LIM_SHIFT 0 /* OUT6R_VOL_LIM - [7:0] */
+#define WM5100_OUT6R_VOL_LIM_WIDTH 8 /* OUT6R_VOL_LIM - [7:0] */
+
+/*
+ * R1088 (0x440) - DAC AEC Control 1
+ */
+#define WM5100_AEC_LOOPBACK_SRC_MASK 0x003C /* AEC_LOOPBACK_SRC - [5:2] */
+#define WM5100_AEC_LOOPBACK_SRC_SHIFT 2 /* AEC_LOOPBACK_SRC - [5:2] */
+#define WM5100_AEC_LOOPBACK_SRC_WIDTH 4 /* AEC_LOOPBACK_SRC - [5:2] */
+#define WM5100_AEC_ENA_STS 0x0002 /* AEC_ENA_STS */
+#define WM5100_AEC_ENA_STS_MASK 0x0002 /* AEC_ENA_STS */
+#define WM5100_AEC_ENA_STS_SHIFT 1 /* AEC_ENA_STS */
+#define WM5100_AEC_ENA_STS_WIDTH 1 /* AEC_ENA_STS */
+#define WM5100_AEC_LOOPBACK_ENA 0x0001 /* AEC_LOOPBACK_ENA */
+#define WM5100_AEC_LOOPBACK_ENA_MASK 0x0001 /* AEC_LOOPBACK_ENA */
+#define WM5100_AEC_LOOPBACK_ENA_SHIFT 0 /* AEC_LOOPBACK_ENA */
+#define WM5100_AEC_LOOPBACK_ENA_WIDTH 1 /* AEC_LOOPBACK_ENA */
+
+/*
+ * R1089 (0x441) - Output Volume Ramp
+ */
+#define WM5100_OUT_VD_RAMP_MASK 0x0070 /* OUT_VD_RAMP - [6:4] */
+#define WM5100_OUT_VD_RAMP_SHIFT 4 /* OUT_VD_RAMP - [6:4] */
+#define WM5100_OUT_VD_RAMP_WIDTH 3 /* OUT_VD_RAMP - [6:4] */
+#define WM5100_OUT_VI_RAMP_MASK 0x0007 /* OUT_VI_RAMP - [2:0] */
+#define WM5100_OUT_VI_RAMP_SHIFT 0 /* OUT_VI_RAMP - [2:0] */
+#define WM5100_OUT_VI_RAMP_WIDTH 3 /* OUT_VI_RAMP - [2:0] */
+
+/*
+ * R1152 (0x480) - DAC Digital Volume 1L
+ */
+#define WM5100_OUT_VU 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_MASK 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT 9 /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH 1 /* OUT_VU */
+#define WM5100_OUT1L_MUTE 0x0100 /* OUT1L_MUTE */
+#define WM5100_OUT1L_MUTE_MASK 0x0100 /* OUT1L_MUTE */
+#define WM5100_OUT1L_MUTE_SHIFT 8 /* OUT1L_MUTE */
+#define WM5100_OUT1L_MUTE_WIDTH 1 /* OUT1L_MUTE */
+#define WM5100_OUT1L_VOL_MASK 0x00FF /* OUT1L_VOL - [7:0] */
+#define WM5100_OUT1L_VOL_SHIFT 0 /* OUT1L_VOL - [7:0] */
+#define WM5100_OUT1L_VOL_WIDTH 8 /* OUT1L_VOL - [7:0] */
+
+/*
+ * R1153 (0x481) - DAC Digital Volume 1R
+ */
+#define WM5100_OUT_VU 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_MASK 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT 9 /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH 1 /* OUT_VU */
+#define WM5100_OUT1R_MUTE 0x0100 /* OUT1R_MUTE */
+#define WM5100_OUT1R_MUTE_MASK 0x0100 /* OUT1R_MUTE */
+#define WM5100_OUT1R_MUTE_SHIFT 8 /* OUT1R_MUTE */
+#define WM5100_OUT1R_MUTE_WIDTH 1 /* OUT1R_MUTE */
+#define WM5100_OUT1R_VOL_MASK 0x00FF /* OUT1R_VOL - [7:0] */
+#define WM5100_OUT1R_VOL_SHIFT 0 /* OUT1R_VOL - [7:0] */
+#define WM5100_OUT1R_VOL_WIDTH 8 /* OUT1R_VOL - [7:0] */
+
+/*
+ * R1154 (0x482) - DAC Digital Volume 2L
+ */
+#define WM5100_OUT_VU 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_MASK 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT 9 /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH 1 /* OUT_VU */
+#define WM5100_OUT2L_MUTE 0x0100 /* OUT2L_MUTE */
+#define WM5100_OUT2L_MUTE_MASK 0x0100 /* OUT2L_MUTE */
+#define WM5100_OUT2L_MUTE_SHIFT 8 /* OUT2L_MUTE */
+#define WM5100_OUT2L_MUTE_WIDTH 1 /* OUT2L_MUTE */
+#define WM5100_OUT2L_VOL_MASK 0x00FF /* OUT2L_VOL - [7:0] */
+#define WM5100_OUT2L_VOL_SHIFT 0 /* OUT2L_VOL - [7:0] */
+#define WM5100_OUT2L_VOL_WIDTH 8 /* OUT2L_VOL - [7:0] */
+
+/*
+ * R1155 (0x483) - DAC Digital Volume 2R
+ */
+#define WM5100_OUT_VU 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_MASK 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT 9 /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH 1 /* OUT_VU */
+#define WM5100_OUT2R_MUTE 0x0100 /* OUT2R_MUTE */
+#define WM5100_OUT2R_MUTE_MASK 0x0100 /* OUT2R_MUTE */
+#define WM5100_OUT2R_MUTE_SHIFT 8 /* OUT2R_MUTE */
+#define WM5100_OUT2R_MUTE_WIDTH 1 /* OUT2R_MUTE */
+#define WM5100_OUT2R_VOL_MASK 0x00FF /* OUT2R_VOL - [7:0] */
+#define WM5100_OUT2R_VOL_SHIFT 0 /* OUT2R_VOL - [7:0] */
+#define WM5100_OUT2R_VOL_WIDTH 8 /* OUT2R_VOL - [7:0] */
+
+/*
+ * R1156 (0x484) - DAC Digital Volume 3L
+ */
+#define WM5100_OUT_VU 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_MASK 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT 9 /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH 1 /* OUT_VU */
+#define WM5100_OUT3L_MUTE 0x0100 /* OUT3L_MUTE */
+#define WM5100_OUT3L_MUTE_MASK 0x0100 /* OUT3L_MUTE */
+#define WM5100_OUT3L_MUTE_SHIFT 8 /* OUT3L_MUTE */
+#define WM5100_OUT3L_MUTE_WIDTH 1 /* OUT3L_MUTE */
+#define WM5100_OUT3L_VOL_MASK 0x00FF /* OUT3L_VOL - [7:0] */
+#define WM5100_OUT3L_VOL_SHIFT 0 /* OUT3L_VOL - [7:0] */
+#define WM5100_OUT3L_VOL_WIDTH 8 /* OUT3L_VOL - [7:0] */
+
+/*
+ * R1157 (0x485) - DAC Digital Volume 3R
+ */
+#define WM5100_OUT_VU 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_MASK 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT 9 /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH 1 /* OUT_VU */
+#define WM5100_OUT3R_MUTE 0x0100 /* OUT3R_MUTE */
+#define WM5100_OUT3R_MUTE_MASK 0x0100 /* OUT3R_MUTE */
+#define WM5100_OUT3R_MUTE_SHIFT 8 /* OUT3R_MUTE */
+#define WM5100_OUT3R_MUTE_WIDTH 1 /* OUT3R_MUTE */
+#define WM5100_OUT3R_VOL_MASK 0x00FF /* OUT3R_VOL - [7:0] */
+#define WM5100_OUT3R_VOL_SHIFT 0 /* OUT3R_VOL - [7:0] */
+#define WM5100_OUT3R_VOL_WIDTH 8 /* OUT3R_VOL - [7:0] */
+
+/*
+ * R1158 (0x486) - DAC Digital Volume 4L
+ */
+#define WM5100_OUT_VU 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_MASK 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT 9 /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH 1 /* OUT_VU */
+#define WM5100_OUT4L_MUTE 0x0100 /* OUT4L_MUTE */
+#define WM5100_OUT4L_MUTE_MASK 0x0100 /* OUT4L_MUTE */
+#define WM5100_OUT4L_MUTE_SHIFT 8 /* OUT4L_MUTE */
+#define WM5100_OUT4L_MUTE_WIDTH 1 /* OUT4L_MUTE */
+#define WM5100_OUT4L_VOL_MASK 0x00FF /* OUT4L_VOL - [7:0] */
+#define WM5100_OUT4L_VOL_SHIFT 0 /* OUT4L_VOL - [7:0] */
+#define WM5100_OUT4L_VOL_WIDTH 8 /* OUT4L_VOL - [7:0] */
+
+/*
+ * R1159 (0x487) - DAC Digital Volume 4R
+ */
+#define WM5100_OUT_VU 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_MASK 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT 9 /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH 1 /* OUT_VU */
+#define WM5100_OUT4R_MUTE 0x0100 /* OUT4R_MUTE */
+#define WM5100_OUT4R_MUTE_MASK 0x0100 /* OUT4R_MUTE */
+#define WM5100_OUT4R_MUTE_SHIFT 8 /* OUT4R_MUTE */
+#define WM5100_OUT4R_MUTE_WIDTH 1 /* OUT4R_MUTE */
+#define WM5100_OUT4R_VOL_MASK 0x00FF /* OUT4R_VOL - [7:0] */
+#define WM5100_OUT4R_VOL_SHIFT 0 /* OUT4R_VOL - [7:0] */
+#define WM5100_OUT4R_VOL_WIDTH 8 /* OUT4R_VOL - [7:0] */
+
+/*
+ * R1160 (0x488) - DAC Digital Volume 5L
+ */
+#define WM5100_OUT_VU 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_MASK 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT 9 /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH 1 /* OUT_VU */
+#define WM5100_OUT5L_MUTE 0x0100 /* OUT5L_MUTE */
+#define WM5100_OUT5L_MUTE_MASK 0x0100 /* OUT5L_MUTE */
+#define WM5100_OUT5L_MUTE_SHIFT 8 /* OUT5L_MUTE */
+#define WM5100_OUT5L_MUTE_WIDTH 1 /* OUT5L_MUTE */
+#define WM5100_OUT5L_VOL_MASK 0x00FF /* OUT5L_VOL - [7:0] */
+#define WM5100_OUT5L_VOL_SHIFT 0 /* OUT5L_VOL - [7:0] */
+#define WM5100_OUT5L_VOL_WIDTH 8 /* OUT5L_VOL - [7:0] */
+
+/*
+ * R1161 (0x489) - DAC Digital Volume 5R
+ */
+#define WM5100_OUT_VU 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_MASK 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT 9 /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH 1 /* OUT_VU */
+#define WM5100_OUT5R_MUTE 0x0100 /* OUT5R_MUTE */
+#define WM5100_OUT5R_MUTE_MASK 0x0100 /* OUT5R_MUTE */
+#define WM5100_OUT5R_MUTE_SHIFT 8 /* OUT5R_MUTE */
+#define WM5100_OUT5R_MUTE_WIDTH 1 /* OUT5R_MUTE */
+#define WM5100_OUT5R_VOL_MASK 0x00FF /* OUT5R_VOL - [7:0] */
+#define WM5100_OUT5R_VOL_SHIFT 0 /* OUT5R_VOL - [7:0] */
+#define WM5100_OUT5R_VOL_WIDTH 8 /* OUT5R_VOL - [7:0] */
+
+/*
+ * R1162 (0x48A) - DAC Digital Volume 6L
+ */
+#define WM5100_OUT_VU 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_MASK 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT 9 /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH 1 /* OUT_VU */
+#define WM5100_OUT6L_MUTE 0x0100 /* OUT6L_MUTE */
+#define WM5100_OUT6L_MUTE_MASK 0x0100 /* OUT6L_MUTE */
+#define WM5100_OUT6L_MUTE_SHIFT 8 /* OUT6L_MUTE */
+#define WM5100_OUT6L_MUTE_WIDTH 1 /* OUT6L_MUTE */
+#define WM5100_OUT6L_VOL_MASK 0x00FF /* OUT6L_VOL - [7:0] */
+#define WM5100_OUT6L_VOL_SHIFT 0 /* OUT6L_VOL - [7:0] */
+#define WM5100_OUT6L_VOL_WIDTH 8 /* OUT6L_VOL - [7:0] */
+
+/*
+ * R1163 (0x48B) - DAC Digital Volume 6R
+ */
+#define WM5100_OUT_VU 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_MASK 0x0200 /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT 9 /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH 1 /* OUT_VU */
+#define WM5100_OUT6R_MUTE 0x0100 /* OUT6R_MUTE */
+#define WM5100_OUT6R_MUTE_MASK 0x0100 /* OUT6R_MUTE */
+#define WM5100_OUT6R_MUTE_SHIFT 8 /* OUT6R_MUTE */
+#define WM5100_OUT6R_MUTE_WIDTH 1 /* OUT6R_MUTE */
+#define WM5100_OUT6R_VOL_MASK 0x00FF /* OUT6R_VOL - [7:0] */
+#define WM5100_OUT6R_VOL_SHIFT 0 /* OUT6R_VOL - [7:0] */
+#define WM5100_OUT6R_VOL_WIDTH 8 /* OUT6R_VOL - [7:0] */
+
+/*
+ * R1216 (0x4C0) - PDM SPK1 CTRL 1
+ */
+#define WM5100_SPK1R_MUTE 0x2000 /* SPK1R_MUTE */
+#define WM5100_SPK1R_MUTE_MASK 0x2000 /* SPK1R_MUTE */
+#define WM5100_SPK1R_MUTE_SHIFT 13 /* SPK1R_MUTE */
+#define WM5100_SPK1R_MUTE_WIDTH 1 /* SPK1R_MUTE */
+#define WM5100_SPK1L_MUTE 0x1000 /* SPK1L_MUTE */
+#define WM5100_SPK1L_MUTE_MASK 0x1000 /* SPK1L_MUTE */
+#define WM5100_SPK1L_MUTE_SHIFT 12 /* SPK1L_MUTE */
+#define WM5100_SPK1L_MUTE_WIDTH 1 /* SPK1L_MUTE */
+#define WM5100_SPK1_MUTE_ENDIAN 0x0100 /* SPK1_MUTE_ENDIAN */
+#define WM5100_SPK1_MUTE_ENDIAN_MASK 0x0100 /* SPK1_MUTE_ENDIAN */
+#define WM5100_SPK1_MUTE_ENDIAN_SHIFT 8 /* SPK1_MUTE_ENDIAN */
+#define WM5100_SPK1_MUTE_ENDIAN_WIDTH 1 /* SPK1_MUTE_ENDIAN */
+#define WM5100_SPK1_MUTE_SEQ1_MASK 0x00FF /* SPK1_MUTE_SEQ1 - [7:0] */
+#define WM5100_SPK1_MUTE_SEQ1_SHIFT 0 /* SPK1_MUTE_SEQ1 - [7:0] */
+#define WM5100_SPK1_MUTE_SEQ1_WIDTH 8 /* SPK1_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R1217 (0x4C1) - PDM SPK1 CTRL 2
+ */
+#define WM5100_SPK1_FMT 0x0001 /* SPK1_FMT */
+#define WM5100_SPK1_FMT_MASK 0x0001 /* SPK1_FMT */
+#define WM5100_SPK1_FMT_SHIFT 0 /* SPK1_FMT */
+#define WM5100_SPK1_FMT_WIDTH 1 /* SPK1_FMT */
+
+/*
+ * R1218 (0x4C2) - PDM SPK2 CTRL 1
+ */
+#define WM5100_SPK2R_MUTE 0x2000 /* SPK2R_MUTE */
+#define WM5100_SPK2R_MUTE_MASK 0x2000 /* SPK2R_MUTE */
+#define WM5100_SPK2R_MUTE_SHIFT 13 /* SPK2R_MUTE */
+#define WM5100_SPK2R_MUTE_WIDTH 1 /* SPK2R_MUTE */
+#define WM5100_SPK2L_MUTE 0x1000 /* SPK2L_MUTE */
+#define WM5100_SPK2L_MUTE_MASK 0x1000 /* SPK2L_MUTE */
+#define WM5100_SPK2L_MUTE_SHIFT 12 /* SPK2L_MUTE */
+#define WM5100_SPK2L_MUTE_WIDTH 1 /* SPK2L_MUTE */
+#define WM5100_SPK2_MUTE_ENDIAN 0x0100 /* SPK2_MUTE_ENDIAN */
+#define WM5100_SPK2_MUTE_ENDIAN_MASK 0x0100 /* SPK2_MUTE_ENDIAN */
+#define WM5100_SPK2_MUTE_ENDIAN_SHIFT 8 /* SPK2_MUTE_ENDIAN */
+#define WM5100_SPK2_MUTE_ENDIAN_WIDTH 1 /* SPK2_MUTE_ENDIAN */
+#define WM5100_SPK2_MUTE_SEQ1_MASK 0x00FF /* SPK2_MUTE_SEQ1 - [7:0] */
+#define WM5100_SPK2_MUTE_SEQ1_SHIFT 0 /* SPK2_MUTE_SEQ1 - [7:0] */
+#define WM5100_SPK2_MUTE_SEQ1_WIDTH 8 /* SPK2_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R1219 (0x4C3) - PDM SPK2 CTRL 2
+ */
+#define WM5100_SPK2_FMT 0x0001 /* SPK2_FMT */
+#define WM5100_SPK2_FMT_MASK 0x0001 /* SPK2_FMT */
+#define WM5100_SPK2_FMT_SHIFT 0 /* SPK2_FMT */
+#define WM5100_SPK2_FMT_WIDTH 1 /* SPK2_FMT */
+
+/*
+ * R1280 (0x500) - Audio IF 1_1
+ */
+#define WM5100_AIF1_BCLK_INV 0x0080 /* AIF1_BCLK_INV */
+#define WM5100_AIF1_BCLK_INV_MASK 0x0080 /* AIF1_BCLK_INV */
+#define WM5100_AIF1_BCLK_INV_SHIFT 7 /* AIF1_BCLK_INV */
+#define WM5100_AIF1_BCLK_INV_WIDTH 1 /* AIF1_BCLK_INV */
+#define WM5100_AIF1_BCLK_FRC 0x0040 /* AIF1_BCLK_FRC */
+#define WM5100_AIF1_BCLK_FRC_MASK 0x0040 /* AIF1_BCLK_FRC */
+#define WM5100_AIF1_BCLK_FRC_SHIFT 6 /* AIF1_BCLK_FRC */
+#define WM5100_AIF1_BCLK_FRC_WIDTH 1 /* AIF1_BCLK_FRC */
+#define WM5100_AIF1_BCLK_MSTR 0x0020 /* AIF1_BCLK_MSTR */
+#define WM5100_AIF1_BCLK_MSTR_MASK 0x0020 /* AIF1_BCLK_MSTR */
+#define WM5100_AIF1_BCLK_MSTR_SHIFT 5 /* AIF1_BCLK_MSTR */
+#define WM5100_AIF1_BCLK_MSTR_WIDTH 1 /* AIF1_BCLK_MSTR */
+#define WM5100_AIF1_BCLK_FREQ_MASK 0x001F /* AIF1_BCLK_FREQ - [4:0] */
+#define WM5100_AIF1_BCLK_FREQ_SHIFT 0 /* AIF1_BCLK_FREQ - [4:0] */
+#define WM5100_AIF1_BCLK_FREQ_WIDTH 5 /* AIF1_BCLK_FREQ - [4:0] */
+
+/*
+ * R1281 (0x501) - Audio IF 1_2
+ */
+#define WM5100_AIF1TX_DAT_TRI 0x0020 /* AIF1TX_DAT_TRI */
+#define WM5100_AIF1TX_DAT_TRI_MASK 0x0020 /* AIF1TX_DAT_TRI */
+#define WM5100_AIF1TX_DAT_TRI_SHIFT 5 /* AIF1TX_DAT_TRI */
+#define WM5100_AIF1TX_DAT_TRI_WIDTH 1 /* AIF1TX_DAT_TRI */
+#define WM5100_AIF1TX_LRCLK_SRC 0x0008 /* AIF1TX_LRCLK_SRC */
+#define WM5100_AIF1TX_LRCLK_SRC_MASK 0x0008 /* AIF1TX_LRCLK_SRC */
+#define WM5100_AIF1TX_LRCLK_SRC_SHIFT 3 /* AIF1TX_LRCLK_SRC */
+#define WM5100_AIF1TX_LRCLK_SRC_WIDTH 1 /* AIF1TX_LRCLK_SRC */
+#define WM5100_AIF1TX_LRCLK_INV 0x0004 /* AIF1TX_LRCLK_INV */
+#define WM5100_AIF1TX_LRCLK_INV_MASK 0x0004 /* AIF1TX_LRCLK_INV */
+#define WM5100_AIF1TX_LRCLK_INV_SHIFT 2 /* AIF1TX_LRCLK_INV */
+#define WM5100_AIF1TX_LRCLK_INV_WIDTH 1 /* AIF1TX_LRCLK_INV */
+#define WM5100_AIF1TX_LRCLK_FRC 0x0002 /* AIF1TX_LRCLK_FRC */
+#define WM5100_AIF1TX_LRCLK_FRC_MASK 0x0002 /* AIF1TX_LRCLK_FRC */
+#define WM5100_AIF1TX_LRCLK_FRC_SHIFT 1 /* AIF1TX_LRCLK_FRC */
+#define WM5100_AIF1TX_LRCLK_FRC_WIDTH 1 /* AIF1TX_LRCLK_FRC */
+#define WM5100_AIF1TX_LRCLK_MSTR 0x0001 /* AIF1TX_LRCLK_MSTR */
+#define WM5100_AIF1TX_LRCLK_MSTR_MASK 0x0001 /* AIF1TX_LRCLK_MSTR */
+#define WM5100_AIF1TX_LRCLK_MSTR_SHIFT 0 /* AIF1TX_LRCLK_MSTR */
+#define WM5100_AIF1TX_LRCLK_MSTR_WIDTH 1 /* AIF1TX_LRCLK_MSTR */
+
+/*
+ * R1282 (0x502) - Audio IF 1_3
+ */
+#define WM5100_AIF1RX_LRCLK_INV 0x0004 /* AIF1RX_LRCLK_INV */
+#define WM5100_AIF1RX_LRCLK_INV_MASK 0x0004 /* AIF1RX_LRCLK_INV */
+#define WM5100_AIF1RX_LRCLK_INV_SHIFT 2 /* AIF1RX_LRCLK_INV */
+#define WM5100_AIF1RX_LRCLK_INV_WIDTH 1 /* AIF1RX_LRCLK_INV */
+#define WM5100_AIF1RX_LRCLK_FRC 0x0002 /* AIF1RX_LRCLK_FRC */
+#define WM5100_AIF1RX_LRCLK_FRC_MASK 0x0002 /* AIF1RX_LRCLK_FRC */
+#define WM5100_AIF1RX_LRCLK_FRC_SHIFT 1 /* AIF1RX_LRCLK_FRC */
+#define WM5100_AIF1RX_LRCLK_FRC_WIDTH 1 /* AIF1RX_LRCLK_FRC */
+#define WM5100_AIF1RX_LRCLK_MSTR 0x0001 /* AIF1RX_LRCLK_MSTR */
+#define WM5100_AIF1RX_LRCLK_MSTR_MASK 0x0001 /* AIF1RX_LRCLK_MSTR */
+#define WM5100_AIF1RX_LRCLK_MSTR_SHIFT 0 /* AIF1RX_LRCLK_MSTR */
+#define WM5100_AIF1RX_LRCLK_MSTR_WIDTH 1 /* AIF1RX_LRCLK_MSTR */
+
+/*
+ * R1283 (0x503) - Audio IF 1_4
+ */
+#define WM5100_AIF1_TRI 0x0040 /* AIF1_TRI */
+#define WM5100_AIF1_TRI_MASK 0x0040 /* AIF1_TRI */
+#define WM5100_AIF1_TRI_SHIFT 6 /* AIF1_TRI */
+#define WM5100_AIF1_TRI_WIDTH 1 /* AIF1_TRI */
+#define WM5100_AIF1_RATE_MASK 0x0003 /* AIF1_RATE - [1:0] */
+#define WM5100_AIF1_RATE_SHIFT 0 /* AIF1_RATE - [1:0] */
+#define WM5100_AIF1_RATE_WIDTH 2 /* AIF1_RATE - [1:0] */
+
+/*
+ * R1284 (0x504) - Audio IF 1_5
+ */
+#define WM5100_AIF1_FMT_MASK 0x0007 /* AIF1_FMT - [2:0] */
+#define WM5100_AIF1_FMT_SHIFT 0 /* AIF1_FMT - [2:0] */
+#define WM5100_AIF1_FMT_WIDTH 3 /* AIF1_FMT - [2:0] */
+
+/*
+ * R1285 (0x505) - Audio IF 1_6
+ */
+#define WM5100_AIF1TX_BCPF_MASK 0x1FFF /* AIF1TX_BCPF - [12:0] */
+#define WM5100_AIF1TX_BCPF_SHIFT 0 /* AIF1TX_BCPF - [12:0] */
+#define WM5100_AIF1TX_BCPF_WIDTH 13 /* AIF1TX_BCPF - [12:0] */
+
+/*
+ * R1286 (0x506) - Audio IF 1_7
+ */
+#define WM5100_AIF1RX_BCPF_MASK 0x1FFF /* AIF1RX_BCPF - [12:0] */
+#define WM5100_AIF1RX_BCPF_SHIFT 0 /* AIF1RX_BCPF - [12:0] */
+#define WM5100_AIF1RX_BCPF_WIDTH 13 /* AIF1RX_BCPF - [12:0] */
+
+/*
+ * R1287 (0x507) - Audio IF 1_8
+ */
+#define WM5100_AIF1TX_WL_MASK 0x3F00 /* AIF1TX_WL - [13:8] */
+#define WM5100_AIF1TX_WL_SHIFT 8 /* AIF1TX_WL - [13:8] */
+#define WM5100_AIF1TX_WL_WIDTH 6 /* AIF1TX_WL - [13:8] */
+#define WM5100_AIF1TX_SLOT_LEN_MASK 0x00FF /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM5100_AIF1TX_SLOT_LEN_SHIFT 0 /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM5100_AIF1TX_SLOT_LEN_WIDTH 8 /* AIF1TX_SLOT_LEN - [7:0] */
+
+/*
+ * R1288 (0x508) - Audio IF 1_9
+ */
+#define WM5100_AIF1RX_WL_MASK 0x3F00 /* AIF1RX_WL - [13:8] */
+#define WM5100_AIF1RX_WL_SHIFT 8 /* AIF1RX_WL - [13:8] */
+#define WM5100_AIF1RX_WL_WIDTH 6 /* AIF1RX_WL - [13:8] */
+#define WM5100_AIF1RX_SLOT_LEN_MASK 0x00FF /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM5100_AIF1RX_SLOT_LEN_SHIFT 0 /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM5100_AIF1RX_SLOT_LEN_WIDTH 8 /* AIF1RX_SLOT_LEN - [7:0] */
+
+/*
+ * R1289 (0x509) - Audio IF 1_10
+ */
+#define WM5100_AIF1TX1_SLOT_MASK 0x003F /* AIF1TX1_SLOT - [5:0] */
+#define WM5100_AIF1TX1_SLOT_SHIFT 0 /* AIF1TX1_SLOT - [5:0] */
+#define WM5100_AIF1TX1_SLOT_WIDTH 6 /* AIF1TX1_SLOT - [5:0] */
+
+/*
+ * R1290 (0x50A) - Audio IF 1_11
+ */
+#define WM5100_AIF1TX2_SLOT_MASK 0x003F /* AIF1TX2_SLOT - [5:0] */
+#define WM5100_AIF1TX2_SLOT_SHIFT 0 /* AIF1TX2_SLOT - [5:0] */
+#define WM5100_AIF1TX2_SLOT_WIDTH 6 /* AIF1TX2_SLOT - [5:0] */
+
+/*
+ * R1291 (0x50B) - Audio IF 1_12
+ */
+#define WM5100_AIF1TX3_SLOT_MASK 0x003F /* AIF1TX3_SLOT - [5:0] */
+#define WM5100_AIF1TX3_SLOT_SHIFT 0 /* AIF1TX3_SLOT - [5:0] */
+#define WM5100_AIF1TX3_SLOT_WIDTH 6 /* AIF1TX3_SLOT - [5:0] */
+
+/*
+ * R1292 (0x50C) - Audio IF 1_13
+ */
+#define WM5100_AIF1TX4_SLOT_MASK 0x003F /* AIF1TX4_SLOT - [5:0] */
+#define WM5100_AIF1TX4_SLOT_SHIFT 0 /* AIF1TX4_SLOT - [5:0] */
+#define WM5100_AIF1TX4_SLOT_WIDTH 6 /* AIF1TX4_SLOT - [5:0] */
+
+/*
+ * R1293 (0x50D) - Audio IF 1_14
+ */
+#define WM5100_AIF1TX5_SLOT_MASK 0x003F /* AIF1TX5_SLOT - [5:0] */
+#define WM5100_AIF1TX5_SLOT_SHIFT 0 /* AIF1TX5_SLOT - [5:0] */
+#define WM5100_AIF1TX5_SLOT_WIDTH 6 /* AIF1TX5_SLOT - [5:0] */
+
+/*
+ * R1294 (0x50E) - Audio IF 1_15
+ */
+#define WM5100_AIF1TX6_SLOT_MASK 0x003F /* AIF1TX6_SLOT - [5:0] */
+#define WM5100_AIF1TX6_SLOT_SHIFT 0 /* AIF1TX6_SLOT - [5:0] */
+#define WM5100_AIF1TX6_SLOT_WIDTH 6 /* AIF1TX6_SLOT - [5:0] */
+
+/*
+ * R1295 (0x50F) - Audio IF 1_16
+ */
+#define WM5100_AIF1TX7_SLOT_MASK 0x003F /* AIF1TX7_SLOT - [5:0] */
+#define WM5100_AIF1TX7_SLOT_SHIFT 0 /* AIF1TX7_SLOT - [5:0] */
+#define WM5100_AIF1TX7_SLOT_WIDTH 6 /* AIF1TX7_SLOT - [5:0] */
+
+/*
+ * R1296 (0x510) - Audio IF 1_17
+ */
+#define WM5100_AIF1TX8_SLOT_MASK 0x003F /* AIF1TX8_SLOT - [5:0] */
+#define WM5100_AIF1TX8_SLOT_SHIFT 0 /* AIF1TX8_SLOT - [5:0] */
+#define WM5100_AIF1TX8_SLOT_WIDTH 6 /* AIF1TX8_SLOT - [5:0] */
+
+/*
+ * R1297 (0x511) - Audio IF 1_18
+ */
+#define WM5100_AIF1RX1_SLOT_MASK 0x003F /* AIF1RX1_SLOT - [5:0] */
+#define WM5100_AIF1RX1_SLOT_SHIFT 0 /* AIF1RX1_SLOT - [5:0] */
+#define WM5100_AIF1RX1_SLOT_WIDTH 6 /* AIF1RX1_SLOT - [5:0] */
+
+/*
+ * R1298 (0x512) - Audio IF 1_19
+ */
+#define WM5100_AIF1RX2_SLOT_MASK 0x003F /* AIF1RX2_SLOT - [5:0] */
+#define WM5100_AIF1RX2_SLOT_SHIFT 0 /* AIF1RX2_SLOT - [5:0] */
+#define WM5100_AIF1RX2_SLOT_WIDTH 6 /* AIF1RX2_SLOT - [5:0] */
+
+/*
+ * R1299 (0x513) - Audio IF 1_20
+ */
+#define WM5100_AIF1RX3_SLOT_MASK 0x003F /* AIF1RX3_SLOT - [5:0] */
+#define WM5100_AIF1RX3_SLOT_SHIFT 0 /* AIF1RX3_SLOT - [5:0] */
+#define WM5100_AIF1RX3_SLOT_WIDTH 6 /* AIF1RX3_SLOT - [5:0] */
+
+/*
+ * R1300 (0x514) - Audio IF 1_21
+ */
+#define WM5100_AIF1RX4_SLOT_MASK 0x003F /* AIF1RX4_SLOT - [5:0] */
+#define WM5100_AIF1RX4_SLOT_SHIFT 0 /* AIF1RX4_SLOT - [5:0] */
+#define WM5100_AIF1RX4_SLOT_WIDTH 6 /* AIF1RX4_SLOT - [5:0] */
+
+/*
+ * R1301 (0x515) - Audio IF 1_22
+ */
+#define WM5100_AIF1RX5_SLOT_MASK 0x003F /* AIF1RX5_SLOT - [5:0] */
+#define WM5100_AIF1RX5_SLOT_SHIFT 0 /* AIF1RX5_SLOT - [5:0] */
+#define WM5100_AIF1RX5_SLOT_WIDTH 6 /* AIF1RX5_SLOT - [5:0] */
+
+/*
+ * R1302 (0x516) - Audio IF 1_23
+ */
+#define WM5100_AIF1RX6_SLOT_MASK 0x003F /* AIF1RX6_SLOT - [5:0] */
+#define WM5100_AIF1RX6_SLOT_SHIFT 0 /* AIF1RX6_SLOT - [5:0] */
+#define WM5100_AIF1RX6_SLOT_WIDTH 6 /* AIF1RX6_SLOT - [5:0] */
+
+/*
+ * R1303 (0x517) - Audio IF 1_24
+ */
+#define WM5100_AIF1RX7_SLOT_MASK 0x003F /* AIF1RX7_SLOT - [5:0] */
+#define WM5100_AIF1RX7_SLOT_SHIFT 0 /* AIF1RX7_SLOT - [5:0] */
+#define WM5100_AIF1RX7_SLOT_WIDTH 6 /* AIF1RX7_SLOT - [5:0] */
+
+/*
+ * R1304 (0x518) - Audio IF 1_25
+ */
+#define WM5100_AIF1RX8_SLOT_MASK 0x003F /* AIF1RX8_SLOT - [5:0] */
+#define WM5100_AIF1RX8_SLOT_SHIFT 0 /* AIF1RX8_SLOT - [5:0] */
+#define WM5100_AIF1RX8_SLOT_WIDTH 6 /* AIF1RX8_SLOT - [5:0] */
+
+/*
+ * R1305 (0x519) - Audio IF 1_26
+ */
+#define WM5100_AIF1TX8_ENA 0x0080 /* AIF1TX8_ENA */
+#define WM5100_AIF1TX8_ENA_MASK 0x0080 /* AIF1TX8_ENA */
+#define WM5100_AIF1TX8_ENA_SHIFT 7 /* AIF1TX8_ENA */
+#define WM5100_AIF1TX8_ENA_WIDTH 1 /* AIF1TX8_ENA */
+#define WM5100_AIF1TX7_ENA 0x0040 /* AIF1TX7_ENA */
+#define WM5100_AIF1TX7_ENA_MASK 0x0040 /* AIF1TX7_ENA */
+#define WM5100_AIF1TX7_ENA_SHIFT 6 /* AIF1TX7_ENA */
+#define WM5100_AIF1TX7_ENA_WIDTH 1 /* AIF1TX7_ENA */
+#define WM5100_AIF1TX6_ENA 0x0020 /* AIF1TX6_ENA */
+#define WM5100_AIF1TX6_ENA_MASK 0x0020 /* AIF1TX6_ENA */
+#define WM5100_AIF1TX6_ENA_SHIFT 5 /* AIF1TX6_ENA */
+#define WM5100_AIF1TX6_ENA_WIDTH 1 /* AIF1TX6_ENA */
+#define WM5100_AIF1TX5_ENA 0x0010 /* AIF1TX5_ENA */
+#define WM5100_AIF1TX5_ENA_MASK 0x0010 /* AIF1TX5_ENA */
+#define WM5100_AIF1TX5_ENA_SHIFT 4 /* AIF1TX5_ENA */
+#define WM5100_AIF1TX5_ENA_WIDTH 1 /* AIF1TX5_ENA */
+#define WM5100_AIF1TX4_ENA 0x0008 /* AIF1TX4_ENA */
+#define WM5100_AIF1TX4_ENA_MASK 0x0008 /* AIF1TX4_ENA */
+#define WM5100_AIF1TX4_ENA_SHIFT 3 /* AIF1TX4_ENA */
+#define WM5100_AIF1TX4_ENA_WIDTH 1 /* AIF1TX4_ENA */
+#define WM5100_AIF1TX3_ENA 0x0004 /* AIF1TX3_ENA */
+#define WM5100_AIF1TX3_ENA_MASK 0x0004 /* AIF1TX3_ENA */
+#define WM5100_AIF1TX3_ENA_SHIFT 2 /* AIF1TX3_ENA */
+#define WM5100_AIF1TX3_ENA_WIDTH 1 /* AIF1TX3_ENA */
+#define WM5100_AIF1TX2_ENA 0x0002 /* AIF1TX2_ENA */
+#define WM5100_AIF1TX2_ENA_MASK 0x0002 /* AIF1TX2_ENA */
+#define WM5100_AIF1TX2_ENA_SHIFT 1 /* AIF1TX2_ENA */
+#define WM5100_AIF1TX2_ENA_WIDTH 1 /* AIF1TX2_ENA */
+#define WM5100_AIF1TX1_ENA 0x0001 /* AIF1TX1_ENA */
+#define WM5100_AIF1TX1_ENA_MASK 0x0001 /* AIF1TX1_ENA */
+#define WM5100_AIF1TX1_ENA_SHIFT 0 /* AIF1TX1_ENA */
+#define WM5100_AIF1TX1_ENA_WIDTH 1 /* AIF1TX1_ENA */
+
+/*
+ * R1306 (0x51A) - Audio IF 1_27
+ */
+#define WM5100_AIF1RX8_ENA 0x0080 /* AIF1RX8_ENA */
+#define WM5100_AIF1RX8_ENA_MASK 0x0080 /* AIF1RX8_ENA */
+#define WM5100_AIF1RX8_ENA_SHIFT 7 /* AIF1RX8_ENA */
+#define WM5100_AIF1RX8_ENA_WIDTH 1 /* AIF1RX8_ENA */
+#define WM5100_AIF1RX7_ENA 0x0040 /* AIF1RX7_ENA */
+#define WM5100_AIF1RX7_ENA_MASK 0x0040 /* AIF1RX7_ENA */
+#define WM5100_AIF1RX7_ENA_SHIFT 6 /* AIF1RX7_ENA */
+#define WM5100_AIF1RX7_ENA_WIDTH 1 /* AIF1RX7_ENA */
+#define WM5100_AIF1RX6_ENA 0x0020 /* AIF1RX6_ENA */
+#define WM5100_AIF1RX6_ENA_MASK 0x0020 /* AIF1RX6_ENA */
+#define WM5100_AIF1RX6_ENA_SHIFT 5 /* AIF1RX6_ENA */
+#define WM5100_AIF1RX6_ENA_WIDTH 1 /* AIF1RX6_ENA */
+#define WM5100_AIF1RX5_ENA 0x0010 /* AIF1RX5_ENA */
+#define WM5100_AIF1RX5_ENA_MASK 0x0010 /* AIF1RX5_ENA */
+#define WM5100_AIF1RX5_ENA_SHIFT 4 /* AIF1RX5_ENA */
+#define WM5100_AIF1RX5_ENA_WIDTH 1 /* AIF1RX5_ENA */
+#define WM5100_AIF1RX4_ENA 0x0008 /* AIF1RX4_ENA */
+#define WM5100_AIF1RX4_ENA_MASK 0x0008 /* AIF1RX4_ENA */
+#define WM5100_AIF1RX4_ENA_SHIFT 3 /* AIF1RX4_ENA */
+#define WM5100_AIF1RX4_ENA_WIDTH 1 /* AIF1RX4_ENA */
+#define WM5100_AIF1RX3_ENA 0x0004 /* AIF1RX3_ENA */
+#define WM5100_AIF1RX3_ENA_MASK 0x0004 /* AIF1RX3_ENA */
+#define WM5100_AIF1RX3_ENA_SHIFT 2 /* AIF1RX3_ENA */
+#define WM5100_AIF1RX3_ENA_WIDTH 1 /* AIF1RX3_ENA */
+#define WM5100_AIF1RX2_ENA 0x0002 /* AIF1RX2_ENA */
+#define WM5100_AIF1RX2_ENA_MASK 0x0002 /* AIF1RX2_ENA */
+#define WM5100_AIF1RX2_ENA_SHIFT 1 /* AIF1RX2_ENA */
+#define WM5100_AIF1RX2_ENA_WIDTH 1 /* AIF1RX2_ENA */
+#define WM5100_AIF1RX1_ENA 0x0001 /* AIF1RX1_ENA */
+#define WM5100_AIF1RX1_ENA_MASK 0x0001 /* AIF1RX1_ENA */
+#define WM5100_AIF1RX1_ENA_SHIFT 0 /* AIF1RX1_ENA */
+#define WM5100_AIF1RX1_ENA_WIDTH 1 /* AIF1RX1_ENA */
+
+/*
+ * R1344 (0x540) - Audio IF 2_1
+ */
+#define WM5100_AIF2_BCLK_INV 0x0080 /* AIF2_BCLK_INV */
+#define WM5100_AIF2_BCLK_INV_MASK 0x0080 /* AIF2_BCLK_INV */
+#define WM5100_AIF2_BCLK_INV_SHIFT 7 /* AIF2_BCLK_INV */
+#define WM5100_AIF2_BCLK_INV_WIDTH 1 /* AIF2_BCLK_INV */
+#define WM5100_AIF2_BCLK_FRC 0x0040 /* AIF2_BCLK_FRC */
+#define WM5100_AIF2_BCLK_FRC_MASK 0x0040 /* AIF2_BCLK_FRC */
+#define WM5100_AIF2_BCLK_FRC_SHIFT 6 /* AIF2_BCLK_FRC */
+#define WM5100_AIF2_BCLK_FRC_WIDTH 1 /* AIF2_BCLK_FRC */
+#define WM5100_AIF2_BCLK_MSTR 0x0020 /* AIF2_BCLK_MSTR */
+#define WM5100_AIF2_BCLK_MSTR_MASK 0x0020 /* AIF2_BCLK_MSTR */
+#define WM5100_AIF2_BCLK_MSTR_SHIFT 5 /* AIF2_BCLK_MSTR */
+#define WM5100_AIF2_BCLK_MSTR_WIDTH 1 /* AIF2_BCLK_MSTR */
+#define WM5100_AIF2_BCLK_FREQ_MASK 0x001F /* AIF2_BCLK_FREQ - [4:0] */
+#define WM5100_AIF2_BCLK_FREQ_SHIFT 0 /* AIF2_BCLK_FREQ - [4:0] */
+#define WM5100_AIF2_BCLK_FREQ_WIDTH 5 /* AIF2_BCLK_FREQ - [4:0] */
+
+/*
+ * R1345 (0x541) - Audio IF 2_2
+ */
+#define WM5100_AIF2TX_DAT_TRI 0x0020 /* AIF2TX_DAT_TRI */
+#define WM5100_AIF2TX_DAT_TRI_MASK 0x0020 /* AIF2TX_DAT_TRI */
+#define WM5100_AIF2TX_DAT_TRI_SHIFT 5 /* AIF2TX_DAT_TRI */
+#define WM5100_AIF2TX_DAT_TRI_WIDTH 1 /* AIF2TX_DAT_TRI */
+#define WM5100_AIF2TX_LRCLK_SRC 0x0008 /* AIF2TX_LRCLK_SRC */
+#define WM5100_AIF2TX_LRCLK_SRC_MASK 0x0008 /* AIF2TX_LRCLK_SRC */
+#define WM5100_AIF2TX_LRCLK_SRC_SHIFT 3 /* AIF2TX_LRCLK_SRC */
+#define WM5100_AIF2TX_LRCLK_SRC_WIDTH 1 /* AIF2TX_LRCLK_SRC */
+#define WM5100_AIF2TX_LRCLK_INV 0x0004 /* AIF2TX_LRCLK_INV */
+#define WM5100_AIF2TX_LRCLK_INV_MASK 0x0004 /* AIF2TX_LRCLK_INV */
+#define WM5100_AIF2TX_LRCLK_INV_SHIFT 2 /* AIF2TX_LRCLK_INV */
+#define WM5100_AIF2TX_LRCLK_INV_WIDTH 1 /* AIF2TX_LRCLK_INV */
+#define WM5100_AIF2TX_LRCLK_FRC 0x0002 /* AIF2TX_LRCLK_FRC */
+#define WM5100_AIF2TX_LRCLK_FRC_MASK 0x0002 /* AIF2TX_LRCLK_FRC */
+#define WM5100_AIF2TX_LRCLK_FRC_SHIFT 1 /* AIF2TX_LRCLK_FRC */
+#define WM5100_AIF2TX_LRCLK_FRC_WIDTH 1 /* AIF2TX_LRCLK_FRC */
+#define WM5100_AIF2TX_LRCLK_MSTR 0x0001 /* AIF2TX_LRCLK_MSTR */
+#define WM5100_AIF2TX_LRCLK_MSTR_MASK 0x0001 /* AIF2TX_LRCLK_MSTR */
+#define WM5100_AIF2TX_LRCLK_MSTR_SHIFT 0 /* AIF2TX_LRCLK_MSTR */
+#define WM5100_AIF2TX_LRCLK_MSTR_WIDTH 1 /* AIF2TX_LRCLK_MSTR */
+
+/*
+ * R1346 (0x542) - Audio IF 2_3
+ */
+#define WM5100_AIF2RX_LRCLK_INV 0x0004 /* AIF2RX_LRCLK_INV */
+#define WM5100_AIF2RX_LRCLK_INV_MASK 0x0004 /* AIF2RX_LRCLK_INV */
+#define WM5100_AIF2RX_LRCLK_INV_SHIFT 2 /* AIF2RX_LRCLK_INV */
+#define WM5100_AIF2RX_LRCLK_INV_WIDTH 1 /* AIF2RX_LRCLK_INV */
+#define WM5100_AIF2RX_LRCLK_FRC 0x0002 /* AIF2RX_LRCLK_FRC */
+#define WM5100_AIF2RX_LRCLK_FRC_MASK 0x0002 /* AIF2RX_LRCLK_FRC */
+#define WM5100_AIF2RX_LRCLK_FRC_SHIFT 1 /* AIF2RX_LRCLK_FRC */
+#define WM5100_AIF2RX_LRCLK_FRC_WIDTH 1 /* AIF2RX_LRCLK_FRC */
+#define WM5100_AIF2RX_LRCLK_MSTR 0x0001 /* AIF2RX_LRCLK_MSTR */
+#define WM5100_AIF2RX_LRCLK_MSTR_MASK 0x0001 /* AIF2RX_LRCLK_MSTR */
+#define WM5100_AIF2RX_LRCLK_MSTR_SHIFT 0 /* AIF2RX_LRCLK_MSTR */
+#define WM5100_AIF2RX_LRCLK_MSTR_WIDTH 1 /* AIF2RX_LRCLK_MSTR */
+
+/*
+ * R1347 (0x543) - Audio IF 2_4
+ */
+#define WM5100_AIF2_TRI 0x0040 /* AIF2_TRI */
+#define WM5100_AIF2_TRI_MASK 0x0040 /* AIF2_TRI */
+#define WM5100_AIF2_TRI_SHIFT 6 /* AIF2_TRI */
+#define WM5100_AIF2_TRI_WIDTH 1 /* AIF2_TRI */
+#define WM5100_AIF2_RATE_MASK 0x0003 /* AIF2_RATE - [1:0] */
+#define WM5100_AIF2_RATE_SHIFT 0 /* AIF2_RATE - [1:0] */
+#define WM5100_AIF2_RATE_WIDTH 2 /* AIF2_RATE - [1:0] */
+
+/*
+ * R1348 (0x544) - Audio IF 2_5
+ */
+#define WM5100_AIF2_FMT_MASK 0x0007 /* AIF2_FMT - [2:0] */
+#define WM5100_AIF2_FMT_SHIFT 0 /* AIF2_FMT - [2:0] */
+#define WM5100_AIF2_FMT_WIDTH 3 /* AIF2_FMT - [2:0] */
+
+/*
+ * R1349 (0x545) - Audio IF 2_6
+ */
+#define WM5100_AIF2TX_BCPF_MASK 0x1FFF /* AIF2TX_BCPF - [12:0] */
+#define WM5100_AIF2TX_BCPF_SHIFT 0 /* AIF2TX_BCPF - [12:0] */
+#define WM5100_AIF2TX_BCPF_WIDTH 13 /* AIF2TX_BCPF - [12:0] */
+
+/*
+ * R1350 (0x546) - Audio IF 2_7
+ */
+#define WM5100_AIF2RX_BCPF_MASK 0x1FFF /* AIF2RX_BCPF - [12:0] */
+#define WM5100_AIF2RX_BCPF_SHIFT 0 /* AIF2RX_BCPF - [12:0] */
+#define WM5100_AIF2RX_BCPF_WIDTH 13 /* AIF2RX_BCPF - [12:0] */
+
+/*
+ * R1351 (0x547) - Audio IF 2_8
+ */
+#define WM5100_AIF2TX_WL_MASK 0x3F00 /* AIF2TX_WL - [13:8] */
+#define WM5100_AIF2TX_WL_SHIFT 8 /* AIF2TX_WL - [13:8] */
+#define WM5100_AIF2TX_WL_WIDTH 6 /* AIF2TX_WL - [13:8] */
+#define WM5100_AIF2TX_SLOT_LEN_MASK 0x00FF /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM5100_AIF2TX_SLOT_LEN_SHIFT 0 /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM5100_AIF2TX_SLOT_LEN_WIDTH 8 /* AIF2TX_SLOT_LEN - [7:0] */
+
+/*
+ * R1352 (0x548) - Audio IF 2_9
+ */
+#define WM5100_AIF2RX_WL_MASK 0x3F00 /* AIF2RX_WL - [13:8] */
+#define WM5100_AIF2RX_WL_SHIFT 8 /* AIF2RX_WL - [13:8] */
+#define WM5100_AIF2RX_WL_WIDTH 6 /* AIF2RX_WL - [13:8] */
+#define WM5100_AIF2RX_SLOT_LEN_MASK 0x00FF /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM5100_AIF2RX_SLOT_LEN_SHIFT 0 /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM5100_AIF2RX_SLOT_LEN_WIDTH 8 /* AIF2RX_SLOT_LEN - [7:0] */
+
+/*
+ * R1353 (0x549) - Audio IF 2_10
+ */
+#define WM5100_AIF2TX1_SLOT_MASK 0x003F /* AIF2TX1_SLOT - [5:0] */
+#define WM5100_AIF2TX1_SLOT_SHIFT 0 /* AIF2TX1_SLOT - [5:0] */
+#define WM5100_AIF2TX1_SLOT_WIDTH 6 /* AIF2TX1_SLOT - [5:0] */
+
+/*
+ * R1354 (0x54A) - Audio IF 2_11
+ */
+#define WM5100_AIF2TX2_SLOT_MASK 0x003F /* AIF2TX2_SLOT - [5:0] */
+#define WM5100_AIF2TX2_SLOT_SHIFT 0 /* AIF2TX2_SLOT - [5:0] */
+#define WM5100_AIF2TX2_SLOT_WIDTH 6 /* AIF2TX2_SLOT - [5:0] */
+
+/*
+ * R1361 (0x551) - Audio IF 2_18
+ */
+#define WM5100_AIF2RX1_SLOT_MASK 0x003F /* AIF2RX1_SLOT - [5:0] */
+#define WM5100_AIF2RX1_SLOT_SHIFT 0 /* AIF2RX1_SLOT - [5:0] */
+#define WM5100_AIF2RX1_SLOT_WIDTH 6 /* AIF2RX1_SLOT - [5:0] */
+
+/*
+ * R1362 (0x552) - Audio IF 2_19
+ */
+#define WM5100_AIF2RX2_SLOT_MASK 0x003F /* AIF2RX2_SLOT - [5:0] */
+#define WM5100_AIF2RX2_SLOT_SHIFT 0 /* AIF2RX2_SLOT - [5:0] */
+#define WM5100_AIF2RX2_SLOT_WIDTH 6 /* AIF2RX2_SLOT - [5:0] */
+
+/*
+ * R1369 (0x559) - Audio IF 2_26
+ */
+#define WM5100_AIF2TX2_ENA 0x0002 /* AIF2TX2_ENA */
+#define WM5100_AIF2TX2_ENA_MASK 0x0002 /* AIF2TX2_ENA */
+#define WM5100_AIF2TX2_ENA_SHIFT 1 /* AIF2TX2_ENA */
+#define WM5100_AIF2TX2_ENA_WIDTH 1 /* AIF2TX2_ENA */
+#define WM5100_AIF2TX1_ENA 0x0001 /* AIF2TX1_ENA */
+#define WM5100_AIF2TX1_ENA_MASK 0x0001 /* AIF2TX1_ENA */
+#define WM5100_AIF2TX1_ENA_SHIFT 0 /* AIF2TX1_ENA */
+#define WM5100_AIF2TX1_ENA_WIDTH 1 /* AIF2TX1_ENA */
+
+/*
+ * R1370 (0x55A) - Audio IF 2_27
+ */
+#define WM5100_AIF2RX2_ENA 0x0002 /* AIF2RX2_ENA */
+#define WM5100_AIF2RX2_ENA_MASK 0x0002 /* AIF2RX2_ENA */
+#define WM5100_AIF2RX2_ENA_SHIFT 1 /* AIF2RX2_ENA */
+#define WM5100_AIF2RX2_ENA_WIDTH 1 /* AIF2RX2_ENA */
+#define WM5100_AIF2RX1_ENA 0x0001 /* AIF2RX1_ENA */
+#define WM5100_AIF2RX1_ENA_MASK 0x0001 /* AIF2RX1_ENA */
+#define WM5100_AIF2RX1_ENA_SHIFT 0 /* AIF2RX1_ENA */
+#define WM5100_AIF2RX1_ENA_WIDTH 1 /* AIF2RX1_ENA */
+
+/*
+ * R1408 (0x580) - Audio IF 3_1
+ */
+#define WM5100_AIF3_BCLK_INV 0x0080 /* AIF3_BCLK_INV */
+#define WM5100_AIF3_BCLK_INV_MASK 0x0080 /* AIF3_BCLK_INV */
+#define WM5100_AIF3_BCLK_INV_SHIFT 7 /* AIF3_BCLK_INV */
+#define WM5100_AIF3_BCLK_INV_WIDTH 1 /* AIF3_BCLK_INV */
+#define WM5100_AIF3_BCLK_FRC 0x0040 /* AIF3_BCLK_FRC */
+#define WM5100_AIF3_BCLK_FRC_MASK 0x0040 /* AIF3_BCLK_FRC */
+#define WM5100_AIF3_BCLK_FRC_SHIFT 6 /* AIF3_BCLK_FRC */
+#define WM5100_AIF3_BCLK_FRC_WIDTH 1 /* AIF3_BCLK_FRC */
+#define WM5100_AIF3_BCLK_MSTR 0x0020 /* AIF3_BCLK_MSTR */
+#define WM5100_AIF3_BCLK_MSTR_MASK 0x0020 /* AIF3_BCLK_MSTR */
+#define WM5100_AIF3_BCLK_MSTR_SHIFT 5 /* AIF3_BCLK_MSTR */
+#define WM5100_AIF3_BCLK_MSTR_WIDTH 1 /* AIF3_BCLK_MSTR */
+#define WM5100_AIF3_BCLK_FREQ_MASK 0x001F /* AIF3_BCLK_FREQ - [4:0] */
+#define WM5100_AIF3_BCLK_FREQ_SHIFT 0 /* AIF3_BCLK_FREQ - [4:0] */
+#define WM5100_AIF3_BCLK_FREQ_WIDTH 5 /* AIF3_BCLK_FREQ - [4:0] */
+
+/*
+ * R1409 (0x581) - Audio IF 3_2
+ */
+#define WM5100_AIF3TX_DAT_TRI 0x0020 /* AIF3TX_DAT_TRI */
+#define WM5100_AIF3TX_DAT_TRI_MASK 0x0020 /* AIF3TX_DAT_TRI */
+#define WM5100_AIF3TX_DAT_TRI_SHIFT 5 /* AIF3TX_DAT_TRI */
+#define WM5100_AIF3TX_DAT_TRI_WIDTH 1 /* AIF3TX_DAT_TRI */
+#define WM5100_AIF3TX_LRCLK_SRC 0x0008 /* AIF3TX_LRCLK_SRC */
+#define WM5100_AIF3TX_LRCLK_SRC_MASK 0x0008 /* AIF3TX_LRCLK_SRC */
+#define WM5100_AIF3TX_LRCLK_SRC_SHIFT 3 /* AIF3TX_LRCLK_SRC */
+#define WM5100_AIF3TX_LRCLK_SRC_WIDTH 1 /* AIF3TX_LRCLK_SRC */
+#define WM5100_AIF3TX_LRCLK_INV 0x0004 /* AIF3TX_LRCLK_INV */
+#define WM5100_AIF3TX_LRCLK_INV_MASK 0x0004 /* AIF3TX_LRCLK_INV */
+#define WM5100_AIF3TX_LRCLK_INV_SHIFT 2 /* AIF3TX_LRCLK_INV */
+#define WM5100_AIF3TX_LRCLK_INV_WIDTH 1 /* AIF3TX_LRCLK_INV */
+#define WM5100_AIF3TX_LRCLK_FRC 0x0002 /* AIF3TX_LRCLK_FRC */
+#define WM5100_AIF3TX_LRCLK_FRC_MASK 0x0002 /* AIF3TX_LRCLK_FRC */
+#define WM5100_AIF3TX_LRCLK_FRC_SHIFT 1 /* AIF3TX_LRCLK_FRC */
+#define WM5100_AIF3TX_LRCLK_FRC_WIDTH 1 /* AIF3TX_LRCLK_FRC */
+#define WM5100_AIF3TX_LRCLK_MSTR 0x0001 /* AIF3TX_LRCLK_MSTR */
+#define WM5100_AIF3TX_LRCLK_MSTR_MASK 0x0001 /* AIF3TX_LRCLK_MSTR */
+#define WM5100_AIF3TX_LRCLK_MSTR_SHIFT 0 /* AIF3TX_LRCLK_MSTR */
+#define WM5100_AIF3TX_LRCLK_MSTR_WIDTH 1 /* AIF3TX_LRCLK_MSTR */
+
+/*
+ * R1410 (0x582) - Audio IF 3_3
+ */
+#define WM5100_AIF3RX_LRCLK_INV 0x0004 /* AIF3RX_LRCLK_INV */
+#define WM5100_AIF3RX_LRCLK_INV_MASK 0x0004 /* AIF3RX_LRCLK_INV */
+#define WM5100_AIF3RX_LRCLK_INV_SHIFT 2 /* AIF3RX_LRCLK_INV */
+#define WM5100_AIF3RX_LRCLK_INV_WIDTH 1 /* AIF3RX_LRCLK_INV */
+#define WM5100_AIF3RX_LRCLK_FRC 0x0002 /* AIF3RX_LRCLK_FRC */
+#define WM5100_AIF3RX_LRCLK_FRC_MASK 0x0002 /* AIF3RX_LRCLK_FRC */
+#define WM5100_AIF3RX_LRCLK_FRC_SHIFT 1 /* AIF3RX_LRCLK_FRC */
+#define WM5100_AIF3RX_LRCLK_FRC_WIDTH 1 /* AIF3RX_LRCLK_FRC */
+#define WM5100_AIF3RX_LRCLK_MSTR 0x0001 /* AIF3RX_LRCLK_MSTR */
+#define WM5100_AIF3RX_LRCLK_MSTR_MASK 0x0001 /* AIF3RX_LRCLK_MSTR */
+#define WM5100_AIF3RX_LRCLK_MSTR_SHIFT 0 /* AIF3RX_LRCLK_MSTR */
+#define WM5100_AIF3RX_LRCLK_MSTR_WIDTH 1 /* AIF3RX_LRCLK_MSTR */
+
+/*
+ * R1411 (0x583) - Audio IF 3_4
+ */
+#define WM5100_AIF3_TRI 0x0040 /* AIF3_TRI */
+#define WM5100_AIF3_TRI_MASK 0x0040 /* AIF3_TRI */
+#define WM5100_AIF3_TRI_SHIFT 6 /* AIF3_TRI */
+#define WM5100_AIF3_TRI_WIDTH 1 /* AIF3_TRI */
+#define WM5100_AIF3_RATE_MASK 0x0003 /* AIF3_RATE - [1:0] */
+#define WM5100_AIF3_RATE_SHIFT 0 /* AIF3_RATE - [1:0] */
+#define WM5100_AIF3_RATE_WIDTH 2 /* AIF3_RATE - [1:0] */
+
+/*
+ * R1412 (0x584) - Audio IF 3_5
+ */
+#define WM5100_AIF3_FMT_MASK 0x0007 /* AIF3_FMT - [2:0] */
+#define WM5100_AIF3_FMT_SHIFT 0 /* AIF3_FMT - [2:0] */
+#define WM5100_AIF3_FMT_WIDTH 3 /* AIF3_FMT - [2:0] */
+
+/*
+ * R1413 (0x585) - Audio IF 3_6
+ */
+#define WM5100_AIF3TX_BCPF_MASK 0x1FFF /* AIF3TX_BCPF - [12:0] */
+#define WM5100_AIF3TX_BCPF_SHIFT 0 /* AIF3TX_BCPF - [12:0] */
+#define WM5100_AIF3TX_BCPF_WIDTH 13 /* AIF3TX_BCPF - [12:0] */
+
+/*
+ * R1414 (0x586) - Audio IF 3_7
+ */
+#define WM5100_AIF3RX_BCPF_MASK 0x1FFF /* AIF3RX_BCPF - [12:0] */
+#define WM5100_AIF3RX_BCPF_SHIFT 0 /* AIF3RX_BCPF - [12:0] */
+#define WM5100_AIF3RX_BCPF_WIDTH 13 /* AIF3RX_BCPF - [12:0] */
+
+/*
+ * R1415 (0x587) - Audio IF 3_8
+ */
+#define WM5100_AIF3TX_WL_MASK 0x3F00 /* AIF3TX_WL - [13:8] */
+#define WM5100_AIF3TX_WL_SHIFT 8 /* AIF3TX_WL - [13:8] */
+#define WM5100_AIF3TX_WL_WIDTH 6 /* AIF3TX_WL - [13:8] */
+#define WM5100_AIF3TX_SLOT_LEN_MASK 0x00FF /* AIF3TX_SLOT_LEN - [7:0] */
+#define WM5100_AIF3TX_SLOT_LEN_SHIFT 0 /* AIF3TX_SLOT_LEN - [7:0] */
+#define WM5100_AIF3TX_SLOT_LEN_WIDTH 8 /* AIF3TX_SLOT_LEN - [7:0] */
+
+/*
+ * R1416 (0x588) - Audio IF 3_9
+ */
+#define WM5100_AIF3RX_WL_MASK 0x3F00 /* AIF3RX_WL - [13:8] */
+#define WM5100_AIF3RX_WL_SHIFT 8 /* AIF3RX_WL - [13:8] */
+#define WM5100_AIF3RX_WL_WIDTH 6 /* AIF3RX_WL - [13:8] */
+#define WM5100_AIF3RX_SLOT_LEN_MASK 0x00FF /* AIF3RX_SLOT_LEN - [7:0] */
+#define WM5100_AIF3RX_SLOT_LEN_SHIFT 0 /* AIF3RX_SLOT_LEN - [7:0] */
+#define WM5100_AIF3RX_SLOT_LEN_WIDTH 8 /* AIF3RX_SLOT_LEN - [7:0] */
+
+/*
+ * R1417 (0x589) - Audio IF 3_10
+ */
+#define WM5100_AIF3TX1_SLOT_MASK 0x003F /* AIF3TX1_SLOT - [5:0] */
+#define WM5100_AIF3TX1_SLOT_SHIFT 0 /* AIF3TX1_SLOT - [5:0] */
+#define WM5100_AIF3TX1_SLOT_WIDTH 6 /* AIF3TX1_SLOT - [5:0] */
+
+/*
+ * R1418 (0x58A) - Audio IF 3_11
+ */
+#define WM5100_AIF3TX2_SLOT_MASK 0x003F /* AIF3TX2_SLOT - [5:0] */
+#define WM5100_AIF3TX2_SLOT_SHIFT 0 /* AIF3TX2_SLOT - [5:0] */
+#define WM5100_AIF3TX2_SLOT_WIDTH 6 /* AIF3TX2_SLOT - [5:0] */
+
+/*
+ * R1425 (0x591) - Audio IF 3_18
+ */
+#define WM5100_AIF3RX1_SLOT_MASK 0x003F /* AIF3RX1_SLOT - [5:0] */
+#define WM5100_AIF3RX1_SLOT_SHIFT 0 /* AIF3RX1_SLOT - [5:0] */
+#define WM5100_AIF3RX1_SLOT_WIDTH 6 /* AIF3RX1_SLOT - [5:0] */
+
+/*
+ * R1426 (0x592) - Audio IF 3_19
+ */
+#define WM5100_AIF3RX2_SLOT_MASK 0x003F /* AIF3RX2_SLOT - [5:0] */
+#define WM5100_AIF3RX2_SLOT_SHIFT 0 /* AIF3RX2_SLOT - [5:0] */
+#define WM5100_AIF3RX2_SLOT_WIDTH 6 /* AIF3RX2_SLOT - [5:0] */
+
+/*
+ * R1433 (0x599) - Audio IF 3_26
+ */
+#define WM5100_AIF3TX2_ENA 0x0002 /* AIF3TX2_ENA */
+#define WM5100_AIF3TX2_ENA_MASK 0x0002 /* AIF3TX2_ENA */
+#define WM5100_AIF3TX2_ENA_SHIFT 1 /* AIF3TX2_ENA */
+#define WM5100_AIF3TX2_ENA_WIDTH 1 /* AIF3TX2_ENA */
+#define WM5100_AIF3TX1_ENA 0x0001 /* AIF3TX1_ENA */
+#define WM5100_AIF3TX1_ENA_MASK 0x0001 /* AIF3TX1_ENA */
+#define WM5100_AIF3TX1_ENA_SHIFT 0 /* AIF3TX1_ENA */
+#define WM5100_AIF3TX1_ENA_WIDTH 1 /* AIF3TX1_ENA */
+
+/*
+ * R1434 (0x59A) - Audio IF 3_27
+ */
+#define WM5100_AIF3RX2_ENA 0x0002 /* AIF3RX2_ENA */
+#define WM5100_AIF3RX2_ENA_MASK 0x0002 /* AIF3RX2_ENA */
+#define WM5100_AIF3RX2_ENA_SHIFT 1 /* AIF3RX2_ENA */
+#define WM5100_AIF3RX2_ENA_WIDTH 1 /* AIF3RX2_ENA */
+#define WM5100_AIF3RX1_ENA 0x0001 /* AIF3RX1_ENA */
+#define WM5100_AIF3RX1_ENA_MASK 0x0001 /* AIF3RX1_ENA */
+#define WM5100_AIF3RX1_ENA_SHIFT 0 /* AIF3RX1_ENA */
+#define WM5100_AIF3RX1_ENA_WIDTH 1 /* AIF3RX1_ENA */
+
+#define WM5100_MIXER_VOL_MASK 0x00FE /* MIXER_VOL - [7:1] */
+#define WM5100_MIXER_VOL_SHIFT 1 /* MIXER_VOL - [7:1] */
+#define WM5100_MIXER_VOL_WIDTH 7 /* MIXER_VOL - [7:1] */
+
+/*
+ * R3072 (0xC00) - GPIO CTRL 1
+ */
+#define WM5100_GP1_DIR 0x8000 /* GP1_DIR */
+#define WM5100_GP1_DIR_MASK 0x8000 /* GP1_DIR */
+#define WM5100_GP1_DIR_SHIFT 15 /* GP1_DIR */
+#define WM5100_GP1_DIR_WIDTH 1 /* GP1_DIR */
+#define WM5100_GP1_PU 0x4000 /* GP1_PU */
+#define WM5100_GP1_PU_MASK 0x4000 /* GP1_PU */
+#define WM5100_GP1_PU_SHIFT 14 /* GP1_PU */
+#define WM5100_GP1_PU_WIDTH 1 /* GP1_PU */
+#define WM5100_GP1_PD 0x2000 /* GP1_PD */
+#define WM5100_GP1_PD_MASK 0x2000 /* GP1_PD */
+#define WM5100_GP1_PD_SHIFT 13 /* GP1_PD */
+#define WM5100_GP1_PD_WIDTH 1 /* GP1_PD */
+#define WM5100_GP1_POL 0x0400 /* GP1_POL */
+#define WM5100_GP1_POL_MASK 0x0400 /* GP1_POL */
+#define WM5100_GP1_POL_SHIFT 10 /* GP1_POL */
+#define WM5100_GP1_POL_WIDTH 1 /* GP1_POL */
+#define WM5100_GP1_OP_CFG 0x0200 /* GP1_OP_CFG */
+#define WM5100_GP1_OP_CFG_MASK 0x0200 /* GP1_OP_CFG */
+#define WM5100_GP1_OP_CFG_SHIFT 9 /* GP1_OP_CFG */
+#define WM5100_GP1_OP_CFG_WIDTH 1 /* GP1_OP_CFG */
+#define WM5100_GP1_DB 0x0100 /* GP1_DB */
+#define WM5100_GP1_DB_MASK 0x0100 /* GP1_DB */
+#define WM5100_GP1_DB_SHIFT 8 /* GP1_DB */
+#define WM5100_GP1_DB_WIDTH 1 /* GP1_DB */
+#define WM5100_GP1_LVL 0x0040 /* GP1_LVL */
+#define WM5100_GP1_LVL_MASK 0x0040 /* GP1_LVL */
+#define WM5100_GP1_LVL_SHIFT 6 /* GP1_LVL */
+#define WM5100_GP1_LVL_WIDTH 1 /* GP1_LVL */
+#define WM5100_GP1_FN_MASK 0x003F /* GP1_FN - [5:0] */
+#define WM5100_GP1_FN_SHIFT 0 /* GP1_FN - [5:0] */
+#define WM5100_GP1_FN_WIDTH 6 /* GP1_FN - [5:0] */
+
+/*
+ * R3073 (0xC01) - GPIO CTRL 2
+ */
+#define WM5100_GP2_DIR 0x8000 /* GP2_DIR */
+#define WM5100_GP2_DIR_MASK 0x8000 /* GP2_DIR */
+#define WM5100_GP2_DIR_SHIFT 15 /* GP2_DIR */
+#define WM5100_GP2_DIR_WIDTH 1 /* GP2_DIR */
+#define WM5100_GP2_PU 0x4000 /* GP2_PU */
+#define WM5100_GP2_PU_MASK 0x4000 /* GP2_PU */
+#define WM5100_GP2_PU_SHIFT 14 /* GP2_PU */
+#define WM5100_GP2_PU_WIDTH 1 /* GP2_PU */
+#define WM5100_GP2_PD 0x2000 /* GP2_PD */
+#define WM5100_GP2_PD_MASK 0x2000 /* GP2_PD */
+#define WM5100_GP2_PD_SHIFT 13 /* GP2_PD */
+#define WM5100_GP2_PD_WIDTH 1 /* GP2_PD */
+#define WM5100_GP2_POL 0x0400 /* GP2_POL */
+#define WM5100_GP2_POL_MASK 0x0400 /* GP2_POL */
+#define WM5100_GP2_POL_SHIFT 10 /* GP2_POL */
+#define WM5100_GP2_POL_WIDTH 1 /* GP2_POL */
+#define WM5100_GP2_OP_CFG 0x0200 /* GP2_OP_CFG */
+#define WM5100_GP2_OP_CFG_MASK 0x0200 /* GP2_OP_CFG */
+#define WM5100_GP2_OP_CFG_SHIFT 9 /* GP2_OP_CFG */
+#define WM5100_GP2_OP_CFG_WIDTH 1 /* GP2_OP_CFG */
+#define WM5100_GP2_DB 0x0100 /* GP2_DB */
+#define WM5100_GP2_DB_MASK 0x0100 /* GP2_DB */
+#define WM5100_GP2_DB_SHIFT 8 /* GP2_DB */
+#define WM5100_GP2_DB_WIDTH 1 /* GP2_DB */
+#define WM5100_GP2_LVL 0x0040 /* GP2_LVL */
+#define WM5100_GP2_LVL_MASK 0x0040 /* GP2_LVL */
+#define WM5100_GP2_LVL_SHIFT 6 /* GP2_LVL */
+#define WM5100_GP2_LVL_WIDTH 1 /* GP2_LVL */
+#define WM5100_GP2_FN_MASK 0x003F /* GP2_FN - [5:0] */
+#define WM5100_GP2_FN_SHIFT 0 /* GP2_FN - [5:0] */
+#define WM5100_GP2_FN_WIDTH 6 /* GP2_FN - [5:0] */
+
+/*
+ * R3074 (0xC02) - GPIO CTRL 3
+ */
+#define WM5100_GP3_DIR 0x8000 /* GP3_DIR */
+#define WM5100_GP3_DIR_MASK 0x8000 /* GP3_DIR */
+#define WM5100_GP3_DIR_SHIFT 15 /* GP3_DIR */
+#define WM5100_GP3_DIR_WIDTH 1 /* GP3_DIR */
+#define WM5100_GP3_PU 0x4000 /* GP3_PU */
+#define WM5100_GP3_PU_MASK 0x4000 /* GP3_PU */
+#define WM5100_GP3_PU_SHIFT 14 /* GP3_PU */
+#define WM5100_GP3_PU_WIDTH 1 /* GP3_PU */
+#define WM5100_GP3_PD 0x2000 /* GP3_PD */
+#define WM5100_GP3_PD_MASK 0x2000 /* GP3_PD */
+#define WM5100_GP3_PD_SHIFT 13 /* GP3_PD */
+#define WM5100_GP3_PD_WIDTH 1 /* GP3_PD */
+#define WM5100_GP3_POL 0x0400 /* GP3_POL */
+#define WM5100_GP3_POL_MASK 0x0400 /* GP3_POL */
+#define WM5100_GP3_POL_SHIFT 10 /* GP3_POL */
+#define WM5100_GP3_POL_WIDTH 1 /* GP3_POL */
+#define WM5100_GP3_OP_CFG 0x0200 /* GP3_OP_CFG */
+#define WM5100_GP3_OP_CFG_MASK 0x0200 /* GP3_OP_CFG */
+#define WM5100_GP3_OP_CFG_SHIFT 9 /* GP3_OP_CFG */
+#define WM5100_GP3_OP_CFG_WIDTH 1 /* GP3_OP_CFG */
+#define WM5100_GP3_DB 0x0100 /* GP3_DB */
+#define WM5100_GP3_DB_MASK 0x0100 /* GP3_DB */
+#define WM5100_GP3_DB_SHIFT 8 /* GP3_DB */
+#define WM5100_GP3_DB_WIDTH 1 /* GP3_DB */
+#define WM5100_GP3_LVL 0x0040 /* GP3_LVL */
+#define WM5100_GP3_LVL_MASK 0x0040 /* GP3_LVL */
+#define WM5100_GP3_LVL_SHIFT 6 /* GP3_LVL */
+#define WM5100_GP3_LVL_WIDTH 1 /* GP3_LVL */
+#define WM5100_GP3_FN_MASK 0x003F /* GP3_FN - [5:0] */
+#define WM5100_GP3_FN_SHIFT 0 /* GP3_FN - [5:0] */
+#define WM5100_GP3_FN_WIDTH 6 /* GP3_FN - [5:0] */
+
+/*
+ * R3075 (0xC03) - GPIO CTRL 4
+ */
+#define WM5100_GP4_DIR 0x8000 /* GP4_DIR */
+#define WM5100_GP4_DIR_MASK 0x8000 /* GP4_DIR */
+#define WM5100_GP4_DIR_SHIFT 15 /* GP4_DIR */
+#define WM5100_GP4_DIR_WIDTH 1 /* GP4_DIR */
+#define WM5100_GP4_PU 0x4000 /* GP4_PU */
+#define WM5100_GP4_PU_MASK 0x4000 /* GP4_PU */
+#define WM5100_GP4_PU_SHIFT 14 /* GP4_PU */
+#define WM5100_GP4_PU_WIDTH 1 /* GP4_PU */
+#define WM5100_GP4_PD 0x2000 /* GP4_PD */
+#define WM5100_GP4_PD_MASK 0x2000 /* GP4_PD */
+#define WM5100_GP4_PD_SHIFT 13 /* GP4_PD */
+#define WM5100_GP4_PD_WIDTH 1 /* GP4_PD */
+#define WM5100_GP4_POL 0x0400 /* GP4_POL */
+#define WM5100_GP4_POL_MASK 0x0400 /* GP4_POL */
+#define WM5100_GP4_POL_SHIFT 10 /* GP4_POL */
+#define WM5100_GP4_POL_WIDTH 1 /* GP4_POL */
+#define WM5100_GP4_OP_CFG 0x0200 /* GP4_OP_CFG */
+#define WM5100_GP4_OP_CFG_MASK 0x0200 /* GP4_OP_CFG */
+#define WM5100_GP4_OP_CFG_SHIFT 9 /* GP4_OP_CFG */
+#define WM5100_GP4_OP_CFG_WIDTH 1 /* GP4_OP_CFG */
+#define WM5100_GP4_DB 0x0100 /* GP4_DB */
+#define WM5100_GP4_DB_MASK 0x0100 /* GP4_DB */
+#define WM5100_GP4_DB_SHIFT 8 /* GP4_DB */
+#define WM5100_GP4_DB_WIDTH 1 /* GP4_DB */
+#define WM5100_GP4_LVL 0x0040 /* GP4_LVL */
+#define WM5100_GP4_LVL_MASK 0x0040 /* GP4_LVL */
+#define WM5100_GP4_LVL_SHIFT 6 /* GP4_LVL */
+#define WM5100_GP4_LVL_WIDTH 1 /* GP4_LVL */
+#define WM5100_GP4_FN_MASK 0x003F /* GP4_FN - [5:0] */
+#define WM5100_GP4_FN_SHIFT 0 /* GP4_FN - [5:0] */
+#define WM5100_GP4_FN_WIDTH 6 /* GP4_FN - [5:0] */
+
+/*
+ * R3076 (0xC04) - GPIO CTRL 5
+ */
+#define WM5100_GP5_DIR 0x8000 /* GP5_DIR */
+#define WM5100_GP5_DIR_MASK 0x8000 /* GP5_DIR */
+#define WM5100_GP5_DIR_SHIFT 15 /* GP5_DIR */
+#define WM5100_GP5_DIR_WIDTH 1 /* GP5_DIR */
+#define WM5100_GP5_PU 0x4000 /* GP5_PU */
+#define WM5100_GP5_PU_MASK 0x4000 /* GP5_PU */
+#define WM5100_GP5_PU_SHIFT 14 /* GP5_PU */
+#define WM5100_GP5_PU_WIDTH 1 /* GP5_PU */
+#define WM5100_GP5_PD 0x2000 /* GP5_PD */
+#define WM5100_GP5_PD_MASK 0x2000 /* GP5_PD */
+#define WM5100_GP5_PD_SHIFT 13 /* GP5_PD */
+#define WM5100_GP5_PD_WIDTH 1 /* GP5_PD */
+#define WM5100_GP5_POL 0x0400 /* GP5_POL */
+#define WM5100_GP5_POL_MASK 0x0400 /* GP5_POL */
+#define WM5100_GP5_POL_SHIFT 10 /* GP5_POL */
+#define WM5100_GP5_POL_WIDTH 1 /* GP5_POL */
+#define WM5100_GP5_OP_CFG 0x0200 /* GP5_OP_CFG */
+#define WM5100_GP5_OP_CFG_MASK 0x0200 /* GP5_OP_CFG */
+#define WM5100_GP5_OP_CFG_SHIFT 9 /* GP5_OP_CFG */
+#define WM5100_GP5_OP_CFG_WIDTH 1 /* GP5_OP_CFG */
+#define WM5100_GP5_DB 0x0100 /* GP5_DB */
+#define WM5100_GP5_DB_MASK 0x0100 /* GP5_DB */
+#define WM5100_GP5_DB_SHIFT 8 /* GP5_DB */
+#define WM5100_GP5_DB_WIDTH 1 /* GP5_DB */
+#define WM5100_GP5_LVL 0x0040 /* GP5_LVL */
+#define WM5100_GP5_LVL_MASK 0x0040 /* GP5_LVL */
+#define WM5100_GP5_LVL_SHIFT 6 /* GP5_LVL */
+#define WM5100_GP5_LVL_WIDTH 1 /* GP5_LVL */
+#define WM5100_GP5_FN_MASK 0x003F /* GP5_FN - [5:0] */
+#define WM5100_GP5_FN_SHIFT 0 /* GP5_FN - [5:0] */
+#define WM5100_GP5_FN_WIDTH 6 /* GP5_FN - [5:0] */
+
+/*
+ * R3077 (0xC05) - GPIO CTRL 6
+ */
+#define WM5100_GP6_DIR 0x8000 /* GP6_DIR */
+#define WM5100_GP6_DIR_MASK 0x8000 /* GP6_DIR */
+#define WM5100_GP6_DIR_SHIFT 15 /* GP6_DIR */
+#define WM5100_GP6_DIR_WIDTH 1 /* GP6_DIR */
+#define WM5100_GP6_PU 0x4000 /* GP6_PU */
+#define WM5100_GP6_PU_MASK 0x4000 /* GP6_PU */
+#define WM5100_GP6_PU_SHIFT 14 /* GP6_PU */
+#define WM5100_GP6_PU_WIDTH 1 /* GP6_PU */
+#define WM5100_GP6_PD 0x2000 /* GP6_PD */
+#define WM5100_GP6_PD_MASK 0x2000 /* GP6_PD */
+#define WM5100_GP6_PD_SHIFT 13 /* GP6_PD */
+#define WM5100_GP6_PD_WIDTH 1 /* GP6_PD */
+#define WM5100_GP6_POL 0x0400 /* GP6_POL */
+#define WM5100_GP6_POL_MASK 0x0400 /* GP6_POL */
+#define WM5100_GP6_POL_SHIFT 10 /* GP6_POL */
+#define WM5100_GP6_POL_WIDTH 1 /* GP6_POL */
+#define WM5100_GP6_OP_CFG 0x0200 /* GP6_OP_CFG */
+#define WM5100_GP6_OP_CFG_MASK 0x0200 /* GP6_OP_CFG */
+#define WM5100_GP6_OP_CFG_SHIFT 9 /* GP6_OP_CFG */
+#define WM5100_GP6_OP_CFG_WIDTH 1 /* GP6_OP_CFG */
+#define WM5100_GP6_DB 0x0100 /* GP6_DB */
+#define WM5100_GP6_DB_MASK 0x0100 /* GP6_DB */
+#define WM5100_GP6_DB_SHIFT 8 /* GP6_DB */
+#define WM5100_GP6_DB_WIDTH 1 /* GP6_DB */
+#define WM5100_GP6_LVL 0x0040 /* GP6_LVL */
+#define WM5100_GP6_LVL_MASK 0x0040 /* GP6_LVL */
+#define WM5100_GP6_LVL_SHIFT 6 /* GP6_LVL */
+#define WM5100_GP6_LVL_WIDTH 1 /* GP6_LVL */
+#define WM5100_GP6_FN_MASK 0x003F /* GP6_FN - [5:0] */
+#define WM5100_GP6_FN_SHIFT 0 /* GP6_FN - [5:0] */
+#define WM5100_GP6_FN_WIDTH 6 /* GP6_FN - [5:0] */
+
+/*
+ * R3107 (0xC23) - Misc Pad Ctrl 1
+ */
+#define WM5100_LDO1ENA_PD 0x8000 /* LDO1ENA_PD */
+#define WM5100_LDO1ENA_PD_MASK 0x8000 /* LDO1ENA_PD */
+#define WM5100_LDO1ENA_PD_SHIFT 15 /* LDO1ENA_PD */
+#define WM5100_LDO1ENA_PD_WIDTH 1 /* LDO1ENA_PD */
+#define WM5100_MCLK2_PD 0x2000 /* MCLK2_PD */
+#define WM5100_MCLK2_PD_MASK 0x2000 /* MCLK2_PD */
+#define WM5100_MCLK2_PD_SHIFT 13 /* MCLK2_PD */
+#define WM5100_MCLK2_PD_WIDTH 1 /* MCLK2_PD */
+#define WM5100_MCLK1_PD 0x1000 /* MCLK1_PD */
+#define WM5100_MCLK1_PD_MASK 0x1000 /* MCLK1_PD */
+#define WM5100_MCLK1_PD_SHIFT 12 /* MCLK1_PD */
+#define WM5100_MCLK1_PD_WIDTH 1 /* MCLK1_PD */
+#define WM5100_RESET_PU 0x0002 /* RESET_PU */
+#define WM5100_RESET_PU_MASK 0x0002 /* RESET_PU */
+#define WM5100_RESET_PU_SHIFT 1 /* RESET_PU */
+#define WM5100_RESET_PU_WIDTH 1 /* RESET_PU */
+#define WM5100_ADDR_PD 0x0001 /* ADDR_PD */
+#define WM5100_ADDR_PD_MASK 0x0001 /* ADDR_PD */
+#define WM5100_ADDR_PD_SHIFT 0 /* ADDR_PD */
+#define WM5100_ADDR_PD_WIDTH 1 /* ADDR_PD */
+
+/*
+ * R3108 (0xC24) - Misc Pad Ctrl 2
+ */
+#define WM5100_DMICDAT4_PD 0x0008 /* DMICDAT4_PD */
+#define WM5100_DMICDAT4_PD_MASK 0x0008 /* DMICDAT4_PD */
+#define WM5100_DMICDAT4_PD_SHIFT 3 /* DMICDAT4_PD */
+#define WM5100_DMICDAT4_PD_WIDTH 1 /* DMICDAT4_PD */
+#define WM5100_DMICDAT3_PD 0x0004 /* DMICDAT3_PD */
+#define WM5100_DMICDAT3_PD_MASK 0x0004 /* DMICDAT3_PD */
+#define WM5100_DMICDAT3_PD_SHIFT 2 /* DMICDAT3_PD */
+#define WM5100_DMICDAT3_PD_WIDTH 1 /* DMICDAT3_PD */
+#define WM5100_DMICDAT2_PD 0x0002 /* DMICDAT2_PD */
+#define WM5100_DMICDAT2_PD_MASK 0x0002 /* DMICDAT2_PD */
+#define WM5100_DMICDAT2_PD_SHIFT 1 /* DMICDAT2_PD */
+#define WM5100_DMICDAT2_PD_WIDTH 1 /* DMICDAT2_PD */
+#define WM5100_DMICDAT1_PD 0x0001 /* DMICDAT1_PD */
+#define WM5100_DMICDAT1_PD_MASK 0x0001 /* DMICDAT1_PD */
+#define WM5100_DMICDAT1_PD_SHIFT 0 /* DMICDAT1_PD */
+#define WM5100_DMICDAT1_PD_WIDTH 1 /* DMICDAT1_PD */
+
+/*
+ * R3109 (0xC25) - Misc Pad Ctrl 3
+ */
+#define WM5100_AIF1RXLRCLK_PU 0x0020 /* AIF1RXLRCLK_PU */
+#define WM5100_AIF1RXLRCLK_PU_MASK 0x0020 /* AIF1RXLRCLK_PU */
+#define WM5100_AIF1RXLRCLK_PU_SHIFT 5 /* AIF1RXLRCLK_PU */
+#define WM5100_AIF1RXLRCLK_PU_WIDTH 1 /* AIF1RXLRCLK_PU */
+#define WM5100_AIF1RXLRCLK_PD 0x0010 /* AIF1RXLRCLK_PD */
+#define WM5100_AIF1RXLRCLK_PD_MASK 0x0010 /* AIF1RXLRCLK_PD */
+#define WM5100_AIF1RXLRCLK_PD_SHIFT 4 /* AIF1RXLRCLK_PD */
+#define WM5100_AIF1RXLRCLK_PD_WIDTH 1 /* AIF1RXLRCLK_PD */
+#define WM5100_AIF1BCLK_PU 0x0008 /* AIF1BCLK_PU */
+#define WM5100_AIF1BCLK_PU_MASK 0x0008 /* AIF1BCLK_PU */
+#define WM5100_AIF1BCLK_PU_SHIFT 3 /* AIF1BCLK_PU */
+#define WM5100_AIF1BCLK_PU_WIDTH 1 /* AIF1BCLK_PU */
+#define WM5100_AIF1BCLK_PD 0x0004 /* AIF1BCLK_PD */
+#define WM5100_AIF1BCLK_PD_MASK 0x0004 /* AIF1BCLK_PD */
+#define WM5100_AIF1BCLK_PD_SHIFT 2 /* AIF1BCLK_PD */
+#define WM5100_AIF1BCLK_PD_WIDTH 1 /* AIF1BCLK_PD */
+#define WM5100_AIF1RXDAT_PU 0x0002 /* AIF1RXDAT_PU */
+#define WM5100_AIF1RXDAT_PU_MASK 0x0002 /* AIF1RXDAT_PU */
+#define WM5100_AIF1RXDAT_PU_SHIFT 1 /* AIF1RXDAT_PU */
+#define WM5100_AIF1RXDAT_PU_WIDTH 1 /* AIF1RXDAT_PU */
+#define WM5100_AIF1RXDAT_PD 0x0001 /* AIF1RXDAT_PD */
+#define WM5100_AIF1RXDAT_PD_MASK 0x0001 /* AIF1RXDAT_PD */
+#define WM5100_AIF1RXDAT_PD_SHIFT 0 /* AIF1RXDAT_PD */
+#define WM5100_AIF1RXDAT_PD_WIDTH 1 /* AIF1RXDAT_PD */
+
+/*
+ * R3110 (0xC26) - Misc Pad Ctrl 4
+ */
+#define WM5100_AIF2RXLRCLK_PU 0x0020 /* AIF2RXLRCLK_PU */
+#define WM5100_AIF2RXLRCLK_PU_MASK 0x0020 /* AIF2RXLRCLK_PU */
+#define WM5100_AIF2RXLRCLK_PU_SHIFT 5 /* AIF2RXLRCLK_PU */
+#define WM5100_AIF2RXLRCLK_PU_WIDTH 1 /* AIF2RXLRCLK_PU */
+#define WM5100_AIF2RXLRCLK_PD 0x0010 /* AIF2RXLRCLK_PD */
+#define WM5100_AIF2RXLRCLK_PD_MASK 0x0010 /* AIF2RXLRCLK_PD */
+#define WM5100_AIF2RXLRCLK_PD_SHIFT 4 /* AIF2RXLRCLK_PD */
+#define WM5100_AIF2RXLRCLK_PD_WIDTH 1 /* AIF2RXLRCLK_PD */
+#define WM5100_AIF2BCLK_PU 0x0008 /* AIF2BCLK_PU */
+#define WM5100_AIF2BCLK_PU_MASK 0x0008 /* AIF2BCLK_PU */
+#define WM5100_AIF2BCLK_PU_SHIFT 3 /* AIF2BCLK_PU */
+#define WM5100_AIF2BCLK_PU_WIDTH 1 /* AIF2BCLK_PU */
+#define WM5100_AIF2BCLK_PD 0x0004 /* AIF2BCLK_PD */
+#define WM5100_AIF2BCLK_PD_MASK 0x0004 /* AIF2BCLK_PD */
+#define WM5100_AIF2BCLK_PD_SHIFT 2 /* AIF2BCLK_PD */
+#define WM5100_AIF2BCLK_PD_WIDTH 1 /* AIF2BCLK_PD */
+#define WM5100_AIF2RXDAT_PU 0x0002 /* AIF2RXDAT_PU */
+#define WM5100_AIF2RXDAT_PU_MASK 0x0002 /* AIF2RXDAT_PU */
+#define WM5100_AIF2RXDAT_PU_SHIFT 1 /* AIF2RXDAT_PU */
+#define WM5100_AIF2RXDAT_PU_WIDTH 1 /* AIF2RXDAT_PU */
+#define WM5100_AIF2RXDAT_PD 0x0001 /* AIF2RXDAT_PD */
+#define WM5100_AIF2RXDAT_PD_MASK 0x0001 /* AIF2RXDAT_PD */
+#define WM5100_AIF2RXDAT_PD_SHIFT 0 /* AIF2RXDAT_PD */
+#define WM5100_AIF2RXDAT_PD_WIDTH 1 /* AIF2RXDAT_PD */
+
+/*
+ * R3111 (0xC27) - Misc Pad Ctrl 5
+ */
+#define WM5100_AIF3RXLRCLK_PU 0x0020 /* AIF3RXLRCLK_PU */
+#define WM5100_AIF3RXLRCLK_PU_MASK 0x0020 /* AIF3RXLRCLK_PU */
+#define WM5100_AIF3RXLRCLK_PU_SHIFT 5 /* AIF3RXLRCLK_PU */
+#define WM5100_AIF3RXLRCLK_PU_WIDTH 1 /* AIF3RXLRCLK_PU */
+#define WM5100_AIF3RXLRCLK_PD 0x0010 /* AIF3RXLRCLK_PD */
+#define WM5100_AIF3RXLRCLK_PD_MASK 0x0010 /* AIF3RXLRCLK_PD */
+#define WM5100_AIF3RXLRCLK_PD_SHIFT 4 /* AIF3RXLRCLK_PD */
+#define WM5100_AIF3RXLRCLK_PD_WIDTH 1 /* AIF3RXLRCLK_PD */
+#define WM5100_AIF3BCLK_PU 0x0008 /* AIF3BCLK_PU */
+#define WM5100_AIF3BCLK_PU_MASK 0x0008 /* AIF3BCLK_PU */
+#define WM5100_AIF3BCLK_PU_SHIFT 3 /* AIF3BCLK_PU */
+#define WM5100_AIF3BCLK_PU_WIDTH 1 /* AIF3BCLK_PU */
+#define WM5100_AIF3BCLK_PD 0x0004 /* AIF3BCLK_PD */
+#define WM5100_AIF3BCLK_PD_MASK 0x0004 /* AIF3BCLK_PD */
+#define WM5100_AIF3BCLK_PD_SHIFT 2 /* AIF3BCLK_PD */
+#define WM5100_AIF3BCLK_PD_WIDTH 1 /* AIF3BCLK_PD */
+#define WM5100_AIF3RXDAT_PU 0x0002 /* AIF3RXDAT_PU */
+#define WM5100_AIF3RXDAT_PU_MASK 0x0002 /* AIF3RXDAT_PU */
+#define WM5100_AIF3RXDAT_PU_SHIFT 1 /* AIF3RXDAT_PU */
+#define WM5100_AIF3RXDAT_PU_WIDTH 1 /* AIF3RXDAT_PU */
+#define WM5100_AIF3RXDAT_PD 0x0001 /* AIF3RXDAT_PD */
+#define WM5100_AIF3RXDAT_PD_MASK 0x0001 /* AIF3RXDAT_PD */
+#define WM5100_AIF3RXDAT_PD_SHIFT 0 /* AIF3RXDAT_PD */
+#define WM5100_AIF3RXDAT_PD_WIDTH 1 /* AIF3RXDAT_PD */
+
+/*
+ * R3112 (0xC28) - Misc GPIO 1
+ */
+#define WM5100_OPCLK_SEL_MASK 0x0003 /* OPCLK_SEL - [1:0] */
+#define WM5100_OPCLK_SEL_SHIFT 0 /* OPCLK_SEL - [1:0] */
+#define WM5100_OPCLK_SEL_WIDTH 2 /* OPCLK_SEL - [1:0] */
+
+/*
+ * R3328 (0xD00) - Interrupt Status 1
+ */
+#define WM5100_GP6_EINT 0x0020 /* GP6_EINT */
+#define WM5100_GP6_EINT_MASK 0x0020 /* GP6_EINT */
+#define WM5100_GP6_EINT_SHIFT 5 /* GP6_EINT */
+#define WM5100_GP6_EINT_WIDTH 1 /* GP6_EINT */
+#define WM5100_GP5_EINT 0x0010 /* GP5_EINT */
+#define WM5100_GP5_EINT_MASK 0x0010 /* GP5_EINT */
+#define WM5100_GP5_EINT_SHIFT 4 /* GP5_EINT */
+#define WM5100_GP5_EINT_WIDTH 1 /* GP5_EINT */
+#define WM5100_GP4_EINT 0x0008 /* GP4_EINT */
+#define WM5100_GP4_EINT_MASK 0x0008 /* GP4_EINT */
+#define WM5100_GP4_EINT_SHIFT 3 /* GP4_EINT */
+#define WM5100_GP4_EINT_WIDTH 1 /* GP4_EINT */
+#define WM5100_GP3_EINT 0x0004 /* GP3_EINT */
+#define WM5100_GP3_EINT_MASK 0x0004 /* GP3_EINT */
+#define WM5100_GP3_EINT_SHIFT 2 /* GP3_EINT */
+#define WM5100_GP3_EINT_WIDTH 1 /* GP3_EINT */
+#define WM5100_GP2_EINT 0x0002 /* GP2_EINT */
+#define WM5100_GP2_EINT_MASK 0x0002 /* GP2_EINT */
+#define WM5100_GP2_EINT_SHIFT 1 /* GP2_EINT */
+#define WM5100_GP2_EINT_WIDTH 1 /* GP2_EINT */
+#define WM5100_GP1_EINT 0x0001 /* GP1_EINT */
+#define WM5100_GP1_EINT_MASK 0x0001 /* GP1_EINT */
+#define WM5100_GP1_EINT_SHIFT 0 /* GP1_EINT */
+#define WM5100_GP1_EINT_WIDTH 1 /* GP1_EINT */
+
+/*
+ * R3329 (0xD01) - Interrupt Status 2
+ */
+#define WM5100_DSP_IRQ6_EINT 0x0020 /* DSP_IRQ6_EINT */
+#define WM5100_DSP_IRQ6_EINT_MASK 0x0020 /* DSP_IRQ6_EINT */
+#define WM5100_DSP_IRQ6_EINT_SHIFT 5 /* DSP_IRQ6_EINT */
+#define WM5100_DSP_IRQ6_EINT_WIDTH 1 /* DSP_IRQ6_EINT */
+#define WM5100_DSP_IRQ5_EINT 0x0010 /* DSP_IRQ5_EINT */
+#define WM5100_DSP_IRQ5_EINT_MASK 0x0010 /* DSP_IRQ5_EINT */
+#define WM5100_DSP_IRQ5_EINT_SHIFT 4 /* DSP_IRQ5_EINT */
+#define WM5100_DSP_IRQ5_EINT_WIDTH 1 /* DSP_IRQ5_EINT */
+#define WM5100_DSP_IRQ4_EINT 0x0008 /* DSP_IRQ4_EINT */
+#define WM5100_DSP_IRQ4_EINT_MASK 0x0008 /* DSP_IRQ4_EINT */
+#define WM5100_DSP_IRQ4_EINT_SHIFT 3 /* DSP_IRQ4_EINT */
+#define WM5100_DSP_IRQ4_EINT_WIDTH 1 /* DSP_IRQ4_EINT */
+#define WM5100_DSP_IRQ3_EINT 0x0004 /* DSP_IRQ3_EINT */
+#define WM5100_DSP_IRQ3_EINT_MASK 0x0004 /* DSP_IRQ3_EINT */
+#define WM5100_DSP_IRQ3_EINT_SHIFT 2 /* DSP_IRQ3_EINT */
+#define WM5100_DSP_IRQ3_EINT_WIDTH 1 /* DSP_IRQ3_EINT */
+#define WM5100_DSP_IRQ2_EINT 0x0002 /* DSP_IRQ2_EINT */
+#define WM5100_DSP_IRQ2_EINT_MASK 0x0002 /* DSP_IRQ2_EINT */
+#define WM5100_DSP_IRQ2_EINT_SHIFT 1 /* DSP_IRQ2_EINT */
+#define WM5100_DSP_IRQ2_EINT_WIDTH 1 /* DSP_IRQ2_EINT */
+#define WM5100_DSP_IRQ1_EINT 0x0001 /* DSP_IRQ1_EINT */
+#define WM5100_DSP_IRQ1_EINT_MASK 0x0001 /* DSP_IRQ1_EINT */
+#define WM5100_DSP_IRQ1_EINT_SHIFT 0 /* DSP_IRQ1_EINT */
+#define WM5100_DSP_IRQ1_EINT_WIDTH 1 /* DSP_IRQ1_EINT */
+
+/*
+ * R3330 (0xD02) - Interrupt Status 3
+ */
+#define WM5100_SPK_SHUTDOWN_WARN_EINT 0x8000 /* SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_SPK_SHUTDOWN_WARN_EINT_MASK 0x8000 /* SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_SPK_SHUTDOWN_WARN_EINT_SHIFT 15 /* SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_SPK_SHUTDOWN_WARN_EINT_WIDTH 1 /* SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_SPK_SHUTDOWN_EINT 0x4000 /* SPK_SHUTDOWN_EINT */
+#define WM5100_SPK_SHUTDOWN_EINT_MASK 0x4000 /* SPK_SHUTDOWN_EINT */
+#define WM5100_SPK_SHUTDOWN_EINT_SHIFT 14 /* SPK_SHUTDOWN_EINT */
+#define WM5100_SPK_SHUTDOWN_EINT_WIDTH 1 /* SPK_SHUTDOWN_EINT */
+#define WM5100_HPDET_EINT 0x2000 /* HPDET_EINT */
+#define WM5100_HPDET_EINT_MASK 0x2000 /* HPDET_EINT */
+#define WM5100_HPDET_EINT_SHIFT 13 /* HPDET_EINT */
+#define WM5100_HPDET_EINT_WIDTH 1 /* HPDET_EINT */
+#define WM5100_ACCDET_EINT 0x1000 /* ACCDET_EINT */
+#define WM5100_ACCDET_EINT_MASK 0x1000 /* ACCDET_EINT */
+#define WM5100_ACCDET_EINT_SHIFT 12 /* ACCDET_EINT */
+#define WM5100_ACCDET_EINT_WIDTH 1 /* ACCDET_EINT */
+#define WM5100_DRC_SIG_DET_EINT 0x0200 /* DRC_SIG_DET_EINT */
+#define WM5100_DRC_SIG_DET_EINT_MASK 0x0200 /* DRC_SIG_DET_EINT */
+#define WM5100_DRC_SIG_DET_EINT_SHIFT 9 /* DRC_SIG_DET_EINT */
+#define WM5100_DRC_SIG_DET_EINT_WIDTH 1 /* DRC_SIG_DET_EINT */
+#define WM5100_ASRC2_LOCK_EINT 0x0100 /* ASRC2_LOCK_EINT */
+#define WM5100_ASRC2_LOCK_EINT_MASK 0x0100 /* ASRC2_LOCK_EINT */
+#define WM5100_ASRC2_LOCK_EINT_SHIFT 8 /* ASRC2_LOCK_EINT */
+#define WM5100_ASRC2_LOCK_EINT_WIDTH 1 /* ASRC2_LOCK_EINT */
+#define WM5100_ASRC1_LOCK_EINT 0x0080 /* ASRC1_LOCK_EINT */
+#define WM5100_ASRC1_LOCK_EINT_MASK 0x0080 /* ASRC1_LOCK_EINT */
+#define WM5100_ASRC1_LOCK_EINT_SHIFT 7 /* ASRC1_LOCK_EINT */
+#define WM5100_ASRC1_LOCK_EINT_WIDTH 1 /* ASRC1_LOCK_EINT */
+#define WM5100_FLL2_LOCK_EINT 0x0008 /* FLL2_LOCK_EINT */
+#define WM5100_FLL2_LOCK_EINT_MASK 0x0008 /* FLL2_LOCK_EINT */
+#define WM5100_FLL2_LOCK_EINT_SHIFT 3 /* FLL2_LOCK_EINT */
+#define WM5100_FLL2_LOCK_EINT_WIDTH 1 /* FLL2_LOCK_EINT */
+#define WM5100_FLL1_LOCK_EINT 0x0004 /* FLL1_LOCK_EINT */
+#define WM5100_FLL1_LOCK_EINT_MASK 0x0004 /* FLL1_LOCK_EINT */
+#define WM5100_FLL1_LOCK_EINT_SHIFT 2 /* FLL1_LOCK_EINT */
+#define WM5100_FLL1_LOCK_EINT_WIDTH 1 /* FLL1_LOCK_EINT */
+#define WM5100_CLKGEN_ERR_EINT 0x0002 /* CLKGEN_ERR_EINT */
+#define WM5100_CLKGEN_ERR_EINT_MASK 0x0002 /* CLKGEN_ERR_EINT */
+#define WM5100_CLKGEN_ERR_EINT_SHIFT 1 /* CLKGEN_ERR_EINT */
+#define WM5100_CLKGEN_ERR_EINT_WIDTH 1 /* CLKGEN_ERR_EINT */
+#define WM5100_CLKGEN_ERR_ASYNC_EINT 0x0001 /* CLKGEN_ERR_ASYNC_EINT */
+#define WM5100_CLKGEN_ERR_ASYNC_EINT_MASK 0x0001 /* CLKGEN_ERR_ASYNC_EINT */
+#define WM5100_CLKGEN_ERR_ASYNC_EINT_SHIFT 0 /* CLKGEN_ERR_ASYNC_EINT */
+#define WM5100_CLKGEN_ERR_ASYNC_EINT_WIDTH 1 /* CLKGEN_ERR_ASYNC_EINT */
+
+/*
+ * R3331 (0xD03) - Interrupt Status 4
+ */
+#define WM5100_AIF3_ERR_EINT 0x2000 /* AIF3_ERR_EINT */
+#define WM5100_AIF3_ERR_EINT_MASK 0x2000 /* AIF3_ERR_EINT */
+#define WM5100_AIF3_ERR_EINT_SHIFT 13 /* AIF3_ERR_EINT */
+#define WM5100_AIF3_ERR_EINT_WIDTH 1 /* AIF3_ERR_EINT */
+#define WM5100_AIF2_ERR_EINT 0x1000 /* AIF2_ERR_EINT */
+#define WM5100_AIF2_ERR_EINT_MASK 0x1000 /* AIF2_ERR_EINT */
+#define WM5100_AIF2_ERR_EINT_SHIFT 12 /* AIF2_ERR_EINT */
+#define WM5100_AIF2_ERR_EINT_WIDTH 1 /* AIF2_ERR_EINT */
+#define WM5100_AIF1_ERR_EINT 0x0800 /* AIF1_ERR_EINT */
+#define WM5100_AIF1_ERR_EINT_MASK 0x0800 /* AIF1_ERR_EINT */
+#define WM5100_AIF1_ERR_EINT_SHIFT 11 /* AIF1_ERR_EINT */
+#define WM5100_AIF1_ERR_EINT_WIDTH 1 /* AIF1_ERR_EINT */
+#define WM5100_CTRLIF_ERR_EINT 0x0400 /* CTRLIF_ERR_EINT */
+#define WM5100_CTRLIF_ERR_EINT_MASK 0x0400 /* CTRLIF_ERR_EINT */
+#define WM5100_CTRLIF_ERR_EINT_SHIFT 10 /* CTRLIF_ERR_EINT */
+#define WM5100_CTRLIF_ERR_EINT_WIDTH 1 /* CTRLIF_ERR_EINT */
+#define WM5100_ISRC2_UNDERCLOCKED_EINT 0x0200 /* ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_ISRC2_UNDERCLOCKED_EINT_MASK 0x0200 /* ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_ISRC2_UNDERCLOCKED_EINT_SHIFT 9 /* ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_ISRC2_UNDERCLOCKED_EINT_WIDTH 1 /* ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_ISRC1_UNDERCLOCKED_EINT 0x0100 /* ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_ISRC1_UNDERCLOCKED_EINT_MASK 0x0100 /* ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_ISRC1_UNDERCLOCKED_EINT_SHIFT 8 /* ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_ISRC1_UNDERCLOCKED_EINT_WIDTH 1 /* ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_FX_UNDERCLOCKED_EINT 0x0080 /* FX_UNDERCLOCKED_EINT */
+#define WM5100_FX_UNDERCLOCKED_EINT_MASK 0x0080 /* FX_UNDERCLOCKED_EINT */
+#define WM5100_FX_UNDERCLOCKED_EINT_SHIFT 7 /* FX_UNDERCLOCKED_EINT */
+#define WM5100_FX_UNDERCLOCKED_EINT_WIDTH 1 /* FX_UNDERCLOCKED_EINT */
+#define WM5100_AIF3_UNDERCLOCKED_EINT 0x0040 /* AIF3_UNDERCLOCKED_EINT */
+#define WM5100_AIF3_UNDERCLOCKED_EINT_MASK 0x0040 /* AIF3_UNDERCLOCKED_EINT */
+#define WM5100_AIF3_UNDERCLOCKED_EINT_SHIFT 6 /* AIF3_UNDERCLOCKED_EINT */
+#define WM5100_AIF3_UNDERCLOCKED_EINT_WIDTH 1 /* AIF3_UNDERCLOCKED_EINT */
+#define WM5100_AIF2_UNDERCLOCKED_EINT 0x0020 /* AIF2_UNDERCLOCKED_EINT */
+#define WM5100_AIF2_UNDERCLOCKED_EINT_MASK 0x0020 /* AIF2_UNDERCLOCKED_EINT */
+#define WM5100_AIF2_UNDERCLOCKED_EINT_SHIFT 5 /* AIF2_UNDERCLOCKED_EINT */
+#define WM5100_AIF2_UNDERCLOCKED_EINT_WIDTH 1 /* AIF2_UNDERCLOCKED_EINT */
+#define WM5100_AIF1_UNDERCLOCKED_EINT 0x0010 /* AIF1_UNDERCLOCKED_EINT */
+#define WM5100_AIF1_UNDERCLOCKED_EINT_MASK 0x0010 /* AIF1_UNDERCLOCKED_EINT */
+#define WM5100_AIF1_UNDERCLOCKED_EINT_SHIFT 4 /* AIF1_UNDERCLOCKED_EINT */
+#define WM5100_AIF1_UNDERCLOCKED_EINT_WIDTH 1 /* AIF1_UNDERCLOCKED_EINT */
+#define WM5100_ASRC_UNDERCLOCKED_EINT 0x0008 /* ASRC_UNDERCLOCKED_EINT */
+#define WM5100_ASRC_UNDERCLOCKED_EINT_MASK 0x0008 /* ASRC_UNDERCLOCKED_EINT */
+#define WM5100_ASRC_UNDERCLOCKED_EINT_SHIFT 3 /* ASRC_UNDERCLOCKED_EINT */
+#define WM5100_ASRC_UNDERCLOCKED_EINT_WIDTH 1 /* ASRC_UNDERCLOCKED_EINT */
+#define WM5100_DAC_UNDERCLOCKED_EINT 0x0004 /* DAC_UNDERCLOCKED_EINT */
+#define WM5100_DAC_UNDERCLOCKED_EINT_MASK 0x0004 /* DAC_UNDERCLOCKED_EINT */
+#define WM5100_DAC_UNDERCLOCKED_EINT_SHIFT 2 /* DAC_UNDERCLOCKED_EINT */
+#define WM5100_DAC_UNDERCLOCKED_EINT_WIDTH 1 /* DAC_UNDERCLOCKED_EINT */
+#define WM5100_ADC_UNDERCLOCKED_EINT 0x0002 /* ADC_UNDERCLOCKED_EINT */
+#define WM5100_ADC_UNDERCLOCKED_EINT_MASK 0x0002 /* ADC_UNDERCLOCKED_EINT */
+#define WM5100_ADC_UNDERCLOCKED_EINT_SHIFT 1 /* ADC_UNDERCLOCKED_EINT */
+#define WM5100_ADC_UNDERCLOCKED_EINT_WIDTH 1 /* ADC_UNDERCLOCKED_EINT */
+#define WM5100_MIXER_UNDERCLOCKED_EINT 0x0001 /* MIXER_UNDERCLOCKED_EINT */
+#define WM5100_MIXER_UNDERCLOCKED_EINT_MASK 0x0001 /* MIXER_UNDERCLOCKED_EINT */
+#define WM5100_MIXER_UNDERCLOCKED_EINT_SHIFT 0 /* MIXER_UNDERCLOCKED_EINT */
+#define WM5100_MIXER_UNDERCLOCKED_EINT_WIDTH 1 /* MIXER_UNDERCLOCKED_EINT */
+
+/*
+ * R3332 (0xD04) - Interrupt Raw Status 2
+ */
+#define WM5100_DSP_IRQ6_STS 0x0020 /* DSP_IRQ6_STS */
+#define WM5100_DSP_IRQ6_STS_MASK 0x0020 /* DSP_IRQ6_STS */
+#define WM5100_DSP_IRQ6_STS_SHIFT 5 /* DSP_IRQ6_STS */
+#define WM5100_DSP_IRQ6_STS_WIDTH 1 /* DSP_IRQ6_STS */
+#define WM5100_DSP_IRQ5_STS 0x0010 /* DSP_IRQ5_STS */
+#define WM5100_DSP_IRQ5_STS_MASK 0x0010 /* DSP_IRQ5_STS */
+#define WM5100_DSP_IRQ5_STS_SHIFT 4 /* DSP_IRQ5_STS */
+#define WM5100_DSP_IRQ5_STS_WIDTH 1 /* DSP_IRQ5_STS */
+#define WM5100_DSP_IRQ4_STS 0x0008 /* DSP_IRQ4_STS */
+#define WM5100_DSP_IRQ4_STS_MASK 0x0008 /* DSP_IRQ4_STS */
+#define WM5100_DSP_IRQ4_STS_SHIFT 3 /* DSP_IRQ4_STS */
+#define WM5100_DSP_IRQ4_STS_WIDTH 1 /* DSP_IRQ4_STS */
+#define WM5100_DSP_IRQ3_STS 0x0004 /* DSP_IRQ3_STS */
+#define WM5100_DSP_IRQ3_STS_MASK 0x0004 /* DSP_IRQ3_STS */
+#define WM5100_DSP_IRQ3_STS_SHIFT 2 /* DSP_IRQ3_STS */
+#define WM5100_DSP_IRQ3_STS_WIDTH 1 /* DSP_IRQ3_STS */
+#define WM5100_DSP_IRQ2_STS 0x0002 /* DSP_IRQ2_STS */
+#define WM5100_DSP_IRQ2_STS_MASK 0x0002 /* DSP_IRQ2_STS */
+#define WM5100_DSP_IRQ2_STS_SHIFT 1 /* DSP_IRQ2_STS */
+#define WM5100_DSP_IRQ2_STS_WIDTH 1 /* DSP_IRQ2_STS */
+#define WM5100_DSP_IRQ1_STS 0x0001 /* DSP_IRQ1_STS */
+#define WM5100_DSP_IRQ1_STS_MASK 0x0001 /* DSP_IRQ1_STS */
+#define WM5100_DSP_IRQ1_STS_SHIFT 0 /* DSP_IRQ1_STS */
+#define WM5100_DSP_IRQ1_STS_WIDTH 1 /* DSP_IRQ1_STS */
+
+/*
+ * R3333 (0xD05) - Interrupt Raw Status 3
+ */
+#define WM5100_SPK_SHUTDOWN_WARN_STS 0x8000 /* SPK_SHUTDOWN_WARN_STS */
+#define WM5100_SPK_SHUTDOWN_WARN_STS_MASK 0x8000 /* SPK_SHUTDOWN_WARN_STS */
+#define WM5100_SPK_SHUTDOWN_WARN_STS_SHIFT 15 /* SPK_SHUTDOWN_WARN_STS */
+#define WM5100_SPK_SHUTDOWN_WARN_STS_WIDTH 1 /* SPK_SHUTDOWN_WARN_STS */
+#define WM5100_SPK_SHUTDOWN_STS 0x4000 /* SPK_SHUTDOWN_STS */
+#define WM5100_SPK_SHUTDOWN_STS_MASK 0x4000 /* SPK_SHUTDOWN_STS */
+#define WM5100_SPK_SHUTDOWN_STS_SHIFT 14 /* SPK_SHUTDOWN_STS */
+#define WM5100_SPK_SHUTDOWN_STS_WIDTH 1 /* SPK_SHUTDOWN_STS */
+#define WM5100_HPDET_STS 0x2000 /* HPDET_STS */
+#define WM5100_HPDET_STS_MASK 0x2000 /* HPDET_STS */
+#define WM5100_HPDET_STS_SHIFT 13 /* HPDET_STS */
+#define WM5100_HPDET_STS_WIDTH 1 /* HPDET_STS */
+#define WM5100_DRC_SID_DET_STS 0x0200 /* DRC_SID_DET_STS */
+#define WM5100_DRC_SID_DET_STS_MASK 0x0200 /* DRC_SID_DET_STS */
+#define WM5100_DRC_SID_DET_STS_SHIFT 9 /* DRC_SID_DET_STS */
+#define WM5100_DRC_SID_DET_STS_WIDTH 1 /* DRC_SID_DET_STS */
+#define WM5100_ASRC2_LOCK_STS 0x0100 /* ASRC2_LOCK_STS */
+#define WM5100_ASRC2_LOCK_STS_MASK 0x0100 /* ASRC2_LOCK_STS */
+#define WM5100_ASRC2_LOCK_STS_SHIFT 8 /* ASRC2_LOCK_STS */
+#define WM5100_ASRC2_LOCK_STS_WIDTH 1 /* ASRC2_LOCK_STS */
+#define WM5100_ASRC1_LOCK_STS 0x0080 /* ASRC1_LOCK_STS */
+#define WM5100_ASRC1_LOCK_STS_MASK 0x0080 /* ASRC1_LOCK_STS */
+#define WM5100_ASRC1_LOCK_STS_SHIFT 7 /* ASRC1_LOCK_STS */
+#define WM5100_ASRC1_LOCK_STS_WIDTH 1 /* ASRC1_LOCK_STS */
+#define WM5100_FLL2_LOCK_STS 0x0008 /* FLL2_LOCK_STS */
+#define WM5100_FLL2_LOCK_STS_MASK 0x0008 /* FLL2_LOCK_STS */
+#define WM5100_FLL2_LOCK_STS_SHIFT 3 /* FLL2_LOCK_STS */
+#define WM5100_FLL2_LOCK_STS_WIDTH 1 /* FLL2_LOCK_STS */
+#define WM5100_FLL1_LOCK_STS 0x0004 /* FLL1_LOCK_STS */
+#define WM5100_FLL1_LOCK_STS_MASK 0x0004 /* FLL1_LOCK_STS */
+#define WM5100_FLL1_LOCK_STS_SHIFT 2 /* FLL1_LOCK_STS */
+#define WM5100_FLL1_LOCK_STS_WIDTH 1 /* FLL1_LOCK_STS */
+#define WM5100_CLKGEN_ERR_STS 0x0002 /* CLKGEN_ERR_STS */
+#define WM5100_CLKGEN_ERR_STS_MASK 0x0002 /* CLKGEN_ERR_STS */
+#define WM5100_CLKGEN_ERR_STS_SHIFT 1 /* CLKGEN_ERR_STS */
+#define WM5100_CLKGEN_ERR_STS_WIDTH 1 /* CLKGEN_ERR_STS */
+#define WM5100_CLKGEN_ERR_ASYNC_STS 0x0001 /* CLKGEN_ERR_ASYNC_STS */
+#define WM5100_CLKGEN_ERR_ASYNC_STS_MASK 0x0001 /* CLKGEN_ERR_ASYNC_STS */
+#define WM5100_CLKGEN_ERR_ASYNC_STS_SHIFT 0 /* CLKGEN_ERR_ASYNC_STS */
+#define WM5100_CLKGEN_ERR_ASYNC_STS_WIDTH 1 /* CLKGEN_ERR_ASYNC_STS */
+
+/*
+ * R3334 (0xD06) - Interrupt Raw Status 4
+ */
+#define WM5100_AIF3_ERR_STS 0x2000 /* AIF3_ERR_STS */
+#define WM5100_AIF3_ERR_STS_MASK 0x2000 /* AIF3_ERR_STS */
+#define WM5100_AIF3_ERR_STS_SHIFT 13 /* AIF3_ERR_STS */
+#define WM5100_AIF3_ERR_STS_WIDTH 1 /* AIF3_ERR_STS */
+#define WM5100_AIF2_ERR_STS 0x1000 /* AIF2_ERR_STS */
+#define WM5100_AIF2_ERR_STS_MASK 0x1000 /* AIF2_ERR_STS */
+#define WM5100_AIF2_ERR_STS_SHIFT 12 /* AIF2_ERR_STS */
+#define WM5100_AIF2_ERR_STS_WIDTH 1 /* AIF2_ERR_STS */
+#define WM5100_AIF1_ERR_STS 0x0800 /* AIF1_ERR_STS */
+#define WM5100_AIF1_ERR_STS_MASK 0x0800 /* AIF1_ERR_STS */
+#define WM5100_AIF1_ERR_STS_SHIFT 11 /* AIF1_ERR_STS */
+#define WM5100_AIF1_ERR_STS_WIDTH 1 /* AIF1_ERR_STS */
+#define WM5100_CTRLIF_ERR_STS 0x0400 /* CTRLIF_ERR_STS */
+#define WM5100_CTRLIF_ERR_STS_MASK 0x0400 /* CTRLIF_ERR_STS */
+#define WM5100_CTRLIF_ERR_STS_SHIFT 10 /* CTRLIF_ERR_STS */
+#define WM5100_CTRLIF_ERR_STS_WIDTH 1 /* CTRLIF_ERR_STS */
+#define WM5100_ISRC2_UNDERCLOCKED_STS 0x0200 /* ISRC2_UNDERCLOCKED_STS */
+#define WM5100_ISRC2_UNDERCLOCKED_STS_MASK 0x0200 /* ISRC2_UNDERCLOCKED_STS */
+#define WM5100_ISRC2_UNDERCLOCKED_STS_SHIFT 9 /* ISRC2_UNDERCLOCKED_STS */
+#define WM5100_ISRC2_UNDERCLOCKED_STS_WIDTH 1 /* ISRC2_UNDERCLOCKED_STS */
+#define WM5100_ISRC1_UNDERCLOCKED_STS 0x0100 /* ISRC1_UNDERCLOCKED_STS */
+#define WM5100_ISRC1_UNDERCLOCKED_STS_MASK 0x0100 /* ISRC1_UNDERCLOCKED_STS */
+#define WM5100_ISRC1_UNDERCLOCKED_STS_SHIFT 8 /* ISRC1_UNDERCLOCKED_STS */
+#define WM5100_ISRC1_UNDERCLOCKED_STS_WIDTH 1 /* ISRC1_UNDERCLOCKED_STS */
+#define WM5100_FX_UNDERCLOCKED_STS 0x0080 /* FX_UNDERCLOCKED_STS */
+#define WM5100_FX_UNDERCLOCKED_STS_MASK 0x0080 /* FX_UNDERCLOCKED_STS */
+#define WM5100_FX_UNDERCLOCKED_STS_SHIFT 7 /* FX_UNDERCLOCKED_STS */
+#define WM5100_FX_UNDERCLOCKED_STS_WIDTH 1 /* FX_UNDERCLOCKED_STS */
+#define WM5100_AIF3_UNDERCLOCKED_STS 0x0040 /* AIF3_UNDERCLOCKED_STS */
+#define WM5100_AIF3_UNDERCLOCKED_STS_MASK 0x0040 /* AIF3_UNDERCLOCKED_STS */
+#define WM5100_AIF3_UNDERCLOCKED_STS_SHIFT 6 /* AIF3_UNDERCLOCKED_STS */
+#define WM5100_AIF3_UNDERCLOCKED_STS_WIDTH 1 /* AIF3_UNDERCLOCKED_STS */
+#define WM5100_AIF2_UNDERCLOCKED_STS 0x0020 /* AIF2_UNDERCLOCKED_STS */
+#define WM5100_AIF2_UNDERCLOCKED_STS_MASK 0x0020 /* AIF2_UNDERCLOCKED_STS */
+#define WM5100_AIF2_UNDERCLOCKED_STS_SHIFT 5 /* AIF2_UNDERCLOCKED_STS */
+#define WM5100_AIF2_UNDERCLOCKED_STS_WIDTH 1 /* AIF2_UNDERCLOCKED_STS */
+#define WM5100_AIF1_UNDERCLOCKED_STS 0x0010 /* AIF1_UNDERCLOCKED_STS */
+#define WM5100_AIF1_UNDERCLOCKED_STS_MASK 0x0010 /* AIF1_UNDERCLOCKED_STS */
+#define WM5100_AIF1_UNDERCLOCKED_STS_SHIFT 4 /* AIF1_UNDERCLOCKED_STS */
+#define WM5100_AIF1_UNDERCLOCKED_STS_WIDTH 1 /* AIF1_UNDERCLOCKED_STS */
+#define WM5100_ASRC_UNDERCLOCKED_STS 0x0008 /* ASRC_UNDERCLOCKED_STS */
+#define WM5100_ASRC_UNDERCLOCKED_STS_MASK 0x0008 /* ASRC_UNDERCLOCKED_STS */
+#define WM5100_ASRC_UNDERCLOCKED_STS_SHIFT 3 /* ASRC_UNDERCLOCKED_STS */
+#define WM5100_ASRC_UNDERCLOCKED_STS_WIDTH 1 /* ASRC_UNDERCLOCKED_STS */
+#define WM5100_DAC_UNDERCLOCKED_STS 0x0004 /* DAC_UNDERCLOCKED_STS */
+#define WM5100_DAC_UNDERCLOCKED_STS_MASK 0x0004 /* DAC_UNDERCLOCKED_STS */
+#define WM5100_DAC_UNDERCLOCKED_STS_SHIFT 2 /* DAC_UNDERCLOCKED_STS */
+#define WM5100_DAC_UNDERCLOCKED_STS_WIDTH 1 /* DAC_UNDERCLOCKED_STS */
+#define WM5100_ADC_UNDERCLOCKED_STS 0x0002 /* ADC_UNDERCLOCKED_STS */
+#define WM5100_ADC_UNDERCLOCKED_STS_MASK 0x0002 /* ADC_UNDERCLOCKED_STS */
+#define WM5100_ADC_UNDERCLOCKED_STS_SHIFT 1 /* ADC_UNDERCLOCKED_STS */
+#define WM5100_ADC_UNDERCLOCKED_STS_WIDTH 1 /* ADC_UNDERCLOCKED_STS */
+#define WM5100_MIXER_UNDERCLOCKED_STS 0x0001 /* MIXER_UNDERCLOCKED_STS */
+#define WM5100_MIXER_UNDERCLOCKED_STS_MASK 0x0001 /* MIXER_UNDERCLOCKED_STS */
+#define WM5100_MIXER_UNDERCLOCKED_STS_SHIFT 0 /* MIXER_UNDERCLOCKED_STS */
+#define WM5100_MIXER_UNDERCLOCKED_STS_WIDTH 1 /* MIXER_UNDERCLOCKED_STS */
+
+/*
+ * R3335 (0xD07) - Interrupt Status 1 Mask
+ */
+#define WM5100_IM_GP6_EINT 0x0020 /* IM_GP6_EINT */
+#define WM5100_IM_GP6_EINT_MASK 0x0020 /* IM_GP6_EINT */
+#define WM5100_IM_GP6_EINT_SHIFT 5 /* IM_GP6_EINT */
+#define WM5100_IM_GP6_EINT_WIDTH 1 /* IM_GP6_EINT */
+#define WM5100_IM_GP5_EINT 0x0010 /* IM_GP5_EINT */
+#define WM5100_IM_GP5_EINT_MASK 0x0010 /* IM_GP5_EINT */
+#define WM5100_IM_GP5_EINT_SHIFT 4 /* IM_GP5_EINT */
+#define WM5100_IM_GP5_EINT_WIDTH 1 /* IM_GP5_EINT */
+#define WM5100_IM_GP4_EINT 0x0008 /* IM_GP4_EINT */
+#define WM5100_IM_GP4_EINT_MASK 0x0008 /* IM_GP4_EINT */
+#define WM5100_IM_GP4_EINT_SHIFT 3 /* IM_GP4_EINT */
+#define WM5100_IM_GP4_EINT_WIDTH 1 /* IM_GP4_EINT */
+#define WM5100_IM_GP3_EINT 0x0004 /* IM_GP3_EINT */
+#define WM5100_IM_GP3_EINT_MASK 0x0004 /* IM_GP3_EINT */
+#define WM5100_IM_GP3_EINT_SHIFT 2 /* IM_GP3_EINT */
+#define WM5100_IM_GP3_EINT_WIDTH 1 /* IM_GP3_EINT */
+#define WM5100_IM_GP2_EINT 0x0002 /* IM_GP2_EINT */
+#define WM5100_IM_GP2_EINT_MASK 0x0002 /* IM_GP2_EINT */
+#define WM5100_IM_GP2_EINT_SHIFT 1 /* IM_GP2_EINT */
+#define WM5100_IM_GP2_EINT_WIDTH 1 /* IM_GP2_EINT */
+#define WM5100_IM_GP1_EINT 0x0001 /* IM_GP1_EINT */
+#define WM5100_IM_GP1_EINT_MASK 0x0001 /* IM_GP1_EINT */
+#define WM5100_IM_GP1_EINT_SHIFT 0 /* IM_GP1_EINT */
+#define WM5100_IM_GP1_EINT_WIDTH 1 /* IM_GP1_EINT */
+
+/*
+ * R3336 (0xD08) - Interrupt Status 2 Mask
+ */
+#define WM5100_IM_DSP_IRQ6_EINT 0x0020 /* IM_DSP_IRQ6_EINT */
+#define WM5100_IM_DSP_IRQ6_EINT_MASK 0x0020 /* IM_DSP_IRQ6_EINT */
+#define WM5100_IM_DSP_IRQ6_EINT_SHIFT 5 /* IM_DSP_IRQ6_EINT */
+#define WM5100_IM_DSP_IRQ6_EINT_WIDTH 1 /* IM_DSP_IRQ6_EINT */
+#define WM5100_IM_DSP_IRQ5_EINT 0x0010 /* IM_DSP_IRQ5_EINT */
+#define WM5100_IM_DSP_IRQ5_EINT_MASK 0x0010 /* IM_DSP_IRQ5_EINT */
+#define WM5100_IM_DSP_IRQ5_EINT_SHIFT 4 /* IM_DSP_IRQ5_EINT */
+#define WM5100_IM_DSP_IRQ5_EINT_WIDTH 1 /* IM_DSP_IRQ5_EINT */
+#define WM5100_IM_DSP_IRQ4_EINT 0x0008 /* IM_DSP_IRQ4_EINT */
+#define WM5100_IM_DSP_IRQ4_EINT_MASK 0x0008 /* IM_DSP_IRQ4_EINT */
+#define WM5100_IM_DSP_IRQ4_EINT_SHIFT 3 /* IM_DSP_IRQ4_EINT */
+#define WM5100_IM_DSP_IRQ4_EINT_WIDTH 1 /* IM_DSP_IRQ4_EINT */
+#define WM5100_IM_DSP_IRQ3_EINT 0x0004 /* IM_DSP_IRQ3_EINT */
+#define WM5100_IM_DSP_IRQ3_EINT_MASK 0x0004 /* IM_DSP_IRQ3_EINT */
+#define WM5100_IM_DSP_IRQ3_EINT_SHIFT 2 /* IM_DSP_IRQ3_EINT */
+#define WM5100_IM_DSP_IRQ3_EINT_WIDTH 1 /* IM_DSP_IRQ3_EINT */
+#define WM5100_IM_DSP_IRQ2_EINT 0x0002 /* IM_DSP_IRQ2_EINT */
+#define WM5100_IM_DSP_IRQ2_EINT_MASK 0x0002 /* IM_DSP_IRQ2_EINT */
+#define WM5100_IM_DSP_IRQ2_EINT_SHIFT 1 /* IM_DSP_IRQ2_EINT */
+#define WM5100_IM_DSP_IRQ2_EINT_WIDTH 1 /* IM_DSP_IRQ2_EINT */
+#define WM5100_IM_DSP_IRQ1_EINT 0x0001 /* IM_DSP_IRQ1_EINT */
+#define WM5100_IM_DSP_IRQ1_EINT_MASK 0x0001 /* IM_DSP_IRQ1_EINT */
+#define WM5100_IM_DSP_IRQ1_EINT_SHIFT 0 /* IM_DSP_IRQ1_EINT */
+#define WM5100_IM_DSP_IRQ1_EINT_WIDTH 1 /* IM_DSP_IRQ1_EINT */
+
+/*
+ * R3337 (0xD09) - Interrupt Status 3 Mask
+ */
+#define WM5100_IM_SPK_SHUTDOWN_WARN_EINT 0x8000 /* IM_SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_WARN_EINT_MASK 0x8000 /* IM_SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_WARN_EINT_SHIFT 15 /* IM_SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_WARN_EINT_WIDTH 1 /* IM_SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_EINT 0x4000 /* IM_SPK_SHUTDOWN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_EINT_MASK 0x4000 /* IM_SPK_SHUTDOWN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_EINT_SHIFT 14 /* IM_SPK_SHUTDOWN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_EINT_WIDTH 1 /* IM_SPK_SHUTDOWN_EINT */
+#define WM5100_IM_HPDET_EINT 0x2000 /* IM_HPDET_EINT */
+#define WM5100_IM_HPDET_EINT_MASK 0x2000 /* IM_HPDET_EINT */
+#define WM5100_IM_HPDET_EINT_SHIFT 13 /* IM_HPDET_EINT */
+#define WM5100_IM_HPDET_EINT_WIDTH 1 /* IM_HPDET_EINT */
+#define WM5100_IM_ACCDET_EINT 0x1000 /* IM_ACCDET_EINT */
+#define WM5100_IM_ACCDET_EINT_MASK 0x1000 /* IM_ACCDET_EINT */
+#define WM5100_IM_ACCDET_EINT_SHIFT 12 /* IM_ACCDET_EINT */
+#define WM5100_IM_ACCDET_EINT_WIDTH 1 /* IM_ACCDET_EINT */
+#define WM5100_IM_DRC_SIG_DET_EINT 0x0200 /* IM_DRC_SIG_DET_EINT */
+#define WM5100_IM_DRC_SIG_DET_EINT_MASK 0x0200 /* IM_DRC_SIG_DET_EINT */
+#define WM5100_IM_DRC_SIG_DET_EINT_SHIFT 9 /* IM_DRC_SIG_DET_EINT */
+#define WM5100_IM_DRC_SIG_DET_EINT_WIDTH 1 /* IM_DRC_SIG_DET_EINT */
+#define WM5100_IM_ASRC2_LOCK_EINT 0x0100 /* IM_ASRC2_LOCK_EINT */
+#define WM5100_IM_ASRC2_LOCK_EINT_MASK 0x0100 /* IM_ASRC2_LOCK_EINT */
+#define WM5100_IM_ASRC2_LOCK_EINT_SHIFT 8 /* IM_ASRC2_LOCK_EINT */
+#define WM5100_IM_ASRC2_LOCK_EINT_WIDTH 1 /* IM_ASRC2_LOCK_EINT */
+#define WM5100_IM_ASRC1_LOCK_EINT 0x0080 /* IM_ASRC1_LOCK_EINT */
+#define WM5100_IM_ASRC1_LOCK_EINT_MASK 0x0080 /* IM_ASRC1_LOCK_EINT */
+#define WM5100_IM_ASRC1_LOCK_EINT_SHIFT 7 /* IM_ASRC1_LOCK_EINT */
+#define WM5100_IM_ASRC1_LOCK_EINT_WIDTH 1 /* IM_ASRC1_LOCK_EINT */
+#define WM5100_IM_FLL2_LOCK_EINT 0x0008 /* IM_FLL2_LOCK_EINT */
+#define WM5100_IM_FLL2_LOCK_EINT_MASK 0x0008 /* IM_FLL2_LOCK_EINT */
+#define WM5100_IM_FLL2_LOCK_EINT_SHIFT 3 /* IM_FLL2_LOCK_EINT */
+#define WM5100_IM_FLL2_LOCK_EINT_WIDTH 1 /* IM_FLL2_LOCK_EINT */
+#define WM5100_IM_FLL1_LOCK_EINT 0x0004 /* IM_FLL1_LOCK_EINT */
+#define WM5100_IM_FLL1_LOCK_EINT_MASK 0x0004 /* IM_FLL1_LOCK_EINT */
+#define WM5100_IM_FLL1_LOCK_EINT_SHIFT 2 /* IM_FLL1_LOCK_EINT */
+#define WM5100_IM_FLL1_LOCK_EINT_WIDTH 1 /* IM_FLL1_LOCK_EINT */
+#define WM5100_IM_CLKGEN_ERR_EINT 0x0002 /* IM_CLKGEN_ERR_EINT */
+#define WM5100_IM_CLKGEN_ERR_EINT_MASK 0x0002 /* IM_CLKGEN_ERR_EINT */
+#define WM5100_IM_CLKGEN_ERR_EINT_SHIFT 1 /* IM_CLKGEN_ERR_EINT */
+#define WM5100_IM_CLKGEN_ERR_EINT_WIDTH 1 /* IM_CLKGEN_ERR_EINT */
+#define WM5100_IM_CLKGEN_ERR_ASYNC_EINT 0x0001 /* IM_CLKGEN_ERR_ASYNC_EINT */
+#define WM5100_IM_CLKGEN_ERR_ASYNC_EINT_MASK 0x0001 /* IM_CLKGEN_ERR_ASYNC_EINT */
+#define WM5100_IM_CLKGEN_ERR_ASYNC_EINT_SHIFT 0 /* IM_CLKGEN_ERR_ASYNC_EINT */
+#define WM5100_IM_CLKGEN_ERR_ASYNC_EINT_WIDTH 1 /* IM_CLKGEN_ERR_ASYNC_EINT */
+
+/*
+ * R3338 (0xD0A) - Interrupt Status 4 Mask
+ */
+#define WM5100_IM_AIF3_ERR_EINT 0x2000 /* IM_AIF3_ERR_EINT */
+#define WM5100_IM_AIF3_ERR_EINT_MASK 0x2000 /* IM_AIF3_ERR_EINT */
+#define WM5100_IM_AIF3_ERR_EINT_SHIFT 13 /* IM_AIF3_ERR_EINT */
+#define WM5100_IM_AIF3_ERR_EINT_WIDTH 1 /* IM_AIF3_ERR_EINT */
+#define WM5100_IM_AIF2_ERR_EINT 0x1000 /* IM_AIF2_ERR_EINT */
+#define WM5100_IM_AIF2_ERR_EINT_MASK 0x1000 /* IM_AIF2_ERR_EINT */
+#define WM5100_IM_AIF2_ERR_EINT_SHIFT 12 /* IM_AIF2_ERR_EINT */
+#define WM5100_IM_AIF2_ERR_EINT_WIDTH 1 /* IM_AIF2_ERR_EINT */
+#define WM5100_IM_AIF1_ERR_EINT 0x0800 /* IM_AIF1_ERR_EINT */
+#define WM5100_IM_AIF1_ERR_EINT_MASK 0x0800 /* IM_AIF1_ERR_EINT */
+#define WM5100_IM_AIF1_ERR_EINT_SHIFT 11 /* IM_AIF1_ERR_EINT */
+#define WM5100_IM_AIF1_ERR_EINT_WIDTH 1 /* IM_AIF1_ERR_EINT */
+#define WM5100_IM_CTRLIF_ERR_EINT 0x0400 /* IM_CTRLIF_ERR_EINT */
+#define WM5100_IM_CTRLIF_ERR_EINT_MASK 0x0400 /* IM_CTRLIF_ERR_EINT */
+#define WM5100_IM_CTRLIF_ERR_EINT_SHIFT 10 /* IM_CTRLIF_ERR_EINT */
+#define WM5100_IM_CTRLIF_ERR_EINT_WIDTH 1 /* IM_CTRLIF_ERR_EINT */
+#define WM5100_IM_ISRC2_UNDERCLOCKED_EINT 0x0200 /* IM_ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC2_UNDERCLOCKED_EINT_MASK 0x0200 /* IM_ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC2_UNDERCLOCKED_EINT_SHIFT 9 /* IM_ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC2_UNDERCLOCKED_EINT_WIDTH 1 /* IM_ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC1_UNDERCLOCKED_EINT 0x0100 /* IM_ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC1_UNDERCLOCKED_EINT_MASK 0x0100 /* IM_ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC1_UNDERCLOCKED_EINT_SHIFT 8 /* IM_ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC1_UNDERCLOCKED_EINT_WIDTH 1 /* IM_ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_IM_FX_UNDERCLOCKED_EINT 0x0080 /* IM_FX_UNDERCLOCKED_EINT */
+#define WM5100_IM_FX_UNDERCLOCKED_EINT_MASK 0x0080 /* IM_FX_UNDERCLOCKED_EINT */
+#define WM5100_IM_FX_UNDERCLOCKED_EINT_SHIFT 7 /* IM_FX_UNDERCLOCKED_EINT */
+#define WM5100_IM_FX_UNDERCLOCKED_EINT_WIDTH 1 /* IM_FX_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF3_UNDERCLOCKED_EINT 0x0040 /* IM_AIF3_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF3_UNDERCLOCKED_EINT_MASK 0x0040 /* IM_AIF3_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF3_UNDERCLOCKED_EINT_SHIFT 6 /* IM_AIF3_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF3_UNDERCLOCKED_EINT_WIDTH 1 /* IM_AIF3_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF2_UNDERCLOCKED_EINT 0x0020 /* IM_AIF2_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF2_UNDERCLOCKED_EINT_MASK 0x0020 /* IM_AIF2_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF2_UNDERCLOCKED_EINT_SHIFT 5 /* IM_AIF2_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF2_UNDERCLOCKED_EINT_WIDTH 1 /* IM_AIF2_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF1_UNDERCLOCKED_EINT 0x0010 /* IM_AIF1_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF1_UNDERCLOCKED_EINT_MASK 0x0010 /* IM_AIF1_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF1_UNDERCLOCKED_EINT_SHIFT 4 /* IM_AIF1_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF1_UNDERCLOCKED_EINT_WIDTH 1 /* IM_AIF1_UNDERCLOCKED_EINT */
+#define WM5100_IM_ASRC_UNDERCLOCKED_EINT 0x0008 /* IM_ASRC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ASRC_UNDERCLOCKED_EINT_MASK 0x0008 /* IM_ASRC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ASRC_UNDERCLOCKED_EINT_SHIFT 3 /* IM_ASRC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ASRC_UNDERCLOCKED_EINT_WIDTH 1 /* IM_ASRC_UNDERCLOCKED_EINT */
+#define WM5100_IM_DAC_UNDERCLOCKED_EINT 0x0004 /* IM_DAC_UNDERCLOCKED_EINT */
+#define WM5100_IM_DAC_UNDERCLOCKED_EINT_MASK 0x0004 /* IM_DAC_UNDERCLOCKED_EINT */
+#define WM5100_IM_DAC_UNDERCLOCKED_EINT_SHIFT 2 /* IM_DAC_UNDERCLOCKED_EINT */
+#define WM5100_IM_DAC_UNDERCLOCKED_EINT_WIDTH 1 /* IM_DAC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ADC_UNDERCLOCKED_EINT 0x0002 /* IM_ADC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ADC_UNDERCLOCKED_EINT_MASK 0x0002 /* IM_ADC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ADC_UNDERCLOCKED_EINT_SHIFT 1 /* IM_ADC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ADC_UNDERCLOCKED_EINT_WIDTH 1 /* IM_ADC_UNDERCLOCKED_EINT */
+#define WM5100_IM_MIXER_UNDERCLOCKED_EINT 0x0001 /* IM_MIXER_UNDERCLOCKED_EINT */
+#define WM5100_IM_MIXER_UNDERCLOCKED_EINT_MASK 0x0001 /* IM_MIXER_UNDERCLOCKED_EINT */
+#define WM5100_IM_MIXER_UNDERCLOCKED_EINT_SHIFT 0 /* IM_MIXER_UNDERCLOCKED_EINT */
+#define WM5100_IM_MIXER_UNDERCLOCKED_EINT_WIDTH 1 /* IM_MIXER_UNDERCLOCKED_EINT */
+
+/*
+ * R3359 (0xD1F) - Interrupt Control
+ */
+#define WM5100_IM_IRQ 0x0001 /* IM_IRQ */
+#define WM5100_IM_IRQ_MASK 0x0001 /* IM_IRQ */
+#define WM5100_IM_IRQ_SHIFT 0 /* IM_IRQ */
+#define WM5100_IM_IRQ_WIDTH 1 /* IM_IRQ */
+
+/*
+ * R3360 (0xD20) - IRQ Debounce 1
+ */
+#define WM5100_SPK_SHUTDOWN_WARN_DB 0x0200 /* SPK_SHUTDOWN_WARN_DB */
+#define WM5100_SPK_SHUTDOWN_WARN_DB_MASK 0x0200 /* SPK_SHUTDOWN_WARN_DB */
+#define WM5100_SPK_SHUTDOWN_WARN_DB_SHIFT 9 /* SPK_SHUTDOWN_WARN_DB */
+#define WM5100_SPK_SHUTDOWN_WARN_DB_WIDTH 1 /* SPK_SHUTDOWN_WARN_DB */
+#define WM5100_SPK_SHUTDOWN_DB 0x0100 /* SPK_SHUTDOWN_DB */
+#define WM5100_SPK_SHUTDOWN_DB_MASK 0x0100 /* SPK_SHUTDOWN_DB */
+#define WM5100_SPK_SHUTDOWN_DB_SHIFT 8 /* SPK_SHUTDOWN_DB */
+#define WM5100_SPK_SHUTDOWN_DB_WIDTH 1 /* SPK_SHUTDOWN_DB */
+#define WM5100_FLL1_LOCK_IRQ_DB 0x0008 /* FLL1_LOCK_IRQ_DB */
+#define WM5100_FLL1_LOCK_IRQ_DB_MASK 0x0008 /* FLL1_LOCK_IRQ_DB */
+#define WM5100_FLL1_LOCK_IRQ_DB_SHIFT 3 /* FLL1_LOCK_IRQ_DB */
+#define WM5100_FLL1_LOCK_IRQ_DB_WIDTH 1 /* FLL1_LOCK_IRQ_DB */
+#define WM5100_FLL2_LOCK_IRQ_DB 0x0004 /* FLL2_LOCK_IRQ_DB */
+#define WM5100_FLL2_LOCK_IRQ_DB_MASK 0x0004 /* FLL2_LOCK_IRQ_DB */
+#define WM5100_FLL2_LOCK_IRQ_DB_SHIFT 2 /* FLL2_LOCK_IRQ_DB */
+#define WM5100_FLL2_LOCK_IRQ_DB_WIDTH 1 /* FLL2_LOCK_IRQ_DB */
+#define WM5100_CLKGEN_ERR_IRQ_DB 0x0002 /* CLKGEN_ERR_IRQ_DB */
+#define WM5100_CLKGEN_ERR_IRQ_DB_MASK 0x0002 /* CLKGEN_ERR_IRQ_DB */
+#define WM5100_CLKGEN_ERR_IRQ_DB_SHIFT 1 /* CLKGEN_ERR_IRQ_DB */
+#define WM5100_CLKGEN_ERR_IRQ_DB_WIDTH 1 /* CLKGEN_ERR_IRQ_DB */
+#define WM5100_CLKGEN_ERR_ASYNC_IRQ_DB 0x0001 /* CLKGEN_ERR_ASYNC_IRQ_DB */
+#define WM5100_CLKGEN_ERR_ASYNC_IRQ_DB_MASK 0x0001 /* CLKGEN_ERR_ASYNC_IRQ_DB */
+#define WM5100_CLKGEN_ERR_ASYNC_IRQ_DB_SHIFT 0 /* CLKGEN_ERR_ASYNC_IRQ_DB */
+#define WM5100_CLKGEN_ERR_ASYNC_IRQ_DB_WIDTH 1 /* CLKGEN_ERR_ASYNC_IRQ_DB */
+
+/*
+ * R3361 (0xD21) - IRQ Debounce 2
+ */
+#define WM5100_AIF_ERR_DB 0x0001 /* AIF_ERR_DB */
+#define WM5100_AIF_ERR_DB_MASK 0x0001 /* AIF_ERR_DB */
+#define WM5100_AIF_ERR_DB_SHIFT 0 /* AIF_ERR_DB */
+#define WM5100_AIF_ERR_DB_WIDTH 1 /* AIF_ERR_DB */
+
+/*
+ * R3584 (0xE00) - FX_Ctrl
+ */
+#define WM5100_FX_STS_MASK 0xFFC0 /* FX_STS - [15:6] */
+#define WM5100_FX_STS_SHIFT 6 /* FX_STS - [15:6] */
+#define WM5100_FX_STS_WIDTH 10 /* FX_STS - [15:6] */
+#define WM5100_FX_RATE_MASK 0x0003 /* FX_RATE - [1:0] */
+#define WM5100_FX_RATE_SHIFT 0 /* FX_RATE - [1:0] */
+#define WM5100_FX_RATE_WIDTH 2 /* FX_RATE - [1:0] */
+
+/*
+ * R3600 (0xE10) - EQ1_1
+ */
+#define WM5100_EQ1_B1_GAIN_MASK 0xF800 /* EQ1_B1_GAIN - [15:11] */
+#define WM5100_EQ1_B1_GAIN_SHIFT 11 /* EQ1_B1_GAIN - [15:11] */
+#define WM5100_EQ1_B1_GAIN_WIDTH 5 /* EQ1_B1_GAIN - [15:11] */
+#define WM5100_EQ1_B2_GAIN_MASK 0x07C0 /* EQ1_B2_GAIN - [10:6] */
+#define WM5100_EQ1_B2_GAIN_SHIFT 6 /* EQ1_B2_GAIN - [10:6] */
+#define WM5100_EQ1_B2_GAIN_WIDTH 5 /* EQ1_B2_GAIN - [10:6] */
+#define WM5100_EQ1_B3_GAIN_MASK 0x003E /* EQ1_B3_GAIN - [5:1] */
+#define WM5100_EQ1_B3_GAIN_SHIFT 1 /* EQ1_B3_GAIN - [5:1] */
+#define WM5100_EQ1_B3_GAIN_WIDTH 5 /* EQ1_B3_GAIN - [5:1] */
+#define WM5100_EQ1_ENA 0x0001 /* EQ1_ENA */
+#define WM5100_EQ1_ENA_MASK 0x0001 /* EQ1_ENA */
+#define WM5100_EQ1_ENA_SHIFT 0 /* EQ1_ENA */
+#define WM5100_EQ1_ENA_WIDTH 1 /* EQ1_ENA */
+
+/*
+ * R3601 (0xE11) - EQ1_2
+ */
+#define WM5100_EQ1_B4_GAIN_MASK 0xF800 /* EQ1_B4_GAIN - [15:11] */
+#define WM5100_EQ1_B4_GAIN_SHIFT 11 /* EQ1_B4_GAIN - [15:11] */
+#define WM5100_EQ1_B4_GAIN_WIDTH 5 /* EQ1_B4_GAIN - [15:11] */
+#define WM5100_EQ1_B5_GAIN_MASK 0x07C0 /* EQ1_B5_GAIN - [10:6] */
+#define WM5100_EQ1_B5_GAIN_SHIFT 6 /* EQ1_B5_GAIN - [10:6] */
+#define WM5100_EQ1_B5_GAIN_WIDTH 5 /* EQ1_B5_GAIN - [10:6] */
+
+/*
+ * R3602 (0xE12) - EQ1_3
+ */
+#define WM5100_EQ1_B1_A_MASK 0xFFFF /* EQ1_B1_A - [15:0] */
+#define WM5100_EQ1_B1_A_SHIFT 0 /* EQ1_B1_A - [15:0] */
+#define WM5100_EQ1_B1_A_WIDTH 16 /* EQ1_B1_A - [15:0] */
+
+/*
+ * R3603 (0xE13) - EQ1_4
+ */
+#define WM5100_EQ1_B1_B_MASK 0xFFFF /* EQ1_B1_B - [15:0] */
+#define WM5100_EQ1_B1_B_SHIFT 0 /* EQ1_B1_B - [15:0] */
+#define WM5100_EQ1_B1_B_WIDTH 16 /* EQ1_B1_B - [15:0] */
+
+/*
+ * R3604 (0xE14) - EQ1_5
+ */
+#define WM5100_EQ1_B1_PG_MASK 0xFFFF /* EQ1_B1_PG - [15:0] */
+#define WM5100_EQ1_B1_PG_SHIFT 0 /* EQ1_B1_PG - [15:0] */
+#define WM5100_EQ1_B1_PG_WIDTH 16 /* EQ1_B1_PG - [15:0] */
+
+/*
+ * R3605 (0xE15) - EQ1_6
+ */
+#define WM5100_EQ1_B2_A_MASK 0xFFFF /* EQ1_B2_A - [15:0] */
+#define WM5100_EQ1_B2_A_SHIFT 0 /* EQ1_B2_A - [15:0] */
+#define WM5100_EQ1_B2_A_WIDTH 16 /* EQ1_B2_A - [15:0] */
+
+/*
+ * R3606 (0xE16) - EQ1_7
+ */
+#define WM5100_EQ1_B2_B_MASK 0xFFFF /* EQ1_B2_B - [15:0] */
+#define WM5100_EQ1_B2_B_SHIFT 0 /* EQ1_B2_B - [15:0] */
+#define WM5100_EQ1_B2_B_WIDTH 16 /* EQ1_B2_B - [15:0] */
+
+/*
+ * R3607 (0xE17) - EQ1_8
+ */
+#define WM5100_EQ1_B2_C_MASK 0xFFFF /* EQ1_B2_C - [15:0] */
+#define WM5100_EQ1_B2_C_SHIFT 0 /* EQ1_B2_C - [15:0] */
+#define WM5100_EQ1_B2_C_WIDTH 16 /* EQ1_B2_C - [15:0] */
+
+/*
+ * R3608 (0xE18) - EQ1_9
+ */
+#define WM5100_EQ1_B2_PG_MASK 0xFFFF /* EQ1_B2_PG - [15:0] */
+#define WM5100_EQ1_B2_PG_SHIFT 0 /* EQ1_B2_PG - [15:0] */
+#define WM5100_EQ1_B2_PG_WIDTH 16 /* EQ1_B2_PG - [15:0] */
+
+/*
+ * R3609 (0xE19) - EQ1_10
+ */
+#define WM5100_EQ1_B3_A_MASK 0xFFFF /* EQ1_B3_A - [15:0] */
+#define WM5100_EQ1_B3_A_SHIFT 0 /* EQ1_B3_A - [15:0] */
+#define WM5100_EQ1_B3_A_WIDTH 16 /* EQ1_B3_A - [15:0] */
+
+/*
+ * R3610 (0xE1A) - EQ1_11
+ */
+#define WM5100_EQ1_B3_B_MASK 0xFFFF /* EQ1_B3_B - [15:0] */
+#define WM5100_EQ1_B3_B_SHIFT 0 /* EQ1_B3_B - [15:0] */
+#define WM5100_EQ1_B3_B_WIDTH 16 /* EQ1_B3_B - [15:0] */
+
+/*
+ * R3611 (0xE1B) - EQ1_12
+ */
+#define WM5100_EQ1_B3_C_MASK 0xFFFF /* EQ1_B3_C - [15:0] */
+#define WM5100_EQ1_B3_C_SHIFT 0 /* EQ1_B3_C - [15:0] */
+#define WM5100_EQ1_B3_C_WIDTH 16 /* EQ1_B3_C - [15:0] */
+
+/*
+ * R3612 (0xE1C) - EQ1_13
+ */
+#define WM5100_EQ1_B3_PG_MASK 0xFFFF /* EQ1_B3_PG - [15:0] */
+#define WM5100_EQ1_B3_PG_SHIFT 0 /* EQ1_B3_PG - [15:0] */
+#define WM5100_EQ1_B3_PG_WIDTH 16 /* EQ1_B3_PG - [15:0] */
+
+/*
+ * R3613 (0xE1D) - EQ1_14
+ */
+#define WM5100_EQ1_B4_A_MASK 0xFFFF /* EQ1_B4_A - [15:0] */
+#define WM5100_EQ1_B4_A_SHIFT 0 /* EQ1_B4_A - [15:0] */
+#define WM5100_EQ1_B4_A_WIDTH 16 /* EQ1_B4_A - [15:0] */
+
+/*
+ * R3614 (0xE1E) - EQ1_15
+ */
+#define WM5100_EQ1_B4_B_MASK 0xFFFF /* EQ1_B4_B - [15:0] */
+#define WM5100_EQ1_B4_B_SHIFT 0 /* EQ1_B4_B - [15:0] */
+#define WM5100_EQ1_B4_B_WIDTH 16 /* EQ1_B4_B - [15:0] */
+
+/*
+ * R3615 (0xE1F) - EQ1_16
+ */
+#define WM5100_EQ1_B4_C_MASK 0xFFFF /* EQ1_B4_C - [15:0] */
+#define WM5100_EQ1_B4_C_SHIFT 0 /* EQ1_B4_C - [15:0] */
+#define WM5100_EQ1_B4_C_WIDTH 16 /* EQ1_B4_C - [15:0] */
+
+/*
+ * R3616 (0xE20) - EQ1_17
+ */
+#define WM5100_EQ1_B4_PG_MASK 0xFFFF /* EQ1_B4_PG - [15:0] */
+#define WM5100_EQ1_B4_PG_SHIFT 0 /* EQ1_B4_PG - [15:0] */
+#define WM5100_EQ1_B4_PG_WIDTH 16 /* EQ1_B4_PG - [15:0] */
+
+/*
+ * R3617 (0xE21) - EQ1_18
+ */
+#define WM5100_EQ1_B5_A_MASK 0xFFFF /* EQ1_B5_A - [15:0] */
+#define WM5100_EQ1_B5_A_SHIFT 0 /* EQ1_B5_A - [15:0] */
+#define WM5100_EQ1_B5_A_WIDTH 16 /* EQ1_B5_A - [15:0] */
+
+/*
+ * R3618 (0xE22) - EQ1_19
+ */
+#define WM5100_EQ1_B5_B_MASK 0xFFFF /* EQ1_B5_B - [15:0] */
+#define WM5100_EQ1_B5_B_SHIFT 0 /* EQ1_B5_B - [15:0] */
+#define WM5100_EQ1_B5_B_WIDTH 16 /* EQ1_B5_B - [15:0] */
+
+/*
+ * R3619 (0xE23) - EQ1_20
+ */
+#define WM5100_EQ1_B5_PG_MASK 0xFFFF /* EQ1_B5_PG - [15:0] */
+#define WM5100_EQ1_B5_PG_SHIFT 0 /* EQ1_B5_PG - [15:0] */
+#define WM5100_EQ1_B5_PG_WIDTH 16 /* EQ1_B5_PG - [15:0] */
+
+/*
+ * R3622 (0xE26) - EQ2_1
+ */
+#define WM5100_EQ2_B1_GAIN_MASK 0xF800 /* EQ2_B1_GAIN - [15:11] */
+#define WM5100_EQ2_B1_GAIN_SHIFT 11 /* EQ2_B1_GAIN - [15:11] */
+#define WM5100_EQ2_B1_GAIN_WIDTH 5 /* EQ2_B1_GAIN - [15:11] */
+#define WM5100_EQ2_B2_GAIN_MASK 0x07C0 /* EQ2_B2_GAIN - [10:6] */
+#define WM5100_EQ2_B2_GAIN_SHIFT 6 /* EQ2_B2_GAIN - [10:6] */
+#define WM5100_EQ2_B2_GAIN_WIDTH 5 /* EQ2_B2_GAIN - [10:6] */
+#define WM5100_EQ2_B3_GAIN_MASK 0x003E /* EQ2_B3_GAIN - [5:1] */
+#define WM5100_EQ2_B3_GAIN_SHIFT 1 /* EQ2_B3_GAIN - [5:1] */
+#define WM5100_EQ2_B3_GAIN_WIDTH 5 /* EQ2_B3_GAIN - [5:1] */
+#define WM5100_EQ2_ENA 0x0001 /* EQ2_ENA */
+#define WM5100_EQ2_ENA_MASK 0x0001 /* EQ2_ENA */
+#define WM5100_EQ2_ENA_SHIFT 0 /* EQ2_ENA */
+#define WM5100_EQ2_ENA_WIDTH 1 /* EQ2_ENA */
+
+/*
+ * R3623 (0xE27) - EQ2_2
+ */
+#define WM5100_EQ2_B4_GAIN_MASK 0xF800 /* EQ2_B4_GAIN - [15:11] */
+#define WM5100_EQ2_B4_GAIN_SHIFT 11 /* EQ2_B4_GAIN - [15:11] */
+#define WM5100_EQ2_B4_GAIN_WIDTH 5 /* EQ2_B4_GAIN - [15:11] */
+#define WM5100_EQ2_B5_GAIN_MASK 0x07C0 /* EQ2_B5_GAIN - [10:6] */
+#define WM5100_EQ2_B5_GAIN_SHIFT 6 /* EQ2_B5_GAIN - [10:6] */
+#define WM5100_EQ2_B5_GAIN_WIDTH 5 /* EQ2_B5_GAIN - [10:6] */
+
+/*
+ * R3624 (0xE28) - EQ2_3
+ */
+#define WM5100_EQ2_B1_A_MASK 0xFFFF /* EQ2_B1_A - [15:0] */
+#define WM5100_EQ2_B1_A_SHIFT 0 /* EQ2_B1_A - [15:0] */
+#define WM5100_EQ2_B1_A_WIDTH 16 /* EQ2_B1_A - [15:0] */
+
+/*
+ * R3625 (0xE29) - EQ2_4
+ */
+#define WM5100_EQ2_B1_B_MASK 0xFFFF /* EQ2_B1_B - [15:0] */
+#define WM5100_EQ2_B1_B_SHIFT 0 /* EQ2_B1_B - [15:0] */
+#define WM5100_EQ2_B1_B_WIDTH 16 /* EQ2_B1_B - [15:0] */
+
+/*
+ * R3626 (0xE2A) - EQ2_5
+ */
+#define WM5100_EQ2_B1_PG_MASK 0xFFFF /* EQ2_B1_PG - [15:0] */
+#define WM5100_EQ2_B1_PG_SHIFT 0 /* EQ2_B1_PG - [15:0] */
+#define WM5100_EQ2_B1_PG_WIDTH 16 /* EQ2_B1_PG - [15:0] */
+
+/*
+ * R3627 (0xE2B) - EQ2_6
+ */
+#define WM5100_EQ2_B2_A_MASK 0xFFFF /* EQ2_B2_A - [15:0] */
+#define WM5100_EQ2_B2_A_SHIFT 0 /* EQ2_B2_A - [15:0] */
+#define WM5100_EQ2_B2_A_WIDTH 16 /* EQ2_B2_A - [15:0] */
+
+/*
+ * R3628 (0xE2C) - EQ2_7
+ */
+#define WM5100_EQ2_B2_B_MASK 0xFFFF /* EQ2_B2_B - [15:0] */
+#define WM5100_EQ2_B2_B_SHIFT 0 /* EQ2_B2_B - [15:0] */
+#define WM5100_EQ2_B2_B_WIDTH 16 /* EQ2_B2_B - [15:0] */
+
+/*
+ * R3629 (0xE2D) - EQ2_8
+ */
+#define WM5100_EQ2_B2_C_MASK 0xFFFF /* EQ2_B2_C - [15:0] */
+#define WM5100_EQ2_B2_C_SHIFT 0 /* EQ2_B2_C - [15:0] */
+#define WM5100_EQ2_B2_C_WIDTH 16 /* EQ2_B2_C - [15:0] */
+
+/*
+ * R3630 (0xE2E) - EQ2_9
+ */
+#define WM5100_EQ2_B2_PG_MASK 0xFFFF /* EQ2_B2_PG - [15:0] */
+#define WM5100_EQ2_B2_PG_SHIFT 0 /* EQ2_B2_PG - [15:0] */
+#define WM5100_EQ2_B2_PG_WIDTH 16 /* EQ2_B2_PG - [15:0] */
+
+/*
+ * R3631 (0xE2F) - EQ2_10
+ */
+#define WM5100_EQ2_B3_A_MASK 0xFFFF /* EQ2_B3_A - [15:0] */
+#define WM5100_EQ2_B3_A_SHIFT 0 /* EQ2_B3_A - [15:0] */
+#define WM5100_EQ2_B3_A_WIDTH 16 /* EQ2_B3_A - [15:0] */
+
+/*
+ * R3632 (0xE30) - EQ2_11
+ */
+#define WM5100_EQ2_B3_B_MASK 0xFFFF /* EQ2_B3_B - [15:0] */
+#define WM5100_EQ2_B3_B_SHIFT 0 /* EQ2_B3_B - [15:0] */
+#define WM5100_EQ2_B3_B_WIDTH 16 /* EQ2_B3_B - [15:0] */
+
+/*
+ * R3633 (0xE31) - EQ2_12
+ */
+#define WM5100_EQ2_B3_C_MASK 0xFFFF /* EQ2_B3_C - [15:0] */
+#define WM5100_EQ2_B3_C_SHIFT 0 /* EQ2_B3_C - [15:0] */
+#define WM5100_EQ2_B3_C_WIDTH 16 /* EQ2_B3_C - [15:0] */
+
+/*
+ * R3634 (0xE32) - EQ2_13
+ */
+#define WM5100_EQ2_B3_PG_MASK 0xFFFF /* EQ2_B3_PG - [15:0] */
+#define WM5100_EQ2_B3_PG_SHIFT 0 /* EQ2_B3_PG - [15:0] */
+#define WM5100_EQ2_B3_PG_WIDTH 16 /* EQ2_B3_PG - [15:0] */
+
+/*
+ * R3635 (0xE33) - EQ2_14
+ */
+#define WM5100_EQ2_B4_A_MASK 0xFFFF /* EQ2_B4_A - [15:0] */
+#define WM5100_EQ2_B4_A_SHIFT 0 /* EQ2_B4_A - [15:0] */
+#define WM5100_EQ2_B4_A_WIDTH 16 /* EQ2_B4_A - [15:0] */
+
+/*
+ * R3636 (0xE34) - EQ2_15
+ */
+#define WM5100_EQ2_B4_B_MASK 0xFFFF /* EQ2_B4_B - [15:0] */
+#define WM5100_EQ2_B4_B_SHIFT 0 /* EQ2_B4_B - [15:0] */
+#define WM5100_EQ2_B4_B_WIDTH 16 /* EQ2_B4_B - [15:0] */
+
+/*
+ * R3637 (0xE35) - EQ2_16
+ */
+#define WM5100_EQ2_B4_C_MASK 0xFFFF /* EQ2_B4_C - [15:0] */
+#define WM5100_EQ2_B4_C_SHIFT 0 /* EQ2_B4_C - [15:0] */
+#define WM5100_EQ2_B4_C_WIDTH 16 /* EQ2_B4_C - [15:0] */
+
+/*
+ * R3638 (0xE36) - EQ2_17
+ */
+#define WM5100_EQ2_B4_PG_MASK 0xFFFF /* EQ2_B4_PG - [15:0] */
+#define WM5100_EQ2_B4_PG_SHIFT 0 /* EQ2_B4_PG - [15:0] */
+#define WM5100_EQ2_B4_PG_WIDTH 16 /* EQ2_B4_PG - [15:0] */
+
+/*
+ * R3639 (0xE37) - EQ2_18
+ */
+#define WM5100_EQ2_B5_A_MASK 0xFFFF /* EQ2_B5_A - [15:0] */
+#define WM5100_EQ2_B5_A_SHIFT 0 /* EQ2_B5_A - [15:0] */
+#define WM5100_EQ2_B5_A_WIDTH 16 /* EQ2_B5_A - [15:0] */
+
+/*
+ * R3640 (0xE38) - EQ2_19
+ */
+#define WM5100_EQ2_B5_B_MASK 0xFFFF /* EQ2_B5_B - [15:0] */
+#define WM5100_EQ2_B5_B_SHIFT 0 /* EQ2_B5_B - [15:0] */
+#define WM5100_EQ2_B5_B_WIDTH 16 /* EQ2_B5_B - [15:0] */
+
+/*
+ * R3641 (0xE39) - EQ2_20
+ */
+#define WM5100_EQ2_B5_PG_MASK 0xFFFF /* EQ2_B5_PG - [15:0] */
+#define WM5100_EQ2_B5_PG_SHIFT 0 /* EQ2_B5_PG - [15:0] */
+#define WM5100_EQ2_B5_PG_WIDTH 16 /* EQ2_B5_PG - [15:0] */
+
+/*
+ * R3644 (0xE3C) - EQ3_1
+ */
+#define WM5100_EQ3_B1_GAIN_MASK 0xF800 /* EQ3_B1_GAIN - [15:11] */
+#define WM5100_EQ3_B1_GAIN_SHIFT 11 /* EQ3_B1_GAIN - [15:11] */
+#define WM5100_EQ3_B1_GAIN_WIDTH 5 /* EQ3_B1_GAIN - [15:11] */
+#define WM5100_EQ3_B2_GAIN_MASK 0x07C0 /* EQ3_B2_GAIN - [10:6] */
+#define WM5100_EQ3_B2_GAIN_SHIFT 6 /* EQ3_B2_GAIN - [10:6] */
+#define WM5100_EQ3_B2_GAIN_WIDTH 5 /* EQ3_B2_GAIN - [10:6] */
+#define WM5100_EQ3_B3_GAIN_MASK 0x003E /* EQ3_B3_GAIN - [5:1] */
+#define WM5100_EQ3_B3_GAIN_SHIFT 1 /* EQ3_B3_GAIN - [5:1] */
+#define WM5100_EQ3_B3_GAIN_WIDTH 5 /* EQ3_B3_GAIN - [5:1] */
+#define WM5100_EQ3_ENA 0x0001 /* EQ3_ENA */
+#define WM5100_EQ3_ENA_MASK 0x0001 /* EQ3_ENA */
+#define WM5100_EQ3_ENA_SHIFT 0 /* EQ3_ENA */
+#define WM5100_EQ3_ENA_WIDTH 1 /* EQ3_ENA */
+
+/*
+ * R3645 (0xE3D) - EQ3_2
+ */
+#define WM5100_EQ3_B4_GAIN_MASK 0xF800 /* EQ3_B4_GAIN - [15:11] */
+#define WM5100_EQ3_B4_GAIN_SHIFT 11 /* EQ3_B4_GAIN - [15:11] */
+#define WM5100_EQ3_B4_GAIN_WIDTH 5 /* EQ3_B4_GAIN - [15:11] */
+#define WM5100_EQ3_B5_GAIN_MASK 0x07C0 /* EQ3_B5_GAIN - [10:6] */
+#define WM5100_EQ3_B5_GAIN_SHIFT 6 /* EQ3_B5_GAIN - [10:6] */
+#define WM5100_EQ3_B5_GAIN_WIDTH 5 /* EQ3_B5_GAIN - [10:6] */
+
+/*
+ * R3646 (0xE3E) - EQ3_3
+ */
+#define WM5100_EQ3_B1_A_MASK 0xFFFF /* EQ3_B1_A - [15:0] */
+#define WM5100_EQ3_B1_A_SHIFT 0 /* EQ3_B1_A - [15:0] */
+#define WM5100_EQ3_B1_A_WIDTH 16 /* EQ3_B1_A - [15:0] */
+
+/*
+ * R3647 (0xE3F) - EQ3_4
+ */
+#define WM5100_EQ3_B1_B_MASK 0xFFFF /* EQ3_B1_B - [15:0] */
+#define WM5100_EQ3_B1_B_SHIFT 0 /* EQ3_B1_B - [15:0] */
+#define WM5100_EQ3_B1_B_WIDTH 16 /* EQ3_B1_B - [15:0] */
+
+/*
+ * R3648 (0xE40) - EQ3_5
+ */
+#define WM5100_EQ3_B1_PG_MASK 0xFFFF /* EQ3_B1_PG - [15:0] */
+#define WM5100_EQ3_B1_PG_SHIFT 0 /* EQ3_B1_PG - [15:0] */
+#define WM5100_EQ3_B1_PG_WIDTH 16 /* EQ3_B1_PG - [15:0] */
+
+/*
+ * R3649 (0xE41) - EQ3_6
+ */
+#define WM5100_EQ3_B2_A_MASK 0xFFFF /* EQ3_B2_A - [15:0] */
+#define WM5100_EQ3_B2_A_SHIFT 0 /* EQ3_B2_A - [15:0] */
+#define WM5100_EQ3_B2_A_WIDTH 16 /* EQ3_B2_A - [15:0] */
+
+/*
+ * R3650 (0xE42) - EQ3_7
+ */
+#define WM5100_EQ3_B2_B_MASK 0xFFFF /* EQ3_B2_B - [15:0] */
+#define WM5100_EQ3_B2_B_SHIFT 0 /* EQ3_B2_B - [15:0] */
+#define WM5100_EQ3_B2_B_WIDTH 16 /* EQ3_B2_B - [15:0] */
+
+/*
+ * R3651 (0xE43) - EQ3_8
+ */
+#define WM5100_EQ3_B2_C_MASK 0xFFFF /* EQ3_B2_C - [15:0] */
+#define WM5100_EQ3_B2_C_SHIFT 0 /* EQ3_B2_C - [15:0] */
+#define WM5100_EQ3_B2_C_WIDTH 16 /* EQ3_B2_C - [15:0] */
+
+/*
+ * R3652 (0xE44) - EQ3_9
+ */
+#define WM5100_EQ3_B2_PG_MASK 0xFFFF /* EQ3_B2_PG - [15:0] */
+#define WM5100_EQ3_B2_PG_SHIFT 0 /* EQ3_B2_PG - [15:0] */
+#define WM5100_EQ3_B2_PG_WIDTH 16 /* EQ3_B2_PG - [15:0] */
+
+/*
+ * R3653 (0xE45) - EQ3_10
+ */
+#define WM5100_EQ3_B3_A_MASK 0xFFFF /* EQ3_B3_A - [15:0] */
+#define WM5100_EQ3_B3_A_SHIFT 0 /* EQ3_B3_A - [15:0] */
+#define WM5100_EQ3_B3_A_WIDTH 16 /* EQ3_B3_A - [15:0] */
+
+/*
+ * R3654 (0xE46) - EQ3_11
+ */
+#define WM5100_EQ3_B3_B_MASK 0xFFFF /* EQ3_B3_B - [15:0] */
+#define WM5100_EQ3_B3_B_SHIFT 0 /* EQ3_B3_B - [15:0] */
+#define WM5100_EQ3_B3_B_WIDTH 16 /* EQ3_B3_B - [15:0] */
+
+/*
+ * R3655 (0xE47) - EQ3_12
+ */
+#define WM5100_EQ3_B3_C_MASK 0xFFFF /* EQ3_B3_C - [15:0] */
+#define WM5100_EQ3_B3_C_SHIFT 0 /* EQ3_B3_C - [15:0] */
+#define WM5100_EQ3_B3_C_WIDTH 16 /* EQ3_B3_C - [15:0] */
+
+/*
+ * R3656 (0xE48) - EQ3_13
+ */
+#define WM5100_EQ3_B3_PG_MASK 0xFFFF /* EQ3_B3_PG - [15:0] */
+#define WM5100_EQ3_B3_PG_SHIFT 0 /* EQ3_B3_PG - [15:0] */
+#define WM5100_EQ3_B3_PG_WIDTH 16 /* EQ3_B3_PG - [15:0] */
+
+/*
+ * R3657 (0xE49) - EQ3_14
+ */
+#define WM5100_EQ3_B4_A_MASK 0xFFFF /* EQ3_B4_A - [15:0] */
+#define WM5100_EQ3_B4_A_SHIFT 0 /* EQ3_B4_A - [15:0] */
+#define WM5100_EQ3_B4_A_WIDTH 16 /* EQ3_B4_A - [15:0] */
+
+/*
+ * R3658 (0xE4A) - EQ3_15
+ */
+#define WM5100_EQ3_B4_B_MASK 0xFFFF /* EQ3_B4_B - [15:0] */
+#define WM5100_EQ3_B4_B_SHIFT 0 /* EQ3_B4_B - [15:0] */
+#define WM5100_EQ3_B4_B_WIDTH 16 /* EQ3_B4_B - [15:0] */
+
+/*
+ * R3659 (0xE4B) - EQ3_16
+ */
+#define WM5100_EQ3_B4_C_MASK 0xFFFF /* EQ3_B4_C - [15:0] */
+#define WM5100_EQ3_B4_C_SHIFT 0 /* EQ3_B4_C - [15:0] */
+#define WM5100_EQ3_B4_C_WIDTH 16 /* EQ3_B4_C - [15:0] */
+
+/*
+ * R3660 (0xE4C) - EQ3_17
+ */
+#define WM5100_EQ3_B4_PG_MASK 0xFFFF /* EQ3_B4_PG - [15:0] */
+#define WM5100_EQ3_B4_PG_SHIFT 0 /* EQ3_B4_PG - [15:0] */
+#define WM5100_EQ3_B4_PG_WIDTH 16 /* EQ3_B4_PG - [15:0] */
+
+/*
+ * R3661 (0xE4D) - EQ3_18
+ */
+#define WM5100_EQ3_B5_A_MASK 0xFFFF /* EQ3_B5_A - [15:0] */
+#define WM5100_EQ3_B5_A_SHIFT 0 /* EQ3_B5_A - [15:0] */
+#define WM5100_EQ3_B5_A_WIDTH 16 /* EQ3_B5_A - [15:0] */
+
+/*
+ * R3662 (0xE4E) - EQ3_19
+ */
+#define WM5100_EQ3_B5_B_MASK 0xFFFF /* EQ3_B5_B - [15:0] */
+#define WM5100_EQ3_B5_B_SHIFT 0 /* EQ3_B5_B - [15:0] */
+#define WM5100_EQ3_B5_B_WIDTH 16 /* EQ3_B5_B - [15:0] */
+
+/*
+ * R3663 (0xE4F) - EQ3_20
+ */
+#define WM5100_EQ3_B5_PG_MASK 0xFFFF /* EQ3_B5_PG - [15:0] */
+#define WM5100_EQ3_B5_PG_SHIFT 0 /* EQ3_B5_PG - [15:0] */
+#define WM5100_EQ3_B5_PG_WIDTH 16 /* EQ3_B5_PG - [15:0] */
+
+/*
+ * R3666 (0xE52) - EQ4_1
+ */
+#define WM5100_EQ4_B1_GAIN_MASK 0xF800 /* EQ4_B1_GAIN - [15:11] */
+#define WM5100_EQ4_B1_GAIN_SHIFT 11 /* EQ4_B1_GAIN - [15:11] */
+#define WM5100_EQ4_B1_GAIN_WIDTH 5 /* EQ4_B1_GAIN - [15:11] */
+#define WM5100_EQ4_B2_GAIN_MASK 0x07C0 /* EQ4_B2_GAIN - [10:6] */
+#define WM5100_EQ4_B2_GAIN_SHIFT 6 /* EQ4_B2_GAIN - [10:6] */
+#define WM5100_EQ4_B2_GAIN_WIDTH 5 /* EQ4_B2_GAIN - [10:6] */
+#define WM5100_EQ4_B3_GAIN_MASK 0x003E /* EQ4_B3_GAIN - [5:1] */
+#define WM5100_EQ4_B3_GAIN_SHIFT 1 /* EQ4_B3_GAIN - [5:1] */
+#define WM5100_EQ4_B3_GAIN_WIDTH 5 /* EQ4_B3_GAIN - [5:1] */
+#define WM5100_EQ4_ENA 0x0001 /* EQ4_ENA */
+#define WM5100_EQ4_ENA_MASK 0x0001 /* EQ4_ENA */
+#define WM5100_EQ4_ENA_SHIFT 0 /* EQ4_ENA */
+#define WM5100_EQ4_ENA_WIDTH 1 /* EQ4_ENA */
+
+/*
+ * R3667 (0xE53) - EQ4_2
+ */
+#define WM5100_EQ4_B4_GAIN_MASK 0xF800 /* EQ4_B4_GAIN - [15:11] */
+#define WM5100_EQ4_B4_GAIN_SHIFT 11 /* EQ4_B4_GAIN - [15:11] */
+#define WM5100_EQ4_B4_GAIN_WIDTH 5 /* EQ4_B4_GAIN - [15:11] */
+#define WM5100_EQ4_B5_GAIN_MASK 0x07C0 /* EQ4_B5_GAIN - [10:6] */
+#define WM5100_EQ4_B5_GAIN_SHIFT 6 /* EQ4_B5_GAIN - [10:6] */
+#define WM5100_EQ4_B5_GAIN_WIDTH 5 /* EQ4_B5_GAIN - [10:6] */
+
+/*
+ * R3668 (0xE54) - EQ4_3
+ */
+#define WM5100_EQ4_B1_A_MASK 0xFFFF /* EQ4_B1_A - [15:0] */
+#define WM5100_EQ4_B1_A_SHIFT 0 /* EQ4_B1_A - [15:0] */
+#define WM5100_EQ4_B1_A_WIDTH 16 /* EQ4_B1_A - [15:0] */
+
+/*
+ * R3669 (0xE55) - EQ4_4
+ */
+#define WM5100_EQ4_B1_B_MASK 0xFFFF /* EQ4_B1_B - [15:0] */
+#define WM5100_EQ4_B1_B_SHIFT 0 /* EQ4_B1_B - [15:0] */
+#define WM5100_EQ4_B1_B_WIDTH 16 /* EQ4_B1_B - [15:0] */
+
+/*
+ * R3670 (0xE56) - EQ4_5
+ */
+#define WM5100_EQ4_B1_PG_MASK 0xFFFF /* EQ4_B1_PG - [15:0] */
+#define WM5100_EQ4_B1_PG_SHIFT 0 /* EQ4_B1_PG - [15:0] */
+#define WM5100_EQ4_B1_PG_WIDTH 16 /* EQ4_B1_PG - [15:0] */
+
+/*
+ * R3671 (0xE57) - EQ4_6
+ */
+#define WM5100_EQ4_B2_A_MASK 0xFFFF /* EQ4_B2_A - [15:0] */
+#define WM5100_EQ4_B2_A_SHIFT 0 /* EQ4_B2_A - [15:0] */
+#define WM5100_EQ4_B2_A_WIDTH 16 /* EQ4_B2_A - [15:0] */
+
+/*
+ * R3672 (0xE58) - EQ4_7
+ */
+#define WM5100_EQ4_B2_B_MASK 0xFFFF /* EQ4_B2_B - [15:0] */
+#define WM5100_EQ4_B2_B_SHIFT 0 /* EQ4_B2_B - [15:0] */
+#define WM5100_EQ4_B2_B_WIDTH 16 /* EQ4_B2_B - [15:0] */
+
+/*
+ * R3673 (0xE59) - EQ4_8
+ */
+#define WM5100_EQ4_B2_C_MASK 0xFFFF /* EQ4_B2_C - [15:0] */
+#define WM5100_EQ4_B2_C_SHIFT 0 /* EQ4_B2_C - [15:0] */
+#define WM5100_EQ4_B2_C_WIDTH 16 /* EQ4_B2_C - [15:0] */
+
+/*
+ * R3674 (0xE5A) - EQ4_9
+ */
+#define WM5100_EQ4_B2_PG_MASK 0xFFFF /* EQ4_B2_PG - [15:0] */
+#define WM5100_EQ4_B2_PG_SHIFT 0 /* EQ4_B2_PG - [15:0] */
+#define WM5100_EQ4_B2_PG_WIDTH 16 /* EQ4_B2_PG - [15:0] */
+
+/*
+ * R3675 (0xE5B) - EQ4_10
+ */
+#define WM5100_EQ4_B3_A_MASK 0xFFFF /* EQ4_B3_A - [15:0] */
+#define WM5100_EQ4_B3_A_SHIFT 0 /* EQ4_B3_A - [15:0] */
+#define WM5100_EQ4_B3_A_WIDTH 16 /* EQ4_B3_A - [15:0] */
+
+/*
+ * R3676 (0xE5C) - EQ4_11
+ */
+#define WM5100_EQ4_B3_B_MASK 0xFFFF /* EQ4_B3_B - [15:0] */
+#define WM5100_EQ4_B3_B_SHIFT 0 /* EQ4_B3_B - [15:0] */
+#define WM5100_EQ4_B3_B_WIDTH 16 /* EQ4_B3_B - [15:0] */
+
+/*
+ * R3677 (0xE5D) - EQ4_12
+ */
+#define WM5100_EQ4_B3_C_MASK 0xFFFF /* EQ4_B3_C - [15:0] */
+#define WM5100_EQ4_B3_C_SHIFT 0 /* EQ4_B3_C - [15:0] */
+#define WM5100_EQ4_B3_C_WIDTH 16 /* EQ4_B3_C - [15:0] */
+
+/*
+ * R3678 (0xE5E) - EQ4_13
+ */
+#define WM5100_EQ4_B3_PG_MASK 0xFFFF /* EQ4_B3_PG - [15:0] */
+#define WM5100_EQ4_B3_PG_SHIFT 0 /* EQ4_B3_PG - [15:0] */
+#define WM5100_EQ4_B3_PG_WIDTH 16 /* EQ4_B3_PG - [15:0] */
+
+/*
+ * R3679 (0xE5F) - EQ4_14
+ */
+#define WM5100_EQ4_B4_A_MASK 0xFFFF /* EQ4_B4_A - [15:0] */
+#define WM5100_EQ4_B4_A_SHIFT 0 /* EQ4_B4_A - [15:0] */
+#define WM5100_EQ4_B4_A_WIDTH 16 /* EQ4_B4_A - [15:0] */
+
+/*
+ * R3680 (0xE60) - EQ4_15
+ */
+#define WM5100_EQ4_B4_B_MASK 0xFFFF /* EQ4_B4_B - [15:0] */
+#define WM5100_EQ4_B4_B_SHIFT 0 /* EQ4_B4_B - [15:0] */
+#define WM5100_EQ4_B4_B_WIDTH 16 /* EQ4_B4_B - [15:0] */
+
+/*
+ * R3681 (0xE61) - EQ4_16
+ */
+#define WM5100_EQ4_B4_C_MASK 0xFFFF /* EQ4_B4_C - [15:0] */
+#define WM5100_EQ4_B4_C_SHIFT 0 /* EQ4_B4_C - [15:0] */
+#define WM5100_EQ4_B4_C_WIDTH 16 /* EQ4_B4_C - [15:0] */
+
+/*
+ * R3682 (0xE62) - EQ4_17
+ */
+#define WM5100_EQ4_B4_PG_MASK 0xFFFF /* EQ4_B4_PG - [15:0] */
+#define WM5100_EQ4_B4_PG_SHIFT 0 /* EQ4_B4_PG - [15:0] */
+#define WM5100_EQ4_B4_PG_WIDTH 16 /* EQ4_B4_PG - [15:0] */
+
+/*
+ * R3683 (0xE63) - EQ4_18
+ */
+#define WM5100_EQ4_B5_A_MASK 0xFFFF /* EQ4_B5_A - [15:0] */
+#define WM5100_EQ4_B5_A_SHIFT 0 /* EQ4_B5_A - [15:0] */
+#define WM5100_EQ4_B5_A_WIDTH 16 /* EQ4_B5_A - [15:0] */
+
+/*
+ * R3684 (0xE64) - EQ4_19
+ */
+#define WM5100_EQ4_B5_B_MASK 0xFFFF /* EQ4_B5_B - [15:0] */
+#define WM5100_EQ4_B5_B_SHIFT 0 /* EQ4_B5_B - [15:0] */
+#define WM5100_EQ4_B5_B_WIDTH 16 /* EQ4_B5_B - [15:0] */
+
+/*
+ * R3685 (0xE65) - EQ4_20
+ */
+#define WM5100_EQ4_B5_PG_MASK 0xFFFF /* EQ4_B5_PG - [15:0] */
+#define WM5100_EQ4_B5_PG_SHIFT 0 /* EQ4_B5_PG - [15:0] */
+#define WM5100_EQ4_B5_PG_WIDTH 16 /* EQ4_B5_PG - [15:0] */
+
+/*
+ * R3712 (0xE80) - DRC1 ctrl1
+ */
+#define WM5100_DRC_SIG_DET_RMS_MASK 0xF800 /* DRC_SIG_DET_RMS - [15:11] */
+#define WM5100_DRC_SIG_DET_RMS_SHIFT 11 /* DRC_SIG_DET_RMS - [15:11] */
+#define WM5100_DRC_SIG_DET_RMS_WIDTH 5 /* DRC_SIG_DET_RMS - [15:11] */
+#define WM5100_DRC_SIG_DET_PK_MASK 0x0600 /* DRC_SIG_DET_PK - [10:9] */
+#define WM5100_DRC_SIG_DET_PK_SHIFT 9 /* DRC_SIG_DET_PK - [10:9] */
+#define WM5100_DRC_SIG_DET_PK_WIDTH 2 /* DRC_SIG_DET_PK - [10:9] */
+#define WM5100_DRC_NG_ENA 0x0100 /* DRC_NG_ENA */
+#define WM5100_DRC_NG_ENA_MASK 0x0100 /* DRC_NG_ENA */
+#define WM5100_DRC_NG_ENA_SHIFT 8 /* DRC_NG_ENA */
+#define WM5100_DRC_NG_ENA_WIDTH 1 /* DRC_NG_ENA */
+#define WM5100_DRC_SIG_DET_MODE 0x0080 /* DRC_SIG_DET_MODE */
+#define WM5100_DRC_SIG_DET_MODE_MASK 0x0080 /* DRC_SIG_DET_MODE */
+#define WM5100_DRC_SIG_DET_MODE_SHIFT 7 /* DRC_SIG_DET_MODE */
+#define WM5100_DRC_SIG_DET_MODE_WIDTH 1 /* DRC_SIG_DET_MODE */
+#define WM5100_DRC_SIG_DET 0x0040 /* DRC_SIG_DET */
+#define WM5100_DRC_SIG_DET_MASK 0x0040 /* DRC_SIG_DET */
+#define WM5100_DRC_SIG_DET_SHIFT 6 /* DRC_SIG_DET */
+#define WM5100_DRC_SIG_DET_WIDTH 1 /* DRC_SIG_DET */
+#define WM5100_DRC_KNEE2_OP_ENA 0x0020 /* DRC_KNEE2_OP_ENA */
+#define WM5100_DRC_KNEE2_OP_ENA_MASK 0x0020 /* DRC_KNEE2_OP_ENA */
+#define WM5100_DRC_KNEE2_OP_ENA_SHIFT 5 /* DRC_KNEE2_OP_ENA */
+#define WM5100_DRC_KNEE2_OP_ENA_WIDTH 1 /* DRC_KNEE2_OP_ENA */
+#define WM5100_DRC_QR 0x0010 /* DRC_QR */
+#define WM5100_DRC_QR_MASK 0x0010 /* DRC_QR */
+#define WM5100_DRC_QR_SHIFT 4 /* DRC_QR */
+#define WM5100_DRC_QR_WIDTH 1 /* DRC_QR */
+#define WM5100_DRC_ANTICLIP 0x0008 /* DRC_ANTICLIP */
+#define WM5100_DRC_ANTICLIP_MASK 0x0008 /* DRC_ANTICLIP */
+#define WM5100_DRC_ANTICLIP_SHIFT 3 /* DRC_ANTICLIP */
+#define WM5100_DRC_ANTICLIP_WIDTH 1 /* DRC_ANTICLIP */
+#define WM5100_DRCL_ENA 0x0002 /* DRCL_ENA */
+#define WM5100_DRCL_ENA_MASK 0x0002 /* DRCL_ENA */
+#define WM5100_DRCL_ENA_SHIFT 1 /* DRCL_ENA */
+#define WM5100_DRCL_ENA_WIDTH 1 /* DRCL_ENA */
+#define WM5100_DRCR_ENA 0x0001 /* DRCR_ENA */
+#define WM5100_DRCR_ENA_MASK 0x0001 /* DRCR_ENA */
+#define WM5100_DRCR_ENA_SHIFT 0 /* DRCR_ENA */
+#define WM5100_DRCR_ENA_WIDTH 1 /* DRCR_ENA */
+
+/*
+ * R3713 (0xE81) - DRC1 ctrl2
+ */
+#define WM5100_DRC_ATK_MASK 0x1E00 /* DRC_ATK - [12:9] */
+#define WM5100_DRC_ATK_SHIFT 9 /* DRC_ATK - [12:9] */
+#define WM5100_DRC_ATK_WIDTH 4 /* DRC_ATK - [12:9] */
+#define WM5100_DRC_DCY_MASK 0x01E0 /* DRC_DCY - [8:5] */
+#define WM5100_DRC_DCY_SHIFT 5 /* DRC_DCY - [8:5] */
+#define WM5100_DRC_DCY_WIDTH 4 /* DRC_DCY - [8:5] */
+#define WM5100_DRC_MINGAIN_MASK 0x001C /* DRC_MINGAIN - [4:2] */
+#define WM5100_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [4:2] */
+#define WM5100_DRC_MINGAIN_WIDTH 3 /* DRC_MINGAIN - [4:2] */
+#define WM5100_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */
+#define WM5100_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */
+#define WM5100_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R3714 (0xE82) - DRC1 ctrl3
+ */
+#define WM5100_DRC_NG_MINGAIN_MASK 0xF000 /* DRC_NG_MINGAIN - [15:12] */
+#define WM5100_DRC_NG_MINGAIN_SHIFT 12 /* DRC_NG_MINGAIN - [15:12] */
+#define WM5100_DRC_NG_MINGAIN_WIDTH 4 /* DRC_NG_MINGAIN - [15:12] */
+#define WM5100_DRC_NG_EXP_MASK 0x0C00 /* DRC_NG_EXP - [11:10] */
+#define WM5100_DRC_NG_EXP_SHIFT 10 /* DRC_NG_EXP - [11:10] */
+#define WM5100_DRC_NG_EXP_WIDTH 2 /* DRC_NG_EXP - [11:10] */
+#define WM5100_DRC_QR_THR_MASK 0x0300 /* DRC_QR_THR - [9:8] */
+#define WM5100_DRC_QR_THR_SHIFT 8 /* DRC_QR_THR - [9:8] */
+#define WM5100_DRC_QR_THR_WIDTH 2 /* DRC_QR_THR - [9:8] */
+#define WM5100_DRC_QR_DCY_MASK 0x00C0 /* DRC_QR_DCY - [7:6] */
+#define WM5100_DRC_QR_DCY_SHIFT 6 /* DRC_QR_DCY - [7:6] */
+#define WM5100_DRC_QR_DCY_WIDTH 2 /* DRC_QR_DCY - [7:6] */
+#define WM5100_DRC_HI_COMP_MASK 0x0038 /* DRC_HI_COMP - [5:3] */
+#define WM5100_DRC_HI_COMP_SHIFT 3 /* DRC_HI_COMP - [5:3] */
+#define WM5100_DRC_HI_COMP_WIDTH 3 /* DRC_HI_COMP - [5:3] */
+#define WM5100_DRC_LO_COMP_MASK 0x0007 /* DRC_LO_COMP - [2:0] */
+#define WM5100_DRC_LO_COMP_SHIFT 0 /* DRC_LO_COMP - [2:0] */
+#define WM5100_DRC_LO_COMP_WIDTH 3 /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R3715 (0xE83) - DRC1 ctrl4
+ */
+#define WM5100_DRC_KNEE_IP_MASK 0x07E0 /* DRC_KNEE_IP - [10:5] */
+#define WM5100_DRC_KNEE_IP_SHIFT 5 /* DRC_KNEE_IP - [10:5] */
+#define WM5100_DRC_KNEE_IP_WIDTH 6 /* DRC_KNEE_IP - [10:5] */
+#define WM5100_DRC_KNEE_OP_MASK 0x001F /* DRC_KNEE_OP - [4:0] */
+#define WM5100_DRC_KNEE_OP_SHIFT 0 /* DRC_KNEE_OP - [4:0] */
+#define WM5100_DRC_KNEE_OP_WIDTH 5 /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R3716 (0xE84) - DRC1 ctrl5
+ */
+#define WM5100_DRC_KNEE2_IP_MASK 0x03E0 /* DRC_KNEE2_IP - [9:5] */
+#define WM5100_DRC_KNEE2_IP_SHIFT 5 /* DRC_KNEE2_IP - [9:5] */
+#define WM5100_DRC_KNEE2_IP_WIDTH 5 /* DRC_KNEE2_IP - [9:5] */
+#define WM5100_DRC_KNEE2_OP_MASK 0x001F /* DRC_KNEE2_OP - [4:0] */
+#define WM5100_DRC_KNEE2_OP_SHIFT 0 /* DRC_KNEE2_OP - [4:0] */
+#define WM5100_DRC_KNEE2_OP_WIDTH 5 /* DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R3776 (0xEC0) - HPLPF1_1
+ */
+#define WM5100_LHPF1_MODE 0x0002 /* LHPF1_MODE */
+#define WM5100_LHPF1_MODE_MASK 0x0002 /* LHPF1_MODE */
+#define WM5100_LHPF1_MODE_SHIFT 1 /* LHPF1_MODE */
+#define WM5100_LHPF1_MODE_WIDTH 1 /* LHPF1_MODE */
+#define WM5100_LHPF1_ENA 0x0001 /* LHPF1_ENA */
+#define WM5100_LHPF1_ENA_MASK 0x0001 /* LHPF1_ENA */
+#define WM5100_LHPF1_ENA_SHIFT 0 /* LHPF1_ENA */
+#define WM5100_LHPF1_ENA_WIDTH 1 /* LHPF1_ENA */
+
+/*
+ * R3777 (0xEC1) - HPLPF1_2
+ */
+#define WM5100_LHPF1_COEFF_MASK 0xFFFF /* LHPF1_COEFF - [15:0] */
+#define WM5100_LHPF1_COEFF_SHIFT 0 /* LHPF1_COEFF - [15:0] */
+#define WM5100_LHPF1_COEFF_WIDTH 16 /* LHPF1_COEFF - [15:0] */
+
+/*
+ * R3780 (0xEC4) - HPLPF2_1
+ */
+#define WM5100_LHPF2_MODE 0x0002 /* LHPF2_MODE */
+#define WM5100_LHPF2_MODE_MASK 0x0002 /* LHPF2_MODE */
+#define WM5100_LHPF2_MODE_SHIFT 1 /* LHPF2_MODE */
+#define WM5100_LHPF2_MODE_WIDTH 1 /* LHPF2_MODE */
+#define WM5100_LHPF2_ENA 0x0001 /* LHPF2_ENA */
+#define WM5100_LHPF2_ENA_MASK 0x0001 /* LHPF2_ENA */
+#define WM5100_LHPF2_ENA_SHIFT 0 /* LHPF2_ENA */
+#define WM5100_LHPF2_ENA_WIDTH 1 /* LHPF2_ENA */
+
+/*
+ * R3781 (0xEC5) - HPLPF2_2
+ */
+#define WM5100_LHPF2_COEFF_MASK 0xFFFF /* LHPF2_COEFF - [15:0] */
+#define WM5100_LHPF2_COEFF_SHIFT 0 /* LHPF2_COEFF - [15:0] */
+#define WM5100_LHPF2_COEFF_WIDTH 16 /* LHPF2_COEFF - [15:0] */
+
+/*
+ * R3784 (0xEC8) - HPLPF3_1
+ */
+#define WM5100_LHPF3_MODE 0x0002 /* LHPF3_MODE */
+#define WM5100_LHPF3_MODE_MASK 0x0002 /* LHPF3_MODE */
+#define WM5100_LHPF3_MODE_SHIFT 1 /* LHPF3_MODE */
+#define WM5100_LHPF3_MODE_WIDTH 1 /* LHPF3_MODE */
+#define WM5100_LHPF3_ENA 0x0001 /* LHPF3_ENA */
+#define WM5100_LHPF3_ENA_MASK 0x0001 /* LHPF3_ENA */
+#define WM5100_LHPF3_ENA_SHIFT 0 /* LHPF3_ENA */
+#define WM5100_LHPF3_ENA_WIDTH 1 /* LHPF3_ENA */
+
+/*
+ * R3785 (0xEC9) - HPLPF3_2
+ */
+#define WM5100_LHPF3_COEFF_MASK 0xFFFF /* LHPF3_COEFF - [15:0] */
+#define WM5100_LHPF3_COEFF_SHIFT 0 /* LHPF3_COEFF - [15:0] */
+#define WM5100_LHPF3_COEFF_WIDTH 16 /* LHPF3_COEFF - [15:0] */
+
+/*
+ * R3788 (0xECC) - HPLPF4_1
+ */
+#define WM5100_LHPF4_MODE 0x0002 /* LHPF4_MODE */
+#define WM5100_LHPF4_MODE_MASK 0x0002 /* LHPF4_MODE */
+#define WM5100_LHPF4_MODE_SHIFT 1 /* LHPF4_MODE */
+#define WM5100_LHPF4_MODE_WIDTH 1 /* LHPF4_MODE */
+#define WM5100_LHPF4_ENA 0x0001 /* LHPF4_ENA */
+#define WM5100_LHPF4_ENA_MASK 0x0001 /* LHPF4_ENA */
+#define WM5100_LHPF4_ENA_SHIFT 0 /* LHPF4_ENA */
+#define WM5100_LHPF4_ENA_WIDTH 1 /* LHPF4_ENA */
+
+/*
+ * R3789 (0xECD) - HPLPF4_2
+ */
+#define WM5100_LHPF4_COEFF_MASK 0xFFFF /* LHPF4_COEFF - [15:0] */
+#define WM5100_LHPF4_COEFF_SHIFT 0 /* LHPF4_COEFF - [15:0] */
+#define WM5100_LHPF4_COEFF_WIDTH 16 /* LHPF4_COEFF - [15:0] */
+
+/*
+ * R16384 (0x4000) - DSP1 DM 0
+ */
+#define WM5100_DSP1_DM_START_1_MASK 0x00FF /* DSP1_DM_START - [7:0] */
+#define WM5100_DSP1_DM_START_1_SHIFT 0 /* DSP1_DM_START - [7:0] */
+#define WM5100_DSP1_DM_START_1_WIDTH 8 /* DSP1_DM_START - [7:0] */
+
+/*
+ * R16385 (0x4001) - DSP1 DM 1
+ */
+#define WM5100_DSP1_DM_START_MASK 0xFFFF /* DSP1_DM_START - [15:0] */
+#define WM5100_DSP1_DM_START_SHIFT 0 /* DSP1_DM_START - [15:0] */
+#define WM5100_DSP1_DM_START_WIDTH 16 /* DSP1_DM_START - [15:0] */
+
+/*
+ * R16386 (0x4002) - DSP1 DM 2
+ */
+#define WM5100_DSP1_DM_1_1_MASK 0x00FF /* DSP1_DM_1 - [7:0] */
+#define WM5100_DSP1_DM_1_1_SHIFT 0 /* DSP1_DM_1 - [7:0] */
+#define WM5100_DSP1_DM_1_1_WIDTH 8 /* DSP1_DM_1 - [7:0] */
+
+/*
+ * R16387 (0x4003) - DSP1 DM 3
+ */
+#define WM5100_DSP1_DM_1_MASK 0xFFFF /* DSP1_DM_1 - [15:0] */
+#define WM5100_DSP1_DM_1_SHIFT 0 /* DSP1_DM_1 - [15:0] */
+#define WM5100_DSP1_DM_1_WIDTH 16 /* DSP1_DM_1 - [15:0] */
+
+/*
+ * R16892 (0x41FC) - DSP1 DM 508
+ */
+#define WM5100_DSP1_DM_254_1_MASK 0x00FF /* DSP1_DM_254 - [7:0] */
+#define WM5100_DSP1_DM_254_1_SHIFT 0 /* DSP1_DM_254 - [7:0] */
+#define WM5100_DSP1_DM_254_1_WIDTH 8 /* DSP1_DM_254 - [7:0] */
+
+/*
+ * R16893 (0x41FD) - DSP1 DM 509
+ */
+#define WM5100_DSP1_DM_254_MASK 0xFFFF /* DSP1_DM_254 - [15:0] */
+#define WM5100_DSP1_DM_254_SHIFT 0 /* DSP1_DM_254 - [15:0] */
+#define WM5100_DSP1_DM_254_WIDTH 16 /* DSP1_DM_254 - [15:0] */
+
+/*
+ * R16894 (0x41FE) - DSP1 DM 510
+ */
+#define WM5100_DSP1_DM_END_1_MASK 0x00FF /* DSP1_DM_END - [7:0] */
+#define WM5100_DSP1_DM_END_1_SHIFT 0 /* DSP1_DM_END - [7:0] */
+#define WM5100_DSP1_DM_END_1_WIDTH 8 /* DSP1_DM_END - [7:0] */
+
+/*
+ * R16895 (0x41FF) - DSP1 DM 511
+ */
+#define WM5100_DSP1_DM_END_MASK 0xFFFF /* DSP1_DM_END - [15:0] */
+#define WM5100_DSP1_DM_END_SHIFT 0 /* DSP1_DM_END - [15:0] */
+#define WM5100_DSP1_DM_END_WIDTH 16 /* DSP1_DM_END - [15:0] */
+
+/*
+ * R18432 (0x4800) - DSP1 PM 0
+ */
+#define WM5100_DSP1_PM_START_2_MASK 0x00FF /* DSP1_PM_START - [7:0] */
+#define WM5100_DSP1_PM_START_2_SHIFT 0 /* DSP1_PM_START - [7:0] */
+#define WM5100_DSP1_PM_START_2_WIDTH 8 /* DSP1_PM_START - [7:0] */
+
+/*
+ * R18433 (0x4801) - DSP1 PM 1
+ */
+#define WM5100_DSP1_PM_START_1_MASK 0xFFFF /* DSP1_PM_START - [15:0] */
+#define WM5100_DSP1_PM_START_1_SHIFT 0 /* DSP1_PM_START - [15:0] */
+#define WM5100_DSP1_PM_START_1_WIDTH 16 /* DSP1_PM_START - [15:0] */
+
+/*
+ * R18434 (0x4802) - DSP1 PM 2
+ */
+#define WM5100_DSP1_PM_START_MASK 0xFFFF /* DSP1_PM_START - [15:0] */
+#define WM5100_DSP1_PM_START_SHIFT 0 /* DSP1_PM_START - [15:0] */
+#define WM5100_DSP1_PM_START_WIDTH 16 /* DSP1_PM_START - [15:0] */
+
+/*
+ * R18435 (0x4803) - DSP1 PM 3
+ */
+#define WM5100_DSP1_PM_1_2_MASK 0x00FF /* DSP1_PM_1 - [7:0] */
+#define WM5100_DSP1_PM_1_2_SHIFT 0 /* DSP1_PM_1 - [7:0] */
+#define WM5100_DSP1_PM_1_2_WIDTH 8 /* DSP1_PM_1 - [7:0] */
+
+/*
+ * R18436 (0x4804) - DSP1 PM 4
+ */
+#define WM5100_DSP1_PM_1_1_MASK 0xFFFF /* DSP1_PM_1 - [15:0] */
+#define WM5100_DSP1_PM_1_1_SHIFT 0 /* DSP1_PM_1 - [15:0] */
+#define WM5100_DSP1_PM_1_1_WIDTH 16 /* DSP1_PM_1 - [15:0] */
+
+/*
+ * R18437 (0x4805) - DSP1 PM 5
+ */
+#define WM5100_DSP1_PM_1_MASK 0xFFFF /* DSP1_PM_1 - [15:0] */
+#define WM5100_DSP1_PM_1_SHIFT 0 /* DSP1_PM_1 - [15:0] */
+#define WM5100_DSP1_PM_1_WIDTH 16 /* DSP1_PM_1 - [15:0] */
+
+/*
+ * R19962 (0x4DFA) - DSP1 PM 1530
+ */
+#define WM5100_DSP1_PM_510_2_MASK 0x00FF /* DSP1_PM_510 - [7:0] */
+#define WM5100_DSP1_PM_510_2_SHIFT 0 /* DSP1_PM_510 - [7:0] */
+#define WM5100_DSP1_PM_510_2_WIDTH 8 /* DSP1_PM_510 - [7:0] */
+
+/*
+ * R19963 (0x4DFB) - DSP1 PM 1531
+ */
+#define WM5100_DSP1_PM_510_1_MASK 0xFFFF /* DSP1_PM_510 - [15:0] */
+#define WM5100_DSP1_PM_510_1_SHIFT 0 /* DSP1_PM_510 - [15:0] */
+#define WM5100_DSP1_PM_510_1_WIDTH 16 /* DSP1_PM_510 - [15:0] */
+
+/*
+ * R19964 (0x4DFC) - DSP1 PM 1532
+ */
+#define WM5100_DSP1_PM_510_MASK 0xFFFF /* DSP1_PM_510 - [15:0] */
+#define WM5100_DSP1_PM_510_SHIFT 0 /* DSP1_PM_510 - [15:0] */
+#define WM5100_DSP1_PM_510_WIDTH 16 /* DSP1_PM_510 - [15:0] */
+
+/*
+ * R19965 (0x4DFD) - DSP1 PM 1533
+ */
+#define WM5100_DSP1_PM_END_2_MASK 0x00FF /* DSP1_PM_END - [7:0] */
+#define WM5100_DSP1_PM_END_2_SHIFT 0 /* DSP1_PM_END - [7:0] */
+#define WM5100_DSP1_PM_END_2_WIDTH 8 /* DSP1_PM_END - [7:0] */
+
+/*
+ * R19966 (0x4DFE) - DSP1 PM 1534
+ */
+#define WM5100_DSP1_PM_END_1_MASK 0xFFFF /* DSP1_PM_END - [15:0] */
+#define WM5100_DSP1_PM_END_1_SHIFT 0 /* DSP1_PM_END - [15:0] */
+#define WM5100_DSP1_PM_END_1_WIDTH 16 /* DSP1_PM_END - [15:0] */
+
+/*
+ * R19967 (0x4DFF) - DSP1 PM 1535
+ */
+#define WM5100_DSP1_PM_END_MASK 0xFFFF /* DSP1_PM_END - [15:0] */
+#define WM5100_DSP1_PM_END_SHIFT 0 /* DSP1_PM_END - [15:0] */
+#define WM5100_DSP1_PM_END_WIDTH 16 /* DSP1_PM_END - [15:0] */
+
+/*
+ * R20480 (0x5000) - DSP1 ZM 0
+ */
+#define WM5100_DSP1_ZM_START_1_MASK 0x00FF /* DSP1_ZM_START - [7:0] */
+#define WM5100_DSP1_ZM_START_1_SHIFT 0 /* DSP1_ZM_START - [7:0] */
+#define WM5100_DSP1_ZM_START_1_WIDTH 8 /* DSP1_ZM_START - [7:0] */
+
+/*
+ * R20481 (0x5001) - DSP1 ZM 1
+ */
+#define WM5100_DSP1_ZM_START_MASK 0xFFFF /* DSP1_ZM_START - [15:0] */
+#define WM5100_DSP1_ZM_START_SHIFT 0 /* DSP1_ZM_START - [15:0] */
+#define WM5100_DSP1_ZM_START_WIDTH 16 /* DSP1_ZM_START - [15:0] */
+
+/*
+ * R20482 (0x5002) - DSP1 ZM 2
+ */
+#define WM5100_DSP1_ZM_1_1_MASK 0x00FF /* DSP1_ZM_1 - [7:0] */
+#define WM5100_DSP1_ZM_1_1_SHIFT 0 /* DSP1_ZM_1 - [7:0] */
+#define WM5100_DSP1_ZM_1_1_WIDTH 8 /* DSP1_ZM_1 - [7:0] */
+
+/*
+ * R20483 (0x5003) - DSP1 ZM 3
+ */
+#define WM5100_DSP1_ZM_1_MASK 0xFFFF /* DSP1_ZM_1 - [15:0] */
+#define WM5100_DSP1_ZM_1_SHIFT 0 /* DSP1_ZM_1 - [15:0] */
+#define WM5100_DSP1_ZM_1_WIDTH 16 /* DSP1_ZM_1 - [15:0] */
+
+/*
+ * R22524 (0x57FC) - DSP1 ZM 2044
+ */
+#define WM5100_DSP1_ZM_1022_1_MASK 0x00FF /* DSP1_ZM_1022 - [7:0] */
+#define WM5100_DSP1_ZM_1022_1_SHIFT 0 /* DSP1_ZM_1022 - [7:0] */
+#define WM5100_DSP1_ZM_1022_1_WIDTH 8 /* DSP1_ZM_1022 - [7:0] */
+
+/*
+ * R22525 (0x57FD) - DSP1 ZM 2045
+ */
+#define WM5100_DSP1_ZM_1022_MASK 0xFFFF /* DSP1_ZM_1022 - [15:0] */
+#define WM5100_DSP1_ZM_1022_SHIFT 0 /* DSP1_ZM_1022 - [15:0] */
+#define WM5100_DSP1_ZM_1022_WIDTH 16 /* DSP1_ZM_1022 - [15:0] */
+
+/*
+ * R22526 (0x57FE) - DSP1 ZM 2046
+ */
+#define WM5100_DSP1_ZM_END_1_MASK 0x00FF /* DSP1_ZM_END - [7:0] */
+#define WM5100_DSP1_ZM_END_1_SHIFT 0 /* DSP1_ZM_END - [7:0] */
+#define WM5100_DSP1_ZM_END_1_WIDTH 8 /* DSP1_ZM_END - [7:0] */
+
+/*
+ * R22527 (0x57FF) - DSP1 ZM 2047
+ */
+#define WM5100_DSP1_ZM_END_MASK 0xFFFF /* DSP1_ZM_END - [15:0] */
+#define WM5100_DSP1_ZM_END_SHIFT 0 /* DSP1_ZM_END - [15:0] */
+#define WM5100_DSP1_ZM_END_WIDTH 16 /* DSP1_ZM_END - [15:0] */
+
+/*
+ * R24576 (0x6000) - DSP2 DM 0
+ */
+#define WM5100_DSP2_DM_START_1_MASK 0x00FF /* DSP2_DM_START - [7:0] */
+#define WM5100_DSP2_DM_START_1_SHIFT 0 /* DSP2_DM_START - [7:0] */
+#define WM5100_DSP2_DM_START_1_WIDTH 8 /* DSP2_DM_START - [7:0] */
+
+/*
+ * R24577 (0x6001) - DSP2 DM 1
+ */
+#define WM5100_DSP2_DM_START_MASK 0xFFFF /* DSP2_DM_START - [15:0] */
+#define WM5100_DSP2_DM_START_SHIFT 0 /* DSP2_DM_START - [15:0] */
+#define WM5100_DSP2_DM_START_WIDTH 16 /* DSP2_DM_START - [15:0] */
+
+/*
+ * R24578 (0x6002) - DSP2 DM 2
+ */
+#define WM5100_DSP2_DM_1_1_MASK 0x00FF /* DSP2_DM_1 - [7:0] */
+#define WM5100_DSP2_DM_1_1_SHIFT 0 /* DSP2_DM_1 - [7:0] */
+#define WM5100_DSP2_DM_1_1_WIDTH 8 /* DSP2_DM_1 - [7:0] */
+
+/*
+ * R24579 (0x6003) - DSP2 DM 3
+ */
+#define WM5100_DSP2_DM_1_MASK 0xFFFF /* DSP2_DM_1 - [15:0] */
+#define WM5100_DSP2_DM_1_SHIFT 0 /* DSP2_DM_1 - [15:0] */
+#define WM5100_DSP2_DM_1_WIDTH 16 /* DSP2_DM_1 - [15:0] */
+
+/*
+ * R25084 (0x61FC) - DSP2 DM 508
+ */
+#define WM5100_DSP2_DM_254_1_MASK 0x00FF /* DSP2_DM_254 - [7:0] */
+#define WM5100_DSP2_DM_254_1_SHIFT 0 /* DSP2_DM_254 - [7:0] */
+#define WM5100_DSP2_DM_254_1_WIDTH 8 /* DSP2_DM_254 - [7:0] */
+
+/*
+ * R25085 (0x61FD) - DSP2 DM 509
+ */
+#define WM5100_DSP2_DM_254_MASK 0xFFFF /* DSP2_DM_254 - [15:0] */
+#define WM5100_DSP2_DM_254_SHIFT 0 /* DSP2_DM_254 - [15:0] */
+#define WM5100_DSP2_DM_254_WIDTH 16 /* DSP2_DM_254 - [15:0] */
+
+/*
+ * R25086 (0x61FE) - DSP2 DM 510
+ */
+#define WM5100_DSP2_DM_END_1_MASK 0x00FF /* DSP2_DM_END - [7:0] */
+#define WM5100_DSP2_DM_END_1_SHIFT 0 /* DSP2_DM_END - [7:0] */
+#define WM5100_DSP2_DM_END_1_WIDTH 8 /* DSP2_DM_END - [7:0] */
+
+/*
+ * R25087 (0x61FF) - DSP2 DM 511
+ */
+#define WM5100_DSP2_DM_END_MASK 0xFFFF /* DSP2_DM_END - [15:0] */
+#define WM5100_DSP2_DM_END_SHIFT 0 /* DSP2_DM_END - [15:0] */
+#define WM5100_DSP2_DM_END_WIDTH 16 /* DSP2_DM_END - [15:0] */
+
+/*
+ * R26624 (0x6800) - DSP2 PM 0
+ */
+#define WM5100_DSP2_PM_START_2_MASK 0x00FF /* DSP2_PM_START - [7:0] */
+#define WM5100_DSP2_PM_START_2_SHIFT 0 /* DSP2_PM_START - [7:0] */
+#define WM5100_DSP2_PM_START_2_WIDTH 8 /* DSP2_PM_START - [7:0] */
+
+/*
+ * R26625 (0x6801) - DSP2 PM 1
+ */
+#define WM5100_DSP2_PM_START_1_MASK 0xFFFF /* DSP2_PM_START - [15:0] */
+#define WM5100_DSP2_PM_START_1_SHIFT 0 /* DSP2_PM_START - [15:0] */
+#define WM5100_DSP2_PM_START_1_WIDTH 16 /* DSP2_PM_START - [15:0] */
+
+/*
+ * R26626 (0x6802) - DSP2 PM 2
+ */
+#define WM5100_DSP2_PM_START_MASK 0xFFFF /* DSP2_PM_START - [15:0] */
+#define WM5100_DSP2_PM_START_SHIFT 0 /* DSP2_PM_START - [15:0] */
+#define WM5100_DSP2_PM_START_WIDTH 16 /* DSP2_PM_START - [15:0] */
+
+/*
+ * R26627 (0x6803) - DSP2 PM 3
+ */
+#define WM5100_DSP2_PM_1_2_MASK 0x00FF /* DSP2_PM_1 - [7:0] */
+#define WM5100_DSP2_PM_1_2_SHIFT 0 /* DSP2_PM_1 - [7:0] */
+#define WM5100_DSP2_PM_1_2_WIDTH 8 /* DSP2_PM_1 - [7:0] */
+
+/*
+ * R26628 (0x6804) - DSP2 PM 4
+ */
+#define WM5100_DSP2_PM_1_1_MASK 0xFFFF /* DSP2_PM_1 - [15:0] */
+#define WM5100_DSP2_PM_1_1_SHIFT 0 /* DSP2_PM_1 - [15:0] */
+#define WM5100_DSP2_PM_1_1_WIDTH 16 /* DSP2_PM_1 - [15:0] */
+
+/*
+ * R26629 (0x6805) - DSP2 PM 5
+ */
+#define WM5100_DSP2_PM_1_MASK 0xFFFF /* DSP2_PM_1 - [15:0] */
+#define WM5100_DSP2_PM_1_SHIFT 0 /* DSP2_PM_1 - [15:0] */
+#define WM5100_DSP2_PM_1_WIDTH 16 /* DSP2_PM_1 - [15:0] */
+
+/*
+ * R28154 (0x6DFA) - DSP2 PM 1530
+ */
+#define WM5100_DSP2_PM_510_2_MASK 0x00FF /* DSP2_PM_510 - [7:0] */
+#define WM5100_DSP2_PM_510_2_SHIFT 0 /* DSP2_PM_510 - [7:0] */
+#define WM5100_DSP2_PM_510_2_WIDTH 8 /* DSP2_PM_510 - [7:0] */
+
+/*
+ * R28155 (0x6DFB) - DSP2 PM 1531
+ */
+#define WM5100_DSP2_PM_510_1_MASK 0xFFFF /* DSP2_PM_510 - [15:0] */
+#define WM5100_DSP2_PM_510_1_SHIFT 0 /* DSP2_PM_510 - [15:0] */
+#define WM5100_DSP2_PM_510_1_WIDTH 16 /* DSP2_PM_510 - [15:0] */
+
+/*
+ * R28156 (0x6DFC) - DSP2 PM 1532
+ */
+#define WM5100_DSP2_PM_510_MASK 0xFFFF /* DSP2_PM_510 - [15:0] */
+#define WM5100_DSP2_PM_510_SHIFT 0 /* DSP2_PM_510 - [15:0] */
+#define WM5100_DSP2_PM_510_WIDTH 16 /* DSP2_PM_510 - [15:0] */
+
+/*
+ * R28157 (0x6DFD) - DSP2 PM 1533
+ */
+#define WM5100_DSP2_PM_END_2_MASK 0x00FF /* DSP2_PM_END - [7:0] */
+#define WM5100_DSP2_PM_END_2_SHIFT 0 /* DSP2_PM_END - [7:0] */
+#define WM5100_DSP2_PM_END_2_WIDTH 8 /* DSP2_PM_END - [7:0] */
+
+/*
+ * R28158 (0x6DFE) - DSP2 PM 1534
+ */
+#define WM5100_DSP2_PM_END_1_MASK 0xFFFF /* DSP2_PM_END - [15:0] */
+#define WM5100_DSP2_PM_END_1_SHIFT 0 /* DSP2_PM_END - [15:0] */
+#define WM5100_DSP2_PM_END_1_WIDTH 16 /* DSP2_PM_END - [15:0] */
+
+/*
+ * R28159 (0x6DFF) - DSP2 PM 1535
+ */
+#define WM5100_DSP2_PM_END_MASK 0xFFFF /* DSP2_PM_END - [15:0] */
+#define WM5100_DSP2_PM_END_SHIFT 0 /* DSP2_PM_END - [15:0] */
+#define WM5100_DSP2_PM_END_WIDTH 16 /* DSP2_PM_END - [15:0] */
+
+/*
+ * R28672 (0x7000) - DSP2 ZM 0
+ */
+#define WM5100_DSP2_ZM_START_1_MASK 0x00FF /* DSP2_ZM_START - [7:0] */
+#define WM5100_DSP2_ZM_START_1_SHIFT 0 /* DSP2_ZM_START - [7:0] */
+#define WM5100_DSP2_ZM_START_1_WIDTH 8 /* DSP2_ZM_START - [7:0] */
+
+/*
+ * R28673 (0x7001) - DSP2 ZM 1
+ */
+#define WM5100_DSP2_ZM_START_MASK 0xFFFF /* DSP2_ZM_START - [15:0] */
+#define WM5100_DSP2_ZM_START_SHIFT 0 /* DSP2_ZM_START - [15:0] */
+#define WM5100_DSP2_ZM_START_WIDTH 16 /* DSP2_ZM_START - [15:0] */
+
+/*
+ * R28674 (0x7002) - DSP2 ZM 2
+ */
+#define WM5100_DSP2_ZM_1_1_MASK 0x00FF /* DSP2_ZM_1 - [7:0] */
+#define WM5100_DSP2_ZM_1_1_SHIFT 0 /* DSP2_ZM_1 - [7:0] */
+#define WM5100_DSP2_ZM_1_1_WIDTH 8 /* DSP2_ZM_1 - [7:0] */
+
+/*
+ * R28675 (0x7003) - DSP2 ZM 3
+ */
+#define WM5100_DSP2_ZM_1_MASK 0xFFFF /* DSP2_ZM_1 - [15:0] */
+#define WM5100_DSP2_ZM_1_SHIFT 0 /* DSP2_ZM_1 - [15:0] */
+#define WM5100_DSP2_ZM_1_WIDTH 16 /* DSP2_ZM_1 - [15:0] */
+
+/*
+ * R30716 (0x77FC) - DSP2 ZM 2044
+ */
+#define WM5100_DSP2_ZM_1022_1_MASK 0x00FF /* DSP2_ZM_1022 - [7:0] */
+#define WM5100_DSP2_ZM_1022_1_SHIFT 0 /* DSP2_ZM_1022 - [7:0] */
+#define WM5100_DSP2_ZM_1022_1_WIDTH 8 /* DSP2_ZM_1022 - [7:0] */
+
+/*
+ * R30717 (0x77FD) - DSP2 ZM 2045
+ */
+#define WM5100_DSP2_ZM_1022_MASK 0xFFFF /* DSP2_ZM_1022 - [15:0] */
+#define WM5100_DSP2_ZM_1022_SHIFT 0 /* DSP2_ZM_1022 - [15:0] */
+#define WM5100_DSP2_ZM_1022_WIDTH 16 /* DSP2_ZM_1022 - [15:0] */
+
+/*
+ * R30718 (0x77FE) - DSP2 ZM 2046
+ */
+#define WM5100_DSP2_ZM_END_1_MASK 0x00FF /* DSP2_ZM_END - [7:0] */
+#define WM5100_DSP2_ZM_END_1_SHIFT 0 /* DSP2_ZM_END - [7:0] */
+#define WM5100_DSP2_ZM_END_1_WIDTH 8 /* DSP2_ZM_END - [7:0] */
+
+/*
+ * R30719 (0x77FF) - DSP2 ZM 2047
+ */
+#define WM5100_DSP2_ZM_END_MASK 0xFFFF /* DSP2_ZM_END - [15:0] */
+#define WM5100_DSP2_ZM_END_SHIFT 0 /* DSP2_ZM_END - [15:0] */
+#define WM5100_DSP2_ZM_END_WIDTH 16 /* DSP2_ZM_END - [15:0] */
+
+/*
+ * R32768 (0x8000) - DSP3 DM 0
+ */
+#define WM5100_DSP3_DM_START_1_MASK 0x00FF /* DSP3_DM_START - [7:0] */
+#define WM5100_DSP3_DM_START_1_SHIFT 0 /* DSP3_DM_START - [7:0] */
+#define WM5100_DSP3_DM_START_1_WIDTH 8 /* DSP3_DM_START - [7:0] */
+
+/*
+ * R32769 (0x8001) - DSP3 DM 1
+ */
+#define WM5100_DSP3_DM_START_MASK 0xFFFF /* DSP3_DM_START - [15:0] */
+#define WM5100_DSP3_DM_START_SHIFT 0 /* DSP3_DM_START - [15:0] */
+#define WM5100_DSP3_DM_START_WIDTH 16 /* DSP3_DM_START - [15:0] */
+
+/*
+ * R32770 (0x8002) - DSP3 DM 2
+ */
+#define WM5100_DSP3_DM_1_1_MASK 0x00FF /* DSP3_DM_1 - [7:0] */
+#define WM5100_DSP3_DM_1_1_SHIFT 0 /* DSP3_DM_1 - [7:0] */
+#define WM5100_DSP3_DM_1_1_WIDTH 8 /* DSP3_DM_1 - [7:0] */
+
+/*
+ * R32771 (0x8003) - DSP3 DM 3
+ */
+#define WM5100_DSP3_DM_1_MASK 0xFFFF /* DSP3_DM_1 - [15:0] */
+#define WM5100_DSP3_DM_1_SHIFT 0 /* DSP3_DM_1 - [15:0] */
+#define WM5100_DSP3_DM_1_WIDTH 16 /* DSP3_DM_1 - [15:0] */
+
+/*
+ * R33276 (0x81FC) - DSP3 DM 508
+ */
+#define WM5100_DSP3_DM_254_1_MASK 0x00FF /* DSP3_DM_254 - [7:0] */
+#define WM5100_DSP3_DM_254_1_SHIFT 0 /* DSP3_DM_254 - [7:0] */
+#define WM5100_DSP3_DM_254_1_WIDTH 8 /* DSP3_DM_254 - [7:0] */
+
+/*
+ * R33277 (0x81FD) - DSP3 DM 509
+ */
+#define WM5100_DSP3_DM_254_MASK 0xFFFF /* DSP3_DM_254 - [15:0] */
+#define WM5100_DSP3_DM_254_SHIFT 0 /* DSP3_DM_254 - [15:0] */
+#define WM5100_DSP3_DM_254_WIDTH 16 /* DSP3_DM_254 - [15:0] */
+
+/*
+ * R33278 (0x81FE) - DSP3 DM 510
+ */
+#define WM5100_DSP3_DM_END_1_MASK 0x00FF /* DSP3_DM_END - [7:0] */
+#define WM5100_DSP3_DM_END_1_SHIFT 0 /* DSP3_DM_END - [7:0] */
+#define WM5100_DSP3_DM_END_1_WIDTH 8 /* DSP3_DM_END - [7:0] */
+
+/*
+ * R33279 (0x81FF) - DSP3 DM 511
+ */
+#define WM5100_DSP3_DM_END_MASK 0xFFFF /* DSP3_DM_END - [15:0] */
+#define WM5100_DSP3_DM_END_SHIFT 0 /* DSP3_DM_END - [15:0] */
+#define WM5100_DSP3_DM_END_WIDTH 16 /* DSP3_DM_END - [15:0] */
+
+/*
+ * R34816 (0x8800) - DSP3 PM 0
+ */
+#define WM5100_DSP3_PM_START_2_MASK 0x00FF /* DSP3_PM_START - [7:0] */
+#define WM5100_DSP3_PM_START_2_SHIFT 0 /* DSP3_PM_START - [7:0] */
+#define WM5100_DSP3_PM_START_2_WIDTH 8 /* DSP3_PM_START - [7:0] */
+
+/*
+ * R34817 (0x8801) - DSP3 PM 1
+ */
+#define WM5100_DSP3_PM_START_1_MASK 0xFFFF /* DSP3_PM_START - [15:0] */
+#define WM5100_DSP3_PM_START_1_SHIFT 0 /* DSP3_PM_START - [15:0] */
+#define WM5100_DSP3_PM_START_1_WIDTH 16 /* DSP3_PM_START - [15:0] */
+
+/*
+ * R34818 (0x8802) - DSP3 PM 2
+ */
+#define WM5100_DSP3_PM_START_MASK 0xFFFF /* DSP3_PM_START - [15:0] */
+#define WM5100_DSP3_PM_START_SHIFT 0 /* DSP3_PM_START - [15:0] */
+#define WM5100_DSP3_PM_START_WIDTH 16 /* DSP3_PM_START - [15:0] */
+
+/*
+ * R34819 (0x8803) - DSP3 PM 3
+ */
+#define WM5100_DSP3_PM_1_2_MASK 0x00FF /* DSP3_PM_1 - [7:0] */
+#define WM5100_DSP3_PM_1_2_SHIFT 0 /* DSP3_PM_1 - [7:0] */
+#define WM5100_DSP3_PM_1_2_WIDTH 8 /* DSP3_PM_1 - [7:0] */
+
+/*
+ * R34820 (0x8804) - DSP3 PM 4
+ */
+#define WM5100_DSP3_PM_1_1_MASK 0xFFFF /* DSP3_PM_1 - [15:0] */
+#define WM5100_DSP3_PM_1_1_SHIFT 0 /* DSP3_PM_1 - [15:0] */
+#define WM5100_DSP3_PM_1_1_WIDTH 16 /* DSP3_PM_1 - [15:0] */
+
+/*
+ * R34821 (0x8805) - DSP3 PM 5
+ */
+#define WM5100_DSP3_PM_1_MASK 0xFFFF /* DSP3_PM_1 - [15:0] */
+#define WM5100_DSP3_PM_1_SHIFT 0 /* DSP3_PM_1 - [15:0] */
+#define WM5100_DSP3_PM_1_WIDTH 16 /* DSP3_PM_1 - [15:0] */
+
+/*
+ * R36346 (0x8DFA) - DSP3 PM 1530
+ */
+#define WM5100_DSP3_PM_510_2_MASK 0x00FF /* DSP3_PM_510 - [7:0] */
+#define WM5100_DSP3_PM_510_2_SHIFT 0 /* DSP3_PM_510 - [7:0] */
+#define WM5100_DSP3_PM_510_2_WIDTH 8 /* DSP3_PM_510 - [7:0] */
+
+/*
+ * R36347 (0x8DFB) - DSP3 PM 1531
+ */
+#define WM5100_DSP3_PM_510_1_MASK 0xFFFF /* DSP3_PM_510 - [15:0] */
+#define WM5100_DSP3_PM_510_1_SHIFT 0 /* DSP3_PM_510 - [15:0] */
+#define WM5100_DSP3_PM_510_1_WIDTH 16 /* DSP3_PM_510 - [15:0] */
+
+/*
+ * R36348 (0x8DFC) - DSP3 PM 1532
+ */
+#define WM5100_DSP3_PM_510_MASK 0xFFFF /* DSP3_PM_510 - [15:0] */
+#define WM5100_DSP3_PM_510_SHIFT 0 /* DSP3_PM_510 - [15:0] */
+#define WM5100_DSP3_PM_510_WIDTH 16 /* DSP3_PM_510 - [15:0] */
+
+/*
+ * R36349 (0x8DFD) - DSP3 PM 1533
+ */
+#define WM5100_DSP3_PM_END_2_MASK 0x00FF /* DSP3_PM_END - [7:0] */
+#define WM5100_DSP3_PM_END_2_SHIFT 0 /* DSP3_PM_END - [7:0] */
+#define WM5100_DSP3_PM_END_2_WIDTH 8 /* DSP3_PM_END - [7:0] */
+
+/*
+ * R36350 (0x8DFE) - DSP3 PM 1534
+ */
+#define WM5100_DSP3_PM_END_1_MASK 0xFFFF /* DSP3_PM_END - [15:0] */
+#define WM5100_DSP3_PM_END_1_SHIFT 0 /* DSP3_PM_END - [15:0] */
+#define WM5100_DSP3_PM_END_1_WIDTH 16 /* DSP3_PM_END - [15:0] */
+
+/*
+ * R36351 (0x8DFF) - DSP3 PM 1535
+ */
+#define WM5100_DSP3_PM_END_MASK 0xFFFF /* DSP3_PM_END - [15:0] */
+#define WM5100_DSP3_PM_END_SHIFT 0 /* DSP3_PM_END - [15:0] */
+#define WM5100_DSP3_PM_END_WIDTH 16 /* DSP3_PM_END - [15:0] */
+
+/*
+ * R36864 (0x9000) - DSP3 ZM 0
+ */
+#define WM5100_DSP3_ZM_START_1_MASK 0x00FF /* DSP3_ZM_START - [7:0] */
+#define WM5100_DSP3_ZM_START_1_SHIFT 0 /* DSP3_ZM_START - [7:0] */
+#define WM5100_DSP3_ZM_START_1_WIDTH 8 /* DSP3_ZM_START - [7:0] */
+
+/*
+ * R36865 (0x9001) - DSP3 ZM 1
+ */
+#define WM5100_DSP3_ZM_START_MASK 0xFFFF /* DSP3_ZM_START - [15:0] */
+#define WM5100_DSP3_ZM_START_SHIFT 0 /* DSP3_ZM_START - [15:0] */
+#define WM5100_DSP3_ZM_START_WIDTH 16 /* DSP3_ZM_START - [15:0] */
+
+/*
+ * R36866 (0x9002) - DSP3 ZM 2
+ */
+#define WM5100_DSP3_ZM_1_1_MASK 0x00FF /* DSP3_ZM_1 - [7:0] */
+#define WM5100_DSP3_ZM_1_1_SHIFT 0 /* DSP3_ZM_1 - [7:0] */
+#define WM5100_DSP3_ZM_1_1_WIDTH 8 /* DSP3_ZM_1 - [7:0] */
+
+/*
+ * R36867 (0x9003) - DSP3 ZM 3
+ */
+#define WM5100_DSP3_ZM_1_MASK 0xFFFF /* DSP3_ZM_1 - [15:0] */
+#define WM5100_DSP3_ZM_1_SHIFT 0 /* DSP3_ZM_1 - [15:0] */
+#define WM5100_DSP3_ZM_1_WIDTH 16 /* DSP3_ZM_1 - [15:0] */
+
+/*
+ * R38908 (0x97FC) - DSP3 ZM 2044
+ */
+#define WM5100_DSP3_ZM_1022_1_MASK 0x00FF /* DSP3_ZM_1022 - [7:0] */
+#define WM5100_DSP3_ZM_1022_1_SHIFT 0 /* DSP3_ZM_1022 - [7:0] */
+#define WM5100_DSP3_ZM_1022_1_WIDTH 8 /* DSP3_ZM_1022 - [7:0] */
+
+/*
+ * R38909 (0x97FD) - DSP3 ZM 2045
+ */
+#define WM5100_DSP3_ZM_1022_MASK 0xFFFF /* DSP3_ZM_1022 - [15:0] */
+#define WM5100_DSP3_ZM_1022_SHIFT 0 /* DSP3_ZM_1022 - [15:0] */
+#define WM5100_DSP3_ZM_1022_WIDTH 16 /* DSP3_ZM_1022 - [15:0] */
+
+/*
+ * R38910 (0x97FE) - DSP3 ZM 2046
+ */
+#define WM5100_DSP3_ZM_END_1_MASK 0x00FF /* DSP3_ZM_END - [7:0] */
+#define WM5100_DSP3_ZM_END_1_SHIFT 0 /* DSP3_ZM_END - [7:0] */
+#define WM5100_DSP3_ZM_END_1_WIDTH 8 /* DSP3_ZM_END - [7:0] */
+
+/*
+ * R38911 (0x97FF) - DSP3 ZM 2047
+ */
+#define WM5100_DSP3_ZM_END_MASK 0xFFFF /* DSP3_ZM_END - [15:0] */
+#define WM5100_DSP3_ZM_END_SHIFT 0 /* DSP3_ZM_END - [15:0] */
+#define WM5100_DSP3_ZM_END_WIDTH 16 /* DSP3_ZM_END - [15:0] */
+
+int wm5100_readable_register(struct snd_soc_codec *codec, unsigned int reg);
+int wm5100_volatile_register(struct snd_soc_codec *codec, unsigned int reg);
+
+extern u16 wm5100_reg_defaults[WM5100_MAX_REGISTER + 1];
+
+#endif
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 6d6dc9efe914..35f3ad83dfb6 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -355,7 +355,7 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
return 1;
}
- ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
if (ret < 0)
return ret;
@@ -392,23 +392,9 @@ static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol,
break;
}
- return snd_soc_get_volsw_2r(kcontrol, ucontrol);
+ return snd_soc_get_volsw(kcontrol, ucontrol);
}
-/* double control with volume update */
-#define SOC_WM8350_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, \
- xinvert, tlv_array) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
- SNDRV_CTL_ELEM_ACCESS_READWRITE | \
- SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw_2r, \
- .get = wm8350_get_volsw_2r, .put = wm8350_put_volsw_2r_vu, \
- .private_value = (unsigned long)&(struct soc_mixer_control) \
- {.reg = reg_left, .rreg = reg_right, .shift = xshift, \
- .rshift = xshift, .max = xmax, .invert = xinvert}, }
-
static const char *wm8350_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" };
static const char *wm8350_dacmutem[] = { "Normal", "Soft" };
@@ -443,26 +429,29 @@ static const unsigned int capture_sd_tlv[] = {
static const struct snd_kcontrol_new wm8350_snd_controls[] = {
SOC_ENUM("Playback Deemphasis", wm8350_enum[0]),
SOC_ENUM("Playback DAC Inversion", wm8350_enum[1]),
- SOC_WM8350_DOUBLE_R_TLV("Playback PCM Volume",
+ SOC_DOUBLE_R_EXT_TLV("Playback PCM Volume",
WM8350_DAC_DIGITAL_VOLUME_L,
WM8350_DAC_DIGITAL_VOLUME_R,
- 0, 255, 0, dac_pcm_tlv),
+ 0, 255, 0, wm8350_get_volsw_2r,
+ wm8350_put_volsw_2r_vu, dac_pcm_tlv),
SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]),
SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]),
SOC_ENUM("Capture PCM Filter", wm8350_enum[4]),
SOC_ENUM("Capture PCM HP Filter", wm8350_enum[5]),
SOC_ENUM("Capture ADC Inversion", wm8350_enum[6]),
- SOC_WM8350_DOUBLE_R_TLV("Capture PCM Volume",
+ SOC_DOUBLE_R_EXT_TLV("Capture PCM Volume",
WM8350_ADC_DIGITAL_VOLUME_L,
WM8350_ADC_DIGITAL_VOLUME_R,
- 0, 255, 0, adc_pcm_tlv),
+ 0, 255, 0, wm8350_get_volsw_2r,
+ wm8350_put_volsw_2r_vu, adc_pcm_tlv),
SOC_DOUBLE_TLV("Capture Sidetone Volume",
WM8350_ADC_DIVIDER,
8, 4, 15, 1, capture_sd_tlv),
- SOC_WM8350_DOUBLE_R_TLV("Capture Volume",
+ SOC_DOUBLE_R_EXT_TLV("Capture Volume",
WM8350_LEFT_INPUT_VOLUME,
WM8350_RIGHT_INPUT_VOLUME,
- 2, 63, 0, pre_amp_tlv),
+ 2, 63, 0, wm8350_get_volsw_2r,
+ wm8350_put_volsw_2r_vu, pre_amp_tlv),
SOC_DOUBLE_R("Capture ZC Switch",
WM8350_LEFT_INPUT_VOLUME,
WM8350_RIGHT_INPUT_VOLUME, 13, 1, 0),
@@ -490,17 +479,19 @@ static const struct snd_kcontrol_new wm8350_snd_controls[] = {
SOC_SINGLE_TLV("Out4 Capture Volume",
WM8350_INPUT_MIXER_VOLUME,
1, 7, 0, out_mix_tlv),
- SOC_WM8350_DOUBLE_R_TLV("Out1 Playback Volume",
+ SOC_DOUBLE_R_EXT_TLV("Out1 Playback Volume",
WM8350_LOUT1_VOLUME,
WM8350_ROUT1_VOLUME,
- 2, 63, 0, out_pga_tlv),
+ 2, 63, 0, wm8350_get_volsw_2r,
+ wm8350_put_volsw_2r_vu, out_pga_tlv),
SOC_DOUBLE_R("Out1 Playback ZC Switch",
WM8350_LOUT1_VOLUME,
WM8350_ROUT1_VOLUME, 13, 1, 0),
- SOC_WM8350_DOUBLE_R_TLV("Out2 Playback Volume",
+ SOC_DOUBLE_R_EXT_TLV("Out2 Playback Volume",
WM8350_LOUT2_VOLUME,
WM8350_ROUT2_VOLUME,
- 2, 63, 0, out_pga_tlv),
+ 2, 63, 0, wm8350_get_volsw_2r,
+ wm8350_put_volsw_2r_vu, out_pga_tlv),
SOC_DOUBLE_R("Out2 Playback ZC Switch", WM8350_LOUT2_VOLUME,
WM8350_ROUT2_VOLUME, 13, 1, 0),
SOC_SINGLE("Out2 Right Invert Switch", WM8350_ROUT2_VOLUME, 10, 1, 0),
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index fbee556cbf35..dc13be2a09c5 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -383,7 +383,7 @@ static int inmixer_event (struct snd_soc_dapm_widget *w,
(1 << WM8400_AINRMUX_PWR))) {
reg |= WM8400_AINR_ENA;
} else {
- reg &= ~WM8400_AINL_ENA;
+ reg &= ~WM8400_AINR_ENA;
}
wm8400_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index db0dced74843..07c9cc759e97 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -479,6 +480,8 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ snd_soc_cache_sync(codec);
+
/* Initial cap charge at VMID 5k */
snd_soc_write(codec, WM8510_POWER1, power1 | 0x3);
mdelay(100);
@@ -540,18 +543,7 @@ static int wm8510_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8510_resume(struct snd_soc_codec *codec)
{
- int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) {
- data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
}
@@ -598,6 +590,11 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
.reg_cache_default =wm8510_reg,
};
+static const struct of_device_id wm8510_of_match[] = {
+ { .compatible = "wlf,wm8510" },
+ { },
+};
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8510_spi_probe(struct spi_device *spi)
{
@@ -628,6 +625,7 @@ static struct spi_driver wm8510_spi_driver = {
.driver = {
.name = "wm8510",
.owner = THIS_MODULE,
+ .of_match_table = wm8510_of_match,
},
.probe = wm8510_spi_probe,
.remove = __devexit_p(wm8510_spi_remove),
@@ -671,6 +669,7 @@ static struct i2c_driver wm8510_i2c_driver = {
.driver = {
.name = "wm8510-codec",
.owner = THIS_MODULE,
+ .of_match_table = wm8510_of_match,
},
.probe = wm8510_i2c_probe,
.remove = __devexit_p(wm8510_i2c_remove),
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 4fd4d8dca0fc..db7a6819499f 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -84,7 +85,7 @@ static const char *wm8523_zd_count_text[] = {
static const struct soc_enum wm8523_zc_count =
SOC_ENUM_SINGLE(WM8523_ZERO_DETECT, 0, 2, wm8523_zd_count_text);
-static const struct snd_kcontrol_new wm8523_snd_controls[] = {
+static const struct snd_kcontrol_new wm8523_controls[] = {
SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR,
0, 448, 0, dac_tlv),
SOC_SINGLE("ZC Switch", WM8523_DAC_CTRL3, 4, 1, 0),
@@ -101,22 +102,11 @@ SND_SOC_DAPM_OUTPUT("LINEVOUTL"),
SND_SOC_DAPM_OUTPUT("LINEVOUTR"),
};
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8523_dapm_routes[] = {
{ "LINEVOUTL", NULL, "DAC" },
{ "LINEVOUTR", NULL, "DAC" },
};
-static int wm8523_add_widgets(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- snd_soc_dapm_new_controls(dapm, wm8523_dapm_widgets,
- ARRAY_SIZE(wm8523_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
- return 0;
-}
-
static struct {
int value;
int ratio;
@@ -416,7 +406,6 @@ static int wm8523_probe(struct snd_soc_codec *codec)
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
int ret, i;
- codec->hw_write = (hw_write_t)i2c_master_send;
wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
wm8523->rate_constraint.count =
ARRAY_SIZE(wm8523->rate_constraint_list);
@@ -479,10 +468,6 @@ static int wm8523_probe(struct snd_soc_codec *codec)
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
- snd_soc_add_controls(codec, wm8523_snd_controls,
- ARRAY_SIZE(wm8523_snd_controls));
- wm8523_add_widgets(codec);
-
return 0;
err_enable:
@@ -512,6 +497,18 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8523 = {
.reg_word_size = sizeof(u16),
.reg_cache_default = wm8523_reg,
.volatile_register = wm8523_volatile_register,
+
+ .controls = wm8523_controls,
+ .num_controls = ARRAY_SIZE(wm8523_controls),
+ .dapm_widgets = wm8523_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8523_dapm_widgets),
+ .dapm_routes = wm8523_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(wm8523_dapm_routes),
+};
+
+static const struct of_device_id wm8523_of_match[] = {
+ { .compatible = "wlf,wm8523" },
+ { },
};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
@@ -551,8 +548,9 @@ MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id);
static struct i2c_driver wm8523_i2c_driver = {
.driver = {
- .name = "wm8523-codec",
+ .name = "wm8523",
.owner = THIS_MODULE,
+ .of_match_table = wm8523_of_match,
},
.probe = wm8523_i2c_probe,
.remove = __devexit_p(wm8523_i2c_remove),
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 4bbc0a79f01e..8212b3c8bfdd 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -26,6 +26,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -212,7 +213,7 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
reg_cache[reg] = 0;
reg_cache[reg2] = 0;
- ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
if (ret < 0)
return ret;
@@ -223,31 +224,19 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
return 0;
}
-#define SOC_WM8580_OUT_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, \
- xinvert, tlv_array) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
- SNDRV_CTL_ELEM_ACCESS_READWRITE, \
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw_2r, \
- .get = snd_soc_get_volsw_2r, .put = wm8580_out_vu, \
- .private_value = (unsigned long)&(struct soc_mixer_control) \
- {.reg = reg_left, .rreg = reg_right, .shift = xshift, \
- .max = xmax, .invert = xinvert} }
-
static const struct snd_kcontrol_new wm8580_snd_controls[] = {
-SOC_WM8580_OUT_DOUBLE_R_TLV("DAC1 Playback Volume",
- WM8580_DIGITAL_ATTENUATION_DACL1,
- WM8580_DIGITAL_ATTENUATION_DACR1,
- 0, 0xff, 0, dac_tlv),
-SOC_WM8580_OUT_DOUBLE_R_TLV("DAC2 Playback Volume",
- WM8580_DIGITAL_ATTENUATION_DACL2,
- WM8580_DIGITAL_ATTENUATION_DACR2,
- 0, 0xff, 0, dac_tlv),
-SOC_WM8580_OUT_DOUBLE_R_TLV("DAC3 Playback Volume",
- WM8580_DIGITAL_ATTENUATION_DACL3,
- WM8580_DIGITAL_ATTENUATION_DACR3,
- 0, 0xff, 0, dac_tlv),
+SOC_DOUBLE_R_EXT_TLV("DAC1 Playback Volume",
+ WM8580_DIGITAL_ATTENUATION_DACL1,
+ WM8580_DIGITAL_ATTENUATION_DACR1,
+ 0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
+SOC_DOUBLE_R_EXT_TLV("DAC2 Playback Volume",
+ WM8580_DIGITAL_ATTENUATION_DACL2,
+ WM8580_DIGITAL_ATTENUATION_DACR2,
+ 0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
+SOC_DOUBLE_R_EXT_TLV("DAC3 Playback Volume",
+ WM8580_DIGITAL_ATTENUATION_DACL3,
+ WM8580_DIGITAL_ATTENUATION_DACR3,
+ 0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
SOC_SINGLE("DAC1 Deemphasis Switch", WM8580_DAC_CONTROL3, 0, 1, 0),
SOC_SINGLE("DAC2 Deemphasis Switch", WM8580_DAC_CONTROL3, 1, 1, 0),
@@ -441,8 +430,7 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
/* Always disable the PLL - it is not safe to leave it running
* while reprogramming it.
*/
- reg = snd_soc_read(codec, WM8580_PWRDN2);
- snd_soc_write(codec, WM8580_PWRDN2, reg | pwr_mask);
+ snd_soc_update_bits(codec, WM8580_PWRDN2, pwr_mask, pwr_mask);
if (!freq_in || !freq_out)
return 0;
@@ -460,8 +448,7 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
snd_soc_write(codec, WM8580_PLLA4 + offset, reg);
/* All done, turn it on */
- reg = snd_soc_read(codec, WM8580_PWRDN2);
- snd_soc_write(codec, WM8580_PWRDN2, reg & ~pwr_mask);
+ snd_soc_update_bits(codec, WM8580_PWRDN2, pwr_mask, 0);
return 0;
}
@@ -759,7 +746,6 @@ static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute)
static int wm8580_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 reg;
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
@@ -768,20 +754,19 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
/* Power up and get individual control of the DACs */
- reg = snd_soc_read(codec, WM8580_PWRDN1);
- reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD);
- snd_soc_write(codec, WM8580_PWRDN1, reg);
+ snd_soc_update_bits(codec, WM8580_PWRDN1,
+ WM8580_PWRDN1_PWDN |
+ WM8580_PWRDN1_ALLDACPD, 0);
/* Make VMID high impedance */
- reg = snd_soc_read(codec, WM8580_ADC_CONTROL1);
- reg &= ~0x100;
- snd_soc_write(codec, WM8580_ADC_CONTROL1, reg);
+ snd_soc_update_bits(codec, WM8580_ADC_CONTROL1,
+ 0x100, 0);
}
break;
case SND_SOC_BIAS_OFF:
- reg = snd_soc_read(codec, WM8580_PWRDN1);
- snd_soc_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN);
+ snd_soc_update_bits(codec, WM8580_PWRDN1,
+ WM8580_PWRDN1_PWDN, WM8580_PWRDN1_PWDN);
break;
}
codec->dapm.bias_level = level;
@@ -907,6 +892,11 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
.reg_cache_default = wm8580_reg,
};
+static const struct of_device_id wm8580_of_match[] = {
+ { .compatible = "wlf,wm8580" },
+ { },
+};
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int wm8580_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
@@ -943,8 +933,9 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
static struct i2c_driver wm8580_i2c_driver = {
.driver = {
- .name = "wm8580-codec",
+ .name = "wm8580",
.owner = THIS_MODULE,
+ .of_match_table = wm8580_of_match,
},
.probe = wm8580_i2c_probe,
.remove = wm8580_i2c_remove,
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index a537e4af6ae7..076bdb9930a1 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -3,7 +3,7 @@
*
* Copyright 2006 Wolfson Microelectronics
*
- * Author: Mike Arthur <linux@wolfsonmicro.com>
+ * Author: Mike Arthur <Mike.Arthur@wolfsonmicro.com>
*
* Based on wm8731.c by Richard Purdie
*
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -150,7 +151,7 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_codec *codec = dai->codec;
struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
- u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc;
+ u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfff3;
int i = get_coeff(wm8711->sysclk, params_rate(params));
u16 srate = (coeff_div[i].sr << 2) |
(coeff_div[i].bosr << 1) | coeff_div[i].usb;
@@ -231,7 +232,7 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
- u16 iface = 0;
+ u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0x000c;
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -286,7 +287,6 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
-
static int wm8711_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
@@ -299,6 +299,9 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+ snd_soc_cache_sync(codec);
+
snd_soc_write(codec, WM8711_PWR, reg | 0x0040);
break;
case SND_SOC_BIAS_OFF:
@@ -345,25 +348,14 @@ static int wm8711_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8711_resume(struct snd_soc_codec *codec)
{
- int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(wm8711_reg); i++) {
- data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
}
static int wm8711_probe(struct snd_soc_codec *codec)
{
struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
- int ret, reg;
+ int ret;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8711->bus_type);
if (ret < 0) {
@@ -380,10 +372,8 @@ static int wm8711_probe(struct snd_soc_codec *codec)
wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the update bits */
- reg = snd_soc_read(codec, WM8711_LOUT1V);
- snd_soc_write(codec, WM8711_LOUT1V, reg | 0x0100);
- reg = snd_soc_read(codec, WM8711_ROUT1V);
- snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100);
+ snd_soc_update_bits(codec, WM8711_LOUT1V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8711_ROUT1V, 0x0100, 0x0100);
snd_soc_add_controls(codec, wm8711_snd_controls,
ARRAY_SIZE(wm8711_snd_controls));
@@ -414,6 +404,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
.num_dapm_routes = ARRAY_SIZE(wm8711_intercon),
};
+static const struct of_device_id wm8711_of_match[] = {
+ { .compatible = "wlf,wm8711", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8711_of_match);
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8711_spi_probe(struct spi_device *spi)
{
@@ -443,8 +439,9 @@ static int __devexit wm8711_spi_remove(struct spi_device *spi)
static struct spi_driver wm8711_spi_driver = {
.driver = {
- .name = "wm8711-codec",
+ .name = "wm8711",
.owner = THIS_MODULE,
+ .of_match_table = wm8711_of_match,
},
.probe = wm8711_spi_probe,
.remove = __devexit_p(wm8711_spi_remove),
@@ -487,8 +484,9 @@ MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id);
static struct i2c_driver wm8711_i2c_driver = {
.driver = {
- .name = "wm8711-codec",
+ .name = "wm8711",
.owner = THIS_MODULE,
+ .of_match_table = wm8711_of_match,
},
.probe = wm8711_i2c_probe,
.remove = __devexit_p(wm8711_i2c_remove),
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 86d4718d3a76..04b027efd5c0 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -269,6 +270,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
.num_dapm_routes = ARRAY_SIZE(wm8728_intercon),
};
+static const struct of_device_id wm8728_of_match[] = {
+ { .compatible = "wlf,wm8728", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8728_of_match);
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8728_spi_probe(struct spi_device *spi)
{
@@ -298,8 +305,9 @@ static int __devexit wm8728_spi_remove(struct spi_device *spi)
static struct spi_driver wm8728_spi_driver = {
.driver = {
- .name = "wm8728-codec",
+ .name = "wm8728",
.owner = THIS_MODULE,
+ .of_match_table = wm8728_of_match,
},
.probe = wm8728_spi_probe,
.remove = __devexit_p(wm8728_spi_remove),
@@ -342,8 +350,9 @@ MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
static struct i2c_driver wm8728_i2c_driver = {
.driver = {
- .name = "wm8728-codec",
+ .name = "wm8728",
.owner = THIS_MODULE,
+ .of_match_table = wm8728_of_match,
},
.probe = wm8728_i2c_probe,
.remove = __devexit_p(wm8728_i2c_remove),
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 76b4361e9b80..7e5ec03f6f8d 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -22,6 +22,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -426,9 +427,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
- int i, ret;
- u8 data[2];
- u16 *cache = codec->reg_cache;
+ int ret;
u16 reg;
switch (level) {
@@ -443,16 +442,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
if (ret != 0)
return ret;
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
- if (cache[i] == wm8731_reg[i])
- continue;
-
- data[0] = (i << 1) | ((cache[i] >> 8)
- & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
+ snd_soc_cache_sync(codec);
}
/* Clear PWROFF, gate CLKOUT, everything else as-is */
@@ -607,6 +597,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
.num_dapm_routes = ARRAY_SIZE(wm8731_intercon),
};
+static const struct of_device_id wm8731_of_match[] = {
+ { .compatible = "wlf,wm8731", },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, wm8731_of_match);
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8731_spi_probe(struct spi_device *spi)
{
@@ -638,6 +635,7 @@ static struct spi_driver wm8731_spi_driver = {
.driver = {
.name = "wm8731",
.owner = THIS_MODULE,
+ .of_match_table = wm8731_of_match,
},
.probe = wm8731_spi_probe,
.remove = __devexit_p(wm8731_spi_remove),
@@ -682,6 +680,7 @@ static struct i2c_driver wm8731_i2c_driver = {
.driver = {
.name = "wm8731",
.owner = THIS_MODULE,
+ .of_match_table = wm8731_of_match,
},
.probe = wm8731_i2c_probe,
.remove = __devexit_p(wm8731_i2c_remove),
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index 30c67d06a904..f6aef58845c2 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -20,6 +20,7 @@
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -634,6 +635,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8737 = {
.reg_cache_default = wm8737_reg,
};
+static const struct of_device_id wm8737_of_match[] = {
+ { .compatible = "wlf,wm8737", },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, wm8737_of_match);
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8737_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
@@ -673,6 +681,7 @@ static struct i2c_driver wm8737_i2c_driver = {
.driver = {
.name = "wm8737",
.owner = THIS_MODULE,
+ .of_match_table = wm8737_of_match,
},
.probe = wm8737_i2c_probe,
.remove = __devexit_p(wm8737_i2c_remove),
@@ -711,6 +720,7 @@ static struct spi_driver wm8737_spi_driver = {
.driver = {
.name = "wm8737",
.owner = THIS_MODULE,
+ .of_match_table = wm8737_of_match,
},
.probe = wm8737_spi_probe,
.remove = __devexit_p(wm8737_spi_remove),
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index 25af901fe813..57ad22aacc51 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -17,9 +17,11 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/spi/spi.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -337,10 +339,10 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
iface |= 0x0004;
break;
case SND_SOC_DAIFMT_DSP_A:
- iface |= 0x0003;
+ iface |= 0x000C;
break;
case SND_SOC_DAIFMT_DSP_B:
- iface |= 0x0013;
+ iface |= 0x001C;
break;
default:
return -EINVAL;
@@ -402,15 +404,7 @@ static struct snd_soc_dai_driver wm8741_dai = {
#ifdef CONFIG_PM
static int wm8741_resume(struct snd_soc_codec *codec)
{
- u16 *cache = codec->reg_cache;
- int i;
-
- /* RESTORE REG Cache */
- for (i = 0; i < WM8741_REGISTER_COUNT; i++) {
- if (cache[i] == wm8741_reg_defaults[i] || WM8741_RESET == i)
- continue;
- snd_soc_write(codec, i, cache[i]);
- }
+ snd_soc_cache_sync(codec);
return 0;
}
#else
@@ -422,17 +416,35 @@ static int wm8741_probe(struct snd_soc_codec *codec)
{
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
+ wm8741->supplies[i].supply = wm8741_supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies),
+ wm8741->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ goto err;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
+ wm8741->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_get;
+ }
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
+ goto err_enable;
}
ret = wm8741_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- return ret;
+ goto err_enable;
}
/* Change some default settings - latch VU */
@@ -442,7 +454,7 @@ static int wm8741_probe(struct snd_soc_codec *codec)
WM8741_UPDATELM, WM8741_UPDATELM);
snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
WM8741_UPDATERL, WM8741_UPDATERL);
- snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
+ snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION,
WM8741_UPDATERM, WM8741_UPDATERM);
snd_soc_add_controls(codec, wm8741_snd_controls,
@@ -451,58 +463,61 @@ static int wm8741_probe(struct snd_soc_codec *codec)
dev_dbg(codec->dev, "Successful registration\n");
return ret;
+
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+err_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+err:
+ return ret;
+}
+
+static int wm8741_remove(struct snd_soc_codec *codec)
+{
+ struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+
+ regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+ regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+
+ return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
.probe = wm8741_probe,
+ .remove = wm8741_remove,
.resume = wm8741_resume,
.reg_cache_size = ARRAY_SIZE(wm8741_reg_defaults),
.reg_word_size = sizeof(u16),
.reg_cache_default = wm8741_reg_defaults,
};
+static const struct of_device_id wm8741_of_match[] = {
+ { .compatible = "wlf,wm8741", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8741_of_match);
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int wm8741_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8741_priv *wm8741;
- int ret, i;
+ int ret;
wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
if (wm8741 == NULL)
return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
- wm8741->supplies[i].supply = wm8741_supply_names[i];
-
- ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies),
- wm8741->supplies);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
- goto err;
- }
-
- ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
- wm8741->supplies);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
- goto err_get;
- }
-
i2c_set_clientdata(i2c, wm8741);
wm8741->control_type = SND_SOC_I2C;
- ret = snd_soc_register_codec(&i2c->dev,
- &soc_codec_dev_wm8741, &wm8741_dai, 1);
- if (ret < 0)
- goto err_enable;
- return ret;
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8741, &wm8741_dai, 1);
+ if (ret != 0)
+ goto err;
-err_enable:
- regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+ return ret;
-err_get:
- regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
err:
kfree(wm8741);
return ret;
@@ -510,10 +525,7 @@ err:
static int wm8741_i2c_remove(struct i2c_client *client)
{
- struct wm8741_priv *wm8741 = i2c_get_clientdata(client);
-
snd_soc_unregister_codec(&client->dev);
- regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
kfree(i2c_get_clientdata(client));
return 0;
}
@@ -526,8 +538,9 @@ MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
static struct i2c_driver wm8741_i2c_driver = {
.driver = {
- .name = "wm8741-codec",
+ .name = "wm8741",
.owner = THIS_MODULE,
+ .of_match_table = wm8741_of_match,
},
.probe = wm8741_i2c_probe,
.remove = wm8741_i2c_remove,
@@ -535,6 +548,44 @@ static struct i2c_driver wm8741_i2c_driver = {
};
#endif
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8741_spi_probe(struct spi_device *spi)
+{
+ struct wm8741_priv *wm8741;
+ int ret;
+
+ wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
+ if (wm8741 == NULL)
+ return -ENOMEM;
+
+ wm8741->control_type = SND_SOC_SPI;
+ spi_set_drvdata(spi, wm8741);
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_wm8741, &wm8741_dai, 1);
+ if (ret < 0)
+ kfree(wm8741);
+ return ret;
+}
+
+static int __devexit wm8741_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ kfree(spi_get_drvdata(spi));
+ return 0;
+}
+
+static struct spi_driver wm8741_spi_driver = {
+ .driver = {
+ .name = "wm8741",
+ .owner = THIS_MODULE,
+ .of_match_table = wm8741_of_match,
+ },
+ .probe = wm8741_spi_probe,
+ .remove = __devexit_p(wm8741_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
static int __init wm8741_modinit(void)
{
int ret = 0;
@@ -544,6 +595,13 @@ static int __init wm8741_modinit(void)
if (ret != 0)
pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
#endif
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&wm8741_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register wm8741 SPI driver: %d\n",
+ ret);
+ }
+#endif
return ret;
}
@@ -551,6 +609,9 @@ module_init(wm8741_modinit);
static void __exit wm8741_exit(void)
{
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8741_spi_driver);
+#endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8741_i2c_driver);
#endif
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index d0003cc3bcd6..ca75a8180708 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -615,6 +616,8 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ snd_soc_cache_sync(codec);
+
/* Set VMID to 5k */
snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
@@ -672,28 +675,14 @@ static int wm8750_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8750_resume(struct snd_soc_codec *codec)
{
- int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(wm8750_reg); i++) {
- if (i == WM8750_RESET)
- continue;
- data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
-
wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
}
static int wm8750_probe(struct snd_soc_codec *codec)
{
struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
- int reg, ret;
+ int ret;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8750->control_type);
if (ret < 0) {
@@ -711,22 +700,14 @@ static int wm8750_probe(struct snd_soc_codec *codec)
wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* set the update bits */
- reg = snd_soc_read(codec, WM8750_LDAC);
- snd_soc_write(codec, WM8750_LDAC, reg | 0x0100);
- reg = snd_soc_read(codec, WM8750_RDAC);
- snd_soc_write(codec, WM8750_RDAC, reg | 0x0100);
- reg = snd_soc_read(codec, WM8750_LOUT1V);
- snd_soc_write(codec, WM8750_LOUT1V, reg | 0x0100);
- reg = snd_soc_read(codec, WM8750_ROUT1V);
- snd_soc_write(codec, WM8750_ROUT1V, reg | 0x0100);
- reg = snd_soc_read(codec, WM8750_LOUT2V);
- snd_soc_write(codec, WM8750_LOUT2V, reg | 0x0100);
- reg = snd_soc_read(codec, WM8750_ROUT2V);
- snd_soc_write(codec, WM8750_ROUT2V, reg | 0x0100);
- reg = snd_soc_read(codec, WM8750_LINVOL);
- snd_soc_write(codec, WM8750_LINVOL, reg | 0x0100);
- reg = snd_soc_read(codec, WM8750_RINVOL);
- snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100);
+ snd_soc_update_bits(codec, WM8750_LDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8750_RDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8750_LOUT1V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8750_ROUT1V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8750_LOUT2V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8750_ROUT2V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8750_LINVOL, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8750_RINVOL, 0x0100, 0x0100);
snd_soc_add_controls(codec, wm8750_snd_controls,
ARRAY_SIZE(wm8750_snd_controls));
@@ -751,6 +732,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8750 = {
.reg_cache_default = wm8750_reg,
};
+static const struct of_device_id wm8750_of_match[] = {
+ { .compatible = "wlf,wm8750", },
+ { .compatible = "wlf,wm8987", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8750_of_match);
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8750_spi_probe(struct spi_device *spi)
{
@@ -787,8 +775,9 @@ MODULE_DEVICE_TABLE(spi, wm8750_spi_ids);
static struct spi_driver wm8750_spi_driver = {
.driver = {
- .name = "wm8750-codec",
+ .name = "wm8750",
.owner = THIS_MODULE,
+ .of_match_table = wm8750_of_match,
},
.id_table = wm8750_spi_ids,
.probe = wm8750_spi_probe,
@@ -833,8 +822,9 @@ MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
static struct i2c_driver wm8750_i2c_driver = {
.driver = {
- .name = "wm8750-codec",
+ .name = "wm8750",
.owner = THIS_MODULE,
+ .of_match_table = wm8750_of_match,
},
.probe = wm8750_i2c_probe,
.remove = __devexit_p(wm8750_i2c_remove),
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index aa091a0d8187..a9504710bb69 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -38,6 +38,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
@@ -1490,6 +1491,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8753 = {
.reg_cache_default = wm8753_reg,
};
+static const struct of_device_id wm8753_of_match[] = {
+ { .compatible = "wlf,wm8753", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8753_of_match);
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8753_spi_probe(struct spi_device *spi)
{
@@ -1519,8 +1526,9 @@ static int __devexit wm8753_spi_remove(struct spi_device *spi)
static struct spi_driver wm8753_spi_driver = {
.driver = {
- .name = "wm8753-codec",
+ .name = "wm8753",
.owner = THIS_MODULE,
+ .of_match_table = wm8753_of_match,
},
.probe = wm8753_spi_probe,
.remove = __devexit_p(wm8753_spi_remove),
@@ -1563,8 +1571,9 @@ MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
static struct i2c_driver wm8753_i2c_driver = {
.driver = {
- .name = "wm8753-codec",
+ .name = "wm8753",
.owner = THIS_MODULE,
+ .of_match_table = wm8753_of_match,
},
.probe = wm8753_i2c_probe,
.remove = __devexit_p(wm8753_i2c_remove),
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
index 19b92baa9e8c..aa05e6507f84 100644
--- a/sound/soc/codecs/wm8770.c
+++ b/sound/soc/codecs/wm8770.c
@@ -14,6 +14,7 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/of_device.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
@@ -684,6 +685,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8770 = {
.reg_cache_default = wm8770_reg_defs
};
+static const struct of_device_id wm8770_of_match[] = {
+ { .compatible = "wlf,wm8770", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8770_of_match);
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8770_spi_probe(struct spi_device *spi)
{
@@ -715,6 +722,7 @@ static struct spi_driver wm8770_spi_driver = {
.driver = {
.name = "wm8770",
.owner = THIS_MODULE,
+ .of_match_table = wm8770_of_match,
},
.probe = wm8770_spi_probe,
.remove = __devexit_p(wm8770_spi_remove)
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index 8e7953b1b790..bfdc52370ad0 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
@@ -215,8 +216,6 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
int ratio_shift, master;
int i;
- iface = 0;
-
switch (dai->driver->id) {
case WM8776_DAI_DAC:
iface_reg = WM8776_DACIFCTRL;
@@ -232,20 +231,23 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
-
/* Set word length */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- break;
- case SNDRV_PCM_FORMAT_S20_3LE:
- iface |= 0x10;
+ switch (snd_pcm_format_width(params_format(params))) {
+ case 16:
+ iface = 0;
+ case 20:
+ iface = 0x10;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
- iface |= 0x20;
+ case 24:
+ iface = 0x20;
break;
- case SNDRV_PCM_FORMAT_S32_LE:
- iface |= 0x30;
+ case 32:
+ iface = 0x30;
break;
+ default:
+ dev_err(codec->dev, "Unsupported sample size: %i\n",
+ snd_pcm_format_width(params_format(params)));
+ return -EINVAL;
}
/* Only need to set MCLK/LRCLK ratio if we're master */
@@ -306,6 +308,8 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ snd_soc_cache_sync(codec);
+
/* Disable the global powerdown; DAPM does the rest */
snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 0);
}
@@ -320,11 +324,6 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-#define WM8776_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
- SNDRV_PCM_RATE_96000)
-
-
#define WM8776_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
@@ -349,7 +348,9 @@ static struct snd_soc_dai_driver wm8776_dai[] = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 2,
- .rates = WM8776_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 32000,
+ .rate_max = 192000,
.formats = WM8776_FORMATS,
},
.ops = &wm8776_dac_ops,
@@ -361,7 +362,9 @@ static struct snd_soc_dai_driver wm8776_dai[] = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = 2,
- .rates = WM8776_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 32000,
+ .rate_max = 96000,
.formats = WM8776_FORMATS,
},
.ops = &wm8776_adc_ops,
@@ -378,21 +381,7 @@ static int wm8776_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8776_resume(struct snd_soc_codec *codec)
{
- int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(wm8776_reg); i++) {
- if (cache[i] == wm8776_reg[i])
- continue;
- data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
-
wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
}
#else
@@ -452,6 +441,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
.reg_cache_default = wm8776_reg,
};
+static const struct of_device_id wm8776_of_match[] = {
+ { .compatible = "wlf,wm8776", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8776_of_match);
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8776_spi_probe(struct spi_device *spi)
{
@@ -481,8 +476,9 @@ static int __devexit wm8776_spi_remove(struct spi_device *spi)
static struct spi_driver wm8776_spi_driver = {
.driver = {
- .name = "wm8776-codec",
+ .name = "wm8776",
.owner = THIS_MODULE,
+ .of_match_table = wm8776_of_match,
},
.probe = wm8776_spi_probe,
.remove = __devexit_p(wm8776_spi_remove),
@@ -525,8 +521,9 @@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
static struct i2c_driver wm8776_i2c_driver = {
.driver = {
- .name = "wm8776-codec",
+ .name = "wm8776",
.owner = THIS_MODULE,
+ .of_match_table = wm8776_of_match,
},
.probe = wm8776_i2c_probe,
.remove = __devexit_p(wm8776_i2c_remove),
diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c
index a2a09f85ea99..f2ced71328b0 100644
--- a/sound/soc/codecs/wm8782.c
+++ b/sound/soc/codecs/wm8782.c
@@ -60,7 +60,7 @@ static struct platform_driver wm8782_codec_driver = {
.owner = THIS_MODULE,
},
.probe = wm8782_probe,
- .remove = wm8782_remove,
+ .remove = __devexit_p(wm8782_remove),
};
static int __init wm8782_init(void)
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 9a5e67c5a6bd..9ee072b85975 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -717,6 +718,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
.volatile_register = wm8804_volatile
};
+static const struct of_device_id wm8804_of_match[] = {
+ { .compatible = "wlf,wm8804", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8804_of_match);
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8804_spi_probe(struct spi_device *spi)
{
@@ -748,6 +755,7 @@ static struct spi_driver wm8804_spi_driver = {
.driver = {
.name = "wm8804",
.owner = THIS_MODULE,
+ .of_match_table = wm8804_of_match,
},
.probe = wm8804_spi_probe,
.remove = __devexit_p(wm8804_spi_remove)
@@ -792,6 +800,7 @@ static struct i2c_driver wm8804_i2c_driver = {
.driver = {
.name = "wm8804",
.owner = THIS_MODULE,
+ .of_match_table = wm8804_of_match,
},
.probe = wm8804_i2c_probe,
.remove = __devexit_p(wm8804_i2c_remove),
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 082040eda8a2..3d0dc1591ecc 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -110,8 +110,8 @@
#define WM8900_REG_CLOCKING1_BCLK_DIR 0x1
#define WM8900_REG_CLOCKING1_MCLK_SRC 0x100
-#define WM8900_REG_CLOCKING1_BCLK_MASK (~0x01e)
-#define WM8900_REG_CLOCKING1_OPCLK_MASK (~0x7000)
+#define WM8900_REG_CLOCKING1_BCLK_MASK 0x01e
+#define WM8900_REG_CLOCKING1_OPCLK_MASK 0x7000
#define WM8900_REG_CLOCKING2_ADC_CLKDIV 0xe0
#define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c
@@ -135,7 +135,7 @@
#define WM8900_REG_HPCTL1_HP_SHORT 0x08
#define WM8900_REG_HPCTL1_HP_SHORT2 0x04
-#define WM8900_LRC_MASK 0xfc00
+#define WM8900_LRC_MASK 0x03ff
struct wm8900_priv {
enum snd_soc_control_type control_type;
@@ -742,26 +742,20 @@ static int wm8900_set_fll(struct snd_soc_codec *codec,
{
struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
struct _fll_div fll_div;
- unsigned int reg;
if (wm8900->fll_in == freq_in && wm8900->fll_out == freq_out)
return 0;
/* The digital side should be disabled during any change. */
- reg = snd_soc_read(codec, WM8900_REG_POWER1);
- snd_soc_write(codec, WM8900_REG_POWER1,
- reg & (~WM8900_REG_POWER1_FLL_ENA));
+ snd_soc_update_bits(codec, WM8900_REG_POWER1,
+ WM8900_REG_POWER1_FLL_ENA, 0);
/* Disable the FLL? */
if (!freq_in || !freq_out) {
- reg = snd_soc_read(codec, WM8900_REG_CLOCKING1);
- snd_soc_write(codec, WM8900_REG_CLOCKING1,
- reg & (~WM8900_REG_CLOCKING1_MCLK_SRC));
-
- reg = snd_soc_read(codec, WM8900_REG_FLLCTL1);
- snd_soc_write(codec, WM8900_REG_FLLCTL1,
- reg & (~WM8900_REG_FLLCTL1_OSC_ENA));
-
+ snd_soc_update_bits(codec, WM8900_REG_CLOCKING1,
+ WM8900_REG_CLOCKING1_MCLK_SRC, 0);
+ snd_soc_update_bits(codec, WM8900_REG_FLLCTL1,
+ WM8900_REG_FLLCTL1_OSC_ENA, 0);
wm8900->fll_in = freq_in;
wm8900->fll_out = freq_out;
@@ -796,15 +790,14 @@ static int wm8900_set_fll(struct snd_soc_codec *codec,
else
snd_soc_write(codec, WM8900_REG_FLLCTL6, 0);
- reg = snd_soc_read(codec, WM8900_REG_POWER1);
- snd_soc_write(codec, WM8900_REG_POWER1,
- reg | WM8900_REG_POWER1_FLL_ENA);
+ snd_soc_update_bits(codec, WM8900_REG_POWER1,
+ WM8900_REG_POWER1_FLL_ENA,
+ WM8900_REG_POWER1_FLL_ENA);
reenable:
- reg = snd_soc_read(codec, WM8900_REG_CLOCKING1);
- snd_soc_write(codec, WM8900_REG_CLOCKING1,
- reg | WM8900_REG_CLOCKING1_MCLK_SRC);
-
+ snd_soc_update_bits(codec, WM8900_REG_CLOCKING1,
+ WM8900_REG_CLOCKING1_MCLK_SRC,
+ WM8900_REG_CLOCKING1_MCLK_SRC);
return 0;
}
@@ -818,43 +811,35 @@ static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
int div_id, int div)
{
struct snd_soc_codec *codec = codec_dai->codec;
- unsigned int reg;
switch (div_id) {
case WM8900_BCLK_DIV:
- reg = snd_soc_read(codec, WM8900_REG_CLOCKING1);
- snd_soc_write(codec, WM8900_REG_CLOCKING1,
- div | (reg & WM8900_REG_CLOCKING1_BCLK_MASK));
+ snd_soc_update_bits(codec, WM8900_REG_CLOCKING1,
+ WM8900_REG_CLOCKING1_BCLK_MASK, div);
break;
case WM8900_OPCLK_DIV:
- reg = snd_soc_read(codec, WM8900_REG_CLOCKING1);
- snd_soc_write(codec, WM8900_REG_CLOCKING1,
- div | (reg & WM8900_REG_CLOCKING1_OPCLK_MASK));
+ snd_soc_update_bits(codec, WM8900_REG_CLOCKING1,
+ WM8900_REG_CLOCKING1_OPCLK_MASK, div);
break;
case WM8900_DAC_LRCLK:
- reg = snd_soc_read(codec, WM8900_REG_AUDIO4);
- snd_soc_write(codec, WM8900_REG_AUDIO4,
- div | (reg & WM8900_LRC_MASK));
+ snd_soc_update_bits(codec, WM8900_REG_AUDIO4,
+ WM8900_LRC_MASK, div);
break;
case WM8900_ADC_LRCLK:
- reg = snd_soc_read(codec, WM8900_REG_AUDIO3);
- snd_soc_write(codec, WM8900_REG_AUDIO3,
- div | (reg & WM8900_LRC_MASK));
+ snd_soc_update_bits(codec, WM8900_REG_AUDIO3,
+ WM8900_LRC_MASK, div);
break;
case WM8900_DAC_CLKDIV:
- reg = snd_soc_read(codec, WM8900_REG_CLOCKING2);
- snd_soc_write(codec, WM8900_REG_CLOCKING2,
- div | (reg & WM8900_REG_CLOCKING2_DAC_CLKDIV));
+ snd_soc_update_bits(codec, WM8900_REG_CLOCKING2,
+ WM8900_REG_CLOCKING2_DAC_CLKDIV, div);
break;
case WM8900_ADC_CLKDIV:
- reg = snd_soc_read(codec, WM8900_REG_CLOCKING2);
- snd_soc_write(codec, WM8900_REG_CLOCKING2,
- div | (reg & WM8900_REG_CLOCKING2_ADC_CLKDIV));
+ snd_soc_update_bits(codec, WM8900_REG_CLOCKING2,
+ WM8900_REG_CLOCKING2_ADC_CLKDIV, div);
break;
case WM8900_LRCLK_MODE:
- reg = snd_soc_read(codec, WM8900_REG_DACCTRL);
- snd_soc_write(codec, WM8900_REG_DACCTRL,
- div | (reg & WM8900_REG_DACCTRL_AIF_LRCLKRATE));
+ snd_soc_update_bits(codec, WM8900_REG_DACCTRL,
+ WM8900_REG_DACCTRL_AIF_LRCLKRATE, div);
break;
default:
return -EINVAL;
@@ -1037,12 +1022,12 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
/* Enable thermal shutdown */
- reg = snd_soc_read(codec, WM8900_REG_GPIO);
- snd_soc_write(codec, WM8900_REG_GPIO,
- reg | WM8900_REG_GPIO_TEMP_ENA);
- reg = snd_soc_read(codec, WM8900_REG_ADDCTL);
- snd_soc_write(codec, WM8900_REG_ADDCTL,
- reg | WM8900_REG_ADDCTL_TEMP_SD);
+ snd_soc_update_bits(codec, WM8900_REG_GPIO,
+ WM8900_REG_GPIO_TEMP_ENA,
+ WM8900_REG_GPIO_TEMP_ENA);
+ snd_soc_update_bits(codec, WM8900_REG_ADDCTL,
+ WM8900_REG_ADDCTL_TEMP_SD,
+ WM8900_REG_ADDCTL_TEMP_SD);
break;
case SND_SOC_BIAS_PREPARE:
@@ -1205,26 +1190,16 @@ static int wm8900_probe(struct snd_soc_codec *codec)
wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the volume update bits */
- snd_soc_write(codec, WM8900_REG_LINVOL,
- snd_soc_read(codec, WM8900_REG_LINVOL) | 0x100);
- snd_soc_write(codec, WM8900_REG_RINVOL,
- snd_soc_read(codec, WM8900_REG_RINVOL) | 0x100);
- snd_soc_write(codec, WM8900_REG_LOUT1CTL,
- snd_soc_read(codec, WM8900_REG_LOUT1CTL) | 0x100);
- snd_soc_write(codec, WM8900_REG_ROUT1CTL,
- snd_soc_read(codec, WM8900_REG_ROUT1CTL) | 0x100);
- snd_soc_write(codec, WM8900_REG_LOUT2CTL,
- snd_soc_read(codec, WM8900_REG_LOUT2CTL) | 0x100);
- snd_soc_write(codec, WM8900_REG_ROUT2CTL,
- snd_soc_read(codec, WM8900_REG_ROUT2CTL) | 0x100);
- snd_soc_write(codec, WM8900_REG_LDAC_DV,
- snd_soc_read(codec, WM8900_REG_LDAC_DV) | 0x100);
- snd_soc_write(codec, WM8900_REG_RDAC_DV,
- snd_soc_read(codec, WM8900_REG_RDAC_DV) | 0x100);
- snd_soc_write(codec, WM8900_REG_LADC_DV,
- snd_soc_read(codec, WM8900_REG_LADC_DV) | 0x100);
- snd_soc_write(codec, WM8900_REG_RADC_DV,
- snd_soc_read(codec, WM8900_REG_RADC_DV) | 0x100);
+ snd_soc_update_bits(codec, WM8900_REG_LINVOL, 0x100, 0x100);
+ snd_soc_update_bits(codec, WM8900_REG_RINVOL, 0x100, 0x100);
+ snd_soc_update_bits(codec, WM8900_REG_LOUT1CTL, 0x100, 0x100);
+ snd_soc_update_bits(codec, WM8900_REG_ROUT1CTL, 0x100, 0x100);
+ snd_soc_update_bits(codec, WM8900_REG_LOUT2CTL, 0x100, 0x100);
+ snd_soc_update_bits(codec, WM8900_REG_ROUT2CTL, 0x100, 0x100);
+ snd_soc_update_bits(codec, WM8900_REG_LDAC_DV, 0x100, 0x100);
+ snd_soc_update_bits(codec, WM8900_REG_RDAC_DV, 0x100, 0x100);
+ snd_soc_update_bits(codec, WM8900_REG_LADC_DV, 0x100, 0x100);
+ snd_soc_update_bits(codec, WM8900_REG_RADC_DV, 0x100, 0x100);
/* Set the DAC and mixer output bias */
snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index b085575d4aa5..285ef87e6704 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -50,7 +50,6 @@ static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = {
struct wm8904_priv {
enum wm8904_type devtype;
- void *control_data;
struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES];
@@ -868,7 +867,7 @@ SOC_ENUM("Right Capture Mode", rin_mode),
SOC_DOUBLE_R("Capture Volume", WM8904_ANALOGUE_LEFT_INPUT_0,
WM8904_ANALOGUE_RIGHT_INPUT_0, 0, 31, 0),
SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0,
- WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 0),
+ WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 1),
SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0),
SOC_ENUM("High Pass Filter Mode", hpf_mode),
@@ -2540,7 +2539,6 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
wm8904->devtype = id->driver_data;
i2c_set_clientdata(i2c, wm8904);
- wm8904->control_data = i2c;
wm8904->pdata = i2c->dev.platform_data;
ret = snd_soc_register_codec(&i2c->dev,
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 056daa0010f9..de9ec9b8b7d9 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -43,9 +43,19 @@
struct wm8940_priv {
unsigned int sysclk;
enum snd_soc_control_type control_type;
- void *control_data;
};
+static int wm8940_volatile_register(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ switch (reg) {
+ case WM8940_SOFTRESET:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static u16 wm8940_reg_defaults[] = {
0x8940, /* Soft Reset */
0x0000, /* Power 1 */
@@ -460,6 +470,14 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
break;
case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ ret = snd_soc_cache_sync(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
+ return ret;
+ }
+ }
+
/* ensure bufioen and biasen */
pwr_reg |= (1 << 2) | (1 << 3);
/* set vmid to 300k for standby */
@@ -470,6 +488,8 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
break;
}
+ codec->dapm.bias_level = level;
+
return ret;
}
@@ -601,7 +621,7 @@ static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
switch (div_id) {
case WM8940_BCLKDIV:
- reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFEF3;
+ reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFE3;
ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2));
break;
case WM8940_MCLKDIV:
@@ -660,30 +680,8 @@ static int wm8940_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8940_resume(struct snd_soc_codec *codec)
{
- int i;
- int ret;
- u8 data[3];
- u16 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware
- * Could use auto incremented writes to speed this up
- */
- for (i = 0; i < ARRAY_SIZE(wm8940_reg_defaults); i++) {
- data[0] = i;
- data[1] = (cache[i] & 0xFF00) >> 8;
- data[2] = cache[i] & 0x00FF;
- ret = codec->hw_write(codec->control_data, data, 3);
- if (ret < 0)
- goto error_ret;
- else if (ret != 3) {
- ret = -EIO;
- goto error_ret;
- }
- }
- ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-error_ret:
- return ret;
+ wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
}
static int wm8940_probe(struct snd_soc_codec *codec)
@@ -693,7 +691,6 @@ static int wm8940_probe(struct snd_soc_codec *codec)
int ret;
u16 reg;
- codec->control_data = wm8940->control_data;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
@@ -744,6 +741,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
.reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults),
.reg_word_size = sizeof(u16),
.reg_cache_default = wm8940_reg_defaults,
+ .volatile_register = wm8940_volatile_register,
};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
@@ -758,7 +756,6 @@ static __devinit int wm8940_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
i2c_set_clientdata(i2c, wm8940);
- wm8940->control_data = i2c;
wm8940->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev,
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 4393394b7bc1..2df253c18568 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -72,7 +72,6 @@ static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {
struct wm8960_priv {
enum snd_soc_control_type control_type;
- void *control_data;
int (*set_bias_level)(struct snd_soc_codec *,
enum snd_soc_bias_level level);
struct snd_soc_dapm_widget *lout1;
@@ -575,6 +574,8 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ snd_soc_cache_sync(codec);
+
/* Enable anti-pop features */
snd_soc_write(codec, WM8960_APOP1,
WM8960_POBCTRL | WM8960_SOFT_ST |
@@ -677,6 +678,9 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
WM8960_VREF | WM8960_VMID_MASK, 0);
break;
+ case SND_SOC_BIAS_OFF:
+ snd_soc_cache_sync(codec);
+ break;
default:
break;
}
@@ -902,16 +906,6 @@ static int wm8960_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8960_resume(struct snd_soc_codec *codec)
{
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
- int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(wm8960_reg); i++) {
- data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -925,7 +919,6 @@ static int wm8960_probe(struct snd_soc_codec *codec)
u16 reg;
wm8960->set_bias_level = wm8960_set_bias_level_out3;
- codec->control_data = wm8960->control_data;
if (!pdata) {
dev_warn(codec->dev, "No platform data supplied\n");
@@ -1015,7 +1008,6 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, wm8960);
wm8960->control_type = SND_SOC_I2C;
- wm8960->control_data = i2c;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8960, &wm8960_dai, 1);
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index cdee8103d09b..9568c8a49f96 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -974,7 +974,9 @@ static int wm8961_probe(struct snd_soc_codec *codec)
}
/* This isn't volatile - readback doesn't correspond to write */
- reg = codec->hw_read(codec, WM8961_RIGHT_INPUT_VOLUME);
+ codec->cache_bypass = 1;
+ reg = snd_soc_read(codec, WM8961_RIGHT_INPUT_VOLUME);
+ codec->cache_bypass = 0;
dev_info(codec->dev, "WM8961 family %d revision %c\n",
(reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT,
((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT)
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index d2c315fa1b9b..91d3c6dbeba3 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -63,6 +63,8 @@ struct wm8962_priv {
int fll_fref;
int fll_fout;
+ u16 dsp2_ena;
+
struct delayed_work mic_work;
struct snd_soc_jack *jack;
@@ -837,7 +839,7 @@ static const struct wm8962_reg_access {
[40] = { 0x00FF, 0x01FF, 0x0000 }, /* R40 - SPKOUTL volume */
[41] = { 0x00FF, 0x01FF, 0x0000 }, /* R41 - SPKOUTR volume */
- [47] = { 0x000F, 0x0000, 0x0000 }, /* R47 - Thermal Shutdown Status */
+ [47] = { 0x000F, 0x0000, 0xFFFF }, /* R47 - Thermal Shutdown Status */
[48] = { 0x7EC7, 0x7E07, 0xFFFF }, /* R48 - Additional Control (4) */
[49] = { 0x00D3, 0x00D7, 0xFFFF }, /* R49 - Class D Control 1 */
[51] = { 0x0047, 0x0047, 0x0000 }, /* R51 - Class D Control 2 */
@@ -965,7 +967,7 @@ static const struct wm8962_reg_access {
[584] = { 0x002D, 0x002D, 0x0000 }, /* R584 - IRQ Debounce */
[586] = { 0xC000, 0xC000, 0x0000 }, /* R586 - MICINT Source Pol */
[768] = { 0x0001, 0x0001, 0x0000 }, /* R768 - DSP2 Power Management */
- [1037] = { 0x0000, 0x003F, 0x0000 }, /* R1037 - DSP2_ExecControl */
+ [1037] = { 0x0000, 0x003F, 0xFFFF }, /* R1037 - DSP2_ExecControl */
[4096] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4096 - Write Sequencer 0 */
[4097] = { 0x00FF, 0x00FF, 0x0000 }, /* R4097 - Write Sequencer 1 */
[4098] = { 0x070F, 0x070F, 0x0000 }, /* R4098 - Write Sequencer 2 */
@@ -1959,7 +1961,13 @@ static int wm8962_readable_register(struct snd_soc_codec *codec, unsigned int re
static int wm8962_reset(struct snd_soc_codec *codec)
{
- return snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0x6243);
+ int ret;
+
+ ret = snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0x6243);
+ if (ret != 0)
+ return ret;
+
+ return snd_soc_write(codec, WM8962_PLL_SOFTWARE_RESET, 0);
}
static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0);
@@ -1986,6 +1994,122 @@ static const unsigned int classd_tlv[] = {
};
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static int wm8962_dsp2_write_config(struct snd_soc_codec *codec)
+{
+ return 0;
+}
+
+static int wm8962_dsp2_set_enable(struct snd_soc_codec *codec, u16 val)
+{
+ u16 adcl = snd_soc_read(codec, WM8962_LEFT_ADC_VOLUME);
+ u16 adcr = snd_soc_read(codec, WM8962_RIGHT_ADC_VOLUME);
+ u16 dac = snd_soc_read(codec, WM8962_ADC_DAC_CONTROL_1);
+
+ /* Mute the ADCs and DACs */
+ snd_soc_write(codec, WM8962_LEFT_ADC_VOLUME, 0);
+ snd_soc_write(codec, WM8962_RIGHT_ADC_VOLUME, WM8962_ADC_VU);
+ snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+ WM8962_DAC_MUTE, WM8962_DAC_MUTE);
+
+ snd_soc_write(codec, WM8962_SOUNDSTAGE_ENABLES_0, val);
+
+ /* Restore the ADCs and DACs */
+ snd_soc_write(codec, WM8962_LEFT_ADC_VOLUME, adcl);
+ snd_soc_write(codec, WM8962_RIGHT_ADC_VOLUME, adcr);
+ snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+ WM8962_DAC_MUTE, dac);
+
+ return 0;
+}
+
+static int wm8962_dsp2_start(struct snd_soc_codec *codec)
+{
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+ wm8962_dsp2_write_config(codec);
+
+ snd_soc_write(codec, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_RUNR);
+
+ wm8962_dsp2_set_enable(codec, wm8962->dsp2_ena);
+
+ return 0;
+}
+
+static int wm8962_dsp2_stop(struct snd_soc_codec *codec)
+{
+ wm8962_dsp2_set_enable(codec, 0);
+
+ snd_soc_write(codec, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_STOP);
+
+ return 0;
+}
+
+#define WM8962_DSP2_ENABLE(xname, xshift) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = wm8962_dsp2_ena_info, \
+ .get = wm8962_dsp2_ena_get, .put = wm8962_dsp2_ena_put, \
+ .private_value = xshift }
+
+static int wm8962_dsp2_ena_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+
+ return 0;
+}
+
+static int wm8962_dsp2_ena_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int shift = kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = !!(wm8962->dsp2_ena & 1 << shift);
+
+ return 0;
+}
+
+static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int shift = kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ int old = wm8962->dsp2_ena;
+ int ret = 0;
+ int dsp2_running = snd_soc_read(codec, WM8962_DSP2_POWER_MANAGEMENT) &
+ WM8962_DSP2_ENA;
+
+ mutex_lock(&codec->mutex);
+
+ if (ucontrol->value.integer.value[0])
+ wm8962->dsp2_ena |= 1 << shift;
+ else
+ wm8962->dsp2_ena &= ~(1 << shift);
+
+ if (wm8962->dsp2_ena == old)
+ goto out;
+
+ ret = 1;
+
+ if (dsp2_running) {
+ if (wm8962->dsp2_ena)
+ wm8962_dsp2_set_enable(codec, wm8962->dsp2_ena);
+ else
+ wm8962_dsp2_stop(codec);
+ }
+
+out:
+ mutex_unlock(&codec->mutex);
+
+ return ret;
+}
+
/* The VU bits for the headphones are in a different register to the mute
* bits and only take effect on the PGA if it is actually powered.
*/
@@ -2021,7 +2145,6 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- u16 *reg_cache = codec->reg_cache;
int ret;
/* Apply the update (if any) */
@@ -2030,16 +2153,19 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
return 0;
/* If the left PGA is enabled hit that VU bit... */
- if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTL_PGA_ENA)
- return snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
- reg_cache[WM8962_SPKOUTL_VOLUME]);
+ ret = snd_soc_read(codec, WM8962_PWR_MGMT_2);
+ if (ret & WM8962_SPKOUTL_PGA_ENA) {
+ snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
+ snd_soc_read(codec, WM8962_SPKOUTL_VOLUME));
+ return 1;
+ }
/* ...otherwise the right. The VU is stereo. */
- if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTR_PGA_ENA)
- return snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
- reg_cache[WM8962_SPKOUTR_VOLUME]);
+ if (ret & WM8962_SPKOUTR_PGA_ENA)
+ snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
+ snd_soc_read(codec, WM8962_SPKOUTR_VOLUME));
- return 0;
+ return 1;
}
static const char *cap_hpf_mode_text[] = {
@@ -2049,6 +2175,14 @@ static const char *cap_hpf_mode_text[] = {
static const struct soc_enum cap_hpf_mode =
SOC_ENUM_SINGLE(WM8962_ADC_DAC_CONTROL_2, 10, 2, cap_hpf_mode_text);
+
+static const char *cap_lhpf_mode_text[] = {
+ "LPF", "HPF"
+};
+
+static const struct soc_enum cap_lhpf_mode =
+ SOC_ENUM_SINGLE(WM8962_LHPF1, 1, 2, cap_lhpf_mode_text);
+
static const struct snd_kcontrol_new wm8962_snd_controls[] = {
SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
@@ -2077,6 +2211,8 @@ SOC_DOUBLE_R("Capture ZC Switch", WM8962_LEFT_INPUT_VOLUME,
SOC_SINGLE("Capture HPF Switch", WM8962_ADC_DAC_CONTROL_1, 0, 1, 1),
SOC_ENUM("Capture HPF Mode", cap_hpf_mode),
SOC_SINGLE("Capture HPF Cutoff", WM8962_ADC_DAC_CONTROL_2, 7, 7, 0),
+SOC_SINGLE("Capture LHPF Switch", WM8962_LHPF1, 0, 1, 0),
+SOC_ENUM("Capture LHPF Mode", cap_lhpf_mode),
SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1,
WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv),
@@ -2134,6 +2270,11 @@ SOC_DOUBLE_R_TLV("EQ4 Volume", WM8962_EQ3, WM8962_EQ23,
WM8962_EQL_B4_GAIN_SHIFT, 31, 0, eq_tlv),
SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23,
WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv),
+
+WM8962_DSP2_ENABLE("VSS Switch", WM8962_VSS_ENA_SHIFT),
+WM8962_DSP2_ENABLE("HPF1 Switch", WM8962_HPF1_ENA_SHIFT),
+WM8962_DSP2_ENABLE("HPF2 Switch", WM8962_HPF2_ENA_SHIFT),
+WM8962_DSP2_ENABLE("HD Bass Switch", WM8962_HDBASS_ENA_SHIFT),
};
static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
@@ -2225,15 +2366,14 @@ static int sysclk_event(struct snd_soc_dapm_widget *w,
snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
WM8962_FLL_ENA, WM8962_FLL_ENA);
- if (wm8962->irq) {
- timeout = msecs_to_jiffies(5);
- timeout = wait_for_completion_timeout(&wm8962->fll_lock,
- timeout);
-
- if (timeout == 0)
- dev_err(codec->dev,
- "Timed out starting FLL\n");
- }
+
+ timeout = msecs_to_jiffies(5);
+ timeout = wait_for_completion_timeout(&wm8962->fll_lock,
+ timeout);
+
+ if (wm8962->irq && timeout == 0)
+ dev_err(codec->dev,
+ "Timed out starting FLL\n");
}
break;
@@ -2365,7 +2505,6 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- u16 *reg_cache = codec->reg_cache;
int reg;
switch (w->shift) {
@@ -2388,13 +2527,38 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- return snd_soc_write(codec, reg, reg_cache[reg]);
+ return snd_soc_write(codec, reg, snd_soc_read(codec, reg));
default:
BUG();
return -EINVAL;
}
}
+static int dsp2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (wm8962->dsp2_ena)
+ wm8962_dsp2_start(codec);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ if (wm8962->dsp2_ena)
+ wm8962_dsp2_stop(codec);
+ break;
+
+ default:
+ BUG();
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static const char *st_text[] = { "None", "Right", "Left" };
static const struct soc_enum str_enum =
@@ -2509,7 +2673,7 @@ SND_SOC_DAPM_INPUT("IN4R"),
SND_SOC_DAPM_INPUT("Beep"),
SND_SOC_DAPM_INPUT("DMICDAT"),
-SND_SOC_DAPM_MICBIAS("MICBIAS", WM8962_PWR_MGMT_1, 1, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS", WM8962_PWR_MGMT_1, 1, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("Class G", WM8962_CHARGE_PUMP_B, 0, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, sysclk_event,
@@ -2517,6 +2681,9 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, sysclk_event,
SND_SOC_DAPM_SUPPLY("Charge Pump", WM8962_CHARGE_PUMP_1, 0, 0, cp_event,
SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("DSP2", 1, WM8962_DSP2_POWER_MANAGEMENT,
+ WM8962_DSP2_ENA_SHIFT, 0, dsp2_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0,
inpgal, ARRAY_SIZE(inpgal)),
@@ -2527,7 +2694,7 @@ SND_SOC_DAPM_MIXER("MIXINL", WM8962_PWR_MGMT_1, 5, 0,
SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0,
mixinr, ARRAY_SIZE(mixinr)),
-SND_SOC_DAPM_AIF_IN("DMIC", NULL, 0, WM8962_PWR_MGMT_1, 10, 0),
+SND_SOC_DAPM_AIF_IN("DMIC_ENA", NULL, 0, WM8962_PWR_MGMT_1, 10, 0),
SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0),
SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0),
@@ -2606,17 +2773,19 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = {
{ "MICBIAS", NULL, "SYSCLK" },
- { "DMIC", NULL, "DMICDAT" },
+ { "DMIC_ENA", NULL, "DMICDAT" },
{ "ADCL", NULL, "SYSCLK" },
{ "ADCL", NULL, "TOCLK" },
{ "ADCL", NULL, "MIXINL" },
- { "ADCL", NULL, "DMIC" },
+ { "ADCL", NULL, "DMIC_ENA" },
+ { "ADCL", NULL, "DSP2" },
{ "ADCR", NULL, "SYSCLK" },
{ "ADCR", NULL, "TOCLK" },
{ "ADCR", NULL, "MIXINR" },
- { "ADCR", NULL, "DMIC" },
+ { "ADCR", NULL, "DMIC_ENA" },
+ { "ADCR", NULL, "DSP2" },
{ "STL", "Left", "ADCL" },
{ "STL", "Right", "ADCR" },
@@ -2628,11 +2797,13 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = {
{ "DACL", NULL, "TOCLK" },
{ "DACL", NULL, "Beep" },
{ "DACL", NULL, "STL" },
+ { "DACL", NULL, "DSP2" },
{ "DACR", NULL, "SYSCLK" },
{ "DACR", NULL, "TOCLK" },
{ "DACR", NULL, "Beep" },
{ "DACR", NULL, "STR" },
+ { "DACR", NULL, "DSP2" },
{ "HPMIXL", "IN4L Switch", "IN4L" },
{ "HPMIXL", "IN4R Switch", "IN4R" },
@@ -3058,9 +3229,9 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
int aif0 = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_DSP_A:
- aif0 |= WM8962_LRCLK_INV;
case SND_SOC_DAIFMT_DSP_B:
+ aif0 |= WM8962_LRCLK_INV | 3;
+ case SND_SOC_DAIFMT_DSP_A:
aif0 |= 3;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -3403,12 +3574,16 @@ static irqreturn_t wm8962_irq(int irq, void *data)
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
int mask;
int active;
+ int reg;
mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2_MASK);
active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
active &= ~mask;
+ if (!active)
+ return IRQ_NONE;
+
/* Acknowledge the interrupts */
snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active);
@@ -3420,9 +3595,21 @@ static irqreturn_t wm8962_irq(int irq, void *data)
if (active & WM8962_FIFOS_ERR_EINT)
dev_err(codec->dev, "FIFO error\n");
- if (active & WM8962_TEMP_SHUT_EINT)
+ if (active & WM8962_TEMP_SHUT_EINT) {
dev_crit(codec->dev, "Thermal shutdown\n");
+ reg = snd_soc_read(codec, WM8962_THERMAL_SHUTDOWN_STATUS);
+
+ if (reg & WM8962_TEMP_ERR_HP)
+ dev_crit(codec->dev, "Headphone thermal error\n");
+ if (reg & WM8962_TEMP_WARN_HP)
+ dev_crit(codec->dev, "Headphone thermal warning\n");
+ if (reg & WM8962_TEMP_ERR_SPK)
+ dev_crit(codec->dev, "Speaker thermal error\n");
+ if (reg & WM8962_TEMP_WARN_SPK)
+ dev_crit(codec->dev, "Speaker thermal warning\n");
+ }
+
if (active & (WM8962_MICSCD_EINT | WM8962_MICD_EINT)) {
dev_dbg(codec->dev, "Microphone event detected\n");
@@ -3847,6 +4034,11 @@ static int wm8962_probe(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8962_CLOCKING2,
WM8962_CLKREG_OVD, WM8962_CLKREG_OVD);
+ /* Ensure that the oscillator and PLLs are disabled */
+ snd_soc_update_bits(codec, WM8962_PLL2,
+ WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
+ 0);
+
regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
if (pdata) {
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 572bb80627a4..b444b297d0b2 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -546,6 +546,9 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+ snd_soc_cache_sync(codec);
+
/* mute dac and set vmid to 500k, enable VREF */
snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
break;
@@ -605,20 +608,8 @@ static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8971_resume(struct snd_soc_codec *codec)
{
- int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
u16 reg;
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(wm8971_reg); i++) {
- if (i + 1 == WM8971_RESET)
- continue;
- data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
-
wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* charge wm8971 caps */
@@ -660,25 +651,14 @@ static int wm8971_probe(struct snd_soc_codec *codec)
msecs_to_jiffies(1000));
/* set the update bits */
- reg = snd_soc_read(codec, WM8971_LDAC);
- snd_soc_write(codec, WM8971_LDAC, reg | 0x0100);
- reg = snd_soc_read(codec, WM8971_RDAC);
- snd_soc_write(codec, WM8971_RDAC, reg | 0x0100);
-
- reg = snd_soc_read(codec, WM8971_LOUT1V);
- snd_soc_write(codec, WM8971_LOUT1V, reg | 0x0100);
- reg = snd_soc_read(codec, WM8971_ROUT1V);
- snd_soc_write(codec, WM8971_ROUT1V, reg | 0x0100);
-
- reg = snd_soc_read(codec, WM8971_LOUT2V);
- snd_soc_write(codec, WM8971_LOUT2V, reg | 0x0100);
- reg = snd_soc_read(codec, WM8971_ROUT2V);
- snd_soc_write(codec, WM8971_ROUT2V, reg | 0x0100);
-
- reg = snd_soc_read(codec, WM8971_LINVOL);
- snd_soc_write(codec, WM8971_LINVOL, reg | 0x0100);
- reg = snd_soc_read(codec, WM8971_RINVOL);
- snd_soc_write(codec, WM8971_RINVOL, reg | 0x0100);
+ snd_soc_update_bits(codec, WM8971_LDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8971_RDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8971_LOUT1V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8971_ROUT1V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8971_LOUT2V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8971_ROUT2V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8971_LINVOL, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8971_RINVOL, 0x0100, 0x0100);
snd_soc_add_controls(codec, wm8971_snd_controls,
ARRAY_SIZE(wm8971_snd_controls));
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index ca646a822444..9352f1e088d2 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -3,7 +3,7 @@
*
* Copyright 2006-2009 Wolfson Microelectronics PLC.
*
- * Author: Liam Girdwood <linux@wolfsonmicro.com>
+ * Author: Liam Girdwood <Liam.Girdwood@wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -530,6 +530,8 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ snd_soc_cache_sync(codec);
+
/* Initial cap charge at VMID 5k */
snd_soc_write(codec, WM8974_POWER1, power1 | 0x3);
mdelay(100);
@@ -589,18 +591,7 @@ static int wm8974_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8974_resume(struct snd_soc_codec *codec)
{
- int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(wm8974_reg); i++) {
- data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
}
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 85e3e630e763..41ca4d9ac20c 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -52,7 +52,6 @@ static const u16 wm8978_reg[WM8978_CACHEREGNUM] = {
/* codec private data */
struct wm8978_priv {
enum snd_soc_control_type control_type;
- void *control_data;
unsigned int f_pllout;
unsigned int f_mclk;
unsigned int f_256fs;
@@ -955,7 +954,6 @@ static int wm8978_probe(struct snd_soc_codec *codec)
* default hardware setting
*/
wm8978->sysclk = WM8978_PLL;
- codec->control_data = wm8978->control_data;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
@@ -1016,7 +1014,6 @@ static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
i2c_set_clientdata(i2c, wm8978);
- wm8978->control_data = i2c;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8978, &wm8978_dai, 1);
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index 17f04ec2b940..93ee28439be5 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -1007,7 +1007,7 @@ static int wm8983_probe(struct snd_soc_codec *codec)
return ret;
}
- ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0x8983);
+ ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
return ret;
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index d7170f1381aa..2e9eba717d1a 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -55,7 +55,6 @@ struct wm8988_priv {
struct snd_pcm_hw_constraint_list *sysclk_constraints;
};
-
#define wm8988_reset(c) snd_soc_write(c, WM8988_RESET, 0)
/*
@@ -676,6 +675,8 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ snd_soc_cache_sync(codec);
+
/* VREF, VMID=2x5k */
snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1);
@@ -736,21 +737,7 @@ static int wm8988_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8988_resume(struct snd_soc_codec *codec)
{
- int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < WM8988_NUM_REG; i++) {
- if (i == WM8988_RESET)
- continue;
- data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
-
wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
}
@@ -759,7 +746,6 @@ static int wm8988_probe(struct snd_soc_codec *codec)
struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0;
- u16 reg;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8988->control_type);
if (ret < 0) {
@@ -774,16 +760,11 @@ static int wm8988_probe(struct snd_soc_codec *codec)
}
/* set the update bits (we always update left then right) */
- reg = snd_soc_read(codec, WM8988_RADC);
- snd_soc_write(codec, WM8988_RADC, reg | 0x100);
- reg = snd_soc_read(codec, WM8988_RDAC);
- snd_soc_write(codec, WM8988_RDAC, reg | 0x0100);
- reg = snd_soc_read(codec, WM8988_ROUT1V);
- snd_soc_write(codec, WM8988_ROUT1V, reg | 0x0100);
- reg = snd_soc_read(codec, WM8988_ROUT2V);
- snd_soc_write(codec, WM8988_ROUT2V, reg | 0x0100);
- reg = snd_soc_read(codec, WM8988_RINVOL);
- snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100);
+ snd_soc_update_bits(codec, WM8988_RADC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8988_RDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8988_ROUT1V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8988_ROUT2V, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8988_RINVOL, 0x0100, 0x0100);
wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 100aeee5ba96..d29a9622964c 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -36,10 +36,17 @@ struct wm8990_priv {
unsigned int pcmclk;
};
-/*
- * wm8990 register cache. Note that register 0 is not included in the
- * cache.
- */
+static int wm8990_volatile_register(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ switch (reg) {
+ case WM8990_RESET:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static const u16 wm8990_reg[] = {
0x8990, /* R0 - Reset */
0x0000, /* R1 - Power Management (1) */
@@ -394,7 +401,7 @@ static int inmixer_event(struct snd_soc_dapm_widget *w,
(1 << WM8990_AINRMUX_PWR_BIT))) {
reg |= WM8990_AINR_ENA;
} else {
- reg &= ~WM8990_AINL_ENA;
+ reg &= ~WM8990_AINR_ENA;
}
snd_soc_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg);
@@ -974,7 +981,6 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target,
static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
int source, unsigned int freq_in, unsigned int freq_out)
{
- u16 reg;
struct snd_soc_codec *codec = codec_dai->codec;
struct _pll_div pll_div;
@@ -982,13 +988,12 @@ static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
pll_factors(&pll_div, freq_out * 4, freq_in);
/* Turn on PLL */
- reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2);
- reg |= WM8990_PLL_ENA;
- snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
+ snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_2,
+ WM8990_PLL_ENA, WM8990_PLL_ENA);
/* sysclk comes from PLL */
- reg = snd_soc_read(codec, WM8990_CLOCKING_2);
- snd_soc_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC);
+ snd_soc_update_bits(codec, WM8990_CLOCKING_2,
+ WM8990_SYSCLK_SRC, WM8990_SYSCLK_SRC);
/* set up N , fractional mode and pre-divisor if necessary */
snd_soc_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM |
@@ -996,10 +1001,9 @@ static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
snd_soc_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8));
snd_soc_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF));
} else {
- /* Turn on PLL */
- reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2);
- reg &= ~WM8990_PLL_ENA;
- snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
+ /* Turn off PLL */
+ snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_2,
+ WM8990_PLL_ENA, 0);
}
return 0;
}
@@ -1077,28 +1081,23 @@ static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
int div_id, int div)
{
struct snd_soc_codec *codec = codec_dai->codec;
- u16 reg;
switch (div_id) {
case WM8990_MCLK_DIV:
- reg = snd_soc_read(codec, WM8990_CLOCKING_2) &
- ~WM8990_MCLK_DIV_MASK;
- snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
+ snd_soc_update_bits(codec, WM8990_CLOCKING_2,
+ WM8990_MCLK_DIV_MASK, div);
break;
case WM8990_DACCLK_DIV:
- reg = snd_soc_read(codec, WM8990_CLOCKING_2) &
- ~WM8990_DAC_CLKDIV_MASK;
- snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
+ snd_soc_update_bits(codec, WM8990_CLOCKING_2,
+ WM8990_DAC_CLKDIV_MASK, div);
break;
case WM8990_ADCCLK_DIV:
- reg = snd_soc_read(codec, WM8990_CLOCKING_2) &
- ~WM8990_ADC_CLKDIV_MASK;
- snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
+ snd_soc_update_bits(codec, WM8990_CLOCKING_2,
+ WM8990_ADC_CLKDIV_MASK, div);
break;
case WM8990_BCLK_DIV:
- reg = snd_soc_read(codec, WM8990_CLOCKING_1) &
- ~WM8990_BCLK_DIV_MASK;
- snd_soc_write(codec, WM8990_CLOCKING_1, reg | div);
+ snd_soc_update_bits(codec, WM8990_CLOCKING_1,
+ WM8990_BCLK_DIV_MASK, div);
break;
default:
return -EINVAL;
@@ -1156,7 +1155,7 @@ static int wm8990_mute(struct snd_soc_dai *dai, int mute)
static int wm8990_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 val;
+ int ret;
switch (level) {
case SND_SOC_BIAS_ON:
@@ -1164,13 +1163,18 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
/* VMID=2*50k */
- val = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_1) &
- ~WM8990_VMID_MODE_MASK;
- snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2);
+ snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_1,
+ WM8990_VMID_MODE_MASK, 0x2);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ ret = snd_soc_cache_sync(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
+ return ret;
+ }
+
/* Enable all output discharge bits */
snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
@@ -1225,9 +1229,8 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
}
/* VMID=2*250k */
- val = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_1) &
- ~WM8990_VMID_MODE_MASK;
- snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4);
+ snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_1,
+ WM8990_VMID_MODE_MASK, 0x4);
break;
case SND_SOC_BIAS_OFF:
@@ -1241,8 +1244,8 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
WM8990_BUFIOEN);
/* mute DAC */
- val = snd_soc_read(codec, WM8990_DAC_CTRL);
- snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
+ snd_soc_update_bits(codec, WM8990_DAC_CTRL,
+ WM8990_DAC_MUTE, WM8990_DAC_MUTE);
/* Enable any disabled outputs */
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
@@ -1319,19 +1322,6 @@ static int wm8990_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8990_resume(struct snd_soc_codec *codec)
{
- int i;
- u8 data[2];
- u16 *cache = codec->reg_cache;
-
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) {
- if (i + 1 == WM8990_RESET)
- continue;
- data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001);
- data[1] = cache[i] & 0x00ff;
- codec->hw_write(codec->control_data, data, 2);
- }
-
wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
@@ -1343,7 +1333,6 @@ static int wm8990_resume(struct snd_soc_codec *codec)
static int wm8990_probe(struct snd_soc_codec *codec)
{
int ret;
- u16 reg;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret < 0) {
@@ -1356,15 +1345,14 @@ static int wm8990_probe(struct snd_soc_codec *codec)
/* charge output caps */
wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- reg = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_4);
- snd_soc_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1);
+ snd_soc_update_bits(codec, WM8990_AUDIO_INTERFACE_4,
+ WM8990_ALRCGPIO1, WM8990_ALRCGPIO1);
- reg = snd_soc_read(codec, WM8990_GPIO1_GPIO2) &
- ~WM8990_GPIO1_SEL_MASK;
- snd_soc_write(codec, WM8990_GPIO1_GPIO2, reg | 1);
+ snd_soc_update_bits(codec, WM8990_GPIO1_GPIO2,
+ WM8990_GPIO1_SEL_MASK, 1);
- reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2);
- snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA);
+ snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_2,
+ WM8990_OPCLK_ENA, WM8990_OPCLK_ENA);
snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
@@ -1392,6 +1380,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
.reg_cache_size = ARRAY_SIZE(wm8990_reg),
.reg_word_size = sizeof(u16),
.reg_cache_default = wm8990_reg,
+ .volatile_register = wm8990_volatile_register,
};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 6af23d06870f..c9ab3ba9bced 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -3,7 +3,7 @@
*
* Copyright 2007-2010 Wolfson Microelectronics PLC.
* Author: Graeme Gregory
- * linux@wolfsonmicro.com
+ * Graeme.Gregory@wolfsonmicro.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -393,7 +393,7 @@ static int inmixer_event(struct snd_soc_dapm_widget *w,
(1 << WM8991_AINRMUX_PWR_BIT)))
reg |= WM8991_AINR_ENA;
else
- reg &= ~WM8991_AINL_ENA;
+ reg &= ~WM8991_AINR_ENA;
snd_soc_write(w->codec, WM8991_POWER_MANAGEMENT_2, reg);
return 0;
@@ -1264,7 +1264,6 @@ static int wm8991_probe(struct snd_soc_codec *codec)
{
struct wm8991_priv *wm8991;
int ret;
- unsigned int reg;
wm8991 = snd_soc_codec_get_drvdata(codec);
@@ -1282,19 +1281,18 @@ static int wm8991_probe(struct snd_soc_codec *codec)
wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- reg = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_4);
- snd_soc_write(codec, WM8991_AUDIO_INTERFACE_4, reg | WM8991_ALRCGPIO1);
+ snd_soc_update_bits(codec, WM8991_AUDIO_INTERFACE_4,
+ WM8991_ALRCGPIO1, WM8991_ALRCGPIO1);
- reg = snd_soc_read(codec, WM8991_GPIO1_GPIO2) &
- ~WM8991_GPIO1_SEL_MASK;
- snd_soc_write(codec, WM8991_GPIO1_GPIO2, reg | 1);
+ snd_soc_update_bits(codec, WM8991_GPIO1_GPIO2,
+ WM8991_GPIO1_SEL_MASK, 1);
- reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_1);
- snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, reg | WM8991_VREF_ENA|
- WM8991_VMID_MODE_MASK);
+ snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_1,
+ WM8991_VREF_ENA | WM8991_VMID_MODE_MASK,
+ WM8991_VREF_ENA | WM8991_VMID_MODE_MASK);
- reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_2);
- snd_soc_write(codec, WM8991_POWER_MANAGEMENT_2, reg | WM8991_OPCLK_ENA);
+ snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_2,
+ WM8991_OPCLK_ENA, WM8991_OPCLK_ENA);
snd_soc_write(codec, WM8991_DAC_CTRL, 0);
snd_soc_write(codec, WM8991_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 6e85b8869af7..eec8e1435116 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -847,6 +847,7 @@ SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8993_BUS_CONTROL_1, 1, 0, clk_sys_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("TOCLK", WM8993_CLOCKING_1, 14, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8993_CLOCKING_3, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_ADC("ADCL", NULL, WM8993_POWER_MANAGEMENT_2, 1, 0),
SND_SOC_DAPM_ADC("ADCR", NULL, WM8993_POWER_MANAGEMENT_2, 0, 0),
@@ -880,6 +881,9 @@ SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
};
static const struct snd_soc_dapm_route routes[] = {
+ { "MICBIAS1", NULL, "VMID" },
+ { "MICBIAS2", NULL, "VMID" },
+
{ "ADCL", NULL, "CLK_SYS" },
{ "ADCL", NULL, "CLK_DSP" },
{ "ADCR", NULL, "CLK_SYS" },
@@ -1433,7 +1437,8 @@ static int wm8993_probe(struct snd_soc_codec *codec)
int ret, i, val;
wm8993->hubs_data.hp_startup_mode = 1;
- wm8993->hubs_data.dcs_codes = -2;
+ wm8993->hubs_data.dcs_codes_l = -2;
+ wm8993->hubs_data.dcs_codes_r = -2;
wm8993->hubs_data.series_startup = 1;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
diff --git a/sound/soc/codecs/wm8994-tables.c b/sound/soc/codecs/wm8994-tables.c
index a87adbd05ee1..df5a8b9a250f 100644
--- a/sound/soc/codecs/wm8994-tables.c
+++ b/sound/soc/codecs/wm8994-tables.c
@@ -1073,8 +1073,8 @@ const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE] = {
{ 0x0000, 0x0000 }, /* R1069 */
{ 0x0000, 0x0000 }, /* R1070 */
{ 0x0000, 0x0000 }, /* R1071 */
- { 0x0000, 0x0000 }, /* R1072 */
- { 0x0000, 0x0000 }, /* R1073 */
+ { 0x006F, 0x006F }, /* R1072 - AIF1 DAC1 Noise Gate */
+ { 0x006F, 0x006F }, /* R1073 - AIF1 DAC2 Noise Gate */
{ 0x0000, 0x0000 }, /* R1074 */
{ 0x0000, 0x0000 }, /* R1075 */
{ 0x0000, 0x0000 }, /* R1076 */
@@ -1329,7 +1329,7 @@ const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE] = {
{ 0x0000, 0x0000 }, /* R1325 */
{ 0x0000, 0x0000 }, /* R1326 */
{ 0x0000, 0x0000 }, /* R1327 */
- { 0x0000, 0x0000 }, /* R1328 */
+ { 0x006F, 0x006F }, /* R1328 - AIF2 DAC Noise Gate */
{ 0x0000, 0x0000 }, /* R1329 */
{ 0x0000, 0x0000 }, /* R1330 */
{ 0x0000, 0x0000 }, /* R1331 */
@@ -1635,8 +1635,8 @@ const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE] = {
0x0000, /* R58 - MICBIAS */
0x000D, /* R59 - LDO 1 */
0x0003, /* R60 - LDO 2 */
- 0x0000, /* R61 */
- 0x0000, /* R62 */
+ 0x0039, /* R61 - MICBIAS1 */
+ 0x0039, /* R62 - MICBIAS2 */
0x0000, /* R63 */
0x0000, /* R64 */
0x0000, /* R65 */
@@ -2646,8 +2646,8 @@ const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE] = {
0x0000, /* R1069 */
0x0000, /* R1070 */
0x0000, /* R1071 */
- 0x0000, /* R1072 */
- 0x0000, /* R1073 */
+ 0x0068, /* R1072 - AIF1 DAC1 Noise Gate */
+ 0x0068, /* R1073 - AIF1 DAC2 Noise Gate */
0x0000, /* R1074 */
0x0000, /* R1075 */
0x0000, /* R1076 */
@@ -2902,7 +2902,7 @@ const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE] = {
0x0000, /* R1325 */
0x0000, /* R1326 */
0x0000, /* R1327 */
- 0x0000, /* R1328 */
+ 0x0068, /* R1328 - AIF2 DAC Noise Gate */
0x0000, /* R1329 */
0x0000, /* R1330 */
0x0000, /* R1331 */
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index b393f9fac97a..9c982e47eb99 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -56,7 +56,7 @@ static int wm8994_retune_mobile_base[] = {
static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
{
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
- struct wm8994 *control = wm8994->control_data;
+ struct wm8994 *control = codec->control_data;
switch (reg) {
case WM8994_GPIO_1:
@@ -107,6 +107,7 @@ static int wm8994_volatile(struct snd_soc_codec *codec, unsigned int reg)
case WM8994_LDO_2:
case WM8958_DSP2_EXECCONTROL:
case WM8958_MIC_DETECT_3:
+ case WM8994_DC_SERVO_4E:
return 1;
default:
return 0;
@@ -207,7 +208,7 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
static int configure_clock(struct snd_soc_codec *codec)
{
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
- int old, new;
+ int change, new;
/* Bring up the AIF clocks first */
configure_aif_clock(codec, 0);
@@ -228,14 +229,11 @@ static int configure_clock(struct snd_soc_codec *codec)
else
new = 0;
- old = snd_soc_read(codec, WM8994_CLOCKING_1) & WM8994_SYSCLK_SRC;
-
- /* If there's no change then we're done. */
- if (old == new)
+ change = snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+ WM8994_SYSCLK_SRC, new);
+ if (!change)
return 0;
- snd_soc_update_bits(codec, WM8994_CLOCKING_1, WM8994_SYSCLK_SRC, new);
-
snd_soc_dapm_sync(&codec->dapm);
return 0;
@@ -281,6 +279,8 @@ static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
static const DECLARE_TLV_DB_SCALE(wm8994_3d_tlv, -1600, 183, 0);
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(mixin_boost_tlv, 0, 900, 0);
#define WM8994_DRC_SWITCH(xname, reg, shift) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -660,8 +660,52 @@ SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0,
eq_tlv),
};
+static const char *wm8958_ng_text[] = {
+ "30ms", "125ms", "250ms", "500ms",
+};
+
+static const struct soc_enum wm8958_aif1dac1_ng_hold =
+ SOC_ENUM_SINGLE(WM8958_AIF1_DAC1_NOISE_GATE,
+ WM8958_AIF1DAC1_NG_THR_SHIFT, 4, wm8958_ng_text);
+
+static const struct soc_enum wm8958_aif1dac2_ng_hold =
+ SOC_ENUM_SINGLE(WM8958_AIF1_DAC2_NOISE_GATE,
+ WM8958_AIF1DAC2_NG_THR_SHIFT, 4, wm8958_ng_text);
+
+static const struct soc_enum wm8958_aif2dac_ng_hold =
+ SOC_ENUM_SINGLE(WM8958_AIF2_DAC_NOISE_GATE,
+ WM8958_AIF2DAC_NG_THR_SHIFT, 4, wm8958_ng_text);
+
static const struct snd_kcontrol_new wm8958_snd_controls[] = {
SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),
+
+SOC_SINGLE("AIF1DAC1 Noise Gate Switch", WM8958_AIF1_DAC1_NOISE_GATE,
+ WM8958_AIF1DAC1_NG_ENA_SHIFT, 1, 0),
+SOC_ENUM("AIF1DAC1 Noise Gate Hold Time", wm8958_aif1dac1_ng_hold),
+SOC_SINGLE_TLV("AIF1DAC1 Noise Gate Threshold Volume",
+ WM8958_AIF1_DAC1_NOISE_GATE, WM8958_AIF1DAC1_NG_THR_SHIFT,
+ 7, 1, ng_tlv),
+
+SOC_SINGLE("AIF1DAC2 Noise Gate Switch", WM8958_AIF1_DAC2_NOISE_GATE,
+ WM8958_AIF1DAC2_NG_ENA_SHIFT, 1, 0),
+SOC_ENUM("AIF1DAC2 Noise Gate Hold Time", wm8958_aif1dac2_ng_hold),
+SOC_SINGLE_TLV("AIF1DAC2 Noise Gate Threshold Volume",
+ WM8958_AIF1_DAC2_NOISE_GATE, WM8958_AIF1DAC2_NG_THR_SHIFT,
+ 7, 1, ng_tlv),
+
+SOC_SINGLE("AIF2DAC Noise Gate Switch", WM8958_AIF2_DAC_NOISE_GATE,
+ WM8958_AIF2DAC_NG_ENA_SHIFT, 1, 0),
+SOC_ENUM("AIF2DAC Noise Gate Hold Time", wm8958_aif2dac_ng_hold),
+SOC_SINGLE_TLV("AIF2DAC Noise Gate Threshold Volume",
+ WM8958_AIF2_DAC_NOISE_GATE, WM8958_AIF2DAC_NG_THR_SHIFT,
+ 7, 1, ng_tlv),
+};
+
+static const struct snd_kcontrol_new wm1811_snd_controls[] = {
+SOC_SINGLE_TLV("MIXINL IN1LP Boost Volume", WM8994_INPUT_MIXER_1, 7, 1, 0,
+ mixin_boost_tlv),
+SOC_SINGLE_TLV("MIXINL IN1RP Boost Volume", WM8994_INPUT_MIXER_1, 8, 1, 0,
+ mixin_boost_tlv),
};
static int clk_sys_event(struct snd_soc_dapm_widget *w,
@@ -681,6 +725,97 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static void vmid_reference(struct snd_soc_codec *codec)
+{
+ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+ wm8994->vmid_refcount++;
+
+ dev_dbg(codec->dev, "Referencing VMID, refcount is now %d\n",
+ wm8994->vmid_refcount);
+
+ if (wm8994->vmid_refcount == 1) {
+ /* Startup bias, VMID ramp & buffer */
+ snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+ WM8994_STARTUP_BIAS_ENA |
+ WM8994_VMID_BUF_ENA |
+ WM8994_VMID_RAMP_MASK,
+ WM8994_STARTUP_BIAS_ENA |
+ WM8994_VMID_BUF_ENA |
+ (0x11 << WM8994_VMID_RAMP_SHIFT));
+
+ /* Main bias enable, VMID=2x40k */
+ snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+ WM8994_BIAS_ENA |
+ WM8994_VMID_SEL_MASK,
+ WM8994_BIAS_ENA | 0x2);
+
+ msleep(20);
+ }
+}
+
+static void vmid_dereference(struct snd_soc_codec *codec)
+{
+ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+ wm8994->vmid_refcount--;
+
+ dev_dbg(codec->dev, "Dereferencing VMID, refcount is now %d\n",
+ wm8994->vmid_refcount);
+
+ if (wm8994->vmid_refcount == 0) {
+ /* Switch over to startup biases */
+ snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+ WM8994_BIAS_SRC |
+ WM8994_STARTUP_BIAS_ENA |
+ WM8994_VMID_BUF_ENA |
+ WM8994_VMID_RAMP_MASK,
+ WM8994_BIAS_SRC |
+ WM8994_STARTUP_BIAS_ENA |
+ WM8994_VMID_BUF_ENA |
+ (1 << WM8994_VMID_RAMP_SHIFT));
+
+ /* Disable main biases */
+ snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
+ WM8994_BIAS_ENA |
+ WM8994_VMID_SEL_MASK, 0);
+
+ /* Discharge line */
+ snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
+ WM8994_LINEOUT1_DISCH |
+ WM8994_LINEOUT2_DISCH,
+ WM8994_LINEOUT1_DISCH |
+ WM8994_LINEOUT2_DISCH);
+
+ msleep(5);
+
+ /* Switch off startup biases */
+ snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+ WM8994_BIAS_SRC |
+ WM8994_STARTUP_BIAS_ENA |
+ WM8994_VMID_BUF_ENA |
+ WM8994_VMID_RAMP_MASK, 0);
+ }
+}
+
+static int vmid_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ vmid_reference(codec);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ vmid_dereference(codec);
+ break;
+ }
+
+ return 0;
+}
+
static void wm8994_update_class_w(struct snd_soc_codec *codec)
{
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
@@ -1208,6 +1343,8 @@ SND_SOC_DAPM_INPUT("Clock"),
SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev,
SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, vmid_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -1282,7 +1419,7 @@ SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux),
SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux),
SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
-SND_SOC_DAPM_AIF_IN("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0),
@@ -1525,6 +1662,8 @@ static const struct snd_soc_dapm_route wm8994_revd_intercon[] = {
static const struct snd_soc_dapm_route wm8994_intercon[] = {
{ "AIF2DACL", NULL, "AIF2DAC Mux" },
{ "AIF2DACR", NULL, "AIF2DAC Mux" },
+ { "MICBIAS1", NULL, "VMID" },
+ { "MICBIAS2", NULL, "VMID" },
};
static const struct snd_soc_dapm_route wm8958_intercon[] = {
@@ -1629,10 +1768,12 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
unsigned int freq_in, unsigned int freq_out)
{
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+ struct wm8994 *control = codec->control_data;
int reg_offset, ret;
struct fll_div fll;
u16 reg, aif1, aif2;
unsigned long timeout;
+ bool was_enabled;
aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
& WM8994_AIF1CLK_ENA;
@@ -1653,6 +1794,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
return -EINVAL;
}
+ reg = snd_soc_read(codec, WM8994_FLL1_CONTROL_1 + reg_offset);
+ was_enabled = reg & WM8994_FLL1_ENA;
+
switch (src) {
case 0:
/* Allow no source specification when stopping */
@@ -1719,6 +1863,21 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
/* Enable (with fractional mode if required) */
if (freq_out) {
+ /* Enable VMID if we need it */
+ if (!was_enabled) {
+ switch (control->type) {
+ case WM8994:
+ vmid_reference(codec);
+ break;
+ case WM8958:
+ if (wm8994->revision < 1)
+ vmid_reference(codec);
+ break;
+ default:
+ break;
+ }
+ }
+
if (fll.k)
reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC;
else
@@ -1736,6 +1895,20 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
} else {
msleep(5);
}
+ } else {
+ if (was_enabled) {
+ switch (control->type) {
+ case WM8994:
+ vmid_dereference(codec);
+ break;
+ case WM8958:
+ if (wm8994->revision < 1)
+ vmid_dereference(codec);
+ break;
+ default:
+ break;
+ }
+ }
}
wm8994->fll[id].in = freq_in;
@@ -1852,9 +2025,6 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_PREPARE:
- /* VMID=2x40k */
- snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
- WM8994_VMID_SEL_MASK, 0x2);
break;
case SND_SOC_BIAS_STANDBY:
@@ -1888,6 +2058,15 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
WM8958_CP_DISCH);
}
break;
+
+ case WM1811:
+ if (wm8994->revision < 2) {
+ snd_soc_write(codec, 0x102, 0x3);
+ snd_soc_write(codec, 0x5d, 0x7e);
+ snd_soc_write(codec, 0x5e, 0x0);
+ snd_soc_write(codec, 0x102, 0x0);
+ }
+ break;
}
/* Discharge LINEOUT1 & 2 */
@@ -1896,65 +2075,13 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
WM8994_LINEOUT2_DISCH,
WM8994_LINEOUT1_DISCH |
WM8994_LINEOUT2_DISCH);
-
- /* Startup bias, VMID ramp & buffer */
- snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
- WM8994_STARTUP_BIAS_ENA |
- WM8994_VMID_BUF_ENA |
- WM8994_VMID_RAMP_MASK,
- WM8994_STARTUP_BIAS_ENA |
- WM8994_VMID_BUF_ENA |
- (0x11 << WM8994_VMID_RAMP_SHIFT));
-
- /* Main bias enable, VMID=2x40k */
- snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
- WM8994_BIAS_ENA |
- WM8994_VMID_SEL_MASK,
- WM8994_BIAS_ENA | 0x2);
-
- msleep(20);
}
- /* VMID=2x500k */
- snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
- WM8994_VMID_SEL_MASK, 0x4);
break;
case SND_SOC_BIAS_OFF:
if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
- /* Switch over to startup biases */
- snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
- WM8994_BIAS_SRC |
- WM8994_STARTUP_BIAS_ENA |
- WM8994_VMID_BUF_ENA |
- WM8994_VMID_RAMP_MASK,
- WM8994_BIAS_SRC |
- WM8994_STARTUP_BIAS_ENA |
- WM8994_VMID_BUF_ENA |
- (1 << WM8994_VMID_RAMP_SHIFT));
-
- /* Disable main biases */
- snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1,
- WM8994_BIAS_ENA |
- WM8994_VMID_SEL_MASK, 0);
-
- /* Discharge line */
- snd_soc_update_bits(codec, WM8994_ANTIPOP_1,
- WM8994_LINEOUT1_DISCH |
- WM8994_LINEOUT2_DISCH,
- WM8994_LINEOUT1_DISCH |
- WM8994_LINEOUT2_DISCH);
-
- msleep(5);
-
- /* Switch off startup biases */
- snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
- WM8994_BIAS_SRC |
- WM8994_STARTUP_BIAS_ENA |
- WM8994_VMID_BUF_ENA |
- WM8994_VMID_RAMP_MASK, 0);
-
wm8994->cur_fw = NULL;
pm_runtime_put(codec->dev);
@@ -2055,10 +2182,18 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
/* The AIF2 format configuration needs to be mirrored to AIF3
* on WM8958 if it's in use so just do it all the time. */
- if (control->type == WM8958 && dai->id == 2)
- snd_soc_update_bits(codec, WM8958_AIF3_CONTROL_1,
- WM8994_AIF1_LRCLK_INV |
- WM8958_AIF3_FMT_MASK, aif1);
+ switch (control->type) {
+ case WM1811:
+ case WM8958:
+ if (dai->id == 2)
+ snd_soc_update_bits(codec, WM8958_AIF3_CONTROL_1,
+ WM8994_AIF1_LRCLK_INV |
+ WM8958_AIF3_FMT_MASK, aif1);
+ break;
+
+ default:
+ break;
+ }
snd_soc_update_bits(codec, aif1_reg,
WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV |
@@ -2100,7 +2235,6 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
- struct wm8994 *control = codec->control_data;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int aif1_reg;
int aif2_reg;
@@ -2143,14 +2277,6 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
dev_dbg(codec->dev, "AIF2 using split LRCLK\n");
}
break;
- case 3:
- switch (control->type) {
- case WM8958:
- aif1_reg = WM8958_AIF3_CONTROL_1;
- break;
- default:
- return 0;
- }
default:
return -EINVAL;
}
@@ -2271,6 +2397,7 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream,
switch (dai->id) {
case 3:
switch (control->type) {
+ case WM1811:
case WM8958:
aif1_reg = WM8958_AIF3_CONTROL_1;
break;
@@ -2311,7 +2438,7 @@ static void wm8994_aif_shutdown(struct snd_pcm_substream *substream,
rate_reg = WM8994_AIF1_RATE;
break;
case 2:
- rate_reg = WM8994_AIF1_RATE;
+ rate_reg = WM8994_AIF2_RATE;
break;
default:
break;
@@ -2384,6 +2511,21 @@ static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
return snd_soc_update_bits(codec, reg, mask, val);
}
+static int wm8994_aif2_probe(struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ /* Disable the pulls on the AIF if we're using it to save power. */
+ snd_soc_update_bits(codec, WM8994_GPIO_3,
+ WM8994_GPN_PU | WM8994_GPN_PD, 0);
+ snd_soc_update_bits(codec, WM8994_GPIO_4,
+ WM8994_GPN_PU | WM8994_GPN_PD, 0);
+ snd_soc_update_bits(codec, WM8994_GPIO_5,
+ WM8994_GPN_PU | WM8994_GPN_PD, 0);
+
+ return 0;
+}
+
#define WM8994_RATES SNDRV_PCM_RATE_8000_96000
#define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
@@ -2451,6 +2593,7 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
.rates = WM8994_RATES,
.formats = WM8994_FORMATS,
},
+ .probe = wm8994_aif2_probe,
.ops = &wm8994_aif2_dai_ops,
},
{
@@ -2485,6 +2628,7 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
case WM8994:
snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0);
break;
+ case WM1811:
case WM8958:
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
WM8958_MICD_ENA, 0);
@@ -2553,6 +2697,7 @@ static int wm8994_resume(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8994_MICBIAS,
WM8994_MICD_ENA, WM8994_MICD_ENA);
break;
+ case WM1811:
case WM8958:
if (wm8994->jack_cb)
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
@@ -2851,8 +2996,13 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = codec->control_data;
- if (control->type != WM8958)
+ switch (control->type) {
+ case WM1811:
+ case WM8958:
+ break;
+ default:
return -EINVAL;
+ }
if (jack) {
if (!cb) {
@@ -2880,19 +3030,34 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
{
struct wm8994_priv *wm8994 = data;
struct snd_soc_codec *codec = wm8994->codec;
- int reg;
+ int reg, count;
- reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
- if (reg < 0) {
- dev_err(codec->dev, "Failed to read mic detect status: %d\n",
- reg);
- return IRQ_NONE;
- }
+ /* We may occasionally read a detection without an impedence
+ * range being provided - if that happens loop again.
+ */
+ count = 10;
+ do {
+ reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
+ if (reg < 0) {
+ dev_err(codec->dev,
+ "Failed to read mic detect status: %d\n",
+ reg);
+ return IRQ_NONE;
+ }
- if (!(reg & WM8958_MICD_VALID)) {
- dev_dbg(codec->dev, "Mic detect data not valid\n");
- goto out;
- }
+ if (!(reg & WM8958_MICD_VALID)) {
+ dev_dbg(codec->dev, "Mic detect data not valid\n");
+ goto out;
+ }
+
+ if (!(reg & WM8958_MICD_STS) || (reg & WM8958_MICD_LVL_MASK))
+ break;
+
+ msleep(1);
+ } while (count--);
+
+ if (count == 0)
+ dev_warn(codec->dev, "No impedence range reported for jack\n");
#ifndef CONFIG_SND_SOC_WM8994_MODULE
trace_snd_soc_jack_irq(dev_name(codec->dev));
@@ -2916,6 +3081,24 @@ static irqreturn_t wm8994_fifo_error(int irq, void *data)
return IRQ_HANDLED;
}
+static irqreturn_t wm8994_temp_warn(int irq, void *data)
+{
+ struct snd_soc_codec *codec = data;
+
+ dev_err(codec->dev, "Thermal warning\n");
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wm8994_temp_shut(int irq, void *data)
+{
+ struct snd_soc_codec *codec = data;
+
+ dev_crit(codec->dev, "Thermal shutdown\n");
+
+ return IRQ_HANDLED;
+}
+
static int wm8994_codec_probe(struct snd_soc_codec *codec)
{
struct wm8994 *control;
@@ -2972,13 +3155,14 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
switch (wm8994->revision) {
case 2:
case 3:
- wm8994->hubs.dcs_codes = -5;
+ wm8994->hubs.dcs_codes_l = -5;
+ wm8994->hubs.dcs_codes_r = -5;
wm8994->hubs.hp_startup_mode = 1;
wm8994->hubs.dcs_readback_mode = 1;
wm8994->hubs.series_startup = 1;
break;
default:
- wm8994->hubs.dcs_readback_mode = 1;
+ wm8994->hubs.dcs_readback_mode = 2;
break;
}
break;
@@ -2987,12 +3171,34 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8994->hubs.dcs_readback_mode = 1;
break;
+ case WM1811:
+ wm8994->hubs.dcs_readback_mode = 2;
+ wm8994->hubs.no_series_update = 1;
+
+ switch (wm8994->revision) {
+ case 0:
+ case 1:
+ wm8994->hubs.dcs_codes_l = -9;
+ wm8994->hubs.dcs_codes_r = -5;
+ break;
+ default:
+ break;
+ }
+
+ snd_soc_update_bits(codec, WM8994_ANALOGUE_HP_1,
+ WM1811_HPOUT1_ATTN, WM1811_HPOUT1_ATTN);
+ break;
+
default:
break;
}
wm8994_request_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR,
wm8994_fifo_error, "FIFO error", codec);
+ wm8994_request_irq(codec->control_data, WM8994_IRQ_TEMP_WARN,
+ wm8994_temp_warn, "Thermal warning", codec);
+ wm8994_request_irq(codec->control_data, WM8994_IRQ_TEMP_SHUT,
+ wm8994_temp_shut, "Thermal shutdown", codec);
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
wm_hubs_dcs_done, "DC servo done",
@@ -3043,6 +3249,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
break;
case WM8958:
+ case WM1811:
if (wm8994->micdet_irq) {
ret = request_threaded_irq(wm8994->micdet_irq, NULL,
wm8958_mic_irq,
@@ -3205,6 +3412,19 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
ARRAY_SIZE(wm8994_dac_widgets));
}
break;
+
+ case WM1811:
+ snd_soc_add_controls(codec, wm8958_snd_controls,
+ ARRAY_SIZE(wm8958_snd_controls));
+ snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
+ ARRAY_SIZE(wm8958_dapm_widgets));
+ snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
+ ARRAY_SIZE(wm8994_lateclk_widgets));
+ snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
+ ARRAY_SIZE(wm8994_adc_widgets));
+ snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
+ ARRAY_SIZE(wm8994_dac_widgets));
+ break;
}
@@ -3241,6 +3461,12 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8958_dsp2_init(codec);
break;
+ case WM1811:
+ snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
+ ARRAY_SIZE(wm8994_lateclk_intercon));
+ snd_soc_dapm_add_routes(dapm, wm8958_intercon,
+ ARRAY_SIZE(wm8958_intercon));
+ break;
}
return 0;
@@ -3257,6 +3483,8 @@ err_irq:
wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
&wm8994->hubs);
wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec);
+ wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_SHUT, codec);
+ wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_WARN, codec);
err:
kfree(wm8994);
return ret;
@@ -3279,6 +3507,8 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
&wm8994->hubs);
wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec);
+ wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_SHUT, codec);
+ wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_WARN, codec);
switch (control->type) {
case WM8994:
@@ -3292,6 +3522,7 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
wm8994);
break;
+ case WM1811:
case WM8958:
if (wm8994->micdet_irq)
free_irq(wm8994->micdet_irq, wm8994);
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 1ab2266039f7..f4f1355efc82 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -83,6 +83,8 @@ struct wm8994_priv {
struct completion fll_locked[2];
bool fll_locked_irq;
+ int vmid_refcount;
+
int dac_rates[2];
int lrclk_shared[2];
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 5ad873fda814..78eeb21e6696 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -485,7 +485,7 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
static int configure_clock(struct snd_soc_codec *codec)
{
struct wm8995_priv *wm8995;
- int old, new;
+ int change, new;
wm8995 = snd_soc_codec_get_drvdata(codec);
@@ -509,15 +509,11 @@ static int configure_clock(struct snd_soc_codec *codec)
else
new = 0;
- old = snd_soc_read(codec, WM8995_CLOCKING_1) & WM8995_SYSCLK_SRC;
-
- /* If there's no change then we're done. */
- if (old == new)
+ change = snd_soc_update_bits(codec, WM8995_CLOCKING_1,
+ WM8995_SYSCLK_SRC_MASK, new);
+ if (!change)
return 0;
- snd_soc_update_bits(codec, WM8995_CLOCKING_1,
- WM8995_SYSCLK_SRC_MASK, new);
-
snd_soc_dapm_sync(&codec->dapm);
return 0;
@@ -1573,11 +1569,16 @@ static int wm8995_resume(struct snd_soc_codec *codec)
static int wm8995_remove(struct snd_soc_codec *codec)
{
struct wm8995_priv *wm8995;
- struct i2c_client *i2c;
+ int i;
- i2c = container_of(codec->dev, struct i2c_client, dev);
wm8995 = snd_soc_codec_get_drvdata(codec);
wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i)
+ regulator_unregister_notifier(wm8995->supplies[i].consumer,
+ &wm8995->disable_nb[i]);
+
+ regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies);
return 0;
}
@@ -1642,6 +1643,7 @@ static int wm8995_probe(struct snd_soc_codec *codec)
if (ret != 0x8995) {
dev_err(codec->dev, "Invalid device ID: %#x\n", ret);
+ ret = -EINVAL;
goto err_reg_enable;
}
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 0cdb9d105671..645c980d6b80 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -41,12 +41,11 @@
#define HPOUT2L 4
#define HPOUT2R 8
-#define WM8996_NUM_SUPPLIES 4
+#define WM8996_NUM_SUPPLIES 3
static const char *wm8996_supply_names[WM8996_NUM_SUPPLIES] = {
"DBVDD",
"AVDD1",
"AVDD2",
- "CPVDD",
};
struct wm8996_priv {
@@ -71,6 +70,8 @@ struct wm8996_priv {
struct regulator_bulk_data supplies[WM8996_NUM_SUPPLIES];
struct notifier_block disable_nb[WM8996_NUM_SUPPLIES];
+ struct regulator *cpvdd;
+ int bg_ena;
struct wm8996_pdata pdata;
@@ -112,7 +113,6 @@ static int wm8996_regulator_event_##n(struct notifier_block *nb, \
WM8996_REGULATOR_EVENT(0)
WM8996_REGULATOR_EVENT(1)
WM8996_REGULATOR_EVENT(2)
-WM8996_REGULATOR_EVENT(3)
static const u16 wm8996_reg[WM8996_MAX_REGISTER] = {
[WM8996_SOFTWARE_RESET] = 0x8996,
@@ -414,6 +414,7 @@ static const DECLARE_TLV_DB_SCALE(out_digital_tlv, -1200, 150, 0);
static const DECLARE_TLV_DB_SCALE(out_tlv, -900, 75, 0);
static const DECLARE_TLV_DB_SCALE(spk_tlv, -900, 150, 0);
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(threedstereo_tlv, -1600, 183, 1);
static const char *sidetone_hpf_text[] = {
"2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz"
@@ -608,6 +609,14 @@ SOC_SINGLE("DAC High Performance Switch", WM8996_OVERSAMPLING, 0, 1, 0),
SOC_SINGLE("DAC Soft Mute Switch", WM8996_DAC_SOFTMUTE, 1, 1, 0),
SOC_SINGLE("DAC Slow Soft Mute Switch", WM8996_DAC_SOFTMUTE, 0, 1, 0),
+SOC_SINGLE("DSP1 3D Stereo Switch", WM8996_DSP1_RX_FILTERS_2, 8, 1, 0),
+SOC_SINGLE("DSP2 3D Stereo Switch", WM8996_DSP2_RX_FILTERS_2, 8, 1, 0),
+
+SOC_SINGLE_TLV("DSP1 3D Stereo Volume", WM8996_DSP1_RX_FILTERS_2, 10, 15,
+ 0, threedstereo_tlv),
+SOC_SINGLE_TLV("DSP2 3D Stereo Volume", WM8996_DSP2_RX_FILTERS_2, 10, 15,
+ 0, threedstereo_tlv),
+
SOC_DOUBLE_TLV("Digital Output 1 Volume", WM8996_DAC1_HPOUT1_VOLUME, 0, 4,
8, 0, out_digital_tlv),
SOC_DOUBLE_TLV("Digital Output 2 Volume", WM8996_DAC2_HPOUT2_VOLUME, 0, 4,
@@ -632,6 +641,14 @@ SOC_DOUBLE_R("Speaker ZC Switch", WM8996_LEFT_PDM_SPEAKER,
SOC_SINGLE("DSP1 EQ Switch", WM8996_DSP1_RX_EQ_GAINS_1, 0, 1, 0),
SOC_SINGLE("DSP2 EQ Switch", WM8996_DSP2_RX_EQ_GAINS_1, 0, 1, 0),
+
+SOC_SINGLE("DSP1 DRC TXL Switch", WM8996_DSP1_DRC_1, 0, 1, 0),
+SOC_SINGLE("DSP1 DRC TXR Switch", WM8996_DSP1_DRC_1, 1, 1, 0),
+SOC_SINGLE("DSP1 DRC RX Switch", WM8996_DSP1_DRC_1, 2, 1, 0),
+
+SOC_SINGLE("DSP2 DRC TXL Switch", WM8996_DSP2_DRC_1, 0, 1, 0),
+SOC_SINGLE("DSP2 DRC TXR Switch", WM8996_DSP2_DRC_1, 1, 1, 0),
+SOC_SINGLE("DSP2 DRC RX Switch", WM8996_DSP2_DRC_1, 2, 1, 0),
};
static const struct snd_kcontrol_new wm8996_eq_controls[] = {
@@ -658,19 +675,75 @@ SOC_SINGLE_TLV("DSP2 EQ B5 Volume", WM8996_DSP2_RX_EQ_GAINS_2, 6, 31, 0,
eq_tlv),
};
+static void wm8996_bg_enable(struct snd_soc_codec *codec)
+{
+ struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+
+ wm8996->bg_ena++;
+ if (wm8996->bg_ena == 1) {
+ snd_soc_update_bits(codec, WM8996_POWER_MANAGEMENT_1,
+ WM8996_BG_ENA, WM8996_BG_ENA);
+ msleep(2);
+ }
+}
+
+static void wm8996_bg_disable(struct snd_soc_codec *codec)
+{
+ struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+
+ wm8996->bg_ena--;
+ if (!wm8996->bg_ena)
+ snd_soc_update_bits(codec, WM8996_POWER_MANAGEMENT_1,
+ WM8996_BG_ENA, 0);
+}
+
+static int bg_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wm8996_bg_enable(codec);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wm8996_bg_disable(codec);
+ break;
+ default:
+ BUG();
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
static int cp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
+ struct snd_soc_codec *codec = w->codec;
+ struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = regulator_enable(wm8996->cpvdd);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to enable CPVDD: %d\n",
+ ret);
+ break;
case SND_SOC_DAPM_POST_PMU:
msleep(5);
break;
+ case SND_SOC_DAPM_POST_PMD:
+ regulator_disable_deferred(wm8996->cpvdd, 20);
+ break;
default:
BUG();
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+ return ret;
}
static int rmv_short_event(struct snd_soc_dapm_widget *w,
@@ -698,7 +771,7 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask)
{
struct i2c_client *i2c = to_i2c_client(codec->dev);
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
- int i, ret;
+ int ret;
unsigned long timeout = 200;
snd_soc_write(codec, WM8996_DC_SERVO_2, mask);
@@ -713,15 +786,12 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask)
} else {
msleep(1);
- if (--i) {
- timeout = 0;
- break;
- }
+ timeout--;
}
ret = snd_soc_read(codec, WM8996_DC_SERVO_2);
dev_dbg(codec->dev, "DC servo state: %x\n", ret);
- } while (ret & mask);
+ } while (timeout && ret & mask);
if (timeout == 0)
dev_err(codec->dev, "DC servo timed out for %x\n", mask);
@@ -979,9 +1049,12 @@ SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8996_AIF_CLOCKING_1, 0, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8996_CLOCKING_1, 1, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8996_CLOCKING_1, 2, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8996_CHARGE_PUMP_1, 15, 0, cp_event,
- SND_SOC_DAPM_POST_PMU),
-
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("Bandgap", SND_SOC_NOPM, 0, 0, bg_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("LDO2", WM8996_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICB1 Audio", WM8996_MICBIAS_1, 4, 1, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICB2 Audio", WM8996_MICBIAS_2, 4, 1, NULL, 0),
SND_SOC_DAPM_MICBIAS("MICB2", WM8996_POWER_MANAGEMENT_1, 9, 0),
SND_SOC_DAPM_MICBIAS("MICB1", WM8996_POWER_MANAGEMENT_1, 8, 0),
@@ -1035,14 +1108,14 @@ SND_SOC_DAPM_DAC("DAC2R", NULL, WM8996_POWER_MANAGEMENT_5, 2, 0),
SND_SOC_DAPM_DAC("DAC1L", NULL, WM8996_POWER_MANAGEMENT_5, 1, 0),
SND_SOC_DAPM_DAC("DAC1R", NULL, WM8996_POWER_MANAGEMENT_5, 0, 0),
-SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 1,
+SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 0,
WM8996_POWER_MANAGEMENT_4, 9, 0),
-SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 2,
+SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 1,
WM8996_POWER_MANAGEMENT_4, 8, 0),
-SND_SOC_DAPM_AIF_IN("AIF2TX1", "AIF2 Capture", 1,
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", "AIF2 Capture", 0,
WM8996_POWER_MANAGEMENT_6, 9, 0),
-SND_SOC_DAPM_AIF_IN("AIF2TX0", "AIF2 Capture", 2,
+SND_SOC_DAPM_AIF_OUT("AIF2TX0", "AIF2 Capture", 1,
WM8996_POWER_MANAGEMENT_6, 8, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5,
@@ -1137,17 +1210,23 @@ static const struct snd_soc_dapm_route wm8996_dapm_routes[] = {
{ "Charge Pump", NULL, "SYSCLK" },
{ "MICB1", NULL, "LDO2" },
+ { "MICB1", NULL, "MICB1 Audio" },
+ { "MICB1", NULL, "Bandgap" },
{ "MICB2", NULL, "LDO2" },
+ { "MICB2", NULL, "MICB2 Audio" },
+ { "MICB2", NULL, "Bandgap" },
{ "IN1L PGA", NULL, "IN2LN" },
{ "IN1L PGA", NULL, "IN2LP" },
{ "IN1L PGA", NULL, "IN1LN" },
{ "IN1L PGA", NULL, "IN1LP" },
+ { "IN1L PGA", NULL, "Bandgap" },
{ "IN1R PGA", NULL, "IN2RN" },
{ "IN1R PGA", NULL, "IN2RP" },
{ "IN1R PGA", NULL, "IN1RN" },
{ "IN1R PGA", NULL, "IN1RP" },
+ { "IN1R PGA", NULL, "Bandgap" },
{ "ADCL", NULL, "IN1L PGA" },
@@ -1281,6 +1360,7 @@ static const struct snd_soc_dapm_route wm8996_dapm_routes[] = {
{ "DAC2R", NULL, "DAC2R Mixer" },
{ "HPOUT2L PGA", NULL, "Charge Pump" },
+ { "HPOUT2L PGA", NULL, "Bandgap" },
{ "HPOUT2L PGA", NULL, "DAC2L" },
{ "HPOUT2L_DLY", NULL, "HPOUT2L PGA" },
{ "HPOUT2L_DCS", NULL, "HPOUT2L_DLY" },
@@ -1288,6 +1368,7 @@ static const struct snd_soc_dapm_route wm8996_dapm_routes[] = {
{ "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_OUTP" },
{ "HPOUT2R PGA", NULL, "Charge Pump" },
+ { "HPOUT2R PGA", NULL, "Bandgap" },
{ "HPOUT2R PGA", NULL, "DAC2R" },
{ "HPOUT2R_DLY", NULL, "HPOUT2R PGA" },
{ "HPOUT2R_DCS", NULL, "HPOUT2R_DLY" },
@@ -1295,6 +1376,7 @@ static const struct snd_soc_dapm_route wm8996_dapm_routes[] = {
{ "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_OUTP" },
{ "HPOUT1L PGA", NULL, "Charge Pump" },
+ { "HPOUT1L PGA", NULL, "Bandgap" },
{ "HPOUT1L PGA", NULL, "DAC1L" },
{ "HPOUT1L_DLY", NULL, "HPOUT1L PGA" },
{ "HPOUT1L_DCS", NULL, "HPOUT1L_DLY" },
@@ -1302,6 +1384,7 @@ static const struct snd_soc_dapm_route wm8996_dapm_routes[] = {
{ "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_OUTP" },
{ "HPOUT1R PGA", NULL, "Charge Pump" },
+ { "HPOUT1R PGA", NULL, "Bandgap" },
{ "HPOUT1R PGA", NULL, "DAC1R" },
{ "HPOUT1R_DLY", NULL, "HPOUT1R PGA" },
{ "HPOUT1R_DCS", NULL, "HPOUT1R_DLY" },
@@ -1620,14 +1703,7 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
- break;
-
case SND_SOC_BIAS_PREPARE:
- if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
- snd_soc_update_bits(codec, WM8996_POWER_MANAGEMENT_1,
- WM8996_BG_ENA, WM8996_BG_ENA);
- msleep(2);
- }
break;
case SND_SOC_BIAS_STANDBY:
@@ -1650,9 +1726,6 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
codec->cache_only = false;
snd_soc_cache_sync(codec);
}
-
- snd_soc_update_bits(codec, WM8996_POWER_MANAGEMENT_1,
- WM8996_BG_ENA, 0);
break;
case SND_SOC_BIAS_OFF:
@@ -1847,7 +1920,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
snd_soc_update_bits(codec, lrclk_reg, WM8996_AIF1RX_RATE_MASK,
lrclk);
snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_2,
- WM8996_DSP1_DIV_SHIFT << dsp_shift, dsp);
+ WM8996_DSP1_DIV_MASK << dsp_shift, dsp);
return 0;
}
@@ -2041,7 +2114,7 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
struct i2c_client *i2c = to_i2c_client(codec->dev);
struct _fll_div fll_div;
unsigned long timeout;
- int ret, reg;
+ int ret, reg, retry;
/* Any change? */
if (source == wm8996->fll_src && Fref == wm8996->fll_fref &&
@@ -2057,6 +2130,8 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
snd_soc_update_bits(codec, WM8996_FLL_CONTROL_1,
WM8996_FLL_ENA, 0);
+ wm8996_bg_disable(codec);
+
return 0;
}
@@ -2111,6 +2186,11 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
snd_soc_write(codec, WM8996_FLL_EFS_1, fll_div.lambda);
+ /* Enable the bandgap if it's not already enabled */
+ ret = snd_soc_read(codec, WM8996_FLL_CONTROL_1);
+ if (!(ret & WM8996_FLL_ENA))
+ wm8996_bg_enable(codec);
+
/* Clear any pending completions (eg, from failed startups) */
try_wait_for_completion(&wm8996->fll_lock);
@@ -2128,17 +2208,29 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
else
timeout = msecs_to_jiffies(2);
- /* Allow substantially longer if we've actually got the IRQ */
+ /* Allow substantially longer if we've actually got the IRQ, poll
+ * at a slightly higher rate if we don't.
+ */
if (i2c->irq)
- timeout *= 1000;
+ timeout *= 10;
+ else
+ timeout /= 2;
- ret = wait_for_completion_timeout(&wm8996->fll_lock, timeout);
+ for (retry = 0; retry < 10; retry++) {
+ ret = wait_for_completion_timeout(&wm8996->fll_lock,
+ timeout);
+ if (ret != 0) {
+ WARN_ON(!i2c->irq);
+ break;
+ }
- if (ret == 0 && i2c->irq) {
+ ret = snd_soc_read(codec, WM8996_INTERRUPT_RAW_STATUS_2);
+ if (ret & WM8996_FLL_LOCK_STS)
+ break;
+ }
+ if (retry == 10) {
dev_err(codec->dev, "Timed out waiting for FLL\n");
ret = -ETIMEDOUT;
- } else {
- ret = 0;
}
dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
@@ -2297,12 +2389,94 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
/* Enable interrupts and we're off */
snd_soc_update_bits(codec, WM8996_INTERRUPT_STATUS_2_MASK,
- WM8996_IM_MICD_EINT, 0);
+ WM8996_IM_MICD_EINT | WM8996_HP_DONE_EINT, 0);
return 0;
}
EXPORT_SYMBOL_GPL(wm8996_detect);
+static void wm8996_hpdet_irq(struct snd_soc_codec *codec)
+{
+ struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+ int val, reg, report;
+
+ /* Assume headphone in error conditions; we need to report
+ * something or we stall our state machine.
+ */
+ report = SND_JACK_HEADPHONE;
+
+ reg = snd_soc_read(codec, WM8996_HEADPHONE_DETECT_2);
+ if (reg < 0) {
+ dev_err(codec->dev, "Failed to read HPDET status\n");
+ goto out;
+ }
+
+ if (!(reg & WM8996_HP_DONE)) {
+ dev_err(codec->dev, "Got HPDET IRQ but HPDET is busy\n");
+ goto out;
+ }
+
+ val = reg & WM8996_HP_LVL_MASK;
+
+ dev_dbg(codec->dev, "HPDET measured %d ohms\n", val);
+
+ /* If we've got high enough impedence then report as line,
+ * otherwise assume headphone.
+ */
+ if (val >= 126)
+ report = SND_JACK_LINEOUT;
+ else
+ report = SND_JACK_HEADPHONE;
+
+out:
+ if (wm8996->jack_mic)
+ report |= SND_JACK_MICROPHONE;
+
+ snd_soc_jack_report(wm8996->jack, report,
+ SND_JACK_LINEOUT | SND_JACK_HEADSET);
+
+ wm8996->detecting = false;
+
+ /* If the output isn't running re-clamp it */
+ if (!(snd_soc_read(codec, WM8996_POWER_MANAGEMENT_1) &
+ (WM8996_HPOUT1L_ENA | WM8996_HPOUT1R_RMV_SHORT)))
+ snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1,
+ WM8996_HPOUT1L_RMV_SHORT |
+ WM8996_HPOUT1R_RMV_SHORT, 0);
+
+ /* Go back to looking at the microphone */
+ snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_1,
+ WM8996_JD_MODE_MASK, 0);
+ snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA,
+ WM8996_MICD_ENA);
+
+ snd_soc_dapm_disable_pin(&codec->dapm, "Bandgap");
+ snd_soc_dapm_sync(&codec->dapm);
+}
+
+static void wm8996_hpdet_start(struct snd_soc_codec *codec)
+{
+ /* Unclamp the output, we can't measure while we're shorting it */
+ snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1,
+ WM8996_HPOUT1L_RMV_SHORT |
+ WM8996_HPOUT1R_RMV_SHORT,
+ WM8996_HPOUT1L_RMV_SHORT |
+ WM8996_HPOUT1R_RMV_SHORT);
+
+ /* We need bandgap for HPDET */
+ snd_soc_dapm_force_enable_pin(&codec->dapm, "Bandgap");
+ snd_soc_dapm_sync(&codec->dapm);
+
+ /* Go into headphone detect left mode */
+ snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA, 0);
+ snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_1,
+ WM8996_JD_MODE_MASK, 1);
+
+ /* Trigger a measurement */
+ snd_soc_update_bits(codec, WM8996_HEADPHONE_DETECT_1,
+ WM8996_HP_POLL, WM8996_HP_POLL);
+}
+
static void wm8996_micd(struct snd_soc_codec *codec)
{
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
@@ -2323,28 +2497,36 @@ static void wm8996_micd(struct snd_soc_codec *codec)
wm8996->jack_mic = false;
wm8996->detecting = true;
snd_soc_jack_report(wm8996->jack, 0,
- SND_JACK_HEADSET | SND_JACK_BTN_0);
+ SND_JACK_LINEOUT | SND_JACK_HEADSET |
+ SND_JACK_BTN_0);
+
snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
WM8996_MICD_RATE_MASK,
WM8996_MICD_RATE_MASK);
return;
}
- /* If the measurement is very high we've got a microphone but
- * do a little debounce to account for mechanical issues.
+ /* If the measurement is very high we've got a microphone,
+ * either we just detected one or if we already reported then
+ * we've got a button release event.
*/
if (val & 0x400) {
- dev_dbg(codec->dev, "Microphone detected\n");
- snd_soc_jack_report(wm8996->jack, SND_JACK_HEADSET,
- SND_JACK_HEADSET | SND_JACK_BTN_0);
- wm8996->jack_mic = true;
- wm8996->detecting = false;
-
- /* Increase poll rate to give better responsiveness
- * for buttons */
- snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
- WM8996_MICD_RATE_MASK,
- 5 << WM8996_MICD_RATE_SHIFT);
+ if (wm8996->detecting) {
+ dev_dbg(codec->dev, "Microphone detected\n");
+ wm8996->jack_mic = true;
+ wm8996_hpdet_start(codec);
+
+ /* Increase poll rate to give better responsiveness
+ * for buttons */
+ snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+ WM8996_MICD_RATE_MASK,
+ 5 << WM8996_MICD_RATE_SHIFT);
+ } else {
+ dev_dbg(codec->dev, "Mic button up\n");
+ snd_soc_jack_report(wm8996->jack, 0, SND_JACK_BTN_0);
+ }
+
+ return;
}
/* If we detected a lower impedence during initial startup
@@ -2376,15 +2558,11 @@ static void wm8996_micd(struct snd_soc_codec *codec)
if (val & 0x3fc) {
if (wm8996->jack_mic) {
dev_dbg(codec->dev, "Mic button detected\n");
- snd_soc_jack_report(wm8996->jack,
- SND_JACK_HEADSET | SND_JACK_BTN_0,
- SND_JACK_HEADSET | SND_JACK_BTN_0);
- } else {
- dev_dbg(codec->dev, "Headphone detected\n");
- snd_soc_jack_report(wm8996->jack,
- SND_JACK_HEADPHONE,
- SND_JACK_HEADSET |
+ snd_soc_jack_report(wm8996->jack, SND_JACK_BTN_0,
SND_JACK_BTN_0);
+ } else if (wm8996->detecting) {
+ dev_dbg(codec->dev, "Headphone detected\n");
+ wm8996_hpdet_start(codec);
/* Increase the detection rate a bit for
* responsiveness.
@@ -2392,8 +2570,6 @@ static void wm8996_micd(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
WM8996_MICD_RATE_MASK,
7 << WM8996_MICD_RATE_SHIFT);
-
- wm8996->detecting = false;
}
}
}
@@ -2412,6 +2588,9 @@ static irqreturn_t wm8996_irq(int irq, void *data)
}
irq_val &= ~snd_soc_read(codec, WM8996_INTERRUPT_STATUS_2_MASK);
+ if (!irq_val)
+ return IRQ_NONE;
+
snd_soc_write(codec, WM8996_INTERRUPT_STATUS_2, irq_val);
if (irq_val & (WM8996_DCS_DONE_01_EINT | WM8996_DCS_DONE_23_EINT)) {
@@ -2430,10 +2609,10 @@ static irqreturn_t wm8996_irq(int irq, void *data)
if (irq_val & WM8996_MICD_EINT)
wm8996_micd(codec);
- if (irq_val)
- return IRQ_HANDLED;
- else
- return IRQ_NONE;
+ if (irq_val & WM8996_HP_DONE_EINT)
+ wm8996_hpdet_irq(codec);
+
+ return IRQ_HANDLED;
}
static irqreturn_t wm8996_edge_irq(int irq, void *data)
@@ -2527,7 +2706,6 @@ static int wm8996_probe(struct snd_soc_codec *codec)
init_completion(&wm8996->fll_lock);
dapm->idle_bias_off = true;
- dapm->bias_level = SND_SOC_BIAS_OFF;
ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
if (ret != 0) {
@@ -2548,7 +2726,13 @@ static int wm8996_probe(struct snd_soc_codec *codec)
wm8996->disable_nb[0].notifier_call = wm8996_regulator_event_0;
wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1;
wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2;
- wm8996->disable_nb[3].notifier_call = wm8996_regulator_event_3;
+
+ wm8996->cpvdd = regulator_get(&i2c->dev, "CPVDD");
+ if (IS_ERR(wm8996->cpvdd)) {
+ ret = PTR_ERR(wm8996->cpvdd);
+ dev_err(&i2c->dev, "Failed to get CPVDD: %d\n", ret);
+ goto err_get;
+ }
/* This should really be moved into the regulator core */
for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) {
@@ -2565,7 +2749,7 @@ static int wm8996_probe(struct snd_soc_codec *codec)
wm8996->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
- goto err_get;
+ goto err_cpvdd;
}
if (wm8996->pdata.ldo_ena >= 0) {
@@ -2808,6 +2992,8 @@ err_enable:
gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
+err_cpvdd:
+ regulator_put(wm8996->cpvdd);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
err:
@@ -2831,6 +3017,7 @@ static int wm8996_remove(struct snd_soc_codec *codec)
for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
regulator_unregister_notifier(wm8996->supplies[i].consumer,
&wm8996->disable_nb[i]);
+ regulator_put(wm8996->cpvdd);
regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
return 0;
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index a4691321f9b3..3cd35a02c28c 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -157,7 +157,6 @@ static struct {
struct wm9081_priv {
enum snd_soc_control_type control_type;
- void *control_data;
int sysclk_source;
int mclk_rate;
int sysclk_rate;
@@ -174,6 +173,7 @@ static int wm9081_volatile_register(struct snd_soc_codec *codec, unsigned int re
{
switch (reg) {
case WM9081_SOFTWARE_RESET:
+ case WM9081_INTERRUPT_STATUS:
return 1;
default:
return 0;
@@ -820,7 +820,7 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
/* VMID 2*240k */
reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
reg &= ~WM9081_VMID_SEL_MASK;
- reg |= 0x40;
+ reg |= 0x04;
snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
/* Standby bias current on */
@@ -1120,8 +1120,8 @@ static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute)
return 0;
}
-static int wm9081_set_sysclk(struct snd_soc_codec *codec,
- int clk_id, unsigned int freq, int dir)
+static int wm9081_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+ int source, unsigned int freq, int dir)
{
struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
@@ -1213,7 +1213,6 @@ static int wm9081_probe(struct snd_soc_codec *codec)
int ret;
u16 reg;
- codec->control_data = wm9081->control_data;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm9081->control_type);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
@@ -1250,8 +1249,6 @@ static int wm9081_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
reg | WM9081_SPKPGAZC);
- snd_soc_add_controls(codec, wm9081_snd_controls,
- ARRAY_SIZE(wm9081_snd_controls));
if (!wm9081->pdata.num_retune_configs) {
dev_dbg(codec->dev,
"No ReTune Mobile data, using normal EQ\n");
@@ -1311,6 +1308,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
.reg_cache_default = wm9081_reg_defaults,
.volatile_register = wm9081_volatile_register,
+ .controls = wm9081_snd_controls,
+ .num_controls = ARRAY_SIZE(wm9081_snd_controls),
.dapm_widgets = wm9081_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm9081_dapm_widgets),
.dapm_routes = wm9081_audio_paths,
@@ -1330,7 +1329,6 @@ static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, wm9081);
wm9081->control_type = SND_SOC_I2C;
- wm9081->control_data = i2c;
if (dev_get_platdata(&i2c->dev))
memcpy(&wm9081->pdata, dev_get_platdata(&i2c->dev),
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index 4de12203e611..2b5252c9e377 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -139,9 +139,7 @@ static const u16 wm9090_reg_defaults[] = {
/* This struct is used to save the context */
struct wm9090_priv {
- struct mutex mutex;
struct wm9090_platform_data pdata;
- void *control_data;
};
static int wm9090_volatile(struct snd_soc_codec *codec, unsigned int reg)
@@ -550,10 +548,8 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
static int wm9090_probe(struct snd_soc_codec *codec)
{
- struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
int ret;
- codec->control_data = wm9090->control_data;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
@@ -662,8 +658,6 @@ static int wm9090_i2c_probe(struct i2c_client *i2c,
sizeof(wm9090->pdata));
i2c_set_clientdata(i2c, wm9090);
- wm9090->control_data = i2c;
- mutex_init(&wm9090->mutex);
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm9090, NULL, 0);
@@ -684,6 +678,7 @@ static int __devexit wm9090_i2c_remove(struct i2c_client *i2c)
static const struct i2c_device_id wm9090_id[] = {
{ "wm9090", 0 },
+ { "wm9093", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm9090_id);
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index e763c54c55dc..84f33d4ea2cd 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -18,6 +18,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
+#include <linux/mfd/wm8994/registers.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -116,14 +117,23 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
{
struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
s8 offset;
- u16 reg, reg_l, reg_r, dcs_cfg;
+ u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg;
+
+ switch (hubs->dcs_readback_mode) {
+ case 2:
+ dcs_reg = WM8994_DC_SERVO_4E;
+ break;
+ default:
+ dcs_reg = WM8993_DC_SERVO_3;
+ break;
+ }
/* If we're using a digital only path and have a previously
* callibrated DC servo offset stored then use that. */
if (hubs->class_w && hubs->class_w_dcs) {
dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
hubs->class_w_dcs);
- snd_soc_write(codec, WM8993_DC_SERVO_3, hubs->class_w_dcs);
+ snd_soc_write(codec, dcs_reg, hubs->class_w_dcs);
wait_for_dc_servo(codec,
WM8993_DCS_TRIG_DAC_WR_0 |
WM8993_DCS_TRIG_DAC_WR_1);
@@ -154,8 +164,9 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
& WM8993_DCS_INTEG_CHAN_1_MASK;
break;
+ case 2:
case 1:
- reg = snd_soc_read(codec, WM8993_DC_SERVO_3);
+ reg = snd_soc_read(codec, dcs_reg);
reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
@@ -168,24 +179,25 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
/* Apply correction to DC servo result */
- if (hubs->dcs_codes) {
- dev_dbg(codec->dev, "Applying %d code DC servo correction\n",
- hubs->dcs_codes);
+ if (hubs->dcs_codes_l || hubs->dcs_codes_r) {
+ dev_dbg(codec->dev,
+ "Applying %d/%d code DC servo correction\n",
+ hubs->dcs_codes_l, hubs->dcs_codes_r);
/* HPOUT1R */
offset = reg_r;
- offset += hubs->dcs_codes;
+ offset += hubs->dcs_codes_r;
dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
/* HPOUT1L */
offset = reg_l;
- offset += hubs->dcs_codes;
+ offset += hubs->dcs_codes_l;
dcs_cfg |= (u8)offset;
dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);
/* Do it */
- snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg);
+ snd_soc_write(codec, dcs_reg, dcs_cfg);
wait_for_dc_servo(codec,
WM8993_DCS_TRIG_DAC_WR_0 |
WM8993_DCS_TRIG_DAC_WR_1);
@@ -210,14 +222,14 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
int ret;
- ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
/* Updating the analogue gains invalidates the DC servo cache */
hubs->class_w_dcs = 0;
/* If we're applying an offset correction then updating the
* callibration would be likely to introduce further offsets. */
- if (hubs->dcs_codes || hubs->no_series_update)
+ if (hubs->dcs_codes_l || hubs->dcs_codes_r || hubs->no_series_update)
return ret;
/* Only need to do this if the outputs are active */
@@ -350,19 +362,11 @@ SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 3, 0, 7, 0,
SOC_ENUM("Speaker Reference", speaker_ref),
SOC_ENUM("Speaker Mode", speaker_mode),
-{
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Volume",
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
- SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .tlv.p = outpga_tlv,
- .info = snd_soc_info_volsw_2r,
- .get = snd_soc_get_volsw_2r, .put = wm8993_put_dc_servo,
- .private_value = (unsigned long)&(struct soc_mixer_control) {
- .reg = WM8993_LEFT_OUTPUT_VOLUME,
- .rreg = WM8993_RIGHT_OUTPUT_VOLUME,
- .shift = 0, .max = 63
- },
-},
+SOC_DOUBLE_R_EXT_TLV("Headphone Volume",
+ WM8993_LEFT_OUTPUT_VOLUME, WM8993_RIGHT_OUTPUT_VOLUME,
+ 0, 63, 0, snd_soc_get_volsw, wm8993_put_dc_servo,
+ outpga_tlv),
+
SOC_DOUBLE_R("Headphone Switch", WM8993_LEFT_OUTPUT_VOLUME,
WM8993_RIGHT_OUTPUT_VOLUME, 6, 1, 0),
SOC_DOUBLE_R("Headphone ZC Switch", WM8993_LEFT_OUTPUT_VOLUME,
@@ -699,6 +703,11 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
{ "IN1L PGA", "IN1LP Switch", "IN1LP" },
{ "IN1L PGA", "IN1LN Switch", "IN1LN" },
+ { "IN1L PGA", NULL, "VMID" },
+ { "IN1R PGA", NULL, "VMID" },
+ { "IN2L PGA", NULL, "VMID" },
+ { "IN2R PGA", NULL, "VMID" },
+
{ "IN1R PGA", "IN1RP Switch", "IN1RP" },
{ "IN1R PGA", "IN1RN Switch", "IN1RN" },
@@ -716,12 +725,14 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
{ "MIXINL", NULL, "Direct Voice" },
{ "MIXINL", NULL, "IN1LP" },
{ "MIXINL", NULL, "Left Output Mixer" },
+ { "MIXINL", NULL, "VMID" },
{ "MIXINR", "IN1R Switch", "IN1R PGA" },
{ "MIXINR", "IN2R Switch", "IN2R PGA" },
{ "MIXINR", NULL, "Direct Voice" },
{ "MIXINR", NULL, "IN1RP" },
{ "MIXINR", NULL, "Right Output Mixer" },
+ { "MIXINR", NULL, "VMID" },
{ "ADCL", NULL, "MIXINL" },
{ "ADCR", NULL, "MIXINR" },
@@ -752,6 +763,7 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
{ "Earpiece Mixer", "Left Output Switch", "Left Output PGA" },
{ "Earpiece Mixer", "Right Output Switch", "Right Output PGA" },
+ { "Earpiece Driver", NULL, "VMID" },
{ "Earpiece Driver", NULL, "Earpiece Mixer" },
{ "HPOUT2N", NULL, "Earpiece Driver" },
{ "HPOUT2P", NULL, "Earpiece Driver" },
@@ -774,9 +786,11 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
{ "SPKR Boost", "SPKR Switch", "SPKR" },
{ "SPKR Boost", "SPKL Switch", "SPKL" },
+ { "SPKL Driver", NULL, "VMID" },
{ "SPKL Driver", NULL, "SPKL Boost" },
{ "SPKL Driver", NULL, "CLK_SYS" },
+ { "SPKR Driver", NULL, "VMID" },
{ "SPKR Driver", NULL, "SPKR Boost" },
{ "SPKR Driver", NULL, "CLK_SYS" },
@@ -790,12 +804,18 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
{ "Headphone PGA", NULL, "Left Headphone Mux" },
{ "Headphone PGA", NULL, "Right Headphone Mux" },
+ { "Headphone PGA", NULL, "VMID" },
{ "Headphone PGA", NULL, "CLK_SYS" },
{ "Headphone PGA", NULL, "Headphone Supply" },
{ "HPOUT1L", NULL, "Headphone PGA" },
{ "HPOUT1R", NULL, "Headphone PGA" },
+ { "LINEOUT1N Driver", NULL, "VMID" },
+ { "LINEOUT1P Driver", NULL, "VMID" },
+ { "LINEOUT2N Driver", NULL, "VMID" },
+ { "LINEOUT2P Driver", NULL, "VMID" },
+
{ "LINEOUT1N", NULL, "LINEOUT1N Driver" },
{ "LINEOUT1P", NULL, "LINEOUT1P Driver" },
{ "LINEOUT2N", NULL, "LINEOUT2N Driver" },
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h
index 676b1252ab91..c674c7a502a6 100644
--- a/sound/soc/codecs/wm_hubs.h
+++ b/sound/soc/codecs/wm_hubs.h
@@ -23,7 +23,8 @@ extern const unsigned int wm_hubs_spkmix_tlv[];
/* This *must* be the first element of the codec->private_data struct */
struct wm_hubs_data {
- int dcs_codes;
+ int dcs_codes_l;
+ int dcs_codes_r;
int dcs_readback_mode;
int hp_startup_mode;
int series_startup;
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index fe7984221eb9..f78c3f0f280c 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -150,8 +150,6 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
snd_soc_dapm_enable_pin(dapm, "Line In");
- snd_soc_dapm_sync(dapm);
-
return 0;
}
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index d0d60b8a54d4..300e12118c00 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -265,6 +265,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int pcr;
unsigned int srgr;
+ bool inv_fs = false;
/* Attention srgr is updated by hw_params! */
srgr = DAVINCI_MCBSP_SRGR_FSGM |
DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) |
@@ -330,7 +331,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
* more empty bit clock slots between channels as the sample
* rate is lowered.
*/
- fmt ^= SND_SOC_DAIFMT_NB_IF;
+ inv_fs = true;
case SND_SOC_DAIFMT_DSP_A:
dev->mode = MOD_DSP_A;
break;
@@ -394,6 +395,8 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
default:
return -EINVAL;
}
+ if (inv_fs == true)
+ pcr ^= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP);
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
dev->pcr = pcr;
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr);
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 8566238db2a5..7173df254a91 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -732,16 +732,19 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
davinci_hw_param(dev, substream->stream);
switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_U8:
case SNDRV_PCM_FORMAT_S8:
dma_params->data_type = 1;
word_length = DAVINCI_AUDIO_WORD_8;
break;
+ case SNDRV_PCM_FORMAT_U16_LE:
case SNDRV_PCM_FORMAT_S16_LE:
dma_params->data_type = 2;
word_length = DAVINCI_AUDIO_WORD_16;
break;
+ case SNDRV_PCM_FORMAT_U32_LE:
case SNDRV_PCM_FORMAT_S32_LE:
dma_params->data_type = 4;
word_length = DAVINCI_AUDIO_WORD_32;
@@ -818,6 +821,13 @@ static struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
};
+#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | \
+ SNDRV_PCM_FMTBIT_U32_LE)
+
static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
{
.name = "davinci-mcasp.0",
@@ -825,17 +835,13 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
.channels_min = 2,
.channels_max = 2,
.rates = DAVINCI_MCASP_RATES,
- .formats = SNDRV_PCM_FMTBIT_S8 |
- SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
+ .formats = DAVINCI_MCASP_PCM_FMTS,
},
.capture = {
.channels_min = 2,
.channels_max = 2,
.rates = DAVINCI_MCASP_RATES,
- .formats = SNDRV_PCM_FMTBIT_S8 |
- SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
+ .formats = DAVINCI_MCASP_PCM_FMTS,
},
.ops = &davinci_mcasp_dai_ops,
@@ -846,7 +852,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
.channels_min = 1,
.channels_max = 384,
.rates = DAVINCI_MCASP_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = DAVINCI_MCASP_PCM_FMTS,
},
.ops = &davinci_mcasp_dai_ops,
},
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index a49e667373bc..d5fe08cc5db7 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -180,7 +180,6 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
{
struct davinci_runtime_data *prtd = substream->runtime->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
- int link = prtd->asp_link[0];
unsigned int period_size;
unsigned int dma_offset;
dma_addr_t dma_pos;
@@ -198,7 +197,8 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
fifo_level = prtd->params->fifo_level;
pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d "
- "dma_ptr = %x period_size=%x\n", link, dma_pos, period_size);
+ "dma_ptr = %x period_size=%x\n", prtd->asp_link[0], dma_pos,
+ period_size);
data_type = prtd->params->data_type;
count = period_size / data_type;
@@ -222,17 +222,19 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
}
acnt = prtd->params->acnt;
- edma_set_src(link, src, INCR, W8BIT);
- edma_set_dest(link, dst, INCR, W8BIT);
+ edma_set_src(prtd->asp_link[0], src, INCR, W8BIT);
+ edma_set_dest(prtd->asp_link[0], dst, INCR, W8BIT);
- edma_set_src_index(link, src_bidx, src_cidx);
- edma_set_dest_index(link, dst_bidx, dst_cidx);
+ edma_set_src_index(prtd->asp_link[0], src_bidx, src_cidx);
+ edma_set_dest_index(prtd->asp_link[0], dst_bidx, dst_cidx);
if (!fifo_level)
- edma_set_transfer_params(link, acnt, count, 1, 0, ASYNC);
+ edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0,
+ ASYNC);
else
- edma_set_transfer_params(link, acnt, fifo_level, count,
- fifo_level, ABSYNC);
+ edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level,
+ count, fifo_level,
+ ABSYNC);
}
static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
@@ -305,7 +307,6 @@ static int ping_pong_dma_setup(struct snd_pcm_substream *substream)
unsigned int acnt = params->acnt;
/* divide by 2 for ping/pong */
unsigned int ping_size = snd_pcm_lib_period_bytes(substream) >> 1;
- int link = prtd->asp_link[1];
unsigned int fifo_level = prtd->params->fifo_level;
unsigned int count;
if ((data_type == 0) || (data_type > 4)) {
@@ -316,28 +317,26 @@ static int ping_pong_dma_setup(struct snd_pcm_substream *substream)
dma_addr_t asp_src_pong = iram_dma->addr + ping_size;
ram_src_cidx = ping_size;
ram_dst_cidx = -ping_size;
- edma_set_src(link, asp_src_pong, INCR, W8BIT);
+ edma_set_src(prtd->asp_link[1], asp_src_pong, INCR, W8BIT);
- link = prtd->asp_link[0];
- edma_set_src_index(link, data_type, data_type * fifo_level);
- link = prtd->asp_link[1];
- edma_set_src_index(link, data_type, data_type * fifo_level);
+ edma_set_src_index(prtd->asp_link[0], data_type,
+ data_type * fifo_level);
+ edma_set_src_index(prtd->asp_link[1], data_type,
+ data_type * fifo_level);
- link = prtd->ram_link;
- edma_set_src(link, runtime->dma_addr, INCR, W32BIT);
+ edma_set_src(prtd->ram_link, runtime->dma_addr, INCR, W32BIT);
} else {
dma_addr_t asp_dst_pong = iram_dma->addr + ping_size;
ram_src_cidx = -ping_size;
ram_dst_cidx = ping_size;
- edma_set_dest(link, asp_dst_pong, INCR, W8BIT);
+ edma_set_dest(prtd->asp_link[1], asp_dst_pong, INCR, W8BIT);
- link = prtd->asp_link[0];
- edma_set_dest_index(link, data_type, data_type * fifo_level);
- link = prtd->asp_link[1];
- edma_set_dest_index(link, data_type, data_type * fifo_level);
+ edma_set_dest_index(prtd->asp_link[0], data_type,
+ data_type * fifo_level);
+ edma_set_dest_index(prtd->asp_link[1], data_type,
+ data_type * fifo_level);
- link = prtd->ram_link;
- edma_set_dest(link, runtime->dma_addr, INCR, W32BIT);
+ edma_set_dest(prtd->ram_link, runtime->dma_addr, INCR, W32BIT);
}
if (!fifo_level) {
@@ -354,10 +353,9 @@ static int ping_pong_dma_setup(struct snd_pcm_substream *substream)
count, fifo_level, ABSYNC);
}
- link = prtd->ram_link;
- edma_set_src_index(link, ping_size, ram_src_cidx);
- edma_set_dest_index(link, ping_size, ram_dst_cidx);
- edma_set_transfer_params(link, ping_size, 2,
+ edma_set_src_index(prtd->ram_link, ping_size, ram_src_cidx);
+ edma_set_dest_index(prtd->ram_link, ping_size, ram_dst_cidx);
+ edma_set_transfer_params(prtd->ram_link, ping_size, 2,
runtime->periods, 2, ASYNC);
/* init master params */
@@ -406,32 +404,32 @@ static int request_ping_pong(struct snd_pcm_substream *substream,
{
dma_addr_t asp_src_ping;
dma_addr_t asp_dst_ping;
- int link;
+ int ret;
struct davinci_pcm_dma_params *params = prtd->params;
/* Request ram master channel */
- link = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY,
+ ret = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY,
davinci_pcm_dma_irq, substream,
prtd->params->ram_chan_q);
- if (link < 0)
+ if (ret < 0)
goto exit1;
/* Request ram link channel */
- link = prtd->ram_link = edma_alloc_slot(
+ ret = prtd->ram_link = edma_alloc_slot(
EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
- if (link < 0)
+ if (ret < 0)
goto exit2;
- link = prtd->asp_link[1] = edma_alloc_slot(
+ ret = prtd->asp_link[1] = edma_alloc_slot(
EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
- if (link < 0)
+ if (ret < 0)
goto exit3;
prtd->ram_link2 = -1;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- link = prtd->ram_link2 = edma_alloc_slot(
+ ret = prtd->ram_link2 = edma_alloc_slot(
EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
- if (link < 0)
+ if (ret < 0)
goto exit4;
}
/* circle ping-pong buffers */
@@ -448,36 +446,33 @@ static int request_ping_pong(struct snd_pcm_substream *substream,
asp_dst_ping = iram_dma->addr;
}
/* ping */
- link = prtd->asp_link[0];
- edma_set_src(link, asp_src_ping, INCR, W16BIT);
- edma_set_dest(link, asp_dst_ping, INCR, W16BIT);
- edma_set_src_index(link, 0, 0);
- edma_set_dest_index(link, 0, 0);
+ edma_set_src(prtd->asp_link[0], asp_src_ping, INCR, W16BIT);
+ edma_set_dest(prtd->asp_link[0], asp_dst_ping, INCR, W16BIT);
+ edma_set_src_index(prtd->asp_link[0], 0, 0);
+ edma_set_dest_index(prtd->asp_link[0], 0, 0);
- edma_read_slot(link, &prtd->asp_params);
+ edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN);
prtd->asp_params.opt |= TCCHEN |
EDMA_TCC(prtd->ram_channel & 0x3f);
- edma_write_slot(link, &prtd->asp_params);
+ edma_write_slot(prtd->asp_link[0], &prtd->asp_params);
/* pong */
- link = prtd->asp_link[1];
- edma_set_src(link, asp_src_ping, INCR, W16BIT);
- edma_set_dest(link, asp_dst_ping, INCR, W16BIT);
- edma_set_src_index(link, 0, 0);
- edma_set_dest_index(link, 0, 0);
+ edma_set_src(prtd->asp_link[1], asp_src_ping, INCR, W16BIT);
+ edma_set_dest(prtd->asp_link[1], asp_dst_ping, INCR, W16BIT);
+ edma_set_src_index(prtd->asp_link[1], 0, 0);
+ edma_set_dest_index(prtd->asp_link[1], 0, 0);
- edma_read_slot(link, &prtd->asp_params);
+ edma_read_slot(prtd->asp_link[1], &prtd->asp_params);
prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f));
/* interrupt after every pong completion */
prtd->asp_params.opt |= TCINTEN | TCCHEN |
EDMA_TCC(prtd->ram_channel & 0x3f);
- edma_write_slot(link, &prtd->asp_params);
+ edma_write_slot(prtd->asp_link[1], &prtd->asp_params);
/* ram */
- link = prtd->ram_link;
- edma_set_src(link, iram_dma->addr, INCR, W32BIT);
- edma_set_dest(link, iram_dma->addr, INCR, W32BIT);
+ edma_set_src(prtd->ram_link, iram_dma->addr, INCR, W32BIT);
+ edma_set_dest(prtd->ram_link, iram_dma->addr, INCR, W32BIT);
pr_debug("%s: audio dma channels/slots in use for ram:%u %u %u,"
"for asp:%u %u %u\n", __func__,
prtd->ram_channel, prtd->ram_link, prtd->ram_link2,
@@ -494,7 +489,7 @@ exit2:
edma_free_channel(prtd->ram_channel);
prtd->ram_channel = -1;
exit1:
- return link;
+ return ret;
}
static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
@@ -502,22 +497,22 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
struct snd_dma_buffer *iram_dma;
struct davinci_runtime_data *prtd = substream->runtime->private_data;
struct davinci_pcm_dma_params *params = prtd->params;
- int link;
+ int ret;
if (!params)
return -ENODEV;
/* Request asp master DMA channel */
- link = prtd->asp_channel = edma_alloc_channel(params->channel,
+ ret = prtd->asp_channel = edma_alloc_channel(params->channel,
davinci_pcm_dma_irq, substream,
prtd->params->asp_chan_q);
- if (link < 0)
+ if (ret < 0)
goto exit1;
/* Request asp link channels */
- link = prtd->asp_link[0] = edma_alloc_slot(
+ ret = prtd->asp_link[0] = edma_alloc_slot(
EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
- if (link < 0)
+ if (ret < 0)
goto exit2;
iram_dma = (struct snd_dma_buffer *)substream->dma_buffer.private_data;
@@ -537,17 +532,17 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
* the buffer and its length (ccnt) ... use it as a template
* so davinci_pcm_enqueue_dma() takes less time in IRQ.
*/
- edma_read_slot(link, &prtd->asp_params);
+ edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
prtd->asp_params.opt |= TCINTEN |
EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel));
- prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(link) << 5;
- edma_write_slot(link, &prtd->asp_params);
+ prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(prtd->asp_link[0]) << 5;
+ edma_write_slot(prtd->asp_link[0], &prtd->asp_params);
return 0;
exit2:
edma_free_channel(prtd->asp_channel);
prtd->asp_channel = -1;
exit1:
- return link;
+ return ret;
}
static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
diff --git a/sound/soc/ep93xx/edb93xx.c b/sound/soc/ep93xx/edb93xx.c
index d3aa15119d26..51930b6a83af 100644
--- a/sound/soc/ep93xx/edb93xx.c
+++ b/sound/soc/ep93xx/edb93xx.c
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -28,12 +29,6 @@
#include <mach/hardware.h>
#include "ep93xx-pcm.h"
-#define edb93xx_has_audio() (machine_is_edb9301() || \
- machine_is_edb9302() || \
- machine_is_edb9302a() || \
- machine_is_edb9307a() || \
- machine_is_edb9315a())
-
static int edb93xx_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -94,49 +89,61 @@ static struct snd_soc_card snd_soc_edb93xx = {
.num_links = 1,
};
-static struct platform_device *edb93xx_snd_device;
-
-static int __init edb93xx_init(void)
+static int __devinit edb93xx_probe(struct platform_device *pdev)
{
+ struct snd_soc_card *card = &snd_soc_edb93xx;
int ret;
- if (!edb93xx_has_audio())
- return -ENODEV;
-
ret = ep93xx_i2s_acquire(EP93XX_SYSCON_DEVCFG_I2SONAC97,
EP93XX_SYSCON_I2SCLKDIV_ORIDE |
EP93XX_SYSCON_I2SCLKDIV_SPOL);
if (ret)
return ret;
- edb93xx_snd_device = platform_device_alloc("soc-audio", -1);
- if (!edb93xx_snd_device) {
- ret = -ENOMEM;
- goto free_i2s;
+ card->dev = &pdev->dev;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+ ret);
+ ep93xx_i2s_release();
}
- platform_set_drvdata(edb93xx_snd_device, &snd_soc_edb93xx);
- ret = platform_device_add(edb93xx_snd_device);
- if (ret)
- goto device_put;
+ return ret;
+}
- return 0;
+static int __devexit edb93xx_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
-device_put:
- platform_device_put(edb93xx_snd_device);
-free_i2s:
+ snd_soc_unregister_card(card);
ep93xx_i2s_release();
- return ret;
+
+ return 0;
+}
+
+static struct platform_driver edb93xx_driver = {
+ .driver = {
+ .name = "edb93xx-audio",
+ .owner = THIS_MODULE,
+ },
+ .probe = edb93xx_probe,
+ .remove = __devexit_p(edb93xx_remove),
+};
+
+static int __init edb93xx_init(void)
+{
+ return platform_driver_register(&edb93xx_driver);
}
module_init(edb93xx_init);
static void __exit edb93xx_exit(void)
{
- platform_device_unregister(edb93xx_snd_device);
- ep93xx_i2s_release();
+ platform_driver_unregister(&edb93xx_driver);
}
module_exit(edb93xx_exit);
MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
MODULE_DESCRIPTION("ALSA SoC EDB93xx");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:edb93xx-audio");
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c
index c7417c76552b..3cd6158d83e1 100644
--- a/sound/soc/ep93xx/ep93xx-ac97.c
+++ b/sound/soc/ep93xx/ep93xx-ac97.c
@@ -335,7 +335,7 @@ static struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
.trigger = ep93xx_ac97_trigger,
};
-struct snd_soc_dai_driver ep93xx_ac97_dai = {
+static struct snd_soc_dai_driver ep93xx_ac97_dai = {
.name = "ep93xx-ac97",
.id = 0,
.ac97_control = 1,
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
index 8dfd3ad84b19..d00230a591b1 100644
--- a/sound/soc/ep93xx/ep93xx-pcm.c
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -355,3 +355,4 @@ module_exit(ep93xx_soc_platform_exit);
MODULE_AUTHOR("Ryan Mallon");
MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-pcm-audio");
diff --git a/sound/soc/ep93xx/simone.c b/sound/soc/ep93xx/simone.c
index 286817946c56..968cb316d511 100644
--- a/sound/soc/ep93xx/simone.c
+++ b/sound/soc/ep93xx/simone.c
@@ -39,53 +39,61 @@ static struct snd_soc_card snd_soc_simone = {
};
static struct platform_device *simone_snd_ac97_device;
-static struct platform_device *simone_snd_device;
-static int __init simone_init(void)
+static int __devinit simone_probe(struct platform_device *pdev)
{
+ struct snd_soc_card *card = &snd_soc_simone;
int ret;
- if (!machine_is_sim_one())
- return -ENODEV;
-
- simone_snd_ac97_device = platform_device_alloc("ac97-codec", -1);
- if (!simone_snd_ac97_device)
- return -ENOMEM;
+ simone_snd_ac97_device = platform_device_register_simple("ac97-codec",
+ -1, NULL, 0);
+ if (IS_ERR(simone_snd_ac97_device))
+ return PTR_ERR(simone_snd_ac97_device);
- ret = platform_device_add(simone_snd_ac97_device);
- if (ret)
- goto fail1;
+ card->dev = &pdev->dev;
- simone_snd_device = platform_device_alloc("soc-audio", -1);
- if (!simone_snd_device) {
- ret = -ENOMEM;
- goto fail2;
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+ ret);
+ platform_device_unregister(simone_snd_ac97_device);
}
- platform_set_drvdata(simone_snd_device, &snd_soc_simone);
- ret = platform_device_add(simone_snd_device);
- if (ret)
- goto fail3;
+ return ret;
+}
+
+static int __devexit simone_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_card(card);
+ platform_device_unregister(simone_snd_ac97_device);
return 0;
+}
-fail3:
- platform_device_put(simone_snd_device);
-fail2:
- platform_device_del(simone_snd_ac97_device);
-fail1:
- platform_device_put(simone_snd_ac97_device);
- return ret;
+static struct platform_driver simone_driver = {
+ .driver = {
+ .name = "simone-audio",
+ .owner = THIS_MODULE,
+ },
+ .probe = simone_probe,
+ .remove = __devexit_p(simone_remove),
+};
+
+static int __init simone_init(void)
+{
+ return platform_driver_register(&simone_driver);
}
module_init(simone_init);
static void __exit simone_exit(void)
{
- platform_device_unregister(simone_snd_device);
- platform_device_unregister(simone_snd_ac97_device);
+ platform_driver_unregister(&simone_driver);
}
module_exit(simone_exit);
MODULE_DESCRIPTION("ALSA SoC Simplemachines Sim.One");
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:simone-audio");
diff --git a/sound/soc/ep93xx/snappercl15.c b/sound/soc/ep93xx/snappercl15.c
index c8aa8a5003ca..2cde43321eec 100644
--- a/sound/soc/ep93xx/snappercl15.c
+++ b/sound/soc/ep93xx/snappercl15.c
@@ -12,6 +12,7 @@
*/
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -104,37 +105,56 @@ static struct snd_soc_card snd_soc_snappercl15 = {
.num_links = 1,
};
-static struct platform_device *snappercl15_snd_device;
-
-static int __init snappercl15_init(void)
+static int __devinit snappercl15_probe(struct platform_device *pdev)
{
+ struct snd_soc_card *card = &snd_soc_snappercl15;
int ret;
- if (!machine_is_snapper_cl15())
- return -ENODEV;
-
ret = ep93xx_i2s_acquire(EP93XX_SYSCON_DEVCFG_I2SONAC97,
EP93XX_SYSCON_I2SCLKDIV_ORIDE |
EP93XX_SYSCON_I2SCLKDIV_SPOL);
if (ret)
return ret;
- snappercl15_snd_device = platform_device_alloc("soc-audio", -1);
- if (!snappercl15_snd_device)
- return -ENOMEM;
-
- platform_set_drvdata(snappercl15_snd_device, &snd_soc_snappercl15);
- ret = platform_device_add(snappercl15_snd_device);
- if (ret)
- platform_device_put(snappercl15_snd_device);
+ card->dev = &pdev->dev;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+ ret);
+ ep93xx_i2s_release();
+ }
return ret;
}
-static void __exit snappercl15_exit(void)
+static int __devexit snappercl15_remove(struct platform_device *pdev)
{
- platform_device_unregister(snappercl15_snd_device);
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_card(card);
ep93xx_i2s_release();
+
+ return 0;
+}
+
+static struct platform_driver snappercl15_driver = {
+ .driver = {
+ .name = "snappercl15-audio",
+ .owner = THIS_MODULE,
+ },
+ .probe = snappercl15_probe,
+ .remove = __devexit_p(snappercl15_remove),
+};
+
+static int __init snappercl15_init(void)
+{
+ return platform_driver_register(&snappercl15_driver);
+}
+
+static void __exit snappercl15_exit(void)
+{
+ platform_driver_unregister(&snappercl15_driver);
}
module_init(snappercl15_init);
@@ -143,4 +163,4 @@ module_exit(snappercl15_exit);
MODULE_AUTHOR("Ryan Mallon");
MODULE_DESCRIPTION("ALSA SoC Snapper CL15");
MODULE_LICENSE("GPL");
-
+MODULE_ALIAS("platform:snappercl15-audio");
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index cb50598338e9..ef15402a3bc4 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -297,7 +297,6 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
static int fsl_dma_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
- struct snd_soc_dai *dai = rtd->cpu_dai;
struct snd_pcm *pcm = rtd->pcm;
static u64 fsl_dma_dmamask = DMA_BIT_MASK(36);
int ret;
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index d48afea5d93d..0268cf989736 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -78,7 +78,6 @@
* @second_stream: pointer to second stream
* @playback: the number of playback streams opened
* @capture: the number of capture streams opened
- * @asynchronous: 0=synchronous mode, 1=asynchronous mode
* @cpu_dai: the CPU DAI for this device
* @dev_attr: the sysfs device attribute structure
* @stats: SSI statistics
@@ -90,9 +89,6 @@ struct fsl_ssi_private {
unsigned int irq;
struct snd_pcm_substream *first_stream;
struct snd_pcm_substream *second_stream;
- unsigned int playback;
- unsigned int capture;
- int asynchronous;
unsigned int fifo_depth;
struct snd_soc_dai_driver cpu_dai_drv;
struct device_attribute dev_attr;
@@ -281,24 +277,18 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ struct fsl_ssi_private *ssi_private =
+ snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
/*
* If this is the first stream opened, then request the IRQ
* and initialize the SSI registers.
*/
- if (!ssi_private->playback && !ssi_private->capture) {
+ if (!ssi_private->first_stream) {
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
- int ret;
-
- /* The 'name' should not have any slashes in it. */
- ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0,
- ssi_private->name, ssi_private);
- if (ret < 0) {
- dev_err(substream->pcm->card->dev,
- "could not claim irq %u\n", ssi_private->irq);
- return ret;
- }
+
+ ssi_private->first_stream = substream;
/*
* Section 16.5 of the MPC8610 reference manual says that the
@@ -316,7 +306,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
clrsetbits_be32(&ssi->scr,
CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
- | (ssi_private->asynchronous ? 0 : CCSR_SSI_SCR_SYN));
+ | (synchronous ? CCSR_SSI_SCR_SYN : 0));
out_be32(&ssi->stcr,
CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
@@ -333,7 +323,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
* master.
*/
- /* 4. Enable the interrupts and DMA requests */
+ /* Enable the interrupts and DMA requests */
out_be32(&ssi->sier, SIER_FLAGS);
/*
@@ -362,58 +352,47 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
* this is bad is because at this point, the PCM driver has not
* finished initializing the DMA controller.
*/
- }
+ } else {
+ if (synchronous) {
+ struct snd_pcm_runtime *first_runtime =
+ ssi_private->first_stream->runtime;
+ /*
+ * This is the second stream open, and we're in
+ * synchronous mode, so we need to impose sample
+ * sample size constraints. This is because STCCR is
+ * used for playback and capture in synchronous mode,
+ * so there's no way to specify different word
+ * lengths.
+ *
+ * Note that this can cause a race condition if the
+ * second stream is opened before the first stream is
+ * fully initialized. We provide some protection by
+ * checking to make sure the first stream is
+ * initialized, but it's not perfect. ALSA sometimes
+ * re-initializes the driver with a different sample
+ * rate or size. If the second stream is opened
+ * before the first stream has received its final
+ * parameters, then the second stream may be
+ * constrained to the wrong sample rate or size.
+ */
+ if (!first_runtime->sample_bits) {
+ dev_err(substream->pcm->card->dev,
+ "set sample size in %s stream first\n",
+ substream->stream ==
+ SNDRV_PCM_STREAM_PLAYBACK
+ ? "capture" : "playback");
+ return -EAGAIN;
+ }
- if (!ssi_private->first_stream)
- ssi_private->first_stream = substream;
- else {
- /* This is the second stream open, so we need to impose sample
- * rate and maybe sample size constraints. Note that this can
- * cause a race condition if the second stream is opened before
- * the first stream is fully initialized.
- *
- * We provide some protection by checking to make sure the first
- * stream is initialized, but it's not perfect. ALSA sometimes
- * re-initializes the driver with a different sample rate or
- * size. If the second stream is opened before the first stream
- * has received its final parameters, then the second stream may
- * be constrained to the wrong sample rate or size.
- *
- * FIXME: This code does not handle opening and closing streams
- * repeatedly. If you open two streams and then close the first
- * one, you may not be able to open another stream until you
- * close the second one as well.
- */
- struct snd_pcm_runtime *first_runtime =
- ssi_private->first_stream->runtime;
-
- if (!first_runtime->sample_bits) {
- dev_err(substream->pcm->card->dev,
- "set sample size in %s stream first\n",
- substream->stream == SNDRV_PCM_STREAM_PLAYBACK
- ? "capture" : "playback");
- return -EAGAIN;
- }
-
- /* If we're in synchronous mode, then we need to constrain
- * the sample size as well. We don't support independent sample
- * rates in asynchronous mode.
- */
- if (!ssi_private->asynchronous)
snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
first_runtime->sample_bits,
first_runtime->sample_bits);
+ }
ssi_private->second_stream = substream;
}
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- ssi_private->playback++;
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ssi_private->capture++;
-
return 0;
}
@@ -434,24 +413,35 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
{
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
+ struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ unsigned int sample_size =
+ snd_pcm_format_width(params_format(hw_params));
+ u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
+ int enabled = in_be32(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
- if (substream == ssi_private->first_stream) {
- struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
- unsigned int sample_size =
- snd_pcm_format_width(params_format(hw_params));
- u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
+ /*
+ * If we're in synchronous mode, and the SSI is already enabled,
+ * then STCCR is already set properly.
+ */
+ if (enabled && ssi_private->cpu_dai_drv.symmetric_rates)
+ return 0;
- /* The SSI should always be disabled at this points (SSIEN=0) */
+ /*
+ * FIXME: The documentation says that SxCCR[WL] should not be
+ * modified while the SSI is enabled. The only time this can
+ * happen is if we're trying to do simultaneous playback and
+ * capture in asynchronous mode. Unfortunately, I have been enable
+ * to get that to work at all on the P1022DS. Therefore, we don't
+ * bother to disable/enable the SSI when setting SxCCR[WL], because
+ * the SSI will stop anyway. Maybe one day, this will get fixed.
+ */
- /* In synchronous mode, the SSI uses STCCR for capture */
- if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
- !ssi_private->asynchronous)
- clrsetbits_be32(&ssi->stccr,
- CCSR_SSI_SxCCR_WL_MASK, wl);
- else
- clrsetbits_be32(&ssi->srccr,
- CCSR_SSI_SxCCR_WL_MASK, wl);
- }
+ /* In synchronous mode, the SSI uses STCCR for capture */
+ if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
+ ssi_private->cpu_dai_drv.symmetric_rates)
+ clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+ else
+ clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
return 0;
}
@@ -474,7 +464,6 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
setbits32(&ssi->scr,
@@ -510,27 +499,18 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- ssi_private->playback--;
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ssi_private->capture--;
-
if (ssi_private->first_stream == substream)
ssi_private->first_stream = ssi_private->second_stream;
ssi_private->second_stream = NULL;
/*
- * If this is the last active substream, disable the SSI and release
- * the IRQ.
+ * If this is the last active substream, disable the SSI.
*/
- if (!ssi_private->playback && !ssi_private->capture) {
+ if (!ssi_private->first_stream) {
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
-
- free_irq(ssi_private->irq, ssi_private);
}
}
@@ -675,22 +655,33 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
ret = of_address_to_resource(np, 0, &res);
if (ret) {
dev_err(&pdev->dev, "could not determine device resources\n");
- kfree(ssi_private);
- return ret;
+ goto error_kmalloc;
}
ssi_private->ssi = of_iomap(np, 0);
if (!ssi_private->ssi) {
dev_err(&pdev->dev, "could not map device resources\n");
- kfree(ssi_private);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto error_kmalloc;
}
ssi_private->ssi_phys = res.start;
+
ssi_private->irq = irq_of_parse_and_map(np, 0);
+ if (ssi_private->irq == NO_IRQ) {
+ dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+ ret = -ENXIO;
+ goto error_iomap;
+ }
+
+ /* The 'name' should not have any slashes in it. */
+ ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0, ssi_private->name,
+ ssi_private);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "could not claim irq %u\n", ssi_private->irq);
+ goto error_irqmap;
+ }
/* Are the RX and the TX clocks locked? */
- if (of_find_property(np, "fsl,ssi-asynchronous", NULL))
- ssi_private->asynchronous = 1;
- else
+ if (!of_find_property(np, "fsl,ssi-asynchronous", NULL))
ssi_private->cpu_dai_drv.symmetric_rates = 1;
/* Determine the FIFO depth. */
@@ -711,7 +702,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "could not create sysfs %s file\n",
ssi_private->dev_attr.attr.name);
- goto error;
+ goto error_irq;
}
/* Register with ASoC */
@@ -720,7 +711,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv);
if (ret) {
dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
- goto error;
+ goto error_dev;
}
/* Trigger the machine driver's probe function. The platform driver
@@ -741,18 +732,28 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
if (IS_ERR(ssi_private->pdev)) {
ret = PTR_ERR(ssi_private->pdev);
dev_err(&pdev->dev, "failed to register platform: %d\n", ret);
- goto error;
+ goto error_dai;
}
return 0;
-error:
+error_dai:
snd_soc_unregister_dai(&pdev->dev);
+
+error_dev:
dev_set_drvdata(&pdev->dev, NULL);
- if (dev_attr)
- device_remove_file(&pdev->dev, dev_attr);
+ device_remove_file(&pdev->dev, dev_attr);
+
+error_irq:
+ free_irq(ssi_private->irq, ssi_private);
+
+error_irqmap:
irq_dispose_mapping(ssi_private->irq);
+
+error_iomap:
iounmap(ssi_private->ssi);
+
+error_kmalloc:
kfree(ssi_private);
return ret;
@@ -766,6 +767,9 @@ static int fsl_ssi_remove(struct platform_device *pdev)
snd_soc_unregister_dai(&pdev->dev);
device_remove_file(&pdev->dev, &ssi_private->dev_attr);
+ free_irq(ssi_private->irq, ssi_private);
+ irq_dispose_mapping(ssi_private->irq);
+
kfree(ssi_private);
dev_set_drvdata(&pdev->dev, NULL);
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 358f0baaf71b..31af405bda84 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -505,7 +505,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
return 0;
error_sound:
- platform_device_unregister(sound_device);
+ platform_device_put(sound_device);
error:
kfree(machine_data);
error_alloc:
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index fcb862eb0c73..2c064a9824ad 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -267,7 +267,7 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
if (bus < 0)
return bus;
- snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
+ snprintf(buf, len, "%s.%u-%04x", temp, bus, addr);
return 0;
}
@@ -506,7 +506,7 @@ static int p1022_ds_probe(struct platform_device *pdev)
error:
if (sound_device)
- platform_device_unregister(sound_device);
+ platform_device_put(sound_device);
kfree(mdata);
error_put:
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index bb699bb55a50..b133bfcc5848 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -29,7 +29,7 @@ config SND_MXC_SOC_WM1133_EV1
config SND_SOC_MX27VIS_AIC32X4
tristate "SoC audio support for Visstrim M10 boards"
depends on MACH_IMX27_VISSTRIM_M10
- select SND_SOC_TVL320AIC32X4
+ select SND_SOC_TLV320AIC32X4
select SND_MXC_SOC_MX2
help
Say Y if you want to add support for SoC audio on Visstrim SM10
@@ -50,6 +50,7 @@ config SND_SOC_EUKREA_TLV320
|| MACH_EUKREA_MBIMXSD25_BASEBOARD \
|| MACH_EUKREA_MBIMXSD35_BASEBOARD \
|| MACH_EUKREA_MBIMXSD51_BASEBOARD
+ depends on I2C
select SND_SOC_TLV320AIC23
select SND_MXC_SOC_FIQ
help
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
index 7945625e0e08..8df0fae21943 100644
--- a/sound/soc/imx/imx-pcm-fiq.c
+++ b/sound/soc/imx/imx-pcm-fiq.c
@@ -240,25 +240,23 @@ static int ssi_irq = 0;
static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *dai = rtd->cpu_dai;
struct snd_pcm *pcm = rtd->pcm;
+ struct snd_pcm_substream *substream;
int ret;
ret = imx_pcm_new(rtd);
if (ret)
return ret;
- if (dai->driver->playback.channels_min) {
- struct snd_pcm_substream *substream =
- pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ if (substream) {
struct snd_dma_buffer *buf = &substream->dma_buffer;
imx_ssi_fiq_tx_buffer = (unsigned long)buf->area;
}
- if (dai->driver->capture.channels_min) {
- struct snd_pcm_substream *substream =
- pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+ substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+ if (substream) {
struct snd_dma_buffer *buf = &substream->dma_buffer;
imx_ssi_fiq_rx_buffer = (unsigned long)buf->area;
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index 10a8e2783751..4c05e2b8f4d2 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -357,8 +357,8 @@ int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
int ret;
- ret = dma_mmap_coherent(NULL, vma, runtime->dma_area,
- runtime->dma_addr, runtime->dma_bytes);
+ ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
runtime->dma_area,
@@ -391,7 +391,6 @@ static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
- struct snd_soc_dai *dai = rtd->cpu_dai;
struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
@@ -399,14 +398,14 @@ int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
card->dev->dma_mask = &imx_pcm_dmamask;
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->driver->playback.channels_min) {
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = imx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->driver->capture.channels_min) {
+ if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
ret = imx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h
index 0a84cec3599e..1072dfb53e47 100644
--- a/sound/soc/imx/imx-ssi.h
+++ b/sound/soc/imx/imx-ssi.h
@@ -218,12 +218,6 @@ struct imx_ssi {
struct platform_device *soc_platform_pdev_fiq;
};
-struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
- struct imx_ssi *ssi);
-void imx_ssi_fiq_exit(struct platform_device *pdev, struct imx_ssi *ssi);
-struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
- struct imx_ssi *ssi);
-
int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
int imx_pcm_new(struct snd_soc_pcm_runtime *rtd);
void imx_pcm_free(struct snd_pcm *pcm);
diff --git a/sound/soc/imx/wm1133-ev1.c b/sound/soc/imx/wm1133-ev1.c
index 75b4c72787e2..490a1260c228 100644
--- a/sound/soc/imx/wm1133-ev1.c
+++ b/sound/soc/imx/wm1133-ev1.c
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c
index a7c9578be983..d1989cde9f14 100644
--- a/sound/soc/jz4740/jz4740-pcm.c
+++ b/sound/soc/jz4740/jz4740-pcm.c
@@ -299,7 +299,7 @@ static void jz4740_pcm_free(struct snd_pcm *pcm)
static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32);
-int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd)
+static int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_soc_dai *dai = rtd->cpu_dai;
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index d0bcf3fcea01..715e841c0507 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -476,7 +476,7 @@ static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
static struct platform_driver kirkwood_i2s_driver = {
.probe = kirkwood_i2s_dev_probe,
- .remove = kirkwood_i2s_dev_remove,
+ .remove = __devexit_p(kirkwood_i2s_dev_remove),
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c
index c8d21956ab52..c772b3cf4039 100644
--- a/sound/soc/kirkwood/kirkwood-t5325.c
+++ b/sound/soc/kirkwood/kirkwood-t5325.c
@@ -79,8 +79,6 @@ static int t5325_dai_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
snd_soc_dapm_enable_pin(dapm, "Speaker");
- snd_soc_dapm_sync(dapm);
-
return 0;
}
diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c
index 429aa1be2cff..cca693ae1bd4 100644
--- a/sound/soc/mid-x86/mfld_machine.c
+++ b/sound/soc/mid-x86/mfld_machine.c
@@ -28,6 +28,7 @@
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -54,9 +55,7 @@ static unsigned int hs_switch;
static unsigned int lo_dac;
struct mfld_mc_private {
- struct platform_device *socdev;
void __iomem *int_base;
- struct snd_soc_codec *codec;
u8 interrupt_status;
};
@@ -235,7 +234,6 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
/* always connected */
snd_soc_dapm_enable_pin(dapm, "Headphones");
snd_soc_dapm_enable_pin(dapm, "Mic");
- snd_soc_dapm_sync(dapm);
ret_val = snd_soc_add_controls(codec, mfld_snd_controls,
ARRAY_SIZE(mfld_snd_controls));
@@ -253,7 +251,6 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
/* we dont use linein in this so set to NC */
snd_soc_dapm_disable_pin(dapm, "LINEINL");
snd_soc_dapm_disable_pin(dapm, "LINEINR");
- snd_soc_dapm_sync(dapm);
/* Headset and button jack detection */
ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack",
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c
index 3e7826058efe..23057020aa0f 100644
--- a/sound/soc/mid-x86/sst_platform.c
+++ b/sound/soc/mid-x86/sst_platform.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -63,7 +64,7 @@ static struct snd_pcm_hardware sst_platform_pcm_hw = {
};
/* MFLD - MSIC */
-struct snd_soc_dai_driver sst_platform_dai[] = {
+static struct snd_soc_dai_driver sst_platform_dai[] = {
{
.name = "Headset-cpu-dai",
.id = 0,
@@ -226,13 +227,18 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream)
static int sst_platform_open(struct snd_pcm_substream *substream)
{
- struct snd_pcm_runtime *runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
struct sst_runtime_stream *stream;
int ret_val = 0;
pr_debug("sst_platform_open called\n");
- runtime = substream->runtime;
- runtime->hw = sst_platform_pcm_hw;
+
+ snd_soc_set_runtime_hwparams(substream, &sst_platform_pcm_hw);
+ ret_val = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret_val < 0)
+ return ret_val;
+
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
if (!stream)
return -ENOMEM;
@@ -259,8 +265,8 @@ static int sst_platform_open(struct snd_pcm_substream *substream)
return ret_val;
}
runtime->private_data = stream;
- return snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS);
+
+ return 0;
}
static int sst_platform_close(struct snd_pcm_substream *substream)
@@ -469,7 +475,7 @@ static struct platform_driver sst_platform_driver = {
static int __init sst_soc_platform_init(void)
{
pr_debug("sst_soc_platform_init called\n");
- return platform_driver_register(&sst_platform_driver);
+ return platform_driver_register(&sst_platform_driver);
}
module_init(sst_soc_platform_init);
diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig
new file mode 100644
index 000000000000..e4ba8d5f25fa
--- /dev/null
+++ b/sound/soc/mxs/Kconfig
@@ -0,0 +1,20 @@
+menuconfig SND_MXS_SOC
+ tristate "SoC Audio for Freescale MXS CPUs"
+ depends on ARCH_MXS
+ select SND_PCM
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the MXS SAIF interface.
+
+
+if SND_MXS_SOC
+
+config SND_SOC_MXS_SGTL5000
+ tristate "SoC Audio support for i.MX boards with sgtl5000"
+ depends on I2C
+ select SND_SOC_SGTL5000
+ help
+ Say Y if you want to add support for SoC audio on an MXS board with
+ a sgtl5000 codec.
+
+endif # SND_MXS_SOC
diff --git a/sound/soc/mxs/Makefile b/sound/soc/mxs/Makefile
new file mode 100644
index 000000000000..565b5b51e8b7
--- /dev/null
+++ b/sound/soc/mxs/Makefile
@@ -0,0 +1,10 @@
+# MXS Platform Support
+snd-soc-mxs-objs := mxs-saif.o
+snd-soc-mxs-pcm-objs := mxs-pcm.o
+
+obj-$(CONFIG_SND_MXS_SOC) += snd-soc-mxs.o snd-soc-mxs-pcm.o
+
+# i.MX Machine Support
+snd-soc-mxs-sgtl5000-objs := mxs-sgtl5000.o
+
+obj-$(CONFIG_SND_SOC_MXS_SGTL5000) += snd-soc-mxs-sgtl5000.o
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
new file mode 100644
index 000000000000..dea5aa4aa647
--- /dev/null
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Based on sound/soc/imx/imx-pcm-dma-mx2.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+#include "mxs-pcm.h"
+
+static struct snd_pcm_hardware snd_mxs_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_INTERLEAVED,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_3LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 52,
+ .buffer_bytes_max = 64 * 1024,
+ .fifo_size = 32,
+
+};
+
+static void audio_dma_irq(void *data)
+{
+ struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+ iprtd->offset += iprtd->period_bytes;
+ iprtd->offset %= iprtd->period_bytes * iprtd->periods;
+ snd_pcm_period_elapsed(substream);
+}
+
+static bool filter(struct dma_chan *chan, void *param)
+{
+ struct mxs_pcm_runtime_data *iprtd = param;
+ struct mxs_pcm_dma_params *dma_params = iprtd->dma_params;
+
+ if (!mxs_dma_is_apbx(chan))
+ return false;
+
+ if (chan->chan_id != dma_params->chan_num)
+ return false;
+
+ chan->private = &iprtd->dma_data;
+
+ return true;
+}
+
+static int mxs_dma_alloc(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+ dma_cap_mask_t mask;
+
+ iprtd->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ iprtd->dma_data.chan_irq = iprtd->dma_params->chan_irq;
+ iprtd->dma_chan = dma_request_channel(mask, filter, iprtd);
+ if (!iprtd->dma_chan)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+ unsigned long dma_addr;
+ struct dma_chan *chan;
+ int ret;
+
+ ret = mxs_dma_alloc(substream, params);
+ if (ret)
+ return ret;
+ chan = iprtd->dma_chan;
+
+ iprtd->size = params_buffer_bytes(params);
+ iprtd->periods = params_periods(params);
+ iprtd->period_bytes = params_period_bytes(params);
+ iprtd->offset = 0;
+ iprtd->period_time = HZ / (params_rate(params) /
+ params_period_size(params));
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+ dma_addr = runtime->dma_addr;
+
+ iprtd->buf = substream->dma_buffer.area;
+
+ iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr,
+ iprtd->period_bytes * iprtd->periods,
+ iprtd->period_bytes,
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ if (!iprtd->desc) {
+ dev_err(&chan->dev->device, "cannot prepare slave dma\n");
+ return -EINVAL;
+ }
+
+ iprtd->desc->callback = audio_dma_irq;
+ iprtd->desc->callback_param = substream;
+
+ return 0;
+}
+
+static int snd_mxs_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+ if (iprtd->dma_chan) {
+ dma_release_channel(iprtd->dma_chan);
+ iprtd->dma_chan = NULL;
+ }
+
+ return 0;
+}
+
+static int snd_mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ dmaengine_submit(iprtd->desc);
+
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ dmaengine_terminate_all(iprtd->dma_chan);
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static snd_pcm_uframes_t snd_mxs_pcm_pointer(
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+ return bytes_to_frames(substream->runtime, iprtd->offset);
+}
+
+static int snd_mxs_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct mxs_pcm_runtime_data *iprtd;
+ int ret;
+
+ iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
+ if (iprtd == NULL)
+ return -ENOMEM;
+ runtime->private_data = iprtd;
+
+ ret = snd_pcm_hw_constraint_integer(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0) {
+ kfree(iprtd);
+ return ret;
+ }
+
+ snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
+
+ return 0;
+}
+
+static int snd_mxs_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+ kfree(iprtd);
+
+ return 0;
+}
+
+static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops mxs_pcm_ops = {
+ .open = snd_mxs_open,
+ .close = snd_mxs_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_mxs_pcm_hw_params,
+ .hw_free = snd_mxs_pcm_hw_free,
+ .trigger = snd_mxs_pcm_trigger,
+ .pointer = snd_mxs_pcm_pointer,
+ .mmap = snd_mxs_pcm_mmap,
+};
+
+static int mxs_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = snd_mxs_hardware.buffer_bytes_max;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+ buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+ buf->bytes = size;
+
+ return 0;
+}
+
+static u64 mxs_pcm_dmamask = DMA_BIT_MASK(32);
+static int mxs_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
+ int ret = 0;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &mxs_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+ ret = mxs_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto out;
+ }
+
+ if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+ ret = mxs_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static void mxs_pcm_free(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_writecombine(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ }
+}
+
+static struct snd_soc_platform_driver mxs_soc_platform = {
+ .ops = &mxs_pcm_ops,
+ .pcm_new = mxs_pcm_new,
+ .pcm_free = mxs_pcm_free,
+};
+
+static int __devinit mxs_soc_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_platform(&pdev->dev, &mxs_soc_platform);
+}
+
+static int __devexit mxs_soc_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+
+ return 0;
+}
+
+static struct platform_driver mxs_pcm_driver = {
+ .driver = {
+ .name = "mxs-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+ .probe = mxs_soc_platform_probe,
+ .remove = __devexit_p(mxs_soc_platform_remove),
+};
+
+static int __init snd_mxs_pcm_init(void)
+{
+ return platform_driver_register(&mxs_pcm_driver);
+}
+module_init(snd_mxs_pcm_init);
+
+static void __exit snd_mxs_pcm_exit(void)
+{
+ platform_driver_unregister(&mxs_pcm_driver);
+}
+module_exit(snd_mxs_pcm_exit);
diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h
new file mode 100644
index 000000000000..f55ac4f7a76a
--- /dev/null
+++ b/sound/soc/mxs/mxs-pcm.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _MXS_PCM_H
+#define _MXS_PCM_H
+
+#include <mach/dma.h>
+
+struct mxs_pcm_dma_params {
+ int chan_irq;
+ int chan_num;
+};
+
+struct mxs_pcm_runtime_data {
+ int period_bytes;
+ int periods;
+ int dma;
+ unsigned long offset;
+ unsigned long size;
+ void *buf;
+ int period_time;
+ struct dma_async_tx_descriptor *desc;
+ struct dma_chan *dma_chan;
+ struct mxs_dma_data dma_data;
+ struct mxs_pcm_dma_params *dma_params;
+};
+
+#endif
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
new file mode 100644
index 000000000000..76dc74d24fc2
--- /dev/null
+++ b/sound/soc/mxs/mxs-saif.c
@@ -0,0 +1,798 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/saif.h>
+#include <mach/dma.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/mxs.h>
+
+#include "mxs-saif.h"
+
+static struct mxs_saif *mxs_saif[2];
+
+/*
+ * SAIF is a little different with other normal SOC DAIs on clock using.
+ *
+ * For MXS, two SAIF modules are instantiated on-chip.
+ * Each SAIF has a set of clock pins and can be operating in master
+ * mode simultaneously if they are connected to different off-chip codecs.
+ * Also, one of the two SAIFs can master or drive the clock pins while the
+ * other SAIF, in slave mode, receives clocking from the master SAIF.
+ * This also means that both SAIFs must operate at the same sample rate.
+ *
+ * We abstract this as each saif has a master, the master could be
+ * himself or other saifs. In the generic saif driver, saif does not need
+ * to know the different clkmux. Saif only needs to know who is his master
+ * and operating his master to generate the proper clock rate for him.
+ * The master id is provided in mach-specific layer according to different
+ * clkmux setting.
+ */
+
+static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+ switch (clk_id) {
+ case MXS_SAIF_MCLK:
+ saif->mclk = freq;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK
+ * is provided by other SAIF, we provide a interface here to get its master
+ * from its master_id.
+ * Note that the master could be himself.
+ */
+static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif * saif)
+{
+ return mxs_saif[saif->master_id];
+}
+
+/*
+ * Set SAIF clock and MCLK
+ */
+static int mxs_saif_set_clk(struct mxs_saif *saif,
+ unsigned int mclk,
+ unsigned int rate)
+{
+ u32 scr;
+ int ret;
+ struct mxs_saif *master_saif;
+
+ dev_dbg(saif->dev, "mclk %d rate %d\n", mclk, rate);
+
+ /* Set master saif to generate proper clock */
+ master_saif = mxs_saif_get_master(saif);
+ if (!master_saif)
+ return -EINVAL;
+
+ dev_dbg(saif->dev, "master saif%d\n", master_saif->id);
+
+ /* Checking if can playback and capture simutaneously */
+ if (master_saif->ongoing && rate != master_saif->cur_rate) {
+ dev_err(saif->dev,
+ "can not change clock, master saif%d(rate %d) is ongoing\n",
+ master_saif->id, master_saif->cur_rate);
+ return -EINVAL;
+ }
+
+ scr = __raw_readl(master_saif->base + SAIF_CTRL);
+ scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE;
+ scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+
+ /*
+ * Set SAIF clock
+ *
+ * The SAIF clock should be either 384*fs or 512*fs.
+ * If MCLK is used, the SAIF clk ratio need to match mclk ratio.
+ * For 32x mclk, set saif clk as 512*fs.
+ * For 48x mclk, set saif clk as 384*fs.
+ *
+ * If MCLK is not used, we just set saif clk to 512*fs.
+ */
+ if (master_saif->mclk_in_use) {
+ if (mclk % 32 == 0) {
+ scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+ ret = clk_set_rate(master_saif->clk, 512 * rate);
+ } else if (mclk % 48 == 0) {
+ scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
+ ret = clk_set_rate(master_saif->clk, 384 * rate);
+ } else {
+ /* SAIF MCLK should be either 32x or 48x */
+ return -EINVAL;
+ }
+ } else {
+ ret = clk_set_rate(master_saif->clk, 512 * rate);
+ scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+ }
+
+ if (ret)
+ return ret;
+
+ master_saif->cur_rate = rate;
+
+ if (!master_saif->mclk_in_use) {
+ __raw_writel(scr, master_saif->base + SAIF_CTRL);
+ return 0;
+ }
+
+ /*
+ * Program the over-sample rate for MCLK output
+ *
+ * The available MCLK range is 32x, 48x... 512x. The rate
+ * could be from 8kHz to 192kH.
+ */
+ switch (mclk / rate) {
+ case 32:
+ scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(4);
+ break;
+ case 64:
+ scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
+ break;
+ case 128:
+ scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
+ break;
+ case 256:
+ scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
+ break;
+ case 512:
+ scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
+ break;
+ case 48:
+ scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
+ break;
+ case 96:
+ scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
+ break;
+ case 192:
+ scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
+ break;
+ case 384:
+ scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ __raw_writel(scr, master_saif->base + SAIF_CTRL);
+
+ return 0;
+}
+
+/*
+ * Put and disable MCLK.
+ */
+int mxs_saif_put_mclk(unsigned int saif_id)
+{
+ struct mxs_saif *saif = mxs_saif[saif_id];
+ u32 stat;
+
+ if (!saif)
+ return -EINVAL;
+
+ stat = __raw_readl(saif->base + SAIF_STAT);
+ if (stat & BM_SAIF_STAT_BUSY) {
+ dev_err(saif->dev, "error: busy\n");
+ return -EBUSY;
+ }
+
+ clk_disable(saif->clk);
+
+ /* disable MCLK output */
+ __raw_writel(BM_SAIF_CTRL_CLKGATE,
+ saif->base + SAIF_CTRL + MXS_SET_ADDR);
+ __raw_writel(BM_SAIF_CTRL_RUN,
+ saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+ saif->mclk_in_use = 0;
+ return 0;
+}
+
+/*
+ * Get MCLK and set clock rate, then enable it
+ *
+ * This interface is used for codecs who are using MCLK provided
+ * by saif.
+ */
+int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk,
+ unsigned int rate)
+{
+ struct mxs_saif *saif = mxs_saif[saif_id];
+ u32 stat;
+ int ret;
+ struct mxs_saif *master_saif;
+
+ if (!saif)
+ return -EINVAL;
+
+ /* Clear Reset */
+ __raw_writel(BM_SAIF_CTRL_SFTRST,
+ saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+ /* FIXME: need clear clk gate for register r/w */
+ __raw_writel(BM_SAIF_CTRL_CLKGATE,
+ saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+ master_saif = mxs_saif_get_master(saif);
+ if (saif != master_saif) {
+ dev_err(saif->dev, "can not get mclk from a non-master saif\n");
+ return -EINVAL;
+ }
+
+ stat = __raw_readl(saif->base + SAIF_STAT);
+ if (stat & BM_SAIF_STAT_BUSY) {
+ dev_err(saif->dev, "error: busy\n");
+ return -EBUSY;
+ }
+
+ saif->mclk_in_use = 1;
+ ret = mxs_saif_set_clk(saif, mclk, rate);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(saif->clk);
+ if (ret)
+ return ret;
+
+ /* enable MCLK output */
+ __raw_writel(BM_SAIF_CTRL_RUN,
+ saif->base + SAIF_CTRL + MXS_SET_ADDR);
+
+ return 0;
+}
+
+/*
+ * SAIF DAI format configuration.
+ * Should only be called when port is inactive.
+ */
+static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+ u32 scr, stat;
+ u32 scr0;
+ struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+ stat = __raw_readl(saif->base + SAIF_STAT);
+ if (stat & BM_SAIF_STAT_BUSY) {
+ dev_err(cpu_dai->dev, "error: busy\n");
+ return -EBUSY;
+ }
+
+ scr0 = __raw_readl(saif->base + SAIF_CTRL);
+ scr0 = scr0 & ~BM_SAIF_CTRL_BITCLK_EDGE & ~BM_SAIF_CTRL_LRCLK_POLARITY \
+ & ~BM_SAIF_CTRL_JUSTIFY & ~BM_SAIF_CTRL_DELAY;
+ scr = 0;
+
+ /* DAI mode */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* data frame low 1clk before data */
+ scr |= BM_SAIF_CTRL_DELAY;
+ scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ /* data frame high with data */
+ scr &= ~BM_SAIF_CTRL_DELAY;
+ scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
+ scr &= ~BM_SAIF_CTRL_JUSTIFY;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* DAI clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ scr |= BM_SAIF_CTRL_BITCLK_EDGE;
+ scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ scr |= BM_SAIF_CTRL_BITCLK_EDGE;
+ scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
+ scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
+ scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
+ break;
+ }
+
+ /*
+ * Note: We simply just support master mode since SAIF TX can only
+ * work as master.
+ * Here the master is relative to codec side.
+ * Saif internally could be slave when working on EXTMASTER mode.
+ * We just hide this to machine driver.
+ */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ if (saif->id == saif->master_id)
+ scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
+ else
+ scr |= BM_SAIF_CTRL_SLAVE_MODE;
+
+ __raw_writel(scr | scr0, saif->base + SAIF_CTRL);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mxs_saif_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+ snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
+
+ /* clear error status to 0 for each re-open */
+ saif->fifo_underrun = 0;
+ saif->fifo_overrun = 0;
+
+ /* Clear Reset for normal operations */
+ __raw_writel(BM_SAIF_CTRL_SFTRST,
+ saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+ /* clear clock gate */
+ __raw_writel(BM_SAIF_CTRL_CLKGATE,
+ saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+ return 0;
+}
+
+/*
+ * Should only be called when port is inactive.
+ * although can be called multiple times by upper layers.
+ */
+static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 scr, stat;
+ int ret;
+
+ /* mclk should already be set */
+ if (!saif->mclk && saif->mclk_in_use) {
+ dev_err(cpu_dai->dev, "set mclk first\n");
+ return -EINVAL;
+ }
+
+ stat = __raw_readl(saif->base + SAIF_STAT);
+ if (stat & BM_SAIF_STAT_BUSY) {
+ dev_err(cpu_dai->dev, "error: busy\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Set saif clk based on sample rate.
+ * If mclk is used, we also set mclk, if not, saif->mclk is
+ * default 0, means not used.
+ */
+ ret = mxs_saif_set_clk(saif, saif->mclk, params_rate(params));
+ if (ret) {
+ dev_err(cpu_dai->dev, "unable to get proper clk\n");
+ return ret;
+ }
+
+ scr = __raw_readl(saif->base + SAIF_CTRL);
+
+ scr &= ~BM_SAIF_CTRL_WORD_LENGTH;
+ scr &= ~BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ scr |= BF_SAIF_CTRL_WORD_LENGTH(0);
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ scr |= BF_SAIF_CTRL_WORD_LENGTH(4);
+ scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ scr |= BF_SAIF_CTRL_WORD_LENGTH(8);
+ scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Tx/Rx config */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* enable TX mode */
+ scr &= ~BM_SAIF_CTRL_READ_MODE;
+ } else {
+ /* enable RX mode */
+ scr |= BM_SAIF_CTRL_READ_MODE;
+ }
+
+ __raw_writel(scr, saif->base + SAIF_CTRL);
+ return 0;
+}
+
+static int mxs_saif_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+ /* enable FIFO error irqs */
+ __raw_writel(BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN,
+ saif->base + SAIF_CTRL + MXS_SET_ADDR);
+
+ return 0;
+}
+
+static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+ struct mxs_saif *master_saif;
+ u32 delay;
+
+ master_saif = mxs_saif_get_master(saif);
+ if (!master_saif)
+ return -EINVAL;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ dev_dbg(cpu_dai->dev, "start\n");
+
+ clk_enable(master_saif->clk);
+ if (!master_saif->mclk_in_use)
+ __raw_writel(BM_SAIF_CTRL_RUN,
+ master_saif->base + SAIF_CTRL + MXS_SET_ADDR);
+
+ /*
+ * If the saif's master is not himself, we also need to enable
+ * itself clk for its internal basic logic to work.
+ */
+ if (saif != master_saif) {
+ clk_enable(saif->clk);
+ __raw_writel(BM_SAIF_CTRL_RUN,
+ saif->base + SAIF_CTRL + MXS_SET_ADDR);
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /*
+ * write a data to saif data register to trigger
+ * the transfer
+ */
+ __raw_writel(0, saif->base + SAIF_DATA);
+ } else {
+ /*
+ * read a data from saif data register to trigger
+ * the receive
+ */
+ __raw_readl(saif->base + SAIF_DATA);
+ }
+
+ master_saif->ongoing = 1;
+
+ dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n",
+ __raw_readl(saif->base + SAIF_CTRL),
+ __raw_readl(saif->base + SAIF_STAT));
+
+ dev_dbg(master_saif->dev, "CTRL 0x%x STAT 0x%x\n",
+ __raw_readl(master_saif->base + SAIF_CTRL),
+ __raw_readl(master_saif->base + SAIF_STAT));
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ dev_dbg(cpu_dai->dev, "stop\n");
+
+ /* wait a while for the current sample to complete */
+ delay = USEC_PER_SEC / master_saif->cur_rate;
+
+ if (!master_saif->mclk_in_use) {
+ __raw_writel(BM_SAIF_CTRL_RUN,
+ master_saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+ udelay(delay);
+ }
+ clk_disable(master_saif->clk);
+
+ if (saif != master_saif) {
+ __raw_writel(BM_SAIF_CTRL_RUN,
+ saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+ udelay(delay);
+ clk_disable(saif->clk);
+ }
+
+ master_saif->ongoing = 0;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#define MXS_SAIF_RATES SNDRV_PCM_RATE_8000_192000
+#define MXS_SAIF_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops mxs_saif_dai_ops = {
+ .startup = mxs_saif_startup,
+ .trigger = mxs_saif_trigger,
+ .prepare = mxs_saif_prepare,
+ .hw_params = mxs_saif_hw_params,
+ .set_sysclk = mxs_saif_set_dai_sysclk,
+ .set_fmt = mxs_saif_set_dai_fmt,
+};
+
+static int mxs_saif_dai_probe(struct snd_soc_dai *dai)
+{
+ struct mxs_saif *saif = dev_get_drvdata(dai->dev);
+
+ snd_soc_dai_set_drvdata(dai, saif);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver mxs_saif_dai = {
+ .name = "mxs-saif",
+ .probe = mxs_saif_dai_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = MXS_SAIF_RATES,
+ .formats = MXS_SAIF_FORMATS,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = MXS_SAIF_RATES,
+ .formats = MXS_SAIF_FORMATS,
+ },
+ .ops = &mxs_saif_dai_ops,
+};
+
+static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
+{
+ struct mxs_saif *saif = dev_id;
+ unsigned int stat;
+
+ stat = __raw_readl(saif->base + SAIF_STAT);
+ if (!(stat & (BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ |
+ BM_SAIF_STAT_FIFO_OVERFLOW_IRQ)))
+ return IRQ_NONE;
+
+ if (stat & BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ) {
+ dev_dbg(saif->dev, "underrun!!! %d\n", ++saif->fifo_underrun);
+ __raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ,
+ saif->base + SAIF_STAT + MXS_CLR_ADDR);
+ }
+
+ if (stat & BM_SAIF_STAT_FIFO_OVERFLOW_IRQ) {
+ dev_dbg(saif->dev, "overrun!!! %d\n", ++saif->fifo_overrun);
+ __raw_writel(BM_SAIF_STAT_FIFO_OVERFLOW_IRQ,
+ saif->base + SAIF_STAT + MXS_CLR_ADDR);
+ }
+
+ dev_dbg(saif->dev, "SAIF_CTRL %x SAIF_STAT %x\n",
+ __raw_readl(saif->base + SAIF_CTRL),
+ __raw_readl(saif->base + SAIF_STAT));
+
+ return IRQ_HANDLED;
+}
+
+static int mxs_saif_probe(struct platform_device *pdev)
+{
+ struct resource *iores, *dmares;
+ struct mxs_saif *saif;
+ struct mxs_saif_platform_data *pdata;
+ int ret = 0;
+
+ if (pdev->id >= ARRAY_SIZE(mxs_saif))
+ return -EINVAL;
+
+ pdata = pdev->dev.platform_data;
+ if (pdata && pdata->init) {
+ ret = pdata->init();
+ if (ret)
+ return ret;
+ }
+
+ saif = kzalloc(sizeof(*saif), GFP_KERNEL);
+ if (!saif)
+ return -ENOMEM;
+
+ mxs_saif[pdev->id] = saif;
+ saif->id = pdev->id;
+
+ saif->master_id = saif->id;
+ if (pdata && pdata->get_master_id) {
+ saif->master_id = pdata->get_master_id(saif->id);
+ if (saif->master_id < 0 ||
+ saif->master_id >= ARRAY_SIZE(mxs_saif))
+ return -EINVAL;
+ }
+
+ saif->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(saif->clk)) {
+ ret = PTR_ERR(saif->clk);
+ dev_err(&pdev->dev, "Cannot get the clock: %d\n",
+ ret);
+ goto failed_clk;
+ }
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iores) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "failed to get io resource: %d\n",
+ ret);
+ goto failed_get_resource;
+ }
+
+ if (!request_mem_region(iores->start, resource_size(iores),
+ "mxs-saif")) {
+ dev_err(&pdev->dev, "request_mem_region failed\n");
+ ret = -EBUSY;
+ goto failed_get_resource;
+ }
+
+ saif->base = ioremap(iores->start, resource_size(iores));
+ if (!saif->base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENODEV;
+ goto failed_ioremap;
+ }
+
+ dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmares) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "failed to get dma resource: %d\n",
+ ret);
+ goto failed_ioremap;
+ }
+ saif->dma_param.chan_num = dmares->start;
+
+ saif->irq = platform_get_irq(pdev, 0);
+ if (saif->irq < 0) {
+ ret = saif->irq;
+ dev_err(&pdev->dev, "failed to get irq resource: %d\n",
+ ret);
+ goto failed_get_irq1;
+ }
+
+ saif->dev = &pdev->dev;
+ ret = request_irq(saif->irq, mxs_saif_irq, 0, "mxs-saif", saif);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq\n");
+ goto failed_get_irq1;
+ }
+
+ saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
+ if (saif->dma_param.chan_irq < 0) {
+ ret = saif->dma_param.chan_irq;
+ dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
+ ret);
+ goto failed_get_irq2;
+ }
+
+ platform_set_drvdata(pdev, saif);
+
+ ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
+ if (ret) {
+ dev_err(&pdev->dev, "register DAI failed\n");
+ goto failed_register;
+ }
+
+ saif->soc_platform_pdev = platform_device_alloc(
+ "mxs-pcm-audio", pdev->id);
+ if (!saif->soc_platform_pdev) {
+ ret = -ENOMEM;
+ goto failed_pdev_alloc;
+ }
+
+ platform_set_drvdata(saif->soc_platform_pdev, saif);
+ ret = platform_device_add(saif->soc_platform_pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add soc platform device\n");
+ goto failed_pdev_add;
+ }
+
+ return 0;
+
+failed_pdev_add:
+ platform_device_put(saif->soc_platform_pdev);
+failed_pdev_alloc:
+ snd_soc_unregister_dai(&pdev->dev);
+failed_register:
+failed_get_irq2:
+ free_irq(saif->irq, saif);
+failed_get_irq1:
+ iounmap(saif->base);
+failed_ioremap:
+ release_mem_region(iores->start, resource_size(iores));
+failed_get_resource:
+ clk_put(saif->clk);
+failed_clk:
+ kfree(saif);
+
+ return ret;
+}
+
+static int __devexit mxs_saif_remove(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct mxs_saif *saif = platform_get_drvdata(pdev);
+
+ platform_device_unregister(saif->soc_platform_pdev);
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ iounmap(saif->base);
+ release_mem_region(res->start, resource_size(res));
+ free_irq(saif->irq, saif);
+
+ clk_put(saif->clk);
+ kfree(saif);
+
+ return 0;
+}
+
+static struct platform_driver mxs_saif_driver = {
+ .probe = mxs_saif_probe,
+ .remove = __devexit_p(mxs_saif_remove),
+
+ .driver = {
+ .name = "mxs-saif",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mxs_saif_init(void)
+{
+ return platform_driver_register(&mxs_saif_driver);
+}
+
+static void __exit mxs_saif_exit(void)
+{
+ platform_driver_unregister(&mxs_saif_driver);
+}
+
+module_init(mxs_saif_init);
+module_exit(mxs_saif_exit);
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXS ASoC SAIF driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h
new file mode 100644
index 000000000000..12c91e4eb941
--- /dev/null
+++ b/sound/soc/mxs/mxs-saif.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#ifndef _MXS_SAIF_H
+#define _MXS_SAIF_H
+
+#define SAIF_CTRL 0x0
+#define SAIF_STAT 0x10
+#define SAIF_DATA 0x20
+#define SAIF_VERSION 0X30
+
+/* SAIF_CTRL */
+#define BM_SAIF_CTRL_SFTRST 0x80000000
+#define BM_SAIF_CTRL_CLKGATE 0x40000000
+#define BP_SAIF_CTRL_BITCLK_MULT_RATE 27
+#define BM_SAIF_CTRL_BITCLK_MULT_RATE 0x38000000
+#define BF_SAIF_CTRL_BITCLK_MULT_RATE(v) \
+ (((v) << 27) & BM_SAIF_CTRL_BITCLK_MULT_RATE)
+#define BM_SAIF_CTRL_BITCLK_BASE_RATE 0x04000000
+#define BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN 0x02000000
+#define BM_SAIF_CTRL_FIFO_SERVICE_IRQ_EN 0x01000000
+#define BP_SAIF_CTRL_RSRVD2 21
+#define BM_SAIF_CTRL_RSRVD2 0x00E00000
+
+#define BP_SAIF_CTRL_DMAWAIT_COUNT 16
+#define BM_SAIF_CTRL_DMAWAIT_COUNT 0x001F0000
+#define BF_SAIF_CTRL_DMAWAIT_COUNT(v) \
+ (((v) << 16) & BM_SAIF_CTRL_DMAWAIT_COUNT)
+#define BP_SAIF_CTRL_CHANNEL_NUM_SELECT 14
+#define BM_SAIF_CTRL_CHANNEL_NUM_SELECT 0x0000C000
+#define BF_SAIF_CTRL_CHANNEL_NUM_SELECT(v) \
+ (((v) << 14) & BM_SAIF_CTRL_CHANNEL_NUM_SELECT)
+#define BM_SAIF_CTRL_LRCLK_PULSE 0x00002000
+#define BM_SAIF_CTRL_BIT_ORDER 0x00001000
+#define BM_SAIF_CTRL_DELAY 0x00000800
+#define BM_SAIF_CTRL_JUSTIFY 0x00000400
+#define BM_SAIF_CTRL_LRCLK_POLARITY 0x00000200
+#define BM_SAIF_CTRL_BITCLK_EDGE 0x00000100
+#define BP_SAIF_CTRL_WORD_LENGTH 4
+#define BM_SAIF_CTRL_WORD_LENGTH 0x000000F0
+#define BF_SAIF_CTRL_WORD_LENGTH(v) \
+ (((v) << 4) & BM_SAIF_CTRL_WORD_LENGTH)
+#define BM_SAIF_CTRL_BITCLK_48XFS_ENABLE 0x00000008
+#define BM_SAIF_CTRL_SLAVE_MODE 0x00000004
+#define BM_SAIF_CTRL_READ_MODE 0x00000002
+#define BM_SAIF_CTRL_RUN 0x00000001
+
+/* SAIF_STAT */
+#define BM_SAIF_STAT_PRESENT 0x80000000
+#define BP_SAIF_STAT_RSRVD2 17
+#define BM_SAIF_STAT_RSRVD2 0x7FFE0000
+#define BF_SAIF_STAT_RSRVD2(v) \
+ (((v) << 17) & BM_SAIF_STAT_RSRVD2)
+#define BM_SAIF_STAT_DMA_PREQ 0x00010000
+#define BP_SAIF_STAT_RSRVD1 7
+#define BM_SAIF_STAT_RSRVD1 0x0000FF80
+#define BF_SAIF_STAT_RSRVD1(v) \
+ (((v) << 7) & BM_SAIF_STAT_RSRVD1)
+
+#define BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ 0x00000040
+#define BM_SAIF_STAT_FIFO_OVERFLOW_IRQ 0x00000020
+#define BM_SAIF_STAT_FIFO_SERVICE_IRQ 0x00000010
+#define BP_SAIF_STAT_RSRVD0 1
+#define BM_SAIF_STAT_RSRVD0 0x0000000E
+#define BF_SAIF_STAT_RSRVD0(v) \
+ (((v) << 1) & BM_SAIF_STAT_RSRVD0)
+#define BM_SAIF_STAT_BUSY 0x00000001
+
+/* SAFI_DATA */
+#define BP_SAIF_DATA_PCM_RIGHT 16
+#define BM_SAIF_DATA_PCM_RIGHT 0xFFFF0000
+#define BF_SAIF_DATA_PCM_RIGHT(v) \
+ (((v) << 16) & BM_SAIF_DATA_PCM_RIGHT)
+#define BP_SAIF_DATA_PCM_LEFT 0
+#define BM_SAIF_DATA_PCM_LEFT 0x0000FFFF
+#define BF_SAIF_DATA_PCM_LEFT(v) \
+ (((v) << 0) & BM_SAIF_DATA_PCM_LEFT)
+
+/* SAIF_VERSION */
+#define BP_SAIF_VERSION_MAJOR 24
+#define BM_SAIF_VERSION_MAJOR 0xFF000000
+#define BF_SAIF_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_SAIF_VERSION_MAJOR)
+#define BP_SAIF_VERSION_MINOR 16
+#define BM_SAIF_VERSION_MINOR 0x00FF0000
+#define BF_SAIF_VERSION_MINOR(v) \
+ (((v) << 16) & BM_SAIF_VERSION_MINOR)
+#define BP_SAIF_VERSION_STEP 0
+#define BM_SAIF_VERSION_STEP 0x0000FFFF
+#define BF_SAIF_VERSION_STEP(v) \
+ (((v) << 0) & BM_SAIF_VERSION_STEP)
+
+#define MXS_SAIF_MCLK 0
+
+#include "mxs-pcm.h"
+
+struct mxs_saif {
+ struct device *dev;
+ struct clk *clk;
+ unsigned int mclk;
+ unsigned int mclk_in_use;
+ void __iomem *base;
+ int irq;
+ struct mxs_pcm_dma_params dma_param;
+ unsigned int id;
+ unsigned int master_id;
+ unsigned int cur_rate;
+ unsigned int ongoing;
+
+ struct platform_device *soc_platform_pdev;
+ u32 fifo_underrun;
+ u32 fifo_overrun;
+};
+
+extern int mxs_saif_put_mclk(unsigned int saif_id);
+extern int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk,
+ unsigned int rate);
+#endif
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
new file mode 100644
index 000000000000..7fbeaec06eb4
--- /dev/null
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
+
+#include "../codecs/sgtl5000.h"
+#include "mxs-saif.h"
+
+static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int rate = params_rate(params);
+ u32 dai_format, mclk;
+ int ret;
+
+ /* sgtl5000 does not support 512*rate when in 96000 fs */
+ switch (rate) {
+ case 96000:
+ mclk = 256 * rate;
+ break;
+ default:
+ mclk = 512 * rate;
+ break;
+ }
+
+ /* Sgtl5000 sysclk should be >= 8MHz and <= 27M */
+ if (mclk < 8000000 || mclk > 27000000)
+ return -EINVAL;
+
+ /* Set SGTL5000's SYSCLK (provided by SAIF MCLK) */
+ ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, 0);
+ if (ret)
+ return ret;
+
+ /* The SAIF MCLK should be the same as SGTL5000_SYSCLK */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_MCLK, mclk, 0);
+ if (ret)
+ return ret;
+
+ /* set codec to slave mode */
+ dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
+ if (ret)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops mxs_sgtl5000_hifi_ops = {
+ .hw_params = mxs_sgtl5000_hw_params,
+};
+
+static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
+ {
+ .name = "HiFi Tx",
+ .stream_name = "HiFi Playback",
+ .codec_dai_name = "sgtl5000",
+ .codec_name = "sgtl5000.0-000a",
+ .cpu_dai_name = "mxs-saif.0",
+ .platform_name = "mxs-pcm-audio.0",
+ .ops = &mxs_sgtl5000_hifi_ops,
+ }, {
+ .name = "HiFi Rx",
+ .stream_name = "HiFi Capture",
+ .codec_dai_name = "sgtl5000",
+ .codec_name = "sgtl5000.0-000a",
+ .cpu_dai_name = "mxs-saif.1",
+ .platform_name = "mxs-pcm-audio.1",
+ .ops = &mxs_sgtl5000_hifi_ops,
+ },
+};
+
+static struct snd_soc_card mxs_sgtl5000 = {
+ .name = "mxs_sgtl5000",
+ .dai_link = mxs_sgtl5000_dai,
+ .num_links = ARRAY_SIZE(mxs_sgtl5000_dai),
+};
+
+static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &mxs_sgtl5000;
+ int ret;
+
+ /*
+ * Set an init clock(11.28Mhz) for sgtl5000 initialization(i2c r/w).
+ * The Sgtl5000 sysclk is derived from saif0 mclk and it's range
+ * should be >= 8MHz and <= 27M.
+ */
+ ret = mxs_saif_get_mclk(0, 44100 * 256, 44100);
+ if (ret)
+ return ret;
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __devexit mxs_sgtl5000_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ mxs_saif_put_mclk(0);
+
+ snd_soc_unregister_card(card);
+
+ return 0;
+}
+
+static struct platform_driver mxs_sgtl5000_audio_driver = {
+ .driver = {
+ .name = "mxs-sgtl5000",
+ .owner = THIS_MODULE,
+ },
+ .probe = mxs_sgtl5000_probe,
+ .remove = __devexit_p(mxs_sgtl5000_remove),
+};
+
+static int __init mxs_sgtl5000_init(void)
+{
+ return platform_driver_register(&mxs_sgtl5000_audio_driver);
+}
+module_init(mxs_sgtl5000_init);
+
+static void __exit mxs_sgtl5000_exit(void)
+{
+ platform_driver_unregister(&mxs_sgtl5000_audio_driver);
+}
+module_exit(mxs_sgtl5000_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXS ALSA SoC Machine driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c
index d589ef14e917..ae8d6806966b 100644
--- a/sound/soc/nuc900/nuc900-pcm.c
+++ b/sound/soc/nuc900/nuc900-pcm.c
@@ -227,7 +227,7 @@ static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd)
return ret;
}
-int nuc900_dma_getposition(struct snd_pcm_substream *substream,
+static int nuc900_dma_getposition(struct snd_pcm_substream *substream,
dma_addr_t *src, dma_addr_t *dst)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -268,7 +268,7 @@ static int nuc900_dma_open(struct snd_pcm_substream *substream)
nuc900_audio = nuc900_ac97_data;
if (request_irq(nuc900_audio->irq_num, nuc900_dma_interrupt,
- IRQF_DISABLED, "nuc900-dma", substream))
+ 0, "nuc900-dma", substream))
return -EBUSY;
runtime->private_data = nuc900_audio;
@@ -318,7 +318,6 @@ static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32);
static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
- struct snd_soc_dai *dai = rtd->cpu_dai;
struct snd_pcm *pcm = rtd->pcm;
if (!card->dev->dma_mask)
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index 59e2c8d1e38d..052fd758722e 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -1,7 +1,7 @@
# OMAP Platform Support
snd-soc-omap-objs := omap-pcm.o
snd-soc-omap-mcbsp-objs := omap-mcbsp.o
-snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o
+snd-soc-omap-mcpdm-objs := omap-mcpdm.o
snd-soc-omap-hdmi-objs := omap-hdmi.o
obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
index 73dde4a1adc3..c1cd4a0cbe9e 100644
--- a/sound/soc/omap/am3517evm.c
+++ b/sound/soc/omap/am3517evm.c
@@ -19,6 +19,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -43,26 +44,6 @@ static int am3517evm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
CODEC_CLOCK, SND_SOC_CLOCK_IN);
@@ -110,28 +91,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MICIN", NULL, "Mic In"},
};
-static int am3517evm_aic23_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- /* Add am3517-evm specific widgets */
- snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
- ARRAY_SIZE(tlv320aic23_dapm_widgets));
-
- /* Set up davinci-evm specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- /* always connected */
- snd_soc_dapm_enable_pin(dapm, "Line Out");
- snd_soc_dapm_enable_pin(dapm, "Line In");
- snd_soc_dapm_enable_pin(dapm, "Mic In");
-
- snd_soc_dapm_sync(dapm);
-
- return 0;
-}
-
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link am3517evm_dai = {
.name = "TLV320AIC23",
@@ -140,7 +99,8 @@ static struct snd_soc_dai_link am3517evm_dai = {
.codec_dai_name = "tlv320aic23-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "tlv320aic23-codec.2-001a",
- .init = am3517evm_aic23_init,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.ops = &am3517evm_ops,
};
@@ -149,6 +109,11 @@ static struct snd_soc_card snd_soc_am3517evm = {
.name = "am3517evm",
.dai_link = &am3517evm_dai,
.num_links = 1,
+
+ .dapm_widgets = tlv320aic23_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *am3517evm_snd_device;
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 0aa475f92efa..ccb8a6aa1817 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -25,6 +25,7 @@
#include <linux/gpio.h>
#include <linux/spinlock.h>
#include <linux/tty.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/jack.h>
@@ -569,7 +570,6 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_disable_pin(dapm, "Speaker");
snd_soc_dapm_disable_pin(dapm, "AGCIN");
snd_soc_dapm_disable_pin(dapm, "AGCOUT");
- snd_soc_dapm_sync(dapm);
/* Add virtual switch */
ret = snd_soc_add_controls(codec, ams_delta_audio_controls,
diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c
index 0ae34702995b..591fbf8f7cd9 100644
--- a/sound/soc/omap/igep0020.c
+++ b/sound/soc/omap/igep0020.c
@@ -21,6 +21,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -38,29 +39,8 @@ static int igep2_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
@@ -84,6 +64,8 @@ static struct snd_soc_dai_link igep2_dai = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.ops = &igep2_ops,
};
diff --git a/sound/soc/omap/mcpdm.c b/sound/soc/omap/mcpdm.c
deleted file mode 100644
index 50e59194ad81..000000000000
--- a/sound/soc/omap/mcpdm.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * mcpdm.c -- McPDM interface driver
- *
- * Author: Jorge Eduardo Candelaria <x0107209@ti.com>
- * Copyright (C) 2009 - Texas Instruments, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-
-#include "mcpdm.h"
-
-static struct omap_mcpdm *mcpdm;
-
-static inline void omap_mcpdm_write(u16 reg, u32 val)
-{
- __raw_writel(val, mcpdm->io_base + reg);
-}
-
-static inline int omap_mcpdm_read(u16 reg)
-{
- return __raw_readl(mcpdm->io_base + reg);
-}
-
-static void omap_mcpdm_reg_dump(void)
-{
- dev_dbg(mcpdm->dev, "***********************\n");
- dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQSTATUS_RAW));
- dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQSTATUS));
- dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQENABLE_SET));
- dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQENABLE_CLR));
- dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQWAKE_EN));
- dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DMAENABLE_SET));
- dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DMAENABLE_CLR));
- dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DMAWAKEEN));
- dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n",
- omap_mcpdm_read(MCPDM_CTRL));
- dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DN_DATA));
- dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
- omap_mcpdm_read(MCPDM_UP_DATA));
- dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
- omap_mcpdm_read(MCPDM_FIFO_CTRL_DN));
- dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n",
- omap_mcpdm_read(MCPDM_FIFO_CTRL_UP));
- dev_dbg(mcpdm->dev, "DN_OFFSET: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DN_OFFSET));
- dev_dbg(mcpdm->dev, "***********************\n");
-}
-
-/*
- * Takes the McPDM module in and out of reset state.
- * Uplink and downlink can be reset individually.
- */
-static void omap_mcpdm_reset_capture(int reset)
-{
- int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
- if (reset)
- ctrl |= SW_UP_RST;
- else
- ctrl &= ~SW_UP_RST;
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-static void omap_mcpdm_reset_playback(int reset)
-{
- int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
- if (reset)
- ctrl |= SW_DN_RST;
- else
- ctrl &= ~SW_DN_RST;
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-/*
- * Enables the transfer through the PDM interface to/from the Phoenix
- * codec by enabling the corresponding UP or DN channels.
- */
-void omap_mcpdm_start(int stream)
-{
- int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
- if (stream)
- ctrl |= mcpdm->up_channels;
- else
- ctrl |= mcpdm->dn_channels;
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-/*
- * Disables the transfer through the PDM interface to/from the Phoenix
- * codec by disabling the corresponding UP or DN channels.
- */
-void omap_mcpdm_stop(int stream)
-{
- int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
- if (stream)
- ctrl &= ~mcpdm->up_channels;
- else
- ctrl &= ~mcpdm->dn_channels;
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-/*
- * Configures McPDM uplink for audio recording.
- * This function should be called before omap_mcpdm_start.
- */
-int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink)
-{
- int irq_mask = 0;
- int ctrl;
-
- if (!uplink)
- return -EINVAL;
-
- mcpdm->uplink = uplink;
-
- /* Enable irq request generation */
- irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
- omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask);
-
- /* Configure uplink threshold */
- if (uplink->threshold > UP_THRES_MAX)
- uplink->threshold = UP_THRES_MAX;
-
- omap_mcpdm_write(MCPDM_FIFO_CTRL_UP, uplink->threshold);
-
- /* Configure DMA controller */
- omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_UP_ENABLE);
-
- /* Set pdm out format */
- ctrl = omap_mcpdm_read(MCPDM_CTRL);
- ctrl &= ~PDMOUTFORMAT;
- ctrl |= uplink->format & PDMOUTFORMAT;
-
- /* Uplink channels */
- mcpdm->up_channels = uplink->channels & (PDM_UP_MASK | PDM_STATUS_MASK);
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-
- return 0;
-}
-
-/*
- * Configures McPDM downlink for audio playback.
- * This function should be called before omap_mcpdm_start.
- */
-int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink)
-{
- int irq_mask = 0;
- int ctrl;
-
- if (!downlink)
- return -EINVAL;
-
- mcpdm->downlink = downlink;
-
- /* Enable irq request generation */
- irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
- omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask);
-
- /* Configure uplink threshold */
- if (downlink->threshold > DN_THRES_MAX)
- downlink->threshold = DN_THRES_MAX;
-
- omap_mcpdm_write(MCPDM_FIFO_CTRL_DN, downlink->threshold);
-
- /* Enable DMA request generation */
- omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_DN_ENABLE);
-
- /* Set pdm out format */
- ctrl = omap_mcpdm_read(MCPDM_CTRL);
- ctrl &= ~PDMOUTFORMAT;
- ctrl |= downlink->format & PDMOUTFORMAT;
-
- /* Downlink channels */
- mcpdm->dn_channels = downlink->channels & (PDM_DN_MASK | PDM_CMD_MASK);
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-
- return 0;
-}
-
-/*
- * Cleans McPDM uplink configuration.
- * This function should be called when the stream is closed.
- */
-int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink)
-{
- int irq_mask = 0;
-
- if (!uplink)
- return -EINVAL;
-
- /* Disable irq request generation */
- irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
- omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask);
-
- /* Disable DMA request generation */
- omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_UP_ENABLE);
-
- /* Clear Downlink channels */
- mcpdm->up_channels = 0;
-
- mcpdm->uplink = NULL;
-
- return 0;
-}
-
-/*
- * Cleans McPDM downlink configuration.
- * This function should be called when the stream is closed.
- */
-int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink)
-{
- int irq_mask = 0;
-
- if (!downlink)
- return -EINVAL;
-
- /* Disable irq request generation */
- irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
- omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask);
-
- /* Disable DMA request generation */
- omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_DN_ENABLE);
-
- /* clear Downlink channels */
- mcpdm->dn_channels = 0;
-
- mcpdm->downlink = NULL;
-
- return 0;
-}
-
-static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
-{
- struct omap_mcpdm *mcpdm_irq = dev_id;
- int irq_status;
-
- irq_status = omap_mcpdm_read(MCPDM_IRQSTATUS);
-
- /* Acknowledge irq event */
- omap_mcpdm_write(MCPDM_IRQSTATUS, irq_status);
-
- if (irq & MCPDM_DN_IRQ_FULL) {
- dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status);
- omap_mcpdm_reset_playback(1);
- omap_mcpdm_playback_open(mcpdm_irq->downlink);
- omap_mcpdm_reset_playback(0);
- }
-
- if (irq & MCPDM_DN_IRQ_EMPTY) {
- dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status);
- omap_mcpdm_reset_playback(1);
- omap_mcpdm_playback_open(mcpdm_irq->downlink);
- omap_mcpdm_reset_playback(0);
- }
-
- if (irq & MCPDM_DN_IRQ) {
- dev_dbg(mcpdm_irq->dev, "DN write request\n");
- }
-
- if (irq & MCPDM_UP_IRQ_FULL) {
- dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status);
- omap_mcpdm_reset_capture(1);
- omap_mcpdm_capture_open(mcpdm_irq->uplink);
- omap_mcpdm_reset_capture(0);
- }
-
- if (irq & MCPDM_UP_IRQ_EMPTY) {
- dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status);
- omap_mcpdm_reset_capture(1);
- omap_mcpdm_capture_open(mcpdm_irq->uplink);
- omap_mcpdm_reset_capture(0);
- }
-
- if (irq & MCPDM_UP_IRQ) {
- dev_dbg(mcpdm_irq->dev, "UP write request\n");
- }
-
- return IRQ_HANDLED;
-}
-
-int omap_mcpdm_request(void)
-{
- int ret;
-
- clk_enable(mcpdm->clk);
-
- spin_lock(&mcpdm->lock);
-
- if (!mcpdm->free) {
- dev_err(mcpdm->dev, "McPDM interface is in use\n");
- spin_unlock(&mcpdm->lock);
- ret = -EBUSY;
- goto err;
- }
- mcpdm->free = 0;
-
- spin_unlock(&mcpdm->lock);
-
- /* Disable lines while request is ongoing */
- omap_mcpdm_write(MCPDM_CTRL, 0x00);
-
- ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
- 0, "McPDM", (void *)mcpdm);
- if (ret) {
- dev_err(mcpdm->dev, "Request for McPDM IRQ failed\n");
- goto err;
- }
-
- return 0;
-
-err:
- clk_disable(mcpdm->clk);
- return ret;
-}
-
-void omap_mcpdm_free(void)
-{
- spin_lock(&mcpdm->lock);
- if (mcpdm->free) {
- dev_err(mcpdm->dev, "McPDM interface is already free\n");
- spin_unlock(&mcpdm->lock);
- return;
- }
- mcpdm->free = 1;
- spin_unlock(&mcpdm->lock);
-
- clk_disable(mcpdm->clk);
-
- free_irq(mcpdm->irq, (void *)mcpdm);
-}
-
-/* Enable/disable DC offset cancelation for the analog
- * headset path (PDM channels 1 and 2).
- */
-int omap_mcpdm_set_offset(int offset1, int offset2)
-{
- int offset;
-
- if ((offset1 > DN_OFST_MAX) || (offset2 > DN_OFST_MAX))
- return -EINVAL;
-
- offset = (offset1 << DN_OFST_RX1) | (offset2 << DN_OFST_RX2);
-
- /* offset cancellation for channel 1 */
- if (offset1)
- offset |= DN_OFST_RX1_EN;
- else
- offset &= ~DN_OFST_RX1_EN;
-
- /* offset cancellation for channel 2 */
- if (offset2)
- offset |= DN_OFST_RX2_EN;
- else
- offset &= ~DN_OFST_RX2_EN;
-
- omap_mcpdm_write(MCPDM_DN_OFFSET, offset);
-
- return 0;
-}
-
-int __devinit omap_mcpdm_probe(struct platform_device *pdev)
-{
- struct resource *res;
- int ret = 0;
-
- mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
- if (!mcpdm) {
- ret = -ENOMEM;
- goto exit;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "no resource\n");
- goto err_resource;
- }
-
- spin_lock_init(&mcpdm->lock);
- mcpdm->free = 1;
- mcpdm->io_base = ioremap(res->start, resource_size(res));
- if (!mcpdm->io_base) {
- ret = -ENOMEM;
- goto err_resource;
- }
-
- mcpdm->irq = platform_get_irq(pdev, 0);
-
- mcpdm->clk = clk_get(&pdev->dev, "pdm_ck");
- if (IS_ERR(mcpdm->clk)) {
- ret = PTR_ERR(mcpdm->clk);
- dev_err(&pdev->dev, "unable to get pdm_ck: %d\n", ret);
- goto err_clk;
- }
-
- mcpdm->dev = &pdev->dev;
- platform_set_drvdata(pdev, mcpdm);
-
- return 0;
-
-err_clk:
- iounmap(mcpdm->io_base);
-err_resource:
- kfree(mcpdm);
-exit:
- return ret;
-}
-
-int omap_mcpdm_remove(struct platform_device *pdev)
-{
- struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev);
-
- platform_set_drvdata(pdev, NULL);
-
- clk_put(mcpdm_ptr->clk);
-
- iounmap(mcpdm_ptr->io_base);
-
- mcpdm_ptr->clk = NULL;
- mcpdm_ptr->free = 0;
- mcpdm_ptr->dev = NULL;
-
- kfree(mcpdm_ptr);
-
- return 0;
-}
-
diff --git a/sound/soc/omap/mcpdm.h b/sound/soc/omap/mcpdm.h
deleted file mode 100644
index 20c20a8649fe..000000000000
--- a/sound/soc/omap/mcpdm.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * mcpdm.h -- Defines for McPDM driver
- *
- * Author: Jorge Eduardo Candelaria <x0107209@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-/* McPDM registers */
-
-#define MCPDM_REVISION 0x00
-#define MCPDM_SYSCONFIG 0x10
-#define MCPDM_IRQSTATUS_RAW 0x24
-#define MCPDM_IRQSTATUS 0x28
-#define MCPDM_IRQENABLE_SET 0x2C
-#define MCPDM_IRQENABLE_CLR 0x30
-#define MCPDM_IRQWAKE_EN 0x34
-#define MCPDM_DMAENABLE_SET 0x38
-#define MCPDM_DMAENABLE_CLR 0x3C
-#define MCPDM_DMAWAKEEN 0x40
-#define MCPDM_CTRL 0x44
-#define MCPDM_DN_DATA 0x48
-#define MCPDM_UP_DATA 0x4C
-#define MCPDM_FIFO_CTRL_DN 0x50
-#define MCPDM_FIFO_CTRL_UP 0x54
-#define MCPDM_DN_OFFSET 0x58
-
-/*
- * MCPDM_IRQ bit fields
- * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
- */
-
-#define MCPDM_DN_IRQ (1 << 0)
-#define MCPDM_DN_IRQ_EMPTY (1 << 1)
-#define MCPDM_DN_IRQ_ALMST_EMPTY (1 << 2)
-#define MCPDM_DN_IRQ_FULL (1 << 3)
-
-#define MCPDM_UP_IRQ (1 << 8)
-#define MCPDM_UP_IRQ_EMPTY (1 << 9)
-#define MCPDM_UP_IRQ_ALMST_FULL (1 << 10)
-#define MCPDM_UP_IRQ_FULL (1 << 11)
-
-#define MCPDM_DOWNLINK_IRQ_MASK 0x00F
-#define MCPDM_UPLINK_IRQ_MASK 0xF00
-
-/*
- * MCPDM_DMAENABLE bit fields
- */
-
-#define DMA_DN_ENABLE 0x1
-#define DMA_UP_ENABLE 0x2
-
-/*
- * MCPDM_CTRL bit fields
- */
-
-#define PDM_UP1_EN 0x0001
-#define PDM_UP2_EN 0x0002
-#define PDM_UP3_EN 0x0004
-#define PDM_DN1_EN 0x0008
-#define PDM_DN2_EN 0x0010
-#define PDM_DN3_EN 0x0020
-#define PDM_DN4_EN 0x0040
-#define PDM_DN5_EN 0x0080
-#define PDMOUTFORMAT 0x0100
-#define CMD_INT 0x0200
-#define STATUS_INT 0x0400
-#define SW_UP_RST 0x0800
-#define SW_DN_RST 0x1000
-#define PDM_UP_MASK 0x007
-#define PDM_DN_MASK 0x0F8
-#define PDM_CMD_MASK 0x200
-#define PDM_STATUS_MASK 0x400
-
-
-#define PDMOUTFORMAT_LJUST (0 << 8)
-#define PDMOUTFORMAT_RJUST (1 << 8)
-
-/*
- * MCPDM_FIFO_CTRL bit fields
- */
-
-#define UP_THRES_MAX 0xF
-#define DN_THRES_MAX 0xF
-
-/*
- * MCPDM_DN_OFFSET bit fields
- */
-
-#define DN_OFST_RX1_EN 0x0001
-#define DN_OFST_RX2_EN 0x0100
-
-#define DN_OFST_RX1 1
-#define DN_OFST_RX2 9
-#define DN_OFST_MAX 0x1F
-
-#define MCPDM_UPLINK 1
-#define MCPDM_DOWNLINK 2
-
-struct omap_mcpdm_link {
- int irq_mask;
- int threshold;
- int format;
- int channels;
-};
-
-struct omap_mcpdm_platform_data {
- unsigned long phys_base;
- u16 irq;
-};
-
-struct omap_mcpdm {
- struct device *dev;
- unsigned long phys_base;
- void __iomem *io_base;
- u8 free;
- int irq;
-
- spinlock_t lock;
- struct omap_mcpdm_platform_data *pdata;
- struct clk *clk;
- struct omap_mcpdm_link *downlink;
- struct omap_mcpdm_link *uplink;
- struct completion irq_completion;
-
- int dn_channels;
- int up_channels;
-};
-
-extern void omap_mcpdm_start(int stream);
-extern void omap_mcpdm_stop(int stream);
-extern int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink);
-extern int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink);
-extern int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink);
-extern int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink);
-extern int omap_mcpdm_request(void);
-extern void omap_mcpdm_free(void);
-extern int omap_mcpdm_set_offset(int offset1, int offset2);
-int __devinit omap_mcpdm_probe(struct platform_device *pdev);
-int omap_mcpdm_remove(struct platform_device *pdev);
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 62e292f49313..fc6209b3f20c 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -31,6 +31,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
@@ -115,25 +116,8 @@ static int n810_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
- /* Set codec DAI configuration */
- err = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (err < 0)
- return err;
-
- /* Set cpu DAI configuration */
- err = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (err < 0)
- return err;
-
/* Set the codec system clock for DAC and ADC */
err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000,
SND_SOC_CLOCK_IN);
@@ -274,7 +258,6 @@ static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int err;
/* Not connected */
snd_soc_dapm_nc_pin(dapm, "MONO_LOUT");
@@ -286,21 +269,6 @@ static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "LINE2L");
snd_soc_dapm_nc_pin(dapm, "LINE2R");
- /* Add N810 specific controls */
- err = snd_soc_add_controls(codec, aic33_n810_controls,
- ARRAY_SIZE(aic33_n810_controls));
- if (err < 0)
- return err;
-
- /* Add N810 specific widgets */
- snd_soc_dapm_new_controls(dapm, aic33_dapm_widgets,
- ARRAY_SIZE(aic33_dapm_widgets));
-
- /* Set up N810 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- snd_soc_dapm_sync(dapm);
-
return 0;
}
@@ -312,6 +280,8 @@ static struct snd_soc_dai_link n810_dai = {
.platform_name = "omap-pcm-audio",
.codec_name = "tlv320aic3x-codec.2-0018",
.codec_dai_name = "tlv320aic3x-hifi",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = n810_aic33_init,
.ops = &n810_ops,
};
@@ -321,6 +291,13 @@ static struct snd_soc_card snd_soc_n810 = {
.name = "N810",
.dai_link = &n810_dai,
.num_links = 1,
+
+ .controls = aic33_n810_controls,
+ .num_controls = ARRAY_SIZE(aic33_n810_controls),
+ .dapm_widgets = aic33_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *n810_snd_device;
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 478d60778453..4314647e735e 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -317,6 +317,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+ regs->rcr2 &= ~(RPHASE | RFRLEN2(0x7f) | RWDLEN2(7));
+ regs->xcr2 &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7));
+ regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7));
+ regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7));
format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
wpf = channels = params_channels(params);
if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
@@ -369,6 +373,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
framesize = wlen * channels;
/* Set FS period and length in terms of bit clock periods */
+ regs->srgr2 &= ~FPER(0xfff);
+ regs->srgr1 &= ~FWID(0xff);
switch (format) {
case SND_SOC_DAIFMT_I2S:
case SND_SOC_DAIFMT_LEFT_J:
@@ -398,7 +404,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
{
struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
- unsigned int temp_fmt = fmt;
+ bool inv_fs = false;
if (mcbsp_data->configured)
return 0;
@@ -430,21 +436,21 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
regs->xcr2 |= XDATDLY(0);
regs->spcr1 |= RJUST(2);
/* Invert FS polarity configuration */
- temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
+ inv_fs = true;
break;
case SND_SOC_DAIFMT_DSP_A:
/* 1-bit data delay */
regs->rcr2 |= RDATDLY(1);
regs->xcr2 |= XDATDLY(1);
/* Invert FS polarity configuration */
- temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
+ inv_fs = true;
break;
case SND_SOC_DAIFMT_DSP_B:
/* 0-bit data delay */
regs->rcr2 |= RDATDLY(0);
regs->xcr2 |= XDATDLY(0);
/* Invert FS polarity configuration */
- temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
+ inv_fs = true;
break;
default:
/* Unsupported data format */
@@ -468,7 +474,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
}
/* Set bit clock (CLKX/CLKR) and FS polarities */
- switch (temp_fmt & SND_SOC_DAIFMT_INV_MASK) {
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
/*
* Normal BCLK + FS.
@@ -489,6 +495,8 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
default:
return -EINVAL;
}
+ if (inv_fs == true)
+ regs->pcr0 ^= FSXP | FSRP;
return 0;
}
@@ -503,6 +511,7 @@ static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
return -ENODEV;
mcbsp_data->clk_div = div;
+ regs->srgr1 &= ~CLKGDV(0xff);
regs->srgr1 |= CLKGDV(div - 1);
return 0;
@@ -516,11 +525,12 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
int err = 0;
- if (mcbsp_data->active)
+ if (mcbsp_data->active) {
if (freq == mcbsp_data->in_freq)
return 0;
else
return -EBUSY;
+ }
/* The McBSP signal muxing functions are only available on McBSP1 */
if (clk_id == OMAP_MCBSP_CLKR_SRC_CLKR ||
@@ -531,6 +541,8 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
return -EINVAL;
mcbsp_data->in_freq = freq;
+ regs->srgr2 &= ~CLKSM;
+ regs->pcr0 &= ~SCLKME;
switch (clk_id) {
case OMAP_MCBSP_SYSCLK_CLK:
@@ -605,8 +617,7 @@ static int mcbsp_dai_probe(struct snd_soc_dai *dai)
return 0;
}
-static struct snd_soc_dai_driver omap_mcbsp_dai =
-{
+static struct snd_soc_dai_driver omap_mcbsp_dai = {
.probe = mcbsp_dai_probe,
.playback = {
.channels_min = 1,
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index bed09c27e44c..41d17067cc73 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -1,11 +1,12 @@
/*
* omap-mcpdm.c -- OMAP ALSA SoC DAI driver using McPDM port
*
- * Copyright (C) 2009 Texas Instruments
+ * Copyright (C) 2009 - 2011 Texas Instruments
*
- * Author: Misael Lopez Cruz <x0052729@ti.com>
+ * Author: Misael Lopez Cruz <misael.lopez@ti.com>
* Contact: Jorge Eduardo Candelaria <x0107209@ti.com>
* Margarita Olaya <magi.olaya@ti.com>
+ * Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,41 +26,42 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
-#include <sound/initval.h>
#include <sound/soc.h>
#include <plat/dma.h>
-#include <plat/mcbsp.h>
-#include "mcpdm.h"
+#include <plat/omap_hwmod.h>
+#include "omap-mcpdm.h"
#include "omap-pcm.h"
-struct omap_mcpdm_data {
- struct omap_mcpdm_link *links;
- int active;
-};
+struct omap_mcpdm {
+ struct device *dev;
+ unsigned long phys_base;
+ void __iomem *io_base;
+ int irq;
-static struct omap_mcpdm_link omap_mcpdm_links[] = {
- /* downlink */
- {
- .irq_mask = MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL,
- .threshold = 1,
- .format = PDMOUTFORMAT_LJUST,
- },
- /* uplink */
- {
- .irq_mask = MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL,
- .threshold = 1,
- .format = PDMOUTFORMAT_LJUST,
- },
-};
+ struct mutex mutex;
+
+ /* channel data */
+ u32 dn_channels;
+ u32 up_channels;
+
+ /* McPDM FIFO thresholds */
+ u32 dn_threshold;
+ u32 up_threshold;
-static struct omap_mcpdm_data mcpdm_data = {
- .links = omap_mcpdm_links,
- .active = 0,
+ /* McPDM dn offsets for rx1, and 2 channels */
+ u32 dn_rx_offset;
};
/*
@@ -71,88 +73,259 @@ static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
.dma_req = OMAP44XX_DMA_MCPDM_DL,
.data_type = OMAP_DMA_DATA_TYPE_S32,
.sync_mode = OMAP_DMA_SYNC_PACKET,
- .packet_size = 16,
- .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_DN_DATA,
+ .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_DN_DATA,
},
{
.name = "Audio capture",
.dma_req = OMAP44XX_DMA_MCPDM_UP,
.data_type = OMAP_DMA_DATA_TYPE_S32,
.sync_mode = OMAP_DMA_SYNC_PACKET,
- .packet_size = 16,
- .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_UP_DATA,
+ .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_UP_DATA,
},
};
-static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
{
- int err = 0;
+ __raw_writel(val, mcpdm->io_base + reg);
+}
- if (!dai->active)
- err = omap_mcpdm_request();
+static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg)
+{
+ return __raw_readl(mcpdm->io_base + reg);
+}
- return err;
+#ifdef DEBUG
+static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm)
+{
+ dev_dbg(mcpdm->dev, "***********************\n");
+ dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS_RAW));
+ dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS));
+ dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_SET));
+ dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_CLR));
+ dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_IRQWAKE_EN));
+ dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_SET));
+ dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_CLR));
+ dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_DMAWAKEEN));
+ dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL));
+ dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_DN_DATA));
+ dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_UP_DATA));
+ dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_DN));
+ dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_UP));
+ dev_dbg(mcpdm->dev, "***********************\n");
}
+#else
+static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
+#endif
-static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+/*
+ * Enables the transfer through the PDM interface to/from the Phoenix
+ * codec by enabling the corresponding UP or DN channels.
+ */
+static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
+{
+ u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+
+ ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+ ctrl |= mcpdm->dn_channels | mcpdm->up_channels;
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+ ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+}
+
+/*
+ * Disables the transfer through the PDM interface to/from the Phoenix
+ * codec by disabling the corresponding UP or DN channels.
+ */
+static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
+{
+ u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+
+ ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+ ctrl &= ~(mcpdm->dn_channels | mcpdm->up_channels);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+ ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+}
+
+/*
+ * Is the physical McPDM interface active.
+ */
+static inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm)
+{
+ return omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL) &
+ (MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK);
+}
+
+/*
+ * Configures McPDM uplink, and downlink for audio.
+ * This function should be called before omap_mcpdm_start.
+ */
+static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
+{
+ omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET,
+ MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL |
+ MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
+
+ /* Enable DN RX1/2 offset cancellation feature, if configured */
+ if (mcpdm->dn_rx_offset) {
+ u32 dn_offset = mcpdm->dn_rx_offset;
+
+ omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
+ dn_offset |= (MCPDM_DN_OFST_RX1_EN | MCPDM_DN_OFST_RX2_EN);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
+ }
+
+ omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->dn_threshold);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->up_threshold);
+
+ omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET,
+ MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE);
+}
+
+/*
+ * Cleans McPDM uplink, and downlink configuration.
+ * This function should be called when the stream is closed.
+ */
+static void omap_mcpdm_close_streams(struct omap_mcpdm *mcpdm)
+{
+ /* Disable irq request generation for downlink */
+ omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
+ MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL);
+
+ /* Disable DMA request generation for downlink */
+ omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_DN_ENABLE);
+
+ /* Disable irq request generation for uplink */
+ omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
+ MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
+
+ /* Disable DMA request generation for uplink */
+ omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_UP_ENABLE);
+
+ /* Disable RX1/2 offset cancellation */
+ if (mcpdm->dn_rx_offset)
+ omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, 0);
+}
+
+static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
+{
+ struct omap_mcpdm *mcpdm = dev_id;
+ int irq_status;
+
+ irq_status = omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS);
+
+ /* Acknowledge irq event */
+ omap_mcpdm_write(mcpdm, MCPDM_REG_IRQSTATUS, irq_status);
+
+ if (irq_status & MCPDM_DN_IRQ_FULL)
+ dev_dbg(mcpdm->dev, "DN (playback) FIFO Full\n");
+
+ if (irq_status & MCPDM_DN_IRQ_EMPTY)
+ dev_dbg(mcpdm->dev, "DN (playback) FIFO Empty\n");
+
+ if (irq_status & MCPDM_DN_IRQ)
+ dev_dbg(mcpdm->dev, "DN (playback) write request\n");
+
+ if (irq_status & MCPDM_UP_IRQ_FULL)
+ dev_dbg(mcpdm->dev, "UP (capture) FIFO Full\n");
+
+ if (irq_status & MCPDM_UP_IRQ_EMPTY)
+ dev_dbg(mcpdm->dev, "UP (capture) FIFO Empty\n");
+
+ if (irq_status & MCPDM_UP_IRQ)
+ dev_dbg(mcpdm->dev, "UP (capture) write request\n");
+
+ return IRQ_HANDLED;
+}
+
+static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
{
- if (!dai->active)
- omap_mcpdm_free();
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+ mutex_lock(&mcpdm->mutex);
+
+ if (!dai->active) {
+ pm_runtime_get_sync(mcpdm->dev);
+
+ /* Enable watch dog for ES above ES 1.0 to avoid saturation */
+ if (omap_rev() != OMAP4430_REV_ES1_0) {
+ u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL,
+ ctrl | MCPDM_WD_EN);
+ }
+ omap_mcpdm_open_streams(mcpdm);
+ }
+
+ mutex_unlock(&mcpdm->mutex);
+
+ return 0;
}
-static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
- int stream = substream->stream;
- int err = 0;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (!mcpdm_priv->active++)
- omap_mcpdm_start(stream);
- break;
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (!--mcpdm_priv->active)
- omap_mcpdm_stop(stream);
- break;
- default:
- err = -EINVAL;
+ mutex_lock(&mcpdm->mutex);
+
+ if (!dai->active) {
+ if (omap_mcpdm_active(mcpdm)) {
+ omap_mcpdm_stop(mcpdm);
+ omap_mcpdm_close_streams(mcpdm);
+ }
+
+ if (!omap_mcpdm_active(mcpdm))
+ pm_runtime_put_sync(mcpdm->dev);
}
- return err;
+ mutex_unlock(&mcpdm->mutex);
}
static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
- struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
int stream = substream->stream;
- int channels, err, link_mask = 0;
-
- snd_soc_dai_set_dma_data(dai, substream,
- &omap_mcpdm_dai_dma_params[stream]);
+ struct omap_pcm_dma_data *dma_data;
+ int channels;
+ int link_mask = 0;
channels = params_channels(params);
switch (channels) {
+ case 5:
+ if (stream == SNDRV_PCM_STREAM_CAPTURE)
+ /* up to 3 channels for capture */
+ return -EINVAL;
+ link_mask |= 1 << 4;
case 4:
if (stream == SNDRV_PCM_STREAM_CAPTURE)
- /* up to 2 channels for capture */
+ /* up to 3 channels for capture */
return -EINVAL;
link_mask |= 1 << 3;
case 3:
- if (stream == SNDRV_PCM_STREAM_CAPTURE)
- /* up to 2 channels for capture */
- return -EINVAL;
link_mask |= 1 << 2;
case 2:
link_mask |= 1 << 1;
@@ -164,95 +337,187 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ dma_data = &omap_mcpdm_dai_dma_params[stream];
+
+ /* Configure McPDM channels, and DMA packet size */
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- mcpdm_links[stream].channels = link_mask << 3;
- err = omap_mcpdm_playback_open(&mcpdm_links[stream]);
+ mcpdm->dn_channels = link_mask << 3;
+ dma_data->packet_size =
+ (MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels;
} else {
- mcpdm_links[stream].channels = link_mask << 0;
- err = omap_mcpdm_capture_open(&mcpdm_links[stream]);
+ mcpdm->up_channels = link_mask << 0;
+ dma_data->packet_size = mcpdm->up_threshold * channels;
}
- return err;
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
+
+ return 0;
}
-static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream,
+static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
- struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
- int stream = substream->stream;
- int err;
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- err = omap_mcpdm_playback_close(&mcpdm_links[stream]);
- else
- err = omap_mcpdm_capture_close(&mcpdm_links[stream]);
+ if (!omap_mcpdm_active(mcpdm)) {
+ omap_mcpdm_start(mcpdm);
+ omap_mcpdm_reg_dump(mcpdm);
+ }
- return err;
+ return 0;
}
static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
.startup = omap_mcpdm_dai_startup,
.shutdown = omap_mcpdm_dai_shutdown,
- .trigger = omap_mcpdm_dai_trigger,
.hw_params = omap_mcpdm_dai_hw_params,
- .hw_free = omap_mcpdm_dai_hw_free,
+ .prepare = omap_mcpdm_prepare,
};
-#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-#define OMAP_MCPDM_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
+static int omap_mcpdm_probe(struct snd_soc_dai *dai)
+{
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+ int ret;
-static int omap_mcpdm_dai_probe(struct snd_soc_dai *dai)
+ pm_runtime_enable(mcpdm->dev);
+
+ /* Disable lines while request is ongoing */
+ pm_runtime_get_sync(mcpdm->dev);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
+
+ ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
+ 0, "McPDM", (void *)mcpdm);
+
+ pm_runtime_put_sync(mcpdm->dev);
+
+ if (ret) {
+ dev_err(mcpdm->dev, "Request for IRQ failed\n");
+ pm_runtime_disable(mcpdm->dev);
+ }
+
+ /* Configure McPDM threshold values */
+ mcpdm->dn_threshold = 2;
+ mcpdm->up_threshold = MCPDM_UP_THRES_MAX - 3;
+ return ret;
+}
+
+static int omap_mcpdm_remove(struct snd_soc_dai *dai)
{
- snd_soc_dai_set_drvdata(dai, &mcpdm_data);
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+ free_irq(mcpdm->irq, (void *)mcpdm);
+ pm_runtime_disable(mcpdm->dev);
+
return 0;
}
+#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+#define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE
+
static struct snd_soc_dai_driver omap_mcpdm_dai = {
- .probe = omap_mcpdm_dai_probe,
+ .probe = omap_mcpdm_probe,
+ .remove = omap_mcpdm_remove,
+ .probe_order = SND_SOC_COMP_ORDER_LATE,
+ .remove_order = SND_SOC_COMP_ORDER_EARLY,
.playback = {
.channels_min = 1,
- .channels_max = 4,
+ .channels_max = 5,
.rates = OMAP_MCPDM_RATES,
.formats = OMAP_MCPDM_FORMATS,
},
.capture = {
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 3,
.rates = OMAP_MCPDM_RATES,
.formats = OMAP_MCPDM_FORMATS,
},
.ops = &omap_mcpdm_dai_ops,
};
+void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
+ u8 rx1, u8 rx2)
+{
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+ mcpdm->dn_rx_offset = MCPDM_DNOFST_RX1(rx1) | MCPDM_DNOFST_RX2(rx2);
+}
+EXPORT_SYMBOL_GPL(omap_mcpdm_configure_dn_offsets);
+
static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
{
- int ret;
+ struct omap_mcpdm *mcpdm;
+ struct resource *res;
+ int ret = 0;
+
+ mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
+ if (!mcpdm)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, mcpdm);
+
+ mutex_init(&mcpdm->mutex);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no resource\n");
+ goto err_res;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res), "McPDM")) {
+ ret = -EBUSY;
+ goto err_res;
+ }
+
+ mcpdm->io_base = ioremap(res->start, resource_size(res));
+ if (!mcpdm->io_base) {
+ ret = -ENOMEM;
+ goto err_iomap;
+ }
+
+ mcpdm->irq = platform_get_irq(pdev, 0);
+ if (mcpdm->irq < 0) {
+ ret = mcpdm->irq;
+ goto err_irq;
+ }
+
+ mcpdm->dev = &pdev->dev;
- ret = omap_mcpdm_probe(pdev);
- if (ret < 0)
- return ret;
ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
- if (ret < 0)
- omap_mcpdm_remove(pdev);
+ if (!ret)
+ return 0;
+
+err_irq:
+ iounmap(mcpdm->io_base);
+err_iomap:
+ release_mem_region(res->start, resource_size(res));
+err_res:
+ kfree(mcpdm);
return ret;
}
static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
{
+ struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev);
+ struct resource *res;
+
snd_soc_unregister_dai(&pdev->dev);
- omap_mcpdm_remove(pdev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iounmap(mcpdm->io_base);
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(mcpdm);
return 0;
}
static struct platform_driver asoc_mcpdm_driver = {
.driver = {
- .name = "omap-mcpdm-dai",
- .owner = THIS_MODULE,
+ .name = "omap-mcpdm",
+ .owner = THIS_MODULE,
},
- .probe = asoc_mcpdm_probe,
- .remove = __devexit_p(asoc_mcpdm_remove),
+ .probe = asoc_mcpdm_probe,
+ .remove = __devexit_p(asoc_mcpdm_remove),
};
static int __init snd_omap_mcpdm_init(void)
@@ -267,6 +532,6 @@ static void __exit snd_omap_mcpdm_exit(void)
}
module_exit(snd_omap_mcpdm_exit);
-MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
+MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
MODULE_DESCRIPTION("OMAP PDM SoC Interface");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h
new file mode 100644
index 000000000000..de8cf26595b1
--- /dev/null
+++ b/sound/soc/omap/omap-mcpdm.h
@@ -0,0 +1,107 @@
+/*
+ * omap-mcpdm.h
+ *
+ * Copyright (C) 2009 - 2011 Texas Instruments
+ *
+ * Contact: Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_MCPDM_H__
+#define __OMAP_MCPDM_H__
+
+#define MCPDM_REG_REVISION 0x00
+#define MCPDM_REG_SYSCONFIG 0x10
+#define MCPDM_REG_IRQSTATUS_RAW 0x24
+#define MCPDM_REG_IRQSTATUS 0x28
+#define MCPDM_REG_IRQENABLE_SET 0x2C
+#define MCPDM_REG_IRQENABLE_CLR 0x30
+#define MCPDM_REG_IRQWAKE_EN 0x34
+#define MCPDM_REG_DMAENABLE_SET 0x38
+#define MCPDM_REG_DMAENABLE_CLR 0x3C
+#define MCPDM_REG_DMAWAKEEN 0x40
+#define MCPDM_REG_CTRL 0x44
+#define MCPDM_REG_DN_DATA 0x48
+#define MCPDM_REG_UP_DATA 0x4C
+#define MCPDM_REG_FIFO_CTRL_DN 0x50
+#define MCPDM_REG_FIFO_CTRL_UP 0x54
+#define MCPDM_REG_DN_OFFSET 0x58
+
+/*
+ * MCPDM_IRQ bit fields
+ * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
+ */
+
+#define MCPDM_DN_IRQ (1 << 0)
+#define MCPDM_DN_IRQ_EMPTY (1 << 1)
+#define MCPDM_DN_IRQ_ALMST_EMPTY (1 << 2)
+#define MCPDM_DN_IRQ_FULL (1 << 3)
+
+#define MCPDM_UP_IRQ (1 << 8)
+#define MCPDM_UP_IRQ_EMPTY (1 << 9)
+#define MCPDM_UP_IRQ_ALMST_FULL (1 << 10)
+#define MCPDM_UP_IRQ_FULL (1 << 11)
+
+#define MCPDM_DOWNLINK_IRQ_MASK 0x00F
+#define MCPDM_UPLINK_IRQ_MASK 0xF00
+
+/*
+ * MCPDM_DMAENABLE bit fields
+ */
+
+#define MCPDM_DMA_DN_ENABLE (1 << 0)
+#define MCPDM_DMA_UP_ENABLE (1 << 1)
+
+/*
+ * MCPDM_CTRL bit fields
+ */
+
+#define MCPDM_PDM_UPLINK_EN(x) (1 << (x - 1)) /* ch1 is at bit 0 */
+#define MCPDM_PDM_DOWNLINK_EN(x) (1 << (x + 2)) /* ch1 is at bit 3 */
+#define MCPDM_PDMOUTFORMAT (1 << 8)
+#define MCPDM_CMD_INT (1 << 9)
+#define MCPDM_STATUS_INT (1 << 10)
+#define MCPDM_SW_UP_RST (1 << 11)
+#define MCPDM_SW_DN_RST (1 << 12)
+#define MCPDM_WD_EN (1 << 14)
+#define MCPDM_PDM_UP_MASK 0x7
+#define MCPDM_PDM_DN_MASK (0x1f << 3)
+
+
+#define MCPDM_PDMOUTFORMAT_LJUST (0 << 8)
+#define MCPDM_PDMOUTFORMAT_RJUST (1 << 8)
+
+/*
+ * MCPDM_FIFO_CTRL bit fields
+ */
+
+#define MCPDM_UP_THRES_MAX 0xF
+#define MCPDM_DN_THRES_MAX 0xF
+
+/*
+ * MCPDM_DN_OFFSET bit fields
+ */
+
+#define MCPDM_DN_OFST_RX1_EN (1 << 0)
+#define MCPDM_DNOFST_RX1(x) ((x & 0x1f) << 1)
+#define MCPDM_DN_OFST_RX2_EN (1 << 8)
+#define MCPDM_DNOFST_RX2(x) ((x & 0x1f) << 9)
+
+void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
+ u8 rx1, u8 rx2);
+
+#endif /* End of __OMAP_MCPDM_H__ */
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 9b5c88ac35b9..6ede7dc6c10a 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -24,6 +24,7 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -198,6 +199,14 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
else if (!substream->runtime->no_period_wakeup)
omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
+ else {
+ /*
+ * No period wakeup:
+ * we need to disable BLOCK_IRQ, which is enabled by the omap
+ * dma core at request dma time.
+ */
+ omap_disable_dma_irq(prtd->dma_ch, OMAP_DMA_BLOCK_IRQ);
+ }
if (!(cpu_class_is_omap1())) {
omap_set_dma_src_burst_mode(prtd->dma_ch,
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
index 40db813c0795..3357dcc47ed4 100644
--- a/sound/soc/omap/omap3beagle.c
+++ b/sound/soc/omap/omap3beagle.c
@@ -21,6 +21,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
index 0daa04469836..68578959e4aa 100644
--- a/sound/soc/omap/omap3evm.c
+++ b/sound/soc/omap/omap3evm.c
@@ -19,6 +19,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -36,29 +37,8 @@ static int omap3evm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "Can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "Can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
@@ -82,6 +62,8 @@ static struct snd_soc_dai_link omap3evm_dai = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.ops = &omap3evm_ops,
};
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 8047c521e318..7605c37c91e7 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -24,6 +24,7 @@
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -48,24 +49,8 @@ static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, fmt);
- if (ret < 0) {
- pr_err(PREFIX "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
- if (ret < 0) {
- pr_err(PREFIX "can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
@@ -189,10 +174,8 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
if (ret < 0)
return ret;
- snd_soc_dapm_add_routes(dapm, omap3pandora_out_map,
+ return snd_soc_dapm_add_routes(dapm, omap3pandora_out_map,
ARRAY_SIZE(omap3pandora_out_map));
-
- return snd_soc_dapm_sync(dapm);
}
static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
@@ -212,10 +195,8 @@ static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
if (ret < 0)
return ret;
- snd_soc_dapm_add_routes(dapm, omap3pandora_in_map,
+ return snd_soc_dapm_add_routes(dapm, omap3pandora_in_map,
ARRAY_SIZE(omap3pandora_in_map));
-
- return snd_soc_dapm_sync(dapm);
}
static struct snd_soc_ops omap3pandora_ops = {
@@ -231,6 +212,8 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
.ops = &omap3pandora_ops,
.init = omap3pandora_out_init,
}, {
@@ -240,6 +223,8 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
.ops = &omap3pandora_ops,
.init = omap3pandora_in_init,
}
diff --git a/sound/soc/omap/omap4-hdmi-card.c b/sound/soc/omap/omap4-hdmi-card.c
index 9f32615b81f7..8671261ba16d 100644
--- a/sound/soc/omap/omap4-hdmi-card.c
+++ b/sound/soc/omap/omap4-hdmi-card.c
@@ -21,6 +21,7 @@
*
*/
+#include <linux/module.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <asm/mach-types.h>
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index 7e75e775fb4a..351ec9db384d 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -30,6 +30,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
@@ -55,29 +56,8 @@ static int osk_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
- /* Set codec DAI configuration */
- err = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (err < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return err;
- }
-
- /* Set cpu DAI configuration */
- err = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (err < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return err;
- }
-
/* Set the codec system clock for DAC and ADC */
err =
snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
@@ -112,27 +92,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MICIN", NULL, "Mic Jack"},
};
-static int osk_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- /* Add osk5912 specific widgets */
- snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
- ARRAY_SIZE(tlv320aic23_dapm_widgets));
-
- /* Set up osk5912 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_enable_pin(dapm, "Line In");
- snd_soc_dapm_enable_pin(dapm, "Mic Jack");
-
- snd_soc_dapm_sync(dapm);
-
- return 0;
-}
-
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link osk_dai = {
.name = "TLV320AIC23",
@@ -141,7 +100,8 @@ static struct snd_soc_dai_link osk_dai = {
.codec_dai_name = "tlv320aic23-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "tlv320aic23-codec",
- .init = osk_tlv320aic23_init,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.ops = &osk_ops,
};
@@ -150,6 +110,11 @@ static struct snd_soc_card snd_soc_card_osk = {
.name = "OSK5912",
.dai_link = &osk_dai,
.num_links = 1,
+
+ .dapm_widgets = tlv320aic23_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *osk_snd_device;
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
index bbcf380bfb56..c3550aeee533 100644
--- a/sound/soc/omap/overo.c
+++ b/sound/soc/omap/overo.c
@@ -21,6 +21,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -38,29 +39,8 @@ static int overo_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
@@ -84,6 +64,8 @@ static struct snd_soc_dai_link overo_dai = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.ops = &overo_ops,
};
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 893300a53bab..4cabb74d97e9 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -115,24 +116,6 @@ static int rx51_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int err;
-
- /* Set codec DAI configuration */
- err = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (err < 0)
- return err;
-
- /* Set cpu DAI configuration */
- err = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (err < 0)
- return err;
/* Set the codec system clock for DAC and ADC */
return snd_soc_dai_set_sysclk(codec_dai, 0, 19200000,
@@ -335,8 +318,6 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
if (err < 0)
return err;
- snd_soc_dapm_sync(dapm);
-
/* AV jack detection */
err = snd_soc_jack_new(codec, "AV Jack",
SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
@@ -377,6 +358,8 @@ static struct snd_soc_dai_link rx51_dai[] = {
.codec_dai_name = "tlv320aic3x-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "tlv320aic3x-codec.2-0018",
+ .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = rx51_aic34_init,
.ops = &rx51_ops,
},
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 9f6a758029d1..e8fbf8efdbb8 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -37,6 +37,7 @@
/* Register descriptions for twl4030 codec part */
#include <linux/mfd/twl4030-audio.h>
+#include <linux/module.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
@@ -53,29 +54,8 @@ static int sdp3430_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
@@ -91,49 +71,6 @@ static struct snd_soc_ops sdp3430_ops = {
.hw_params = sdp3430_hw_params,
};
-static int sdp3430_hw_voice_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret;
-
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
- /* Set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
- SND_SOC_CLOCK_IN);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec system clock\n");
- return ret;
- }
-
- return 0;
-}
-
-static struct snd_soc_ops sdp3430_voice_ops = {
- .hw_params = sdp3430_hw_voice_params,
-};
-
/* Headset jack */
static struct snd_soc_jack hs_jack;
@@ -193,15 +130,6 @@ static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
- /* Add SDP3430 specific widgets */
- ret = snd_soc_dapm_new_controls(dapm, sdp3430_twl4030_dapm_widgets,
- ARRAY_SIZE(sdp3430_twl4030_dapm_widgets));
- if (ret)
- return ret;
-
- /* Set up SDP3430 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
/* SDP3430 connected pins */
snd_soc_dapm_enable_pin(dapm, "Ext Mic");
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
@@ -223,10 +151,6 @@ static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "CARKITL");
snd_soc_dapm_nc_pin(dapm, "CARKITR");
- ret = snd_soc_dapm_sync(dapm);
- if (ret)
- return ret;
-
/* Headset jack detection */
ret = snd_soc_jack_new(codec, "Headset Jack",
SND_JACK_HEADSET, &hs_jack);
@@ -267,6 +191,8 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = sdp3430_twl4030_init,
.ops = &sdp3430_ops,
},
@@ -277,8 +203,10 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
.codec_dai_name = "twl4030-voice",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = sdp3430_twl4030_voice_init,
- .ops = &sdp3430_voice_ops,
+ .ops = &sdp3430_ops,
},
};
@@ -287,6 +215,11 @@ static struct snd_soc_card snd_soc_sdp3430 = {
.name = "SDP3430",
.dai_link = sdp3430_dai,
.num_links = ARRAY_SIZE(sdp3430_dai),
+
+ .dapm_widgets = sdp3430_twl4030_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sdp3430_twl4030_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *sdp3430_snd_device;
diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c
index b80efb02bfca..03d9fa4192fe 100644
--- a/sound/soc/omap/sdp4430.c
+++ b/sound/soc/omap/sdp4430.c
@@ -22,6 +22,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/mfd/twl6040.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -32,7 +33,7 @@
#include <plat/hardware.h>
#include <plat/mux.h>
-#include "mcpdm.h"
+#include "omap-mcpdm.h"
#include "omap-pcm.h"
#include "../codecs/twl6040.h"
@@ -88,7 +89,7 @@ static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_HP("Headset Stereophone", NULL),
SND_SOC_DAPM_SPK("Earphone Spk", NULL),
- SND_SOC_DAPM_INPUT("Aux/FM Stereo In"),
+ SND_SOC_DAPM_INPUT("FM Stereo In"),
};
static const struct snd_soc_dapm_route audio_map[] = {
@@ -113,36 +114,22 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Earphone Spk", NULL, "EP"},
/* Aux/FM Stereo In: AFML, AFMR */
- {"AFML", NULL, "Aux/FM Stereo In"},
- {"AFMR", NULL, "Aux/FM Stereo In"},
+ {"AFML", NULL, "FM Stereo In"},
+ {"AFMR", NULL, "FM Stereo In"},
};
static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
-
- /* Add SDP4430 specific widgets */
- ret = snd_soc_dapm_new_controls(dapm, sdp4430_twl6040_dapm_widgets,
- ARRAY_SIZE(sdp4430_twl6040_dapm_widgets));
- if (ret)
- return ret;
-
- /* Set up SDP4430 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+ int ret, hs_trim;
- /* SDP4430 connected pins */
- snd_soc_dapm_enable_pin(dapm, "Ext Mic");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk");
- snd_soc_dapm_enable_pin(dapm, "AFML");
- snd_soc_dapm_enable_pin(dapm, "AFMR");
- snd_soc_dapm_enable_pin(dapm, "Headset Mic");
- snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");
-
- ret = snd_soc_dapm_sync(dapm);
- if (ret)
- return ret;
+ /*
+ * Configure McPDM offset cancellation based on the HSOTRIM value from
+ * twl6040.
+ */
+ hs_trim = twl6040_get_trim_value(codec, TWL6040_TRIM_HSOTRIM);
+ omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim),
+ TWL6040_HSF_TRIM_RIGHT(hs_trim));
/* Headset jack detection */
ret = snd_soc_jack_new(codec, "Headset Jack",
@@ -165,8 +152,8 @@ static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
static struct snd_soc_dai_link sdp4430_dai = {
.name = "TWL6040",
.stream_name = "TWL6040",
- .cpu_dai_name ="omap-mcpdm-dai",
- .codec_dai_name = "twl6040-hifi",
+ .cpu_dai_name = "omap-mcpdm",
+ .codec_dai_name = "twl6040-legacy",
.platform_name = "omap-pcm-audio",
.codec_name = "twl6040-codec",
.init = sdp4430_twl6040_init,
@@ -178,6 +165,11 @@ static struct snd_soc_card snd_soc_sdp4430 = {
.name = "SDP4430",
.dai_link = &sdp4430_dai,
.num_links = 1,
+
+ .dapm_widgets = sdp4430_twl6040_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sdp4430_twl6040_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *sdp4430_snd_device;
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index 9a2666ffc16c..7641a7fa8f97 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -33,6 +33,7 @@
/* Register descriptions for twl4030 codec part */
#include <linux/mfd/twl4030-audio.h>
+#include <linux/module.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
@@ -44,29 +45,8 @@ static int zoom2_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
@@ -82,49 +62,6 @@ static struct snd_soc_ops zoom2_ops = {
.hw_params = zoom2_hw_params,
};
-static int zoom2_hw_voice_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret;
-
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
- /* Set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
- SND_SOC_CLOCK_IN);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec system clock\n");
- return ret;
- }
-
- return 0;
-}
-
-static struct snd_soc_ops zoom2_voice_ops = {
- .hw_params = zoom2_hw_voice_params,
-};
-
/* Zoom2 machine DAPM */
static const struct snd_soc_dapm_widget zoom2_twl4030_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Ext Mic", NULL),
@@ -162,23 +99,6 @@ static int zoom2_twl4030_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
-
- /* Add Zoom2 specific widgets */
- ret = snd_soc_dapm_new_controls(dapm, zoom2_twl4030_dapm_widgets,
- ARRAY_SIZE(zoom2_twl4030_dapm_widgets));
- if (ret)
- return ret;
-
- /* Set up Zoom2 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- /* Zoom2 connected pins */
- snd_soc_dapm_enable_pin(dapm, "Ext Mic");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk");
- snd_soc_dapm_enable_pin(dapm, "Headset Mic");
- snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");
- snd_soc_dapm_enable_pin(dapm, "Aux In");
/* TWL4030 not connected pins */
snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
@@ -190,9 +110,7 @@ static int zoom2_twl4030_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "CARKITL");
snd_soc_dapm_nc_pin(dapm, "CARKITR");
- ret = snd_soc_dapm_sync(dapm);
-
- return ret;
+ return 0;
}
static int zoom2_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
@@ -217,6 +135,8 @@ static struct snd_soc_dai_link zoom2_dai[] = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = zoom2_twl4030_init,
.ops = &zoom2_ops,
},
@@ -227,8 +147,10 @@ static struct snd_soc_dai_link zoom2_dai[] = {
.codec_dai_name = "twl4030-voice",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = zoom2_twl4030_voice_init,
- .ops = &zoom2_voice_ops,
+ .ops = &zoom2_ops,
},
};
@@ -237,6 +159,11 @@ static struct snd_soc_card snd_soc_zoom2 = {
.name = "Zoom2",
.dai_link = zoom2_dai,
.num_links = ARRAY_SIZE(zoom2_dai),
+
+ .dapm_widgets = zoom2_twl4030_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(zoom2_twl4030_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *zoom2_snd_device;
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 33ebc46b45b5..ffd2242e305f 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -121,6 +121,7 @@ config SND_PXA2XX_SOC_PALM27X
config SND_SOC_SAARB
tristate "SoC Audio support for Marvell Saarb"
depends on SND_PXA2XX_SOC && MACH_SAARB
+ select MFD_88PM860X
select SND_PXA_SOC_SSP
select SND_SOC_88PM860X
help
@@ -130,6 +131,7 @@ config SND_SOC_SAARB
config SND_SOC_TAVOREVB3
tristate "SoC Audio support for Marvell Tavor EVB3"
depends on SND_PXA2XX_SOC && MACH_TAVOREVB3
+ select MFD_88PM860X
select SND_PXA_SOC_SSP
select SND_SOC_88PM860X
help
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 28757fb9df31..b0e2fb720910 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -299,7 +299,6 @@ static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd)
/* Set up corgi specific audio path audio_map */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_sync(dapm);
return 0;
}
diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c
index dc65650a6fa1..35ed7eb8cff2 100644
--- a/sound/soc/pxa/e740_wm9705.c
+++ b/sound/soc/pxa/e740_wm9705.c
@@ -108,8 +108,6 @@ static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_sync(dapm);
-
return 0;
}
diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c
index 51897fcd911b..ce5f056009a7 100644
--- a/sound/soc/pxa/e750_wm9705.c
+++ b/sound/soc/pxa/e750_wm9705.c
@@ -90,8 +90,6 @@ static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_sync(dapm);
-
return 0;
}
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c
index 053ed208e59f..6a8f38b6c379 100644
--- a/sound/soc/pxa/e800_wm9712.c
+++ b/sound/soc/pxa/e800_wm9712.c
@@ -80,7 +80,6 @@ static int e800_ac97_init(struct snd_soc_pcm_runtime *rtd)
ARRAY_SIZE(e800_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_sync(dapm);
return 0;
}
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index 67dcc36cd621..e79f516c400e 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -92,11 +92,10 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned int acps, acds, width, rate;
+ unsigned int acps, acds, width;
unsigned int div4 = PXA_SSP_CLK_SCDB_4;
int ret = 0;
- rate = params_rate(params);
width = snd_pcm_format_physical_width(params_format(params));
/*
@@ -424,7 +423,6 @@ static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
/* Set up magician specific audio path interconnects */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_sync(dapm);
return 0;
}
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index 38ca6759907e..0b8d1ee738a4 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -151,7 +151,6 @@ static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_enable_pin(dapm, "Front Mic");
snd_soc_dapm_enable_pin(dapm, "GSM Line In");
snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_sync(dapm);
return 0;
}
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c
index 504e4004f004..7edc1fb71fae 100644
--- a/sound/soc/pxa/palm27x.c
+++ b/sound/soc/pxa/palm27x.c
@@ -107,10 +107,6 @@ static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "PHONE");
snd_soc_dapm_nc_pin(dapm, "MIC2");
- err = snd_soc_dapm_sync(dapm);
- if (err)
- return err;
-
/* Jack detection API stuff */
err = snd_soc_jack_new(codec, "Headphone Jack",
SND_JACK_HEADPHONE, &hs_jack);
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index da3ae4316cf2..4c29bc1f9cfe 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -265,7 +265,6 @@ static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd)
/* Set up poodle specific audio path audio_map */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_sync(dapm);
return 0;
}
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index c43060053dd7..600676f709a9 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -11,6 +11,7 @@
*/
#include <linux/dma-mapping.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/soc.h>
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c
index 1a591f1ebfbd..b899a3bc8f42 100644
--- a/sound/soc/pxa/raumfeld.c
+++ b/sound/soc/pxa/raumfeld.c
@@ -306,8 +306,10 @@ static int __init raumfeld_audio_init(void)
&snd_soc_raumfeld_connector);
ret = platform_device_add(raumfeld_audio_device);
- if (ret < 0)
+ if (ret < 0) {
+ platform_device_put(raumfeld_audio_device);
return ret;
+ }
raumfeld_enable_audio(true);
return 0;
diff --git a/sound/soc/pxa/saarb.c b/sound/soc/pxa/saarb.c
index 9595189fc681..d9467a2c6de0 100644
--- a/sound/soc/pxa/saarb.c
+++ b/sound/soc/pxa/saarb.c
@@ -146,10 +146,6 @@ static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_disable_pin(dapm, "Headset Mic 2");
snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
- ret = snd_soc_dapm_sync(dapm);
- if (ret)
- return ret;
-
/* Headset jack detection */
snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
| SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index b253d864868a..c2d6ff9b1588 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -301,7 +301,6 @@ static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
/* Set up spitz specific audio paths */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_sync(dapm);
return 0;
}
@@ -312,7 +311,7 @@ static struct snd_soc_dai_link spitz_dai = {
.cpu_dai_name = "pxa2xx-i2s",
.codec_dai_name = "wm8750-hifi",
.platform_name = "pxa-pcm-audio",
- .codec_name = "wm8750-codec.0-001b",
+ .codec_name = "wm8750.0-001b",
.init = spitz_wm8750_init,
.ops = &spitz_ops,
};
diff --git a/sound/soc/pxa/tavorevb3.c b/sound/soc/pxa/tavorevb3.c
index f881f65ec172..eeec892e0e04 100644
--- a/sound/soc/pxa/tavorevb3.c
+++ b/sound/soc/pxa/tavorevb3.c
@@ -146,10 +146,6 @@ static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_disable_pin(dapm, "Headset Mic 2");
snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
- ret = snd_soc_dapm_sync(dapm);
- if (ret)
- return ret;
-
/* Headset jack detection */
snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
| SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index 9a2351366957..620fc69ae632 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -211,7 +211,6 @@ static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd)
/* set up tosa specific audio path audio_map */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_sync(dapm);
return 0;
}
diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c
index d69d9fc32233..b311ffe04b71 100644
--- a/sound/soc/pxa/z2.c
+++ b/sound/soc/pxa/z2.c
@@ -161,10 +161,6 @@ static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
/* Set up z2 specific audio paths */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
- ret = snd_soc_dapm_sync(dapm);
- if (ret)
- goto err;
-
/* Jack detection API stuff */
ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
&hs_jack);
@@ -198,7 +194,7 @@ static struct snd_soc_dai_link z2_dai = {
.cpu_dai_name = "pxa2xx-i2s",
.codec_dai_name = "wm8750-hifi",
.platform_name = "pxa-pcm-audio",
- .codec_name = "wm8750-codec.0-001b",
+ .codec_name = "wm8750.0-001b",
.init = z2_wm8750_init,
.ops = &z2_ops,
};
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c
index 2b8350b52232..580aae38e502 100644
--- a/sound/soc/pxa/zylonite.c
+++ b/sound/soc/pxa/zylonite.c
@@ -87,7 +87,6 @@ static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_enable_pin(dapm, "Headphone");
snd_soc_dapm_enable_pin(dapm, "Headset Earpiece");
- snd_soc_dapm_sync(dapm);
return 0;
}
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c
index 80c85fd64e1a..55efc2bdf0bd 100644
--- a/sound/soc/s6000/s6000-pcm.c
+++ b/sound/soc/s6000/s6000-pcm.c
@@ -446,7 +446,6 @@ static u64 s6000_pcm_dmamask = DMA_BIT_MASK(32);
static int s6000_pcm_new(struct snd_soc_pcm_runtime *runtime)
{
struct snd_card *card = runtime->card->snd_card;
- struct snd_soc_dai *dai = runtime->cpu_dai;
struct snd_pcm *pcm = runtime->pcm;
struct s6000_pcm_dma_params *params;
int res;
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 65f980ef2870..53aaa69eda03 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -63,7 +63,9 @@ config SND_SOC_SAMSUNG_SMDK_WM8580
config SND_SOC_SAMSUNG_SMDK_WM8994
tristate "SoC I2S Audio support for WM8994 on SMDK"
- depends on SND_SOC_SAMSUNG && (MACH_SMDKV310 || MACH_SMDKC210)
+ depends on SND_SOC_SAMSUNG && (MACH_SMDKV310 || MACH_SMDKC210 || MACH_SMDK4212)
+ depends on I2C=y && GENERIC_HARDIRQS
+ select MFD_WM8994
select SND_SOC_WM8994
select SND_SAMSUNG_I2S
help
@@ -150,7 +152,9 @@ config SND_SOC_SMARTQ
config SND_SOC_GONI_AQUILA_WM8994
tristate "SoC I2S Audio support for AQUILA/GONI - WM8994"
depends on SND_SOC_SAMSUNG && (MACH_GONI || MACH_AQUILA)
+ depends on I2C=y && GENERIC_HARDIRQS
select SND_SAMSUNG_I2S
+ select MFD_WM8994
select SND_SOC_WM8994
help
Say Y if you want to add support for SoC audio on goni or aquila
@@ -158,7 +162,7 @@ config SND_SOC_GONI_AQUILA_WM8994
config SND_SOC_SAMSUNG_SMDK_SPDIF
tristate "SoC S/PDIF Audio support for SMDK"
- depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210 || MACH_SMDKV310)
+ depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210 || MACH_SMDKV310 || MACH_SMDK4212)
select SND_SAMSUNG_SPDIF
help
Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
@@ -173,7 +177,9 @@ config SND_SOC_SMDK_WM8580_PCM
config SND_SOC_SMDK_WM8994_PCM
tristate "SoC PCM Audio support for WM8994 on SMDK"
- depends on SND_SOC_SAMSUNG && (MACH_SMDKC210 || MACH_SMDKV310)
+ depends on SND_SOC_SAMSUNG && (MACH_SMDKC210 || MACH_SMDKV310 || MACH_SMDK4212)
+ depends on I2C=y && GENERIC_HARDIRQS
+ select MFD_WM8994
select SND_SOC_WM8994
select SND_SAMSUNG_PCM
help
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index f97110e72e85..16521e3ffc0c 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/clk.h>
+#include <linux/module.h>
#include <sound/soc.h>
@@ -271,7 +272,10 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
- s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+ if (!dma_data->ops)
+ dma_data->ops = samsung_dma_get_ops();
+
+ dma_data->ops->started(dma_data->channel);
return 0;
}
@@ -317,7 +321,10 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
- s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+ if (!dma_data->ops)
+ dma_data->ops = samsung_dma_get_ops();
+
+ dma_data->ops->started(dma_data->channel);
return 0;
}
@@ -444,7 +451,7 @@ static __devinit int s3c_ac97_probe(struct platform_device *pdev)
}
ret = request_irq(irq_res->start, s3c_ac97_irq,
- IRQF_DISABLED, "AC97", NULL);
+ 0, "AC97", NULL);
if (ret < 0) {
dev_err(&pdev->dev, "ac97: interrupt request failed.\n");
goto err4;
@@ -495,7 +502,7 @@ static __devexit int s3c_ac97_remove(struct platform_device *pdev)
static struct platform_driver s3c_ac97_driver = {
.probe = s3c_ac97_probe,
- .remove = s3c_ac97_remove,
+ .remove = __devexit_p(s3c_ac97_remove),
.driver = {
.name = "samsung-ac97",
.owner = THIS_MODULE,
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
index 9465588b02f2..a68b26441784 100644
--- a/sound/soc/samsung/dma.c
+++ b/sound/soc/samsung/dma.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/dma-mapping.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
@@ -54,7 +55,6 @@ struct runtime_data {
spinlock_t lock;
int state;
unsigned int dma_loaded;
- unsigned int dma_limit;
unsigned int dma_period;
dma_addr_t dma_start;
dma_addr_t dma_pos;
@@ -62,77 +62,79 @@ struct runtime_data {
struct s3c_dma_params *params;
};
+static void audio_buffdone(void *data);
+
/* dma_enqueue
*
* place a dma buffer onto the queue for the dma system
* to handle.
-*/
+ */
static void dma_enqueue(struct snd_pcm_substream *substream)
{
struct runtime_data *prtd = substream->runtime->private_data;
dma_addr_t pos = prtd->dma_pos;
unsigned int limit;
- int ret;
+ struct samsung_dma_prep_info dma_info;
pr_debug("Entered %s\n", __func__);
- if (s3c_dma_has_circular())
- limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
- else
- limit = prtd->dma_limit;
+ limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
pr_debug("%s: loaded %d, limit %d\n",
__func__, prtd->dma_loaded, limit);
- while (prtd->dma_loaded < limit) {
- unsigned long len = prtd->dma_period;
+ dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE);
+ dma_info.direction =
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+ ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ dma_info.fp = audio_buffdone;
+ dma_info.fp_param = substream;
+ dma_info.period = prtd->dma_period;
+ dma_info.len = prtd->dma_period*limit;
+ while (prtd->dma_loaded < limit) {
pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
- if ((pos + len) > prtd->dma_end) {
- len = prtd->dma_end - pos;
- pr_debug("%s: corrected dma len %ld\n", __func__, len);
+ if ((pos + dma_info.period) > prtd->dma_end) {
+ dma_info.period = prtd->dma_end - pos;
+ pr_debug("%s: corrected dma len %ld\n",
+ __func__, dma_info.period);
}
- ret = s3c2410_dma_enqueue(prtd->params->channel,
- substream, pos, len);
+ dma_info.buf = pos;
+ prtd->params->ops->prepare(prtd->params->ch, &dma_info);
- if (ret == 0) {
- prtd->dma_loaded++;
- pos += prtd->dma_period;
- if (pos >= prtd->dma_end)
- pos = prtd->dma_start;
- } else
- break;
+ prtd->dma_loaded++;
+ pos += prtd->dma_period;
+ if (pos >= prtd->dma_end)
+ pos = prtd->dma_start;
}
prtd->dma_pos = pos;
}
-static void audio_buffdone(struct s3c2410_dma_chan *channel,
- void *dev_id, int size,
- enum s3c2410_dma_buffresult result)
+static void audio_buffdone(void *data)
{
- struct snd_pcm_substream *substream = dev_id;
- struct runtime_data *prtd;
+ struct snd_pcm_substream *substream = data;
+ struct runtime_data *prtd = substream->runtime->private_data;
pr_debug("Entered %s\n", __func__);
- if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)
- return;
-
- prtd = substream->runtime->private_data;
+ if (prtd->state & ST_RUNNING) {
+ prtd->dma_pos += prtd->dma_period;
+ if (prtd->dma_pos >= prtd->dma_end)
+ prtd->dma_pos = prtd->dma_start;
- if (substream)
- snd_pcm_period_elapsed(substream);
+ if (substream)
+ snd_pcm_period_elapsed(substream);
- spin_lock(&prtd->lock);
- if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
- prtd->dma_loaded--;
- dma_enqueue(substream);
+ spin_lock(&prtd->lock);
+ if (!samsung_dma_has_circular()) {
+ prtd->dma_loaded--;
+ dma_enqueue(substream);
+ }
+ spin_unlock(&prtd->lock);
}
-
- spin_unlock(&prtd->lock);
}
static int dma_hw_params(struct snd_pcm_substream *substream,
@@ -144,8 +146,7 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
unsigned long totbytes = params_buffer_bytes(params);
struct s3c_dma_params *dma =
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
- int ret = 0;
-
+ struct samsung_dma_info dma_info;
pr_debug("Entered %s\n", __func__);
@@ -163,30 +164,26 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
pr_debug("params %p, client %p, channel %d\n", prtd->params,
prtd->params->client, prtd->params->channel);
- ret = s3c2410_dma_request(prtd->params->channel,
- prtd->params->client, NULL);
-
- if (ret < 0) {
- printk(KERN_ERR "failed to get dma channel\n");
- return ret;
- }
-
- /* use the circular buffering if we have it available. */
- if (s3c_dma_has_circular())
- s3c2410_dma_setflags(prtd->params->channel,
- S3C2410_DMAF_CIRCULAR);
+ prtd->params->ops = samsung_dma_get_ops();
+
+ dma_info.cap = (samsung_dma_has_circular() ?
+ DMA_CYCLIC : DMA_SLAVE);
+ dma_info.client = prtd->params->client;
+ dma_info.direction =
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+ ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ dma_info.width = prtd->params->dma_size;
+ dma_info.fifo = prtd->params->dma_addr;
+ prtd->params->ch = prtd->params->ops->request(
+ prtd->params->channel, &dma_info);
}
- s3c2410_dma_set_buffdone_fn(prtd->params->channel,
- audio_buffdone);
-
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = totbytes;
spin_lock_irq(&prtd->lock);
prtd->dma_loaded = 0;
- prtd->dma_limit = runtime->hw.periods_min;
prtd->dma_period = params_period_bytes(params);
prtd->dma_start = runtime->dma_addr;
prtd->dma_pos = prtd->dma_start;
@@ -202,11 +199,12 @@ static int dma_hw_free(struct snd_pcm_substream *substream)
pr_debug("Entered %s\n", __func__);
- /* TODO - do we need to ensure DMA flushed */
snd_pcm_set_runtime_buffer(substream, NULL);
if (prtd->params) {
- s3c2410_dma_free(prtd->params->channel, prtd->params->client);
+ prtd->params->ops->flush(prtd->params->ch);
+ prtd->params->ops->release(prtd->params->ch,
+ prtd->params->client);
prtd->params = NULL;
}
@@ -225,23 +223,9 @@ static int dma_prepare(struct snd_pcm_substream *substream)
if (!prtd->params)
return 0;
- /* channel needs configuring for mem=>device, increment memory addr,
- * sync to pclk, half-word transfers to the IIS-FIFO. */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- s3c2410_dma_devconfig(prtd->params->channel,
- S3C2410_DMASRC_MEM,
- prtd->params->dma_addr);
- } else {
- s3c2410_dma_devconfig(prtd->params->channel,
- S3C2410_DMASRC_HW,
- prtd->params->dma_addr);
- }
-
- s3c2410_dma_config(prtd->params->channel,
- prtd->params->dma_size);
-
/* flush the DMA channel */
- s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
+ prtd->params->ops->flush(prtd->params->ch);
+
prtd->dma_loaded = 0;
prtd->dma_pos = prtd->dma_start;
@@ -265,14 +249,14 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
prtd->state |= ST_RUNNING;
- s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START);
+ prtd->params->ops->trigger(prtd->params->ch);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
prtd->state &= ~ST_RUNNING;
- s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP);
+ prtd->params->ops->stop(prtd->params->ch);
break;
default:
@@ -291,21 +275,12 @@ dma_pointer(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct runtime_data *prtd = runtime->private_data;
unsigned long res;
- dma_addr_t src, dst;
pr_debug("Entered %s\n", __func__);
- spin_lock(&prtd->lock);
- s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- res = dst - prtd->dma_start;
- else
- res = src - prtd->dma_start;
-
- spin_unlock(&prtd->lock);
+ res = prtd->dma_pos - prtd->dma_start;
- pr_debug("Pointer %x %x\n", src, dst);
+ pr_debug("Pointer offset: %lu\n", res);
/* we seem to be getting the odd error from the pcm library due
* to out-of-bounds pointers. this is maybe due to the dma engine
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h
index c50659269a40..7d1ead77ef21 100644
--- a/sound/soc/samsung/dma.h
+++ b/sound/soc/samsung/dma.h
@@ -6,7 +6,7 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
- * ALSA PCM interface for the Samsung S3C24xx CPU
+ * ALSA PCM interface for the Samsung SoC
*/
#ifndef _S3C_AUDIO_H
@@ -17,6 +17,8 @@ struct s3c_dma_params {
int channel; /* Channel ID */
dma_addr_t dma_addr;
int dma_size; /* Size of the DMA transfer */
+ unsigned ch;
+ struct samsung_dma_ops *ops;
};
#endif
diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c
index eb6d72ed55a7..84f9c3cf7f3e 100644
--- a/sound/soc/samsung/goni_wm8994.c
+++ b/sound/soc/samsung/goni_wm8994.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/jack.h>
@@ -99,14 +100,6 @@ static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
- /* add goni specific widgets */
- snd_soc_dapm_new_controls(dapm, goni_dapm_widgets,
- ARRAY_SIZE(goni_dapm_widgets));
-
- /* set up goni specific audio routes */
- snd_soc_dapm_add_routes(dapm, goni_dapm_routes,
- ARRAY_SIZE(goni_dapm_routes));
-
/* set endpoints to not connected */
snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
@@ -120,8 +113,6 @@ static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "SPKOUTRP");
}
- snd_soc_dapm_sync(dapm);
-
/* Headset jack detection */
ret = snd_soc_jack_new(codec, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
@@ -255,6 +246,11 @@ static struct snd_soc_card goni = {
.name = "goni",
.dai_link = goni_dai,
.num_links = ARRAY_SIZE(goni_dai),
+
+ .dapm_widgets = goni_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(goni_dapm_widgets),
+ .dapm_routes = goni_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(goni_dapm_routes),
};
static int __init goni_init(void)
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index c6c65892294e..03cfa5fcdcca 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -15,6 +15,7 @@
#include <linux/types.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/jack.h>
@@ -182,24 +183,10 @@ static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dapm_context *dapm = &codec->dapm;
int err;
- /* Add h1940 specific widgets */
- err = snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets,
- ARRAY_SIZE(uda1380_dapm_widgets));
- if (err)
- return err;
-
- /* Set up h1940 specific audio path audio_mapnects */
- err = snd_soc_dapm_add_routes(dapm, audio_map,
- ARRAY_SIZE(audio_map));
- if (err)
- return err;
-
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
snd_soc_dapm_enable_pin(dapm, "Speaker");
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
- snd_soc_dapm_sync(dapm);
-
snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
&hp_jack);
@@ -230,6 +217,11 @@ static struct snd_soc_card h1940_asoc = {
.name = "h1940",
.dai_link = h1940_uda1380_dai,
.num_links = ARRAY_SIZE(h1940_uda1380_dai),
+
+ .dapm_widgets = uda1380_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static int __init h1940_init(void)
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index c086b78539ee..bff42bf370b9 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
@@ -1136,7 +1137,7 @@ static __devexit int samsung_i2s_remove(struct platform_device *pdev)
static struct platform_driver samsung_i2s_driver = {
.probe = samsung_i2s_probe,
- .remove = samsung_i2s_remove,
+ .remove = __devexit_p(samsung_i2s_remove),
.driver = {
.name = "samsung-i2s",
.owner = THIS_MODULE,
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index ebde0740ab19..c41178efc908 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c
index 14eb6ea69e7c..1826acf20f7c 100644
--- a/sound/soc/samsung/jive_wm8750.c
+++ b/sound/soc/samsung/jive_wm8750.c
@@ -11,6 +11,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <sound/soc.h>
#include <asm/mach-types.h>
@@ -110,18 +111,6 @@ static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "OUT3");
snd_soc_dapm_nc_pin(dapm, "MONO");
- /* Add jive specific widgets */
- err = snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets,
- ARRAY_SIZE(wm8750_dapm_widgets));
- if (err) {
- printk(KERN_ERR "%s: failed to add widgets (%d)\n",
- __func__, err);
- return err;
- }
-
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_sync(dapm);
-
return 0;
}
@@ -131,7 +120,7 @@ static struct snd_soc_dai_link jive_dai = {
.cpu_dai_name = "s3c2412-i2s",
.codec_dai_name = "wm8750-hifi",
.platform_name = "samsung-audio",
- .codec_name = "wm8750-codec.0-001a",
+ .codec_name = "wm8750.0-001a",
.init = jive_wm8750_init,
.ops = &jive_ops,
};
@@ -141,6 +130,11 @@ static struct snd_soc_card snd_soc_machine_jive = {
.name = "Jive",
.dai_link = &jive_dai,
.num_links = 1,
+
+ .dapm_widgtets = wm8750_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *jive_snd_device;
diff --git a/sound/soc/samsung/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c
index bd91c19a6c08..cde38b8e9dc2 100644
--- a/sound/soc/samsung/ln2440sbc_alc650.c
+++ b/sound/soc/samsung/ln2440sbc_alc650.c
@@ -16,6 +16,7 @@
*
*/
+#include <linux/module.h>
#include <sound/soc.h>
static struct snd_soc_card ln2440sbc;
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index 16152ed08648..7207189cd211 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -367,8 +367,6 @@ static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- snd_soc_dapm_sync(dapm);
-
return 0;
}
@@ -409,8 +407,6 @@ static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm)
snd_soc_dapm_ignore_suspend(dapm, "Handset Spk");
snd_soc_dapm_ignore_suspend(dapm, "Headphone");
- snd_soc_dapm_sync(dapm);
-
return 0;
}
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index 9c7e8b48aed6..05a47cf7f06e 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
@@ -624,7 +625,7 @@ static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
static struct platform_driver s3c_pcm_driver = {
.probe = s3c_pcm_dev_probe,
- .remove = s3c_pcm_dev_remove,
+ .remove = __devexit_p(s3c_pcm_dev_remove),
.driver = {
.name = "samsung-pcm",
.owner = THIS_MODULE,
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index bc8c1676459f..71b4c029fc35 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -19,6 +19,7 @@
#include <linux/types.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/jack.h>
@@ -90,12 +91,6 @@ static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
},
};
-static struct snd_soc_card rx1950_asoc = {
- .name = "rx1950",
- .dai_link = rx1950_uda1380_dai,
- .num_links = ARRAY_SIZE(rx1950_uda1380_dai),
-};
-
/* rx1950 machine dapm widgets */
static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
@@ -117,6 +112,17 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"VINM", NULL, "Mic Jack"},
};
+static struct snd_soc_card rx1950_asoc = {
+ .name = "rx1950",
+ .dai_link = rx1950_uda1380_dai,
+ .num_links = ARRAY_SIZE(rx1950_uda1380_dai),
+
+ .dapm_widgets = uda1380_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
static struct platform_device *s3c24xx_snd_device;
static int rx1950_startup(struct snd_pcm_substream *substream)
@@ -220,26 +226,10 @@ static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dapm_context *dapm = &codec->dapm;
int err;
- /* Add rx1950 specific widgets */
- err = snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets,
- ARRAY_SIZE(uda1380_dapm_widgets));
-
- if (err)
- return err;
-
- /* Set up rx1950 specific audio path audio_mapnects */
- err = snd_soc_dapm_add_routes(dapm, audio_map,
- ARRAY_SIZE(audio_map));
-
- if (err)
- return err;
-
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
snd_soc_dapm_enable_pin(dapm, "Speaker");
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
- snd_soc_dapm_sync(dapm);
-
snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
&hp_jack);
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
index 52074a2b0696..7a73380b3560 100644
--- a/sound/soc/samsung/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -16,6 +16,7 @@
* option) any later version.
*/
+#include <linux/module.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index 841ab14c1100..7bbec25e6e15 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -20,6 +20,7 @@
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
@@ -69,10 +70,10 @@ static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
s3c2412_i2s.iis_cclk = clk_get(dai->dev, "i2sclk");
- if (s3c2412_i2s.iis_cclk == NULL) {
+ if (IS_ERR(s3c2412_i2s.iis_cclk)) {
pr_err("failed to get i2sclk clock\n");
iounmap(s3c2412_i2s.regs);
- return -ENODEV;
+ return PTR_ERR(s3c2412_i2s.iis_cclk);
}
/* Set MPLL as the source for IIS CLK */
@@ -176,7 +177,7 @@ static __devexit int s3c2412_iis_dev_remove(struct platform_device *pdev)
static struct platform_driver s3c2412_iis_driver = {
.probe = s3c2412_iis_dev_probe,
- .remove = s3c2412_iis_dev_remove,
+ .remove = __devexit_p(s3c2412_iis_dev_remove),
.driver = {
.name = "s3c2412-iis",
.owner = THIS_MODULE,
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 63d8849d80bd..558c64bbed2e 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -18,6 +18,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
@@ -383,10 +384,10 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
return -ENXIO;
s3c24xx_i2s.iis_clk = clk_get(dai->dev, "iis");
- if (s3c24xx_i2s.iis_clk == NULL) {
+ if (IS_ERR(s3c24xx_i2s.iis_clk)) {
pr_err("failed to get iis_clock\n");
iounmap(s3c24xx_i2s.regs);
- return -ENODEV;
+ return PTR_ERR(s3c24xx_i2s.iis_clk);
}
clk_enable(s3c24xx_i2s.iis_clk);
@@ -481,7 +482,7 @@ static __devexit int s3c24xx_iis_dev_remove(struct platform_device *pdev)
static struct platform_driver s3c24xx_iis_driver = {
.probe = s3c24xx_iis_dev_probe,
- .remove = s3c24xx_iis_dev_remove,
+ .remove = __devexit_p(s3c24xx_iis_dev_remove),
.driver = {
.name = "s3c24xx-iis",
.owner = THIS_MODULE,
diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c
index 349566f0686b..a253bcc1646a 100644
--- a/sound/soc/samsung/s3c24xx_simtec.c
+++ b/sound/soc/samsung/s3c24xx_simtec.c
@@ -9,6 +9,7 @@
#include <linux/gpio.h>
#include <linux/clk.h>
+#include <linux/module.h>
#include <sound/soc.h>
@@ -300,7 +301,7 @@ static void detach_gpio_amp(struct s3c24xx_audio_simtec_pdata *pd)
}
#ifdef CONFIG_PM
-int simtec_audio_resume(struct device *dev)
+static int simtec_audio_resume(struct device *dev)
{
simtec_call_startup(pdata);
return 0;
diff --git a/sound/soc/samsung/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c
index ce6aef604179..d125e79baf7f 100644
--- a/sound/soc/samsung/s3c24xx_simtec_hermes.c
+++ b/sound/soc/samsung/s3c24xx_simtec_hermes.c
@@ -7,6 +7,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <sound/soc.h>
#include "s3c24xx_simtec.h"
@@ -65,18 +66,12 @@ static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- snd_soc_dapm_new_controls(dapm, dapm_widgets,
- ARRAY_SIZE(dapm_widgets));
-
- snd_soc_dapm_add_routes(dapm, base_map, ARRAY_SIZE(base_map));
-
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
snd_soc_dapm_enable_pin(dapm, "Line In");
snd_soc_dapm_enable_pin(dapm, "Line Out");
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
simtec_audio_init(rtd);
- snd_soc_dapm_sync(dapm);
return 0;
}
@@ -96,6 +91,11 @@ static struct snd_soc_card snd_soc_machine_simtec_aic33 = {
.name = "Simtec-Hermes",
.dai_link = &simtec_dai_aic33,
.num_links = 1,
+
+ .dapm_widgets = dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
+ .dapm_routes = base_map,
+ .num_dapm_routes = ARRAY_SIZE(base_map),
};
static int __devinit simtec_audio_hermes_probe(struct platform_device *pd)
diff --git a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
index a7ef7db54687..5e4fd46b7200 100644
--- a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
+++ b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
@@ -7,6 +7,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <sound/soc.h>
#include "s3c24xx_simtec.h"
@@ -54,18 +55,12 @@ static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- snd_soc_dapm_new_controls(dapm, dapm_widgets,
- ARRAY_SIZE(dapm_widgets));
-
- snd_soc_dapm_add_routes(dapm, base_map, ARRAY_SIZE(base_map));
-
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
snd_soc_dapm_enable_pin(dapm, "Line In");
snd_soc_dapm_enable_pin(dapm, "Line Out");
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
simtec_audio_init(rtd);
- snd_soc_dapm_sync(dapm);
return 0;
}
@@ -85,6 +80,11 @@ static struct snd_soc_card snd_soc_machine_simtec_aic23 = {
.name = "Simtec",
.dai_link = &simtec_dai_aic23,
.num_links = 1,
+
+ .dapm_widgets = dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
+ .dapm_routes = base_map,
+ .num_dapm_routes = ARRAY_SIZE(base_map),
};
static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd)
diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c
index dc9d551f6788..548c6ac6e7b0 100644
--- a/sound/soc/samsung/s3c24xx_uda134x.c
+++ b/sound/soc/samsung/s3c24xx_uda134x.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/s3c24xx_uda134x.h>
@@ -66,17 +67,17 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
pr_debug("%s %d\n", __func__, clk_users);
if (clk_users == 0) {
xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal");
- if (!xtal) {
+ if (IS_ERR(xtal)) {
printk(KERN_ERR "%s cannot get xtal\n", __func__);
- ret = -EBUSY;
+ ret = PTR_ERR(xtal);
} else {
pclk = clk_get(&s3c24xx_uda134x_snd_device->dev,
"pclk");
- if (!pclk) {
+ if (IS_ERR(pclk)) {
printk(KERN_ERR "%s cannot get pclk\n",
__func__);
clk_put(xtal);
- ret = -EBUSY;
+ ret = PTR_ERR(pclk);
}
}
if (!ret) {
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
index 0a2c4f223038..a22fc4402802 100644
--- a/sound/soc/samsung/smartq_wm8987.c
+++ b/sound/soc/samsung/smartq_wm8987.c
@@ -14,6 +14,7 @@
*/
#include <linux/gpio.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/jack.h>
@@ -153,20 +154,6 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dapm_context *dapm = &codec->dapm;
int err = 0;
- /* Add SmartQ specific widgets */
- snd_soc_dapm_new_controls(dapm, wm8987_dapm_widgets,
- ARRAY_SIZE(wm8987_dapm_widgets));
-
- /* add SmartQ specific controls */
- err = snd_soc_add_controls(codec, wm8987_smartq_controls,
- ARRAY_SIZE(wm8987_smartq_controls));
-
- if (err < 0)
- return err;
-
- /* setup SmartQ specific audio path */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
/* set endpoints to not connected */
snd_soc_dapm_nc_pin(dapm, "LINPUT1");
snd_soc_dapm_nc_pin(dapm, "RINPUT1");
@@ -178,10 +165,6 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_enable_pin(dapm, "Internal Mic");
snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
- err = snd_soc_dapm_sync(dapm);
- if (err)
- return err;
-
/* Headphone jack detection */
err = snd_soc_jack_new(codec, "Headphone Jack",
SND_JACK_HEADPHONE, &smartq_jack);
@@ -207,7 +190,7 @@ static struct snd_soc_dai_link smartq_dai[] = {
.cpu_dai_name = "samsung-i2s.0",
.codec_dai_name = "wm8750-hifi",
.platform_name = "samsung-audio",
- .codec_name = "wm8750-codec.0-0x1a",
+ .codec_name = "wm8750.0-0x1a",
.init = smartq_wm8987_init,
.ops = &smartq_hifi_ops,
},
@@ -217,6 +200,13 @@ static struct snd_soc_card snd_soc_smartq = {
.name = "SmartQ",
.dai_link = smartq_dai,
.num_links = ARRAY_SIZE(smartq_dai),
+
+ .dapm_widgets = wm8987_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8987_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+ .controls = wm8987_smartq_controls,
+ .num_controls = ARRAY_SIZE(wm8987_smartq_controls),
};
static struct platform_device *smartq_snd_device;
diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c
index e8ac961c6ba1..e0fd8ad23552 100644
--- a/sound/soc/samsung/smdk_spdif.c
+++ b/sound/soc/samsung/smdk_spdif.c
@@ -11,6 +11,7 @@
*/
#include <linux/clk.h>
+#include <linux/module.h>
#include <sound/soc.h>
diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c
index 3d26f6607aa4..81b447823992 100644
--- a/sound/soc/samsung/smdk_wm8580.c
+++ b/sound/soc/samsung/smdk_wm8580.c
@@ -10,6 +10,7 @@
* option) any later version.
*/
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
@@ -119,30 +120,24 @@ static struct snd_soc_ops smdk_ops = {
};
/* SMDK Playback widgets */
-static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
+static const struct snd_soc_dapm_widget smdk_wm8580_dapm_widgets[] = {
SND_SOC_DAPM_HP("Front", NULL),
SND_SOC_DAPM_HP("Center+Sub", NULL),
SND_SOC_DAPM_HP("Rear", NULL),
-};
-/* SMDK Capture widgets */
-static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = {
SND_SOC_DAPM_MIC("MicIn", NULL),
SND_SOC_DAPM_LINE("LineIn", NULL),
};
/* SMDK-PAIFTX connections */
-static const struct snd_soc_dapm_route audio_map_tx[] = {
+static const struct snd_soc_dapm_route smdk_wm8580_audio_map[] = {
/* MicIn feeds AINL */
{"AINL", NULL, "MicIn"},
/* LineIn feeds AINL/R */
{"AINL", NULL, "LineIn"},
{"AINR", NULL, "LineIn"},
-};
-/* SMDK-PAIFRX connections */
-static const struct snd_soc_dapm_route audio_map_rx[] = {
/* Front Left/Right are fed VOUT1L/R */
{"Front", NULL, "VOUT1L"},
{"Front", NULL, "VOUT1R"},
@@ -161,39 +156,11 @@ static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- /* Add smdk specific Capture widgets */
- snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets_cpt,
- ARRAY_SIZE(wm8580_dapm_widgets_cpt));
-
- /* Set up PAIFTX audio path */
- snd_soc_dapm_add_routes(dapm, audio_map_tx, ARRAY_SIZE(audio_map_tx));
-
/* Enabling the microphone requires the fitting of a 0R
* resistor to connect the line from the microphone jack.
*/
snd_soc_dapm_disable_pin(dapm, "MicIn");
- /* signal a DAPM event */
- snd_soc_dapm_sync(dapm);
-
- return 0;
-}
-
-static int smdk_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- /* Add smdk specific Playback widgets */
- snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets_pbk,
- ARRAY_SIZE(wm8580_dapm_widgets_pbk));
-
- /* Set up PAIFRX audio path */
- snd_soc_dapm_add_routes(dapm, audio_map_rx, ARRAY_SIZE(audio_map_rx));
-
- /* signal a DAPM event */
- snd_soc_dapm_sync(dapm);
-
return 0;
}
@@ -210,8 +177,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
.cpu_dai_name = "samsung-i2s.0",
.codec_dai_name = "wm8580-hifi-playback",
.platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
- .init = smdk_wm8580_init_paifrx,
+ .codec_name = "wm8580.0-001b",
.ops = &smdk_ops,
},
[PRI_CAPTURE] = { /* Primary Capture i/f */
@@ -220,7 +186,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
.cpu_dai_name = "samsung-i2s.0",
.codec_dai_name = "wm8580-hifi-capture",
.platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
+ .codec_name = "wm8580.0-001b",
.init = smdk_wm8580_init_paiftx,
.ops = &smdk_ops,
},
@@ -230,8 +196,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
.cpu_dai_name = "samsung-i2s.x",
.codec_dai_name = "wm8580-hifi-playback",
.platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
- .init = smdk_wm8580_init_paifrx,
+ .codec_name = "wm8580.0-001b",
.ops = &smdk_ops,
},
};
@@ -240,6 +205,11 @@ static struct snd_soc_card smdk = {
.name = "SMDK-I2S",
.dai_link = smdk_dai,
.num_links = 2,
+
+ .dapm_widgets = smdk_wm8580_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(smdk_wm8580_dapm_widgets),
+ .dapm_routes = smdk_wm8580_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(smdk_wm8580_audio_map),
};
static struct platform_device *smdk_snd_device;
diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c
index 0d12092df164..0677473e6b60 100644
--- a/sound/soc/samsung/smdk_wm8580pcm.c
+++ b/sound/soc/samsung/smdk_wm8580pcm.c
@@ -8,6 +8,7 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include <sound/pcm.h>
@@ -127,7 +128,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
.cpu_dai_name = "samsung-pcm.0",
.codec_dai_name = "wm8580-hifi-playback",
.platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
+ .codec_name = "wm8580.0-001b",
.ops = &smdk_wm8580_pcm_ops,
}, {
.name = "WM8580 PAIF PCM TX",
@@ -135,7 +136,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
.cpu_dai_name = "samsung-pcm.0",
.codec_dai_name = "wm8580-hifi-capture",
.platform_name = "samsung-audio",
- .codec_name = "wm8580-codec.0-001b",
+ .codec_name = "wm8580.0-001b",
.ops = &smdk_wm8580_pcm_ops,
},
};
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c
index 45fbe2b3727f..f75e43997d5b 100644
--- a/sound/soc/samsung/smdk_wm8994.c
+++ b/sound/soc/samsung/smdk_wm8994.c
@@ -117,8 +117,6 @@ static int smdk_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "IN1RP");
snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
- snd_soc_dapm_sync(dapm);
-
return 0;
}
diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c
index 5f2111685480..da9c2a264d93 100644
--- a/sound/soc/samsung/smdk_wm8994pcm.c
+++ b/sound/soc/samsung/smdk_wm8994pcm.c
@@ -9,6 +9,7 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c
index fffe3c1dd1bd..31c6daf6d4d0 100644
--- a/sound/soc/samsung/smdk_wm9713.c
+++ b/sound/soc/samsung/smdk_wm9713.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/module.h>
#include <sound/soc.h>
static struct snd_soc_card smdk;
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 28c491dacf7a..468cff1bb1af 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -12,6 +12,7 @@
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
@@ -340,7 +341,7 @@ static struct snd_soc_dai_ops spdif_dai_ops = {
.shutdown = spdif_shutdown,
};
-struct snd_soc_dai_driver samsung_spdif_dai = {
+static struct snd_soc_dai_driver samsung_spdif_dai = {
.name = "samsung-spdif",
.playback = {
.stream_name = "S/PDIF Playback",
@@ -475,7 +476,7 @@ static __devexit int spdif_remove(struct platform_device *pdev)
static struct platform_driver samsung_spdif_driver = {
.probe = spdif_probe,
- .remove = spdif_remove,
+ .remove = __devexit_p(spdif_remove),
.driver = {
.name = "samsung-spdif",
.owner = THIS_MODULE,
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 590e9274b062..85bf541a771d 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -13,6 +13,7 @@
#include <sound/soc-dapm.h>
#include <sound/jack.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include "../codecs/wm8996.h"
#include "../codecs/wm9081.h"
@@ -125,10 +126,6 @@ static struct snd_soc_jack_pin speyside_headset_pins[] = {
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
- {
- .pin = "Headphone",
- .mask = SND_JACK_HEADPHONE,
- },
};
/* Default the headphone selection to active high */
@@ -171,7 +168,8 @@ static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
ret = snd_soc_jack_new(codec, "Headset",
- SND_JACK_HEADSET | SND_JACK_BTN_0,
+ SND_JACK_LINEOUT | SND_JACK_HEADSET |
+ SND_JACK_BTN_0,
&speyside_headset);
if (ret)
return ret;
@@ -227,7 +225,7 @@ static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm)
snd_soc_dapm_nc_pin(dapm, "LINEOUT");
/* At any time the WM9081 is active it will have this clock */
- return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK,
+ return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0,
48000 * 256, 0);
}
@@ -252,6 +250,7 @@ static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("Main AMIC"),
SOC_DAPM_PIN_SWITCH("WM1250 Input"),
SOC_DAPM_PIN_SWITCH("WM1250 Output"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
};
static struct snd_soc_dapm_widget widgets[] = {
diff --git a/sound/soc/samsung/speyside_wm8962.c b/sound/soc/samsung/speyside_wm8962.c
index 72535f2daaf2..e3e27166cc50 100644
--- a/sound/soc/samsung/speyside_wm8962.c
+++ b/sound/soc/samsung/speyside_wm8962.c
@@ -13,9 +13,12 @@
#include <sound/soc-dapm.h>
#include <sound/jack.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include "../codecs/wm8962.h"
+static int sample_rate = 44100;
+
static int speyside_wm8962_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
@@ -31,13 +34,13 @@ static int speyside_wm8962_set_bias_level(struct snd_soc_card *card,
if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
WM8962_FLL_MCLK, 32768,
- 44100 * 256);
+ sample_rate * 512);
if (ret < 0)
pr_err("Failed to start FLL: %d\n", ret);
ret = snd_soc_dai_set_sysclk(codec_dai,
WM8962_SYSCLK_FLL,
- 44100 * 256,
+ sample_rate * 512,
SND_SOC_CLOCK_IN);
if (ret < 0) {
pr_err("Failed to set SYSCLK: %d\n", ret);
@@ -92,22 +95,7 @@ static int speyside_wm8962_set_bias_level_post(struct snd_soc_card *card,
static int speyside_wm8962_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- int ret;
-
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
- | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
- | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
+ sample_rate = params_rate(params);
return 0;
}
@@ -124,12 +112,15 @@ static struct snd_soc_dai_link speyside_wm8962_dai[] = {
.codec_dai_name = "wm8962",
.platform_name = "samsung-audio",
.codec_name = "wm8962.1-001a",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
.ops = &speyside_wm8962_ops,
},
};
static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("Main Speaker"),
+ SOC_DAPM_PIN_SWITCH("DMIC"),
};
static struct snd_soc_dapm_widget widgets[] = {
@@ -137,6 +128,7 @@ static struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("DMIC", NULL),
+ SND_SOC_DAPM_MIC("AMIC", NULL),
SND_SOC_DAPM_SPK("Main Speaker", NULL),
};
@@ -148,12 +140,16 @@ static struct snd_soc_dapm_route audio_paths[] = {
{ "Main Speaker", NULL, "SPKOUTL" },
{ "Main Speaker", NULL, "SPKOUTR" },
- { "MICBIAS", NULL, "Headset Mic" },
- { "IN4L", NULL, "MICBIAS" },
- { "IN4R", NULL, "MICBIAS" },
+ { "Headset Mic", NULL, "MICBIAS" },
+ { "IN4L", NULL, "Headset Mic" },
+ { "IN4R", NULL, "Headset Mic" },
+
+ { "AMIC", NULL, "MICBIAS" },
+ { "IN1L", NULL, "AMIC" },
+ { "IN1R", NULL, "AMIC" },
- { "MICBIAS", NULL, "DMIC" },
- { "DMICDAT", NULL, "MICBIAS" },
+ { "DMIC", NULL, "MICBIAS" },
+ { "DMICDAT", NULL, "DMIC" },
};
static struct snd_soc_jack speyside_wm8962_headset;
diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c
index 770a71a15366..dff64b95f5dc 100644
--- a/sound/soc/sh/fsi-ak4642.c
+++ b/sound/soc/sh/fsi-ak4642.c
@@ -10,6 +10,7 @@
*/
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/sh_fsi.h>
struct fsi_ak4642_data {
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
index 59553fd8c2fb..f5586b5b0c3b 100644
--- a/sound/soc/sh/fsi-da7210.c
+++ b/sound/soc/sh/fsi-da7210.c
@@ -11,6 +11,7 @@
*/
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/sh_fsi.h>
static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd)
diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c
index d3d9fd880680..3ebebe706ad3 100644
--- a/sound/soc/sh/fsi-hdmi.c
+++ b/sound/soc/sh/fsi-hdmi.c
@@ -10,6 +10,7 @@
*/
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/sh_fsi.h>
struct fsi_hdmi_data {
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 8e112ccffb13..3d7016e128f9 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -16,6 +16,7 @@
#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/sh_fsi.h>
@@ -210,7 +211,7 @@ struct fsi_master {
* basic read write function
*/
-static void __fsi_reg_write(u32 reg, u32 data)
+static void __fsi_reg_write(u32 __iomem *reg, u32 data)
{
/* valid data area is 24bit */
data &= 0x00ffffff;
@@ -218,12 +219,12 @@ static void __fsi_reg_write(u32 reg, u32 data)
__raw_writel(data, reg);
}
-static u32 __fsi_reg_read(u32 reg)
+static u32 __fsi_reg_read(u32 __iomem *reg)
{
return __raw_readl(reg);
}
-static void __fsi_reg_mask_set(u32 reg, u32 mask, u32 data)
+static void __fsi_reg_mask_set(u32 __iomem *reg, u32 mask, u32 data)
{
u32 val = __fsi_reg_read(reg);
@@ -250,7 +251,7 @@ static u32 _fsi_master_read(struct fsi_master *master, u32 reg)
unsigned long flags;
spin_lock_irqsave(&master->lock, flags);
- ret = __fsi_reg_read((u32)(master->base + reg));
+ ret = __fsi_reg_read(master->base + reg);
spin_unlock_irqrestore(&master->lock, flags);
return ret;
@@ -264,7 +265,7 @@ static void _fsi_master_mask_set(struct fsi_master *master,
unsigned long flags;
spin_lock_irqsave(&master->lock, flags);
- __fsi_reg_mask_set((u32)(master->base + reg), mask, data);
+ __fsi_reg_mask_set(master->base + reg, mask, data);
spin_unlock_irqrestore(&master->lock, flags);
}
@@ -1285,7 +1286,7 @@ static int fsi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
dev_set_drvdata(&pdev->dev, master);
- ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED,
+ ret = request_irq(irq, &fsi_interrupt, 0,
id_entry->name, master);
if (ret) {
dev_err(&pdev->dev, "irq request err\n");
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c
index 917d3ceadc9d..c62ae689c4a1 100644
--- a/sound/soc/sh/sh7760-ac97.c
+++ b/sound/soc/sh/sh7760-ac97.c
@@ -20,12 +20,6 @@
extern struct snd_soc_dai_driver sh4_hac_dai[2];
extern struct snd_soc_platform_driver sh7760_soc_platform;
-static int machine_init(struct snd_soc_pcm_runtime *rtd)
-{
- snd_soc_dapm_sync(&rtd->codec->dapm);
- return 0;
-}
-
static struct snd_soc_dai_link sh7760_ac97_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
@@ -33,7 +27,6 @@ static struct snd_soc_dai_link sh7760_ac97_dai = {
.codec_dai_name = "ac97-hifi",
.platform_name = "sh7760-pcm-audio",
.codec_name = "ac97-codec",
- .init = machine_init,
.ops = NULL,
};
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
index 4973c2939d79..edacfeb13b94 100644
--- a/sound/soc/sh/siu_dai.c
+++ b/sound/soc/sh/siu_dai.c
@@ -23,6 +23,7 @@
#include <linux/firmware.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <asm/clock.h>
#include <asm/siu.h>
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
index 05192d97b377..e0c621c0553b 100644
--- a/sound/soc/sh/ssi.c
+++ b/sound/soc/sh/ssi.c
@@ -342,7 +342,7 @@ static struct snd_soc_dai_ops ssi_dai_ops = {
.set_fmt = ssi_set_fmt,
};
-struct snd_soc_dai_driver sh4_ssi_dai[] = {
+static struct snd_soc_dai_driver sh4_ssi_dai[] = {
{
.name = "ssi-dai.0",
.playback = {
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index 20b7f3b003a3..9077aa4b3b4e 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -17,6 +17,7 @@
#include <linux/lzo.h>
#include <linux/bitmap.h>
#include <linux/rbtree.h>
+#include <linux/export.h>
#include <trace/events/asoc.h>
@@ -548,9 +549,6 @@ static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec,
static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec)
{
- const struct snd_soc_codec_driver *codec_drv;
-
- codec_drv = codec->driver;
return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
}
@@ -868,10 +866,6 @@ static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
{
- const struct snd_soc_codec_driver *codec_drv;
-
- codec_drv = codec->driver;
-
if (codec->reg_def_copy)
codec->reg_cache = kmemdup(codec->reg_def_copy,
codec->reg_size, GFP_KERNEL);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index ef69f5a02709..a5d3685a5d38 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -106,7 +106,7 @@ static int format_register_str(struct snd_soc_codec *codec,
if (wordsize + regsize + 2 + 1 != len)
return -EINVAL;
- ret = snd_soc_read(codec , reg);
+ ret = snd_soc_read(codec, reg);
if (ret < 0) {
memset(regbuf, 'X', regsize);
regbuf[regsize] = '\0';
@@ -144,7 +144,7 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf,
step = codec->driver->reg_cache_step;
for (i = 0; i < codec->driver->reg_cache_size; i += step) {
- if (codec->readable_register && !codec->readable_register(codec, i))
+ if (!snd_soc_codec_readable_register(codec, i))
continue;
if (codec->driver->display_register) {
count += codec->driver->display_register(codec, buf + count,
@@ -245,7 +245,6 @@ static ssize_t codec_reg_write_file(struct file *file,
size_t buf_size;
char *start = buf;
unsigned long reg, value;
- int step = 1;
struct snd_soc_codec *codec = file->private_data;
buf_size = min(count, (sizeof(buf)-1));
@@ -253,9 +252,6 @@ static ssize_t codec_reg_write_file(struct file *file,
return -EFAULT;
buf[buf_size] = 0;
- if (codec->driver->reg_cache_step)
- step = codec->driver->reg_cache_step;
-
while (*start == ' ')
start++;
reg = simple_strtoul(start, &start, 16);
@@ -957,6 +953,8 @@ static int soc_probe_codec(struct snd_soc_card *card,
snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
driver->num_dapm_widgets);
+ codec->dapm.idle_bias_off = driver->idle_bias_off;
+
if (driver->probe) {
ret = driver->probe(codec);
if (ret < 0) {
@@ -1057,6 +1055,9 @@ static int soc_post_component_init(struct snd_soc_card *card,
}
rtd->card = card;
+ /* Make sure all DAPM widgets are instantiated */
+ snd_soc_dapm_new_widgets(&codec->dapm);
+
/* machine controls, routes and widgets are not prefixed */
temp = codec->name_prefix;
codec->name_prefix = NULL;
@@ -1072,9 +1073,6 @@ static int soc_post_component_init(struct snd_soc_card *card,
}
codec->name_prefix = temp;
- /* Make sure all DAPM widgets are instantiated */
- snd_soc_dapm_new_widgets(&codec->dapm);
-
/* register the rtd device */
rtd->codec = codec;
rtd->dev.parent = card->dev;
@@ -1319,6 +1317,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
struct snd_soc_codec *codec;
struct snd_soc_codec_conf *codec_conf;
enum snd_soc_compress_type compress_type;
+ struct snd_soc_dai_link *dai_link;
int ret, i, order;
mutex_lock(&card->mutex);
@@ -1431,6 +1430,28 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
card->num_dapm_routes);
+ snd_soc_dapm_new_widgets(&card->dapm);
+
+ for (i = 0; i < card->num_links; i++) {
+ dai_link = &card->dai_link[i];
+
+ if (dai_link->dai_fmt) {
+ ret = snd_soc_dai_set_fmt(card->rtd[i].codec_dai,
+ dai_link->dai_fmt);
+ if (ret != 0)
+ dev_warn(card->rtd[i].codec_dai->dev,
+ "Failed to set DAI format: %d\n",
+ ret);
+
+ ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
+ dai_link->dai_fmt);
+ if (ret != 0)
+ dev_warn(card->rtd[i].cpu_dai->dev,
+ "Failed to set DAI format: %d\n",
+ ret);
+ }
+ }
+
snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
"%s", card->name);
snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
@@ -1459,6 +1480,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
}
}
+ snd_soc_dapm_new_widgets(&card->dapm);
+
ret = snd_card_register(card->snd_card);
if (ret < 0) {
printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
@@ -1479,6 +1502,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
#endif
card->instantiated = 1;
+ snd_soc_dapm_sync(&card->dapm);
mutex_unlock(&card->mutex);
return;
@@ -2229,7 +2253,8 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
* @kcontrol: mixer control
* @uinfo: control element information
*
- * Callback to provide information about a single mixer control.
+ * Callback to provide information about a single mixer control, or a double
+ * mixer control that spans 2 registers.
*
* Returns 0 for success.
*/
@@ -2239,8 +2264,6 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
int platform_max;
- unsigned int shift = mc->shift;
- unsigned int rshift = mc->rshift;
if (!mc->platform_max)
mc->platform_max = mc->max;
@@ -2251,7 +2274,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
else
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = shift == rshift ? 1 : 2;
+ uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = platform_max;
return 0;
@@ -2263,7 +2286,8 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
* @kcontrol: mixer control
* @ucontrol: control element information
*
- * Callback to get the value of a single mixer control.
+ * Callback to get the value of a single mixer control, or a double mixer
+ * control that spans 2 registers.
*
* Returns 0 for success.
*/
@@ -2274,6 +2298,7 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
unsigned int rshift = mc->rshift;
int max = mc->max;
@@ -2282,13 +2307,18 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] =
(snd_soc_read(codec, reg) >> shift) & mask;
- if (shift != rshift)
- ucontrol->value.integer.value[1] =
- (snd_soc_read(codec, reg) >> rshift) & mask;
- if (invert) {
+ if (invert)
ucontrol->value.integer.value[0] =
max - ucontrol->value.integer.value[0];
- if (shift != rshift)
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ if (reg == reg2)
+ ucontrol->value.integer.value[1] =
+ (snd_soc_read(codec, reg) >> rshift) & mask;
+ else
+ ucontrol->value.integer.value[1] =
+ (snd_soc_read(codec, reg2) >> shift) & mask;
+ if (invert)
ucontrol->value.integer.value[1] =
max - ucontrol->value.integer.value[1];
}
@@ -2302,7 +2332,8 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
* @kcontrol: mixer control
* @ucontrol: control element information
*
- * Callback to set the value of a single mixer control.
+ * Callback to set the value of a single mixer control, or a double mixer
+ * control that spans 2 registers.
*
* Returns 0 for success.
*/
@@ -2313,143 +2344,44 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
unsigned int rshift = mc->rshift;
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
- unsigned int val, val2, val_mask;
+ int err;
+ bool type_2r = 0;
+ unsigned int val2 = 0;
+ unsigned int val, val_mask;
val = (ucontrol->value.integer.value[0] & mask);
if (invert)
val = max - val;
val_mask = mask << shift;
val = val << shift;
- if (shift != rshift) {
+ if (snd_soc_volsw_is_stereo(mc)) {
val2 = (ucontrol->value.integer.value[1] & mask);
if (invert)
val2 = max - val2;
- val_mask |= mask << rshift;
- val |= val2 << rshift;
- }
- return snd_soc_update_bits_locked(codec, reg, val_mask, val);
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
-
-/**
- * snd_soc_info_volsw_2r - double mixer info callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Callback to provide information about a double mixer control that
- * spans 2 codec registers.
- *
- * Returns 0 for success.
- */
-int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int platform_max;
-
- if (!mc->platform_max)
- mc->platform_max = mc->max;
- platform_max = mc->platform_max;
-
- if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume"))
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- else
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = platform_max;
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r);
-
-/**
- * snd_soc_get_volsw_2r - double mixer get callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to get the value of a double mixer control that spans 2 registers.
- *
- * Returns 0 for success.
- */
-int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
- unsigned int shift = mc->shift;
- int max = mc->max;
- unsigned int mask = (1 << fls(max)) - 1;
- unsigned int invert = mc->invert;
-
- ucontrol->value.integer.value[0] =
- (snd_soc_read(codec, reg) >> shift) & mask;
- ucontrol->value.integer.value[1] =
- (snd_soc_read(codec, reg2) >> shift) & mask;
- if (invert) {
- ucontrol->value.integer.value[0] =
- max - ucontrol->value.integer.value[0];
- ucontrol->value.integer.value[1] =
- max - ucontrol->value.integer.value[1];
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r);
-
-/**
- * snd_soc_put_volsw_2r - double mixer set callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to set the value of a double mixer control that spans 2 registers.
- *
- * Returns 0 for success.
- */
-int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
- unsigned int shift = mc->shift;
- int max = mc->max;
- unsigned int mask = (1 << fls(max)) - 1;
- unsigned int invert = mc->invert;
- int err;
- unsigned int val, val2, val_mask;
-
- val_mask = mask << shift;
- val = (ucontrol->value.integer.value[0] & mask);
- val2 = (ucontrol->value.integer.value[1] & mask);
-
- if (invert) {
- val = max - val;
- val2 = max - val2;
+ if (reg == reg2) {
+ val_mask |= mask << rshift;
+ val |= val2 << rshift;
+ } else {
+ val2 = val2 << shift;
+ type_2r = 1;
+ }
}
-
- val = val << shift;
- val2 = val2 << shift;
-
err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
if (err < 0)
return err;
- err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2);
+ if (type_2r)
+ err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2);
+
return err;
}
-EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r);
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
/**
* snd_soc_info_volsw_s8 - signed mixer info callback
@@ -2680,7 +2612,7 @@ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
if (dai->driver && dai->driver->ops->set_sysclk)
return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
else if (dai->codec && dai->codec->driver->set_sysclk)
- return dai->codec->driver->set_sysclk(dai->codec, clk_id,
+ return dai->codec->driver->set_sysclk(dai->codec, clk_id, 0,
freq, dir);
else
return -EINVAL;
@@ -2691,16 +2623,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
* snd_soc_codec_set_sysclk - configure CODEC system or master clock.
* @codec: CODEC
* @clk_id: DAI specific clock ID
+ * @source: Source for the clock
* @freq: new clock frequency in Hz
* @dir: new clock direction - input/output.
*
* Configures the CODEC master (MCLK) or system (SYSCLK) clocking.
*/
int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
- unsigned int freq, int dir)
+ int source, unsigned int freq, int dir)
{
if (codec->driver->set_sysclk)
- return codec->driver->set_sysclk(codec, clk_id, freq, dir);
+ return codec->driver->set_sysclk(codec, clk_id, source,
+ freq, dir);
else
return -EINVAL;
}
@@ -2895,6 +2829,7 @@ int snd_soc_register_card(struct snd_soc_card *card)
card->rtd[i].dai_link = &card->dai_link[i];
INIT_LIST_HEAD(&card->list);
+ INIT_LIST_HEAD(&card->dapm_dirty);
card->instantiated = 0;
mutex_init(&card->mutex);
@@ -3153,6 +3088,7 @@ int snd_soc_register_platform(struct device *dev,
platform->driver = platform_drv;
platform->dapm.dev = dev;
platform->dapm.platform = platform;
+ platform->dapm.stream_event = platform_drv->stream_event;
mutex_lock(&client_mutex);
list_add(&platform->list, &platform_list);
@@ -3265,6 +3201,7 @@ int snd_soc_register_codec(struct device *dev,
codec->dapm.dev = dev;
codec->dapm.codec = codec;
codec->dapm.seq_notifier = codec_drv->seq_notifier;
+ codec->dapm.stream_event = codec_drv->stream_event;
codec->dev = dev;
codec->driver = codec_drv;
codec->num_dai = num_dai;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index d67c637557a7..f42e8b9fb17d 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -48,6 +48,8 @@
#include <trace/events/asoc.h>
+#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
+
/* dapm power sequences - make this per codec in the future */
static int dapm_up_seq[] = {
[snd_soc_dapm_pre] = 0,
@@ -117,6 +119,21 @@ static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
kfree(buf);
}
+static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
+{
+ return !list_empty(&w->dirty);
+}
+
+void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
+{
+ if (!dapm_dirty_widget(w)) {
+ dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
+ w->name, reason);
+ list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
+ }
+}
+EXPORT_SYMBOL_GPL(dapm_mark_dirty);
+
/* create a new dapm widget */
static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
const struct snd_soc_dapm_widget *_widget)
@@ -316,7 +333,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
}
}
break;
- /* does not effect routing - always connected */
+ /* does not affect routing - always connected */
case snd_soc_dapm_pga:
case snd_soc_dapm_out_drv:
case snd_soc_dapm_output:
@@ -328,13 +345,13 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
case snd_soc_dapm_supply:
case snd_soc_dapm_aif_in:
case snd_soc_dapm_aif_out:
- p->connect = 1;
- break;
- /* does effect routing - dynamically connected */
case snd_soc_dapm_hp:
case snd_soc_dapm_mic:
case snd_soc_dapm_spk:
case snd_soc_dapm_line:
+ p->connect = 1;
+ break;
+ /* does affect routing - dynamically connected */
case snd_soc_dapm_pre:
case snd_soc_dapm_post:
p->connect = 0;
@@ -443,6 +460,11 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
if (path->name != (char *)w->kcontrol_news[i].name)
continue;
+ if (w->kcontrols[i]) {
+ path->kcontrol = w->kcontrols[i];
+ continue;
+ }
+
wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
sizeof(struct snd_soc_dapm_widget *),
wlist = kzalloc(wlistsize, GFP_KERNEL);
@@ -579,8 +601,8 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
name + prefix_len, prefix);
ret = snd_ctl_add(card, kcontrol);
if (ret < 0) {
- dev_err(dapm->dev,
- "asoc: failed to add kcontrol %s\n", w->name);
+ dev_err(dapm->dev, "failed to add kcontrol %s: %d\n",
+ w->name, ret);
kfree(wlist);
return ret;
}
@@ -644,30 +666,45 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
struct snd_soc_dapm_path *path;
int con = 0;
+ if (widget->outputs >= 0)
+ return widget->outputs;
+
+ DAPM_UPDATE_STAT(widget, path_checks);
+
if (widget->id == snd_soc_dapm_supply)
return 0;
switch (widget->id) {
case snd_soc_dapm_adc:
case snd_soc_dapm_aif_out:
- if (widget->active)
- return snd_soc_dapm_suspend_check(widget);
+ if (widget->active) {
+ widget->outputs = snd_soc_dapm_suspend_check(widget);
+ return widget->outputs;
+ }
default:
break;
}
if (widget->connected) {
/* connected pin ? */
- if (widget->id == snd_soc_dapm_output && !widget->ext)
- return snd_soc_dapm_suspend_check(widget);
+ if (widget->id == snd_soc_dapm_output && !widget->ext) {
+ widget->outputs = snd_soc_dapm_suspend_check(widget);
+ return widget->outputs;
+ }
/* connected jack or spk ? */
- if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk ||
- (widget->id == snd_soc_dapm_line && !list_empty(&widget->sources)))
- return snd_soc_dapm_suspend_check(widget);
+ if (widget->id == snd_soc_dapm_hp ||
+ widget->id == snd_soc_dapm_spk ||
+ (widget->id == snd_soc_dapm_line &&
+ !list_empty(&widget->sources))) {
+ widget->outputs = snd_soc_dapm_suspend_check(widget);
+ return widget->outputs;
+ }
}
list_for_each_entry(path, &widget->sinks, list_source) {
+ DAPM_UPDATE_STAT(widget, neighbour_checks);
+
if (path->weak)
continue;
@@ -680,6 +717,8 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
}
}
+ widget->outputs = con;
+
return con;
}
@@ -692,6 +731,11 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
struct snd_soc_dapm_path *path;
int con = 0;
+ if (widget->inputs >= 0)
+ return widget->inputs;
+
+ DAPM_UPDATE_STAT(widget, path_checks);
+
if (widget->id == snd_soc_dapm_supply)
return 0;
@@ -699,28 +743,40 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
switch (widget->id) {
case snd_soc_dapm_dac:
case snd_soc_dapm_aif_in:
- if (widget->active)
- return snd_soc_dapm_suspend_check(widget);
+ if (widget->active) {
+ widget->inputs = snd_soc_dapm_suspend_check(widget);
+ return widget->inputs;
+ }
default:
break;
}
if (widget->connected) {
/* connected pin ? */
- if (widget->id == snd_soc_dapm_input && !widget->ext)
- return snd_soc_dapm_suspend_check(widget);
+ if (widget->id == snd_soc_dapm_input && !widget->ext) {
+ widget->inputs = snd_soc_dapm_suspend_check(widget);
+ return widget->inputs;
+ }
/* connected VMID/Bias for lower pops */
- if (widget->id == snd_soc_dapm_vmid)
- return snd_soc_dapm_suspend_check(widget);
+ if (widget->id == snd_soc_dapm_vmid) {
+ widget->inputs = snd_soc_dapm_suspend_check(widget);
+ return widget->inputs;
+ }
/* connected jack ? */
if (widget->id == snd_soc_dapm_mic ||
- (widget->id == snd_soc_dapm_line && !list_empty(&widget->sinks)))
- return snd_soc_dapm_suspend_check(widget);
+ (widget->id == snd_soc_dapm_line &&
+ !list_empty(&widget->sinks))) {
+ widget->inputs = snd_soc_dapm_suspend_check(widget);
+ return widget->inputs;
+ }
+
}
list_for_each_entry(path, &widget->sources, list_sink) {
+ DAPM_UPDATE_STAT(widget, neighbour_checks);
+
if (path->weak)
continue;
@@ -733,6 +789,8 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
}
}
+ widget->inputs = con;
+
return con;
}
@@ -756,12 +814,29 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
}
EXPORT_SYMBOL_GPL(dapm_reg_event);
+static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
+{
+ if (w->power_checked)
+ return w->new_power;
+
+ if (w->force)
+ w->new_power = 1;
+ else
+ w->new_power = w->power_check(w);
+
+ w->power_checked = true;
+
+ return w->new_power;
+}
+
/* Generic check to see if a widget should be powered.
*/
static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
{
int in, out;
+ DAPM_UPDATE_STAT(w, power_checks);
+
in = is_connected_input_ep(w);
dapm_clear_walk(w->dapm);
out = is_connected_output_ep(w);
@@ -774,6 +849,8 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
{
int in;
+ DAPM_UPDATE_STAT(w, power_checks);
+
if (w->active) {
in = is_connected_input_ep(w);
dapm_clear_walk(w->dapm);
@@ -788,6 +865,8 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
{
int out;
+ DAPM_UPDATE_STAT(w, power_checks);
+
if (w->active) {
out = is_connected_output_ep(w);
dapm_clear_walk(w->dapm);
@@ -801,10 +880,13 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
{
struct snd_soc_dapm_path *path;
- int power = 0;
+
+ DAPM_UPDATE_STAT(w, power_checks);
/* Check if one of our outputs is connected */
list_for_each_entry(path, &w->sinks, list_source) {
+ DAPM_UPDATE_STAT(w, neighbour_checks);
+
if (path->weak)
continue;
@@ -815,21 +897,18 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
if (!path->sink)
continue;
- if (path->sink->force) {
- power = 1;
- break;
- }
-
- if (path->sink->power_check &&
- path->sink->power_check(path->sink)) {
- power = 1;
- break;
- }
+ if (dapm_widget_power_check(path->sink))
+ return 1;
}
dapm_clear_walk(w->dapm);
- return power;
+ return 0;
+}
+
+static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
+{
+ return 1;
}
static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
@@ -1172,6 +1251,85 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
}
}
+static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
+ bool power, bool connect)
+{
+ /* If a connection is being made or broken then that update
+ * will have marked the peer dirty, otherwise the widgets are
+ * not connected and this update has no impact. */
+ if (!connect)
+ return;
+
+ /* If the peer is already in the state we're moving to then we
+ * won't have an impact on it. */
+ if (power != peer->power)
+ dapm_mark_dirty(peer, "peer state change");
+}
+
+static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
+ struct list_head *up_list,
+ struct list_head *down_list)
+{
+ struct snd_soc_dapm_path *path;
+
+ if (w->power == power)
+ return;
+
+ trace_snd_soc_dapm_widget_power(w, power);
+
+ /* If we changed our power state perhaps our neigbours changed
+ * also.
+ */
+ list_for_each_entry(path, &w->sources, list_sink) {
+ if (path->source) {
+ dapm_widget_set_peer_power(path->source, power,
+ path->connect);
+ }
+ }
+ switch (w->id) {
+ case snd_soc_dapm_supply:
+ /* Supplies can't affect their outputs, only their inputs */
+ break;
+ default:
+ list_for_each_entry(path, &w->sinks, list_source) {
+ if (path->sink) {
+ dapm_widget_set_peer_power(path->sink, power,
+ path->connect);
+ }
+ }
+ break;
+ }
+
+ if (power)
+ dapm_seq_insert(w, up_list, true);
+ else
+ dapm_seq_insert(w, down_list, false);
+
+ w->power = power;
+}
+
+static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
+ struct list_head *up_list,
+ struct list_head *down_list)
+{
+ int power;
+
+ switch (w->id) {
+ case snd_soc_dapm_pre:
+ dapm_seq_insert(w, down_list, false);
+ break;
+ case snd_soc_dapm_post:
+ dapm_seq_insert(w, up_list, true);
+ break;
+
+ default:
+ power = dapm_widget_power_check(w);
+
+ dapm_widget_set_power(w, power, up_list, down_list);
+ break;
+ }
+}
+
/*
* Scan each dapm widget for complete audio path.
* A complete path is a route that has valid endpoints i.e.:-
@@ -1190,7 +1348,6 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
LIST_HEAD(down_list);
LIST_HEAD(async_domain);
enum snd_soc_bias_level bias;
- int power;
trace_snd_soc_dapm_start(card);
@@ -1203,61 +1360,47 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
}
}
- /* Check which widgets we need to power and store them in
- * lists indicating if they should be powered up or down.
- */
+ memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
+
list_for_each_entry(w, &card->widgets, list) {
- switch (w->id) {
- case snd_soc_dapm_pre:
- dapm_seq_insert(w, &down_list, false);
- break;
- case snd_soc_dapm_post:
- dapm_seq_insert(w, &up_list, true);
- break;
+ w->power_checked = false;
+ w->inputs = -1;
+ w->outputs = -1;
+ }
- default:
- if (!w->power_check)
- continue;
+ /* Check which widgets we need to power and store them in
+ * lists indicating if they should be powered up or down. We
+ * only check widgets that have been flagged as dirty but note
+ * that new widgets may be added to the dirty list while we
+ * iterate.
+ */
+ list_for_each_entry(w, &card->dapm_dirty, dirty) {
+ dapm_power_one_widget(w, &up_list, &down_list);
+ }
- if (!w->force)
- power = w->power_check(w);
- else
- power = 1;
+ list_for_each_entry(w, &card->widgets, list) {
+ list_del_init(&w->dirty);
- if (power) {
- d = w->dapm;
+ if (w->power) {
+ d = w->dapm;
- /* Supplies and micbiases only bring
- * the context up to STANDBY as unless
- * something else is active and
- * passing audio they generally don't
- * require full power.
- */
- switch (w->id) {
- case snd_soc_dapm_supply:
- case snd_soc_dapm_micbias:
- if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
- d->target_bias_level = SND_SOC_BIAS_STANDBY;
- break;
- default:
- d->target_bias_level = SND_SOC_BIAS_ON;
- break;
- }
+ /* Supplies and micbiases only bring the
+ * context up to STANDBY as unless something
+ * else is active and passing audio they
+ * generally don't require full power.
+ */
+ switch (w->id) {
+ case snd_soc_dapm_supply:
+ case snd_soc_dapm_micbias:
+ if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
+ d->target_bias_level = SND_SOC_BIAS_STANDBY;
+ break;
+ default:
+ d->target_bias_level = SND_SOC_BIAS_ON;
+ break;
}
-
- if (w->power == power)
- continue;
-
- trace_snd_soc_dapm_widget_power(w, power);
-
- if (power)
- dapm_seq_insert(w, &up_list, true);
- else
- dapm_seq_insert(w, &down_list, false);
-
- w->power = power;
- break;
}
+
}
/* If there are no DAPM widgets then try to figure out power from the
@@ -1286,14 +1429,18 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
}
}
- /* Force all contexts in the card to the same bias state */
+ /* Force all contexts in the card to the same bias state if
+ * they're not ground referenced.
+ */
bias = SND_SOC_BIAS_OFF;
list_for_each_entry(d, &card->dapm_list, list)
if (d->target_bias_level > bias)
bias = d->target_bias_level;
list_for_each_entry(d, &card->dapm_list, list)
- d->target_bias_level = bias;
+ if (!d->idle_bias_off)
+ d->target_bias_level = bias;
+ trace_snd_soc_dapm_walk_done(card);
/* Run all the bias changes in parallel */
list_for_each_entry(d, &dapm->card->dapm_list, list)
@@ -1524,14 +1671,21 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
found = 1;
/* we now need to match the string in the enum to the path */
- if (!(strcmp(path->name, e->texts[mux])))
+ if (!(strcmp(path->name, e->texts[mux]))) {
path->connect = 1; /* new connection */
- else
+ dapm_mark_dirty(path->source, "mux connection");
+ } else {
+ if (path->connect)
+ dapm_mark_dirty(path->source,
+ "mux disconnection");
path->connect = 0; /* old connection must be powered down */
+ }
}
- if (found)
+ if (found) {
+ dapm_mark_dirty(widget, "mux change");
dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
+ }
return 0;
}
@@ -1556,11 +1710,13 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
/* found, now check type */
found = 1;
path->connect = connect;
- break;
+ dapm_mark_dirty(path->source, "mixer connection");
}
- if (found)
+ if (found) {
+ dapm_mark_dirty(widget, "mixer update");
dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
+ }
return 0;
}
@@ -1704,6 +1860,7 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
w->connected = status;
if (status == 0)
w->force = 0;
+ dapm_mark_dirty(w, "pin configuration");
return 0;
}
@@ -1719,6 +1876,13 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
*/
int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
{
+ /*
+ * Suppress early reports (eg, jacks syncing their state) to avoid
+ * silly DAPM runs during card startup.
+ */
+ if (!dapm->card || !dapm->card->instantiated)
+ return 0;
+
return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
@@ -2004,42 +2168,18 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
case snd_soc_dapm_switch:
case snd_soc_dapm_mixer:
case snd_soc_dapm_mixer_named_ctl:
- w->power_check = dapm_generic_check_power;
dapm_new_mixer(w);
break;
case snd_soc_dapm_mux:
case snd_soc_dapm_virt_mux:
case snd_soc_dapm_value_mux:
- w->power_check = dapm_generic_check_power;
dapm_new_mux(w);
break;
- case snd_soc_dapm_adc:
- case snd_soc_dapm_aif_out:
- w->power_check = dapm_adc_check_power;
- break;
- case snd_soc_dapm_dac:
- case snd_soc_dapm_aif_in:
- w->power_check = dapm_dac_check_power;
- break;
case snd_soc_dapm_pga:
case snd_soc_dapm_out_drv:
- w->power_check = dapm_generic_check_power;
dapm_new_pga(w);
break;
- case snd_soc_dapm_input:
- case snd_soc_dapm_output:
- case snd_soc_dapm_micbias:
- case snd_soc_dapm_spk:
- case snd_soc_dapm_hp:
- case snd_soc_dapm_mic:
- case snd_soc_dapm_line:
- w->power_check = dapm_generic_check_power;
- break;
- case snd_soc_dapm_supply:
- w->power_check = dapm_supply_check_power;
- case snd_soc_dapm_vmid:
- case snd_soc_dapm_pre:
- case snd_soc_dapm_post:
+ default:
break;
}
@@ -2056,6 +2196,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
w->new = 1;
+ dapm_mark_dirty(w, "new widget");
dapm_debugfs_add_widget(w);
}
@@ -2530,6 +2671,44 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
else
snprintf(w->name, name_len, "%s", widget->name);
+ switch (w->id) {
+ case snd_soc_dapm_switch:
+ case snd_soc_dapm_mixer:
+ case snd_soc_dapm_mixer_named_ctl:
+ w->power_check = dapm_generic_check_power;
+ break;
+ case snd_soc_dapm_mux:
+ case snd_soc_dapm_virt_mux:
+ case snd_soc_dapm_value_mux:
+ w->power_check = dapm_generic_check_power;
+ break;
+ case snd_soc_dapm_adc:
+ case snd_soc_dapm_aif_out:
+ w->power_check = dapm_adc_check_power;
+ break;
+ case snd_soc_dapm_dac:
+ case snd_soc_dapm_aif_in:
+ w->power_check = dapm_dac_check_power;
+ break;
+ case snd_soc_dapm_pga:
+ case snd_soc_dapm_out_drv:
+ case snd_soc_dapm_input:
+ case snd_soc_dapm_output:
+ case snd_soc_dapm_micbias:
+ case snd_soc_dapm_spk:
+ case snd_soc_dapm_hp:
+ case snd_soc_dapm_mic:
+ case snd_soc_dapm_line:
+ w->power_check = dapm_generic_check_power;
+ break;
+ case snd_soc_dapm_supply:
+ w->power_check = dapm_supply_check_power;
+ break;
+ default:
+ w->power_check = dapm_always_on_check_power;
+ break;
+ }
+
dapm->n_widgets++;
w->dapm = dapm;
w->codec = dapm->codec;
@@ -2537,6 +2716,7 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
INIT_LIST_HEAD(&w->sources);
INIT_LIST_HEAD(&w->sinks);
INIT_LIST_HEAD(&w->list);
+ INIT_LIST_HEAD(&w->dirty);
list_add(&w->list, &dapm->card->widgets);
/* machine layer set ups unconnected pins and insertions */
@@ -2584,9 +2764,10 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
{
if (!w->sname || w->dapm != dapm)
continue;
- dev_dbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n",
+ dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n",
w->name, w->sname, stream, event);
if (strstr(w->sname, stream)) {
+ dapm_mark_dirty(w, "stream event");
switch(event) {
case SND_SOC_DAPM_STREAM_START:
w->active = 1;
@@ -2604,6 +2785,10 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
}
dapm_power_widgets(dapm, event);
+
+ /* do we need to notify any clients that DAPM stream is complete */
+ if (dapm->stream_event)
+ dapm->stream_event(dapm, event);
}
/**
@@ -2672,6 +2857,7 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin);
w->connected = 1;
w->force = 1;
+ dapm_mark_dirty(w, "force enable");
return 0;
}
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index a62f7dd4ba96..c8610cbf34a5 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -13,26 +13,15 @@
#include <linux/i2c.h>
#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/export.h>
#include <sound/soc.h>
#include <trace/events/asoc.h>
-#ifdef CONFIG_SPI_MASTER
-static int do_spi_write(void *control, const char *data, int len)
-{
- struct spi_device *spi = control;
- int ret;
-
- ret = spi_write(spi, data, len);
- if (ret < 0)
- return ret;
-
- return len;
-}
-#endif
-
-static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value, const void *data, int len)
+#ifdef CONFIG_REGMAP
+static int hw_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
{
int ret;
@@ -49,13 +38,7 @@ static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
return 0;
}
- ret = codec->hw_write(codec->control_data, data, len);
- if (ret == len)
- return 0;
- if (ret < 0)
- return ret;
- else
- return -EIO;
+ return regmap_write(codec->control_data, reg, value);
}
static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
@@ -69,8 +52,11 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
if (codec->cache_only)
return -1;
- BUG_ON(!codec->hw_read);
- return codec->hw_read(codec, reg);
+ ret = regmap_read(codec->control_data, reg, &val);
+ if (ret == 0)
+ return val;
+ else
+ return -1;
}
ret = snd_soc_cache_read(codec, reg, &val);
@@ -79,202 +65,18 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
return val;
}
-static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- u16 data;
-
- data = cpu_to_be16((reg << 12) | (value & 0xffffff));
-
- return do_hw_write(codec, reg, value, &data, 2);
-}
-
-static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- u16 data;
-
- data = cpu_to_be16((reg << 9) | (value & 0x1ff));
-
- return do_hw_write(codec, reg, value, &data, 2);
-}
-
-static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- u8 data[2];
-
- reg &= 0xff;
- data[0] = reg;
- data[1] = value & 0xff;
-
- return do_hw_write(codec, reg, value, data, 2);
-}
-
-static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- u8 data[3];
- u16 val = cpu_to_be16(value);
-
- data[0] = reg;
- memcpy(&data[1], &val, sizeof(val));
-
- return do_hw_write(codec, reg, value, data, 3);
-}
-
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int do_i2c_read(struct snd_soc_codec *codec,
- void *reg, int reglen,
- void *data, int datalen)
-{
- struct i2c_msg xfer[2];
- int ret;
- struct i2c_client *client = codec->control_data;
-
- /* Write register */
- xfer[0].addr = client->addr;
- xfer[0].flags = 0;
- xfer[0].len = reglen;
- xfer[0].buf = reg;
-
- /* Read data */
- xfer[1].addr = client->addr;
- xfer[1].flags = I2C_M_RD;
- xfer[1].len = datalen;
- xfer[1].buf = data;
-
- ret = i2c_transfer(client->adapter, xfer, 2);
- if (ret == 2)
- return 0;
- else if (ret < 0)
- return ret;
- else
- return -EIO;
-}
-#endif
-
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
- unsigned int r)
-{
- u8 reg = r;
- u8 data;
- int ret;
-
- ret = do_i2c_read(codec, &reg, 1, &data, 1);
- if (ret < 0)
- return 0;
- return data;
-}
-#else
-#define snd_soc_8_8_read_i2c NULL
-#endif
-
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
- unsigned int r)
-{
- u8 reg = r;
- u16 data;
- int ret;
-
- ret = do_i2c_read(codec, &reg, 1, &data, 2);
- if (ret < 0)
- return 0;
- return (data >> 8) | ((data & 0xff) << 8);
-}
-#else
-#define snd_soc_8_16_read_i2c NULL
-#endif
-
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
- unsigned int r)
-{
- u16 reg = r;
- u8 data;
- int ret;
-
- ret = do_i2c_read(codec, &reg, 2, &data, 1);
- if (ret < 0)
- return 0;
- return data;
-}
-#else
-#define snd_soc_16_8_read_i2c NULL
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-static unsigned int snd_soc_16_8_read_spi(struct snd_soc_codec *codec,
- unsigned int r)
-{
- struct spi_device *spi = codec->control_data;
-
- const u16 reg = cpu_to_be16(r | 0x100);
- u8 data;
- int ret;
-
- ret = spi_write_then_read(spi, &reg, 2, &data, 1);
- if (ret < 0)
- return 0;
- return data;
-}
-#else
-#define snd_soc_16_8_read_spi NULL
-#endif
-
-static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- u8 data[3];
- u16 rval = cpu_to_be16(reg);
-
- memcpy(data, &rval, sizeof(rval));
- data[2] = value;
-
- return do_hw_write(codec, reg, value, data, 3);
-}
-
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
- unsigned int r)
-{
- u16 reg = cpu_to_be16(r);
- u16 data;
- int ret;
-
- ret = do_i2c_read(codec, &reg, 2, &data, 2);
- if (ret < 0)
- return 0;
- return be16_to_cpu(data);
-}
-#else
-#define snd_soc_16_16_read_i2c NULL
-#endif
-
-static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- u16 data[2];
-
- data[0] = cpu_to_be16(reg);
- data[1] = cpu_to_be16(value);
-
- return do_hw_write(codec, reg, value, data, sizeof(data));
-}
-
/* Primitive bulk write support for soc-cache. The data pointed to by
- * `data' needs to already be in the form the hardware expects
- * including any leading register specific data. Any data written
- * through this function will not go through the cache as it only
- * handles writing to volatile or out of bounds registers.
+ * `data' needs to already be in the form the hardware expects. Any
+ * data written through this function will not go through the cache as
+ * it only handles writing to volatile or out of bounds registers.
+ *
+ * This is currently only supported for devices using the regmap API
+ * wrappers.
*/
-static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
+static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec,
+ unsigned int reg,
const void *data, size_t len)
{
- int ret;
-
/* To ensure that we don't get out of sync with the cache, check
* whether the base register is volatile or if we've directly asked
* to bypass the cache. Out of bounds registers are considered
@@ -285,68 +87,9 @@ static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int r
&& reg < codec->driver->reg_cache_size)
return -EINVAL;
- switch (codec->control_type) {
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
- case SND_SOC_I2C:
- ret = i2c_master_send(to_i2c_client(codec->dev), data, len);
- break;
-#endif
-#if defined(CONFIG_SPI_MASTER)
- case SND_SOC_SPI:
- ret = spi_write(to_spi_device(codec->dev), data, len);
- break;
-#endif
- default:
- BUG();
- }
-
- if (ret == len)
- return 0;
- if (ret < 0)
- return ret;
- else
- return -EIO;
+ return regmap_raw_write(codec->control_data, reg, data, len);
}
-static struct {
- int addr_bits;
- int data_bits;
- int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
- unsigned int (*read)(struct snd_soc_codec *, unsigned int);
- unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
- unsigned int (*spi_read)(struct snd_soc_codec *, unsigned int);
-} io_types[] = {
- {
- .addr_bits = 4, .data_bits = 12,
- .write = snd_soc_4_12_write,
- },
- {
- .addr_bits = 7, .data_bits = 9,
- .write = snd_soc_7_9_write,
- },
- {
- .addr_bits = 8, .data_bits = 8,
- .write = snd_soc_8_8_write,
- .i2c_read = snd_soc_8_8_read_i2c,
- },
- {
- .addr_bits = 8, .data_bits = 16,
- .write = snd_soc_8_16_write,
- .i2c_read = snd_soc_8_16_read_i2c,
- },
- {
- .addr_bits = 16, .data_bits = 8,
- .write = snd_soc_16_8_write,
- .i2c_read = snd_soc_16_8_read_i2c,
- .spi_read = snd_soc_16_8_read_spi,
- },
- {
- .addr_bits = 16, .data_bits = 16,
- .write = snd_soc_16_16_write,
- .i2c_read = snd_soc_16_16_read_i2c,
- },
-};
-
/**
* snd_soc_codec_set_cache_io: Set up standard I/O functions.
*
@@ -370,50 +113,51 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
int addr_bits, int data_bits,
enum snd_soc_control_type control)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(io_types); i++)
- if (io_types[i].addr_bits == addr_bits &&
- io_types[i].data_bits == data_bits)
- break;
- if (i == ARRAY_SIZE(io_types)) {
- printk(KERN_ERR
- "No I/O functions for %d bit address %d bit data\n",
- addr_bits, data_bits);
- return -EINVAL;
- }
+ struct regmap_config config;
- codec->write = io_types[i].write;
+ memset(&config, 0, sizeof(config));
+ codec->write = hw_write;
codec->read = hw_read;
codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
+ config.reg_bits = addr_bits;
+ config.val_bits = data_bits;
+
switch (control) {
+#if defined(CONFIG_REGMAP_I2C) || defined(CONFIG_REGMAP_I2C_MODULE)
case SND_SOC_I2C:
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
- codec->hw_write = (hw_write_t)i2c_master_send;
-#endif
- if (io_types[i].i2c_read)
- codec->hw_read = io_types[i].i2c_read;
-
- codec->control_data = container_of(codec->dev,
- struct i2c_client,
- dev);
+ codec->control_data = regmap_init_i2c(to_i2c_client(codec->dev),
+ &config);
break;
+#endif
+#if defined(CONFIG_REGMAP_SPI) || defined(CONFIG_REGMAP_SPI_MODULE)
case SND_SOC_SPI:
-#ifdef CONFIG_SPI_MASTER
- codec->hw_write = do_spi_write;
+ codec->control_data = regmap_init_spi(to_spi_device(codec->dev),
+ &config);
+ break;
#endif
- if (io_types[i].spi_read)
- codec->hw_read = io_types[i].spi_read;
- codec->control_data = container_of(codec->dev,
- struct spi_device,
- dev);
+ case SND_SOC_REGMAP:
+ /* Device has made its own regmap arrangements */
break;
+
+ default:
+ return -EINVAL;
}
+ if (IS_ERR(codec->control_data))
+ return PTR_ERR(codec->control_data);
+
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
-
+#else
+int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
+ int addr_bits, int data_bits,
+ enum snd_soc_control_type control)
+{
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
+#endif
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index fa31d9c2abd8..6c5ebd38c1b0 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -17,6 +17,7 @@
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <trace/events/asoc.h>
/**
@@ -188,6 +189,8 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
list_add(&(pins[i].list), &jack->pins);
}
+ snd_soc_dapm_new_widgets(&jack->codec->card->dapm);
+
/* Update to reflect the last reported status; canned jack
* implementations are likely to set their state before the
* card has an opportunity to associate pins.
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 2879c883eebc..ee15337353fa 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -27,17 +27,13 @@
#include <sound/soc.h>
#include <sound/initval.h>
-static DEFINE_MUTEX(pcm_mutex);
-
-static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
+static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *soc_dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
- if (!codec_dai->driver->symmetric_rates &&
- !cpu_dai->driver->symmetric_rates &&
+ if (!soc_dai->driver->symmetric_rates &&
!rtd->dai_link->symmetric_rates)
return 0;
@@ -45,19 +41,19 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
* the second can need to get its constraints before the first has
* picked a rate. Complain and allow the application to carry on.
*/
- if (!rtd->rate) {
- dev_warn(&rtd->dev,
+ if (!soc_dai->rate) {
+ dev_warn(soc_dai->dev,
"Not enforcing symmetric_rates due to race\n");
return 0;
}
- dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n", rtd->rate);
+ dev_dbg(soc_dai->dev, "Symmetry forces %dHz rate\n", soc_dai->rate);
ret = snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_RATE,
- rtd->rate, rtd->rate);
+ soc_dai->rate, soc_dai->rate);
if (ret < 0) {
- dev_err(&rtd->dev,
+ dev_err(soc_dai->dev,
"Unable to apply rate symmetry constraint: %d\n", ret);
return ret;
}
@@ -187,8 +183,14 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
}
/* Symmetry only applies if we've already got an active stream. */
- if (cpu_dai->active || codec_dai->active) {
- ret = soc_pcm_apply_symmetry(substream);
+ if (cpu_dai->active) {
+ ret = soc_pcm_apply_symmetry(substream, cpu_dai);
+ if (ret != 0)
+ goto config_err;
+ }
+
+ if (codec_dai->active) {
+ ret = soc_pcm_apply_symmetry(substream, codec_dai);
if (ret != 0)
goto config_err;
}
@@ -290,8 +292,12 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
codec_dai->active--;
codec->active--;
- if (!cpu_dai->active && !codec_dai->active)
- rtd->rate = 0;
+ /* clear the corresponding DAIs rate when inactive */
+ if (!cpu_dai->active)
+ cpu_dai->rate = 0;
+
+ if (!codec_dai->active)
+ codec_dai->rate = 0;
/* Muting the DAC suppresses artifacts caused during digital
* shutdown, for example from stopping clocks.
@@ -313,10 +319,17 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
cpu_dai->runtime = NULL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- /* start delayed pop wq here for playback streams */
- codec_dai->pop_wait = 1;
- schedule_delayed_work(&rtd->delayed_work,
- msecs_to_jiffies(rtd->pmdown_time));
+ if (unlikely(codec->ignore_pmdown_time)) {
+ /* powered down playback stream now */
+ snd_soc_dapm_stream_event(rtd,
+ codec_dai->driver->playback.stream_name,
+ SND_SOC_DAPM_STREAM_STOP);
+ } else {
+ /* start delayed pop wq here for playback streams */
+ codec_dai->pop_wait = 1;
+ schedule_delayed_work(&rtd->delayed_work,
+ msecs_to_jiffies(rtd->pmdown_time));
+ }
} else {
/* capture streams can be powered down now */
snd_soc_dapm_stream_event(rtd,
@@ -449,7 +462,9 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
}
}
- rtd->rate = params_rate(params);
+ /* store the rate for each DAIs */
+ cpu_dai->rate = params_rate(params);
+ codec_dai->rate = params_rate(params);
out:
mutex_unlock(&rtd->pcm_mutex);
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index ec921ec99c26..0c12b98484bd 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -14,6 +14,7 @@
*/
#include <linux/platform_device.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
index dfa85cbb05c8..f8428e410e05 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -24,6 +24,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include "tegra_asoc_utils.h"
diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c
index 9f24ef73f2cb..3b55a44146af 100644
--- a/sound/soc/tegra/tegra_das.c
+++ b/sound/soc/tegra/tegra_das.c
@@ -212,7 +212,7 @@ err_release:
release_mem_region(res->start, resource_size(res));
err_free:
kfree(das);
- das = 0;
+ das = NULL;
exit:
return ret;
}
@@ -234,7 +234,7 @@ static int __devexit tegra_das_remove(struct platform_device *pdev)
release_mem_region(res->start, resource_size(res));
kfree(das);
- das = 0;
+ das = NULL;
return 0;
}
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c
index f36b9969cfec..6728fab8c411 100644
--- a/sound/soc/tegra/tegra_i2s.c
+++ b/sound/soc/tegra/tegra_i2s.c
@@ -312,7 +312,7 @@ static struct snd_soc_dai_ops tegra_i2s_dai_ops = {
.trigger = tegra_i2s_trigger,
};
-struct snd_soc_dai_driver tegra_i2s_dai[] = {
+static struct snd_soc_dai_driver tegra_i2s_dai[] = {
{
.name = DRV_NAME ".0",
.probe = tegra_i2s_probe,
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index c7cfd96e991e..436def1dfa39 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -367,7 +367,7 @@ static void tegra_pcm_free(struct snd_pcm *pcm)
tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
}
-struct snd_soc_platform_driver tegra_pcm_platform = {
+static struct snd_soc_platform_driver tegra_pcm_platform = {
.ops = &tegra_pcm_ops,
.pcm_new = tegra_pcm_new,
.pcm_free = tegra_pcm_free,
diff --git a/sound/soc/tegra/tegra_spdif.c b/sound/soc/tegra/tegra_spdif.c
index abe606b0a29e..dd11d0c63474 100644
--- a/sound/soc/tegra/tegra_spdif.c
+++ b/sound/soc/tegra/tegra_spdif.c
@@ -127,7 +127,7 @@ static int tegra_spdif_hw_params(struct snd_pcm_substream *substream,
{
struct device *dev = substream->pcm->card->dev;
struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
- int ret, srate, spdifclock;
+ int ret, spdifclock;
spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_PACK;
spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_BIT_MODE_MASK;
@@ -140,7 +140,6 @@ static int tegra_spdif_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- srate = params_rate(params);
switch (params_rate(params)) {
case 32000:
spdifclock = 4096000;
@@ -232,7 +231,7 @@ static struct snd_soc_dai_ops tegra_spdif_dai_ops = {
.trigger = tegra_spdif_trigger,
};
-struct snd_soc_dai_driver tegra_spdif_dai = {
+static struct snd_soc_dai_driver tegra_spdif_dai = {
.name = DRV_NAME,
.probe = tegra_spdif_probe,
.playback = {
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index be27f1d229af..a81cf39257bf 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -339,8 +339,6 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "LINEOUTL");
}
- snd_soc_dapm_sync(dapm);
-
return 0;
}
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
index 8fc07e9adf2e..b3a7efa6d960 100644
--- a/sound/soc/tegra/trimslice.c
+++ b/sound/soc/tegra/trimslice.c
@@ -124,8 +124,6 @@ static int trimslice_asoc_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "RHPOUT");
snd_soc_dapm_nc_pin(dapm, "MICIN");
- snd_soc_dapm_sync(dapm);
-
return 0;
}
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
index 743d07b82c06..a4e3f5501847 100644
--- a/sound/soc/txx9/txx9aclc-ac97.c
+++ b/sound/soc/txx9/txx9aclc-ac97.c
@@ -201,7 +201,7 @@ static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev)
if (!drvdata->base)
return -EBUSY;
err = devm_request_irq(&pdev->dev, irq, txx9aclc_ac97_irq,
- IRQF_DISABLED, dev_name(&pdev->dev), drvdata);
+ 0, dev_name(&pdev->dev), drvdata);
if (err < 0)
return err;
diff --git a/sound/soc/txx9/txx9aclc-generic.c b/sound/soc/txx9/txx9aclc-generic.c
index 6770e7166be4..9b5e283af51c 100644
--- a/sound/soc/txx9/txx9aclc-generic.c
+++ b/sound/soc/txx9/txx9aclc-generic.c
@@ -62,7 +62,7 @@ static int __exit txx9aclc_generic_remove(struct platform_device *pdev)
}
static struct platform_driver txx9aclc_generic_driver = {
- .remove = txx9aclc_generic_remove,
+ .remove = __exit_p(txx9aclc_generic_remove),
.driver = {
.name = "txx9aclc-generic",
.owner = THIS_MODULE,