summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/arm/pxa2xx-pcm.c2
-rw-r--r--sound/arm/pxa2xx-pcm.h3
-rw-r--r--sound/isa/es18xx.c10
-rw-r--r--sound/pci/hda/hda_controller.c34
-rw-r--r--sound/pci/hda/hda_intel.c3
-rw-r--r--sound/pci/hda/hda_priv.h1
-rw-r--r--sound/pci/hda/patch_hdmi.c4
-rw-r--r--sound/pci/hda/patch_realtek.c7
-rw-r--r--sound/soc/atmel/Kconfig2
-rw-r--r--sound/soc/atmel/atmel-pcm-pdc.c63
-rw-r--r--sound/soc/atmel/snd-soc-afeb9260.c12
-rw-r--r--sound/soc/blackfin/Kconfig26
-rw-r--r--sound/soc/blackfin/Makefile4
-rw-r--r--sound/soc/blackfin/bfin-eval-adau1x61.c142
-rw-r--r--sound/soc/blackfin/bfin-eval-adau1x81.c130
-rw-r--r--sound/soc/codecs/88pm860x-codec.c20
-rw-r--r--sound/soc/codecs/Kconfig72
-rw-r--r--sound/soc/codecs/Makefile28
-rw-r--r--sound/soc/codecs/ab8500-codec.c12
-rw-r--r--sound/soc/codecs/ad1980.c39
-rw-r--r--sound/soc/codecs/adau1373.c7
-rw-r--r--sound/soc/codecs/adau1761-i2c.c60
-rw-r--r--sound/soc/codecs/adau1761-spi.c77
-rw-r--r--sound/soc/codecs/adau1761.c803
-rw-r--r--sound/soc/codecs/adau1761.h23
-rw-r--r--sound/soc/codecs/adau1781-i2c.c58
-rw-r--r--sound/soc/codecs/adau1781-spi.c75
-rw-r--r--sound/soc/codecs/adau1781.c511
-rw-r--r--sound/soc/codecs/adau1781.h23
-rw-r--r--sound/soc/codecs/adau17x1.c866
-rw-r--r--sound/soc/codecs/adau17x1.h124
-rw-r--r--sound/soc/codecs/adav80x.c12
-rw-r--r--sound/soc/codecs/ak4104.c62
-rw-r--r--sound/soc/codecs/ak4641.c4
-rw-r--r--sound/soc/codecs/ak4642.c75
-rw-r--r--sound/soc/codecs/alc5623.c22
-rw-r--r--sound/soc/codecs/arizona.h4
-rw-r--r--sound/soc/codecs/cq93vc.c10
-rw-r--r--sound/soc/codecs/cs4270.c2
-rw-r--r--sound/soc/codecs/cs4271.c4
-rw-r--r--sound/soc/codecs/cs42l51-i2c.c59
-rw-r--r--sound/soc/codecs/cs42l51.c80
-rw-r--r--sound/soc/codecs/cs42l51.h6
-rw-r--r--sound/soc/codecs/cs42l52.c18
-rw-r--r--sound/soc/codecs/cs42l56.c1427
-rw-r--r--sound/soc/codecs/cs42l56.h175
-rw-r--r--sound/soc/codecs/cs42l73.c6
-rw-r--r--sound/soc/codecs/cs42xx8.c3
-rw-r--r--sound/soc/codecs/da7210.c4
-rw-r--r--sound/soc/codecs/da7213.c4
-rw-r--r--sound/soc/codecs/da732x.c4
-rw-r--r--sound/soc/codecs/da9055.c2
-rw-r--r--sound/soc/codecs/hdmi.c1
-rw-r--r--sound/soc/codecs/lm4857.c4
-rw-r--r--sound/soc/codecs/max9768.c4
-rw-r--r--sound/soc/codecs/max98088.c12
-rw-r--r--sound/soc/codecs/max98090.c87
-rw-r--r--sound/soc/codecs/max98090.h1
-rw-r--r--sound/soc/codecs/max98095.c23
-rw-r--r--sound/soc/codecs/mc13783.c36
-rw-r--r--sound/soc/codecs/pcm1681.c4
-rw-r--r--sound/soc/codecs/pcm512x.c4
-rw-r--r--sound/soc/codecs/rt5631.c4
-rw-r--r--sound/soc/codecs/rt5640.c424
-rw-r--r--sound/soc/codecs/rt5640.h10
-rw-r--r--sound/soc/codecs/rt5645.c2475
-rw-r--r--sound/soc/codecs/rt5645.h2188
-rw-r--r--sound/soc/codecs/rt5651.c1897
-rw-r--r--sound/soc/codecs/rt5651.h2081
-rw-r--r--sound/soc/codecs/sgtl5000.c15
-rw-r--r--sound/soc/codecs/si476x.c14
-rw-r--r--sound/soc/codecs/sirf-audio-codec.c74
-rw-r--r--sound/soc/codecs/sirf-audio-codec.h50
-rw-r--r--sound/soc/codecs/sta32x.c4
-rw-r--r--sound/soc/codecs/sta350.c1311
-rw-r--r--sound/soc/codecs/sta350.h238
-rw-r--r--sound/soc/codecs/tas5086.c4
-rw-r--r--sound/soc/codecs/tlv320aic23-i2c.c1
-rw-r--r--sound/soc/codecs/tlv320aic23.c4
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c3
-rw-r--r--sound/soc/codecs/tlv320aic3x.c11
-rw-r--r--sound/soc/codecs/tlv320dac33.c12
-rw-r--r--sound/soc/codecs/tpa6130a2.c1
-rw-r--r--sound/soc/codecs/twl4030.c10
-rw-r--r--sound/soc/codecs/twl6040.c8
-rw-r--r--sound/soc/codecs/wl1273.c12
-rw-r--r--sound/soc/codecs/wm2000.c8
-rw-r--r--sound/soc/codecs/wm2200.c4
-rw-r--r--sound/soc/codecs/wm5100.c4
-rw-r--r--sound/soc/codecs/wm5102.c26
-rw-r--r--sound/soc/codecs/wm5110.c35
-rw-r--r--sound/soc/codecs/wm8350.c14
-rw-r--r--sound/soc/codecs/wm8400.c12
-rw-r--r--sound/soc/codecs/wm8580.c2
-rw-r--r--sound/soc/codecs/wm8731.c11
-rw-r--r--sound/soc/codecs/wm8753.c4
-rw-r--r--sound/soc/codecs/wm8804.c11
-rw-r--r--sound/soc/codecs/wm8903.c4
-rw-r--r--sound/soc/codecs/wm8904.c14
-rw-r--r--sound/soc/codecs/wm8955.c13
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c32
-rw-r--r--sound/soc/codecs/wm8960.c4
-rw-r--r--sound/soc/codecs/wm8962.c35
-rw-r--r--sound/soc/codecs/wm8962.h4
-rw-r--r--sound/soc/codecs/wm8983.c4
-rw-r--r--sound/soc/codecs/wm8985.c11
-rw-r--r--sound/soc/codecs/wm8988.c8
-rw-r--r--sound/soc/codecs/wm8990.c2
-rw-r--r--sound/soc/codecs/wm8991.c2
-rw-r--r--sound/soc/codecs/wm8994.c32
-rw-r--r--sound/soc/codecs/wm8995.c10
-rw-r--r--sound/soc/codecs/wm8996.c4
-rw-r--r--sound/soc/codecs/wm8997.c25
-rw-r--r--sound/soc/codecs/wm9081.c4
-rw-r--r--sound/soc/codecs/wm_adsp.c4
-rw-r--r--sound/soc/codecs/wm_hubs.c2
-rw-r--r--sound/soc/davinci/Kconfig10
-rw-r--r--sound/soc/davinci/davinci-i2s.c1
-rw-r--r--sound/soc/davinci/davinci-mcasp.c260
-rw-r--r--sound/soc/davinci/davinci-mcasp.h1
-rw-r--r--sound/soc/davinci/davinci-pcm.c8
-rw-r--r--sound/soc/davinci/davinci-pcm.h8
-rw-r--r--sound/soc/davinci/davinci-vcif.c1
-rw-r--r--sound/soc/fsl/Kconfig77
-rw-r--r--sound/soc/fsl/Makefile3
-rw-r--r--sound/soc/fsl/fsl_esai.c54
-rw-r--r--sound/soc/fsl/fsl_sai.c255
-rw-r--r--sound/soc/fsl/fsl_sai.h16
-rw-r--r--sound/soc/fsl/fsl_spdif.c186
-rw-r--r--sound/soc/fsl/fsl_spdif.h14
-rw-r--r--sound/soc/fsl/fsl_ssi.c996
-rw-r--r--sound/soc/fsl/fsl_ssi.h62
-rw-r--r--sound/soc/fsl/fsl_ssi_dbg.c163
-rw-r--r--sound/soc/fsl/imx-audmux.c2
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c1
-rw-r--r--sound/soc/generic/simple-card.c250
-rw-r--r--sound/soc/intel/Makefile2
-rw-r--r--sound/soc/intel/byt-rt5640.c34
-rw-r--r--sound/soc/intel/haswell.c6
-rw-r--r--sound/soc/intel/sst-acpi.c1
-rw-r--r--sound/soc/intel/sst-baytrail-dsp.c16
-rw-r--r--sound/soc/intel/sst-baytrail-ipc.c132
-rw-r--r--sound/soc/intel/sst-baytrail-ipc.h7
-rw-r--r--sound/soc/intel/sst-baytrail-pcm.c162
-rw-r--r--sound/soc/intel/sst-dsp-priv.h5
-rw-r--r--sound/soc/intel/sst-dsp.c1
-rw-r--r--sound/soc/intel/sst-dsp.h1
-rw-r--r--sound/soc/intel/sst-firmware.c67
-rw-r--r--sound/soc/intel/sst-haswell-dsp.c4
-rw-r--r--sound/soc/intel/sst-haswell-ipc.c38
-rw-r--r--sound/soc/intel/sst-haswell-ipc.h4
-rw-r--r--sound/soc/intel/sst-haswell-pcm.c115
-rw-r--r--sound/soc/intel/sst-mfld-dsp.h8
-rw-r--r--sound/soc/intel/sst-mfld-platform-compress.c237
-rw-r--r--sound/soc/intel/sst-mfld-platform-pcm.c (renamed from sound/soc/intel/sst-mfld-platform.c)250
-rw-r--r--sound/soc/intel/sst-mfld-platform.h11
-rw-r--r--sound/soc/jz4740/Kconfig11
-rw-r--r--sound/soc/jz4740/Makefile2
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c5
-rw-r--r--sound/soc/jz4740/qi_lb60.c84
-rw-r--r--sound/soc/kirkwood/kirkwood-t5325.c13
-rw-r--r--sound/soc/nuc900/Kconfig1
-rw-r--r--sound/soc/nuc900/nuc900-ac97.c1
-rw-r--r--sound/soc/omap/Kconfig4
-rw-r--r--sound/soc/omap/am3517evm.c2
-rw-r--r--sound/soc/omap/ams-delta.c68
-rw-r--r--sound/soc/omap/n810.c2
-rw-r--r--sound/soc/omap/omap-abe-twl6040.c13
-rw-r--r--sound/soc/omap/omap-dmic.c9
-rw-r--r--sound/soc/omap/omap-hdmi-card.c2
-rw-r--r--sound/soc/omap/omap-hdmi.c6
-rw-r--r--sound/soc/omap/omap-mcbsp.c25
-rw-r--r--sound/soc/omap/omap-mcbsp.h2
-rw-r--r--sound/soc/omap/omap-mcpdm.c16
-rw-r--r--sound/soc/omap/omap-pcm.c25
-rw-r--r--sound/soc/omap/omap-pcm.h30
-rw-r--r--sound/soc/omap/omap-twl4030.c15
-rw-r--r--sound/soc/omap/omap3pandora.c35
-rw-r--r--sound/soc/omap/osk5912.c2
-rw-r--r--sound/soc/omap/rx51.c275
-rw-r--r--sound/soc/pxa/Kconfig2
-rw-r--r--sound/soc/pxa/brownstone.c7
-rw-r--r--sound/soc/pxa/palm27x.c8
-rw-r--r--sound/soc/pxa/poodle.c1
-rw-r--r--sound/soc/pxa/pxa-ssp.c3
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c2
-rw-r--r--sound/soc/pxa/ttc-dkb.c4
-rw-r--r--sound/soc/samsung/Kconfig22
-rw-r--r--sound/soc/samsung/Makefile2
-rw-r--r--sound/soc/samsung/ac97.c9
-rw-r--r--sound/soc/samsung/bells.c16
-rw-r--r--sound/soc/samsung/dma.c8
-rw-r--r--sound/soc/samsung/dma.h1
-rw-r--r--sound/soc/samsung/dmaengine.c13
-rw-r--r--sound/soc/samsung/goni_wm8994.c9
-rw-r--r--sound/soc/samsung/h1940_uda1380.c5
-rw-r--r--sound/soc/samsung/i2s.c10
-rw-r--r--sound/soc/samsung/i2s.h1
-rw-r--r--sound/soc/samsung/idma.c11
-rw-r--r--sound/soc/samsung/littlemill.c18
-rw-r--r--sound/soc/samsung/lowland.c18
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c8
-rw-r--r--sound/soc/samsung/pcm.c17
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c5
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c2
-rw-r--r--sound/soc/samsung/s3c2412-i2s.c15
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c19
-rw-r--r--sound/soc/samsung/s3c24xx_simtec_hermes.c8
-rw-r--r--sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c8
-rw-r--r--sound/soc/samsung/smartq_wm8987.c2
-rw-r--r--sound/soc/samsung/smdk_wm8580pcm.c15
-rw-r--r--sound/soc/samsung/smdk_wm8994.c12
-rw-r--r--sound/soc/samsung/smdk_wm8994pcm.c15
-rw-r--r--sound/soc/samsung/snow.c123
-rw-r--r--sound/soc/samsung/spdif.c11
-rw-r--r--sound/soc/samsung/speyside.c18
-rw-r--r--sound/soc/samsung/tobermory.c18
-rw-r--r--sound/soc/sh/Kconfig2
-rw-r--r--sound/soc/sh/rcar/Makefile2
-rw-r--r--sound/soc/sh/rcar/adg.c57
-rw-r--r--sound/soc/sh/rcar/core.c168
-rw-r--r--sound/soc/sh/rcar/dvc.c273
-rw-r--r--sound/soc/sh/rcar/gen.c25
-rw-r--r--sound/soc/sh/rcar/rsnd.h68
-rw-r--r--sound/soc/sh/rcar/src.c194
-rw-r--r--sound/soc/sh/rcar/ssi.c89
-rw-r--r--sound/soc/sirf/sirf-audio-port.c107
-rw-r--r--sound/soc/sirf/sirf-audio-port.h62
-rw-r--r--sound/soc/soc-cache.c5
-rw-r--r--sound/soc/soc-compress.c6
-rw-r--r--sound/soc/soc-core.c991
-rw-r--r--sound/soc/soc-dapm.c274
-rw-r--r--sound/soc/soc-devres.c35
-rw-r--r--sound/soc/soc-io.c296
-rw-r--r--sound/soc/soc-pcm.c29
-rw-r--r--sound/soc/tegra/tegra_wm9712.c4
-rw-r--r--sound/soc/ux500/mop500_ab8500.c2
-rw-r--r--sound/usb/card.c12
-rw-r--r--sound/usb/card.h1
-rw-r--r--sound/usb/endpoint.c15
-rw-r--r--sound/usb/pcm.c5
-rw-r--r--sound/usb/usbaudio.h1
242 files changed, 19910 insertions, 3992 deletions
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c
index e6c727b317fb..83be8e3f095e 100644
--- a/sound/arm/pxa2xx-pcm.c
+++ b/sound/arm/pxa2xx-pcm.c
@@ -14,6 +14,8 @@
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
+#include <mach/dma.h>
+
#include <sound/core.h>
#include <sound/pxa2xx-lib.h>
#include <sound/dmaengine_pcm.h>
diff --git a/sound/arm/pxa2xx-pcm.h b/sound/arm/pxa2xx-pcm.h
index 2a8fc08d52a1..00330985beec 100644
--- a/sound/arm/pxa2xx-pcm.h
+++ b/sound/arm/pxa2xx-pcm.h
@@ -9,12 +9,11 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <mach/dma.h>
struct pxa2xx_runtime_data {
int dma_ch;
struct snd_dmaengine_dai_dma_data *params;
- pxa_dma_desc *dma_desc_array;
+ struct pxa_dma_desc *dma_desc_array;
dma_addr_t dma_desc_array_phys;
};
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 1c16830af3d8..6faaac60161a 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -520,7 +520,7 @@ static int snd_es18xx_playback1_trigger(struct snd_es18xx *chip,
snd_es18xx_mixer_write(chip, 0x78, 0x93);
#ifdef AVOID_POPS
/* Avoid pops */
- udelay(100000);
+ mdelay(100);
if (chip->caps & ES18XX_PCM2)
/* Restore Audio 2 volume */
snd_es18xx_mixer_write(chip, 0x7C, chip->audio2_vol);
@@ -537,7 +537,7 @@ static int snd_es18xx_playback1_trigger(struct snd_es18xx *chip,
/* Stop DMA */
snd_es18xx_mixer_write(chip, 0x78, 0x00);
#ifdef AVOID_POPS
- udelay(25000);
+ mdelay(25);
if (chip->caps & ES18XX_PCM2)
/* Set Audio 2 volume to 0 */
snd_es18xx_mixer_write(chip, 0x7C, 0);
@@ -596,7 +596,7 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream)
snd_es18xx_write(chip, 0xA5, count >> 8);
#ifdef AVOID_POPS
- udelay(100000);
+ mdelay(100);
#endif
/* Set format */
@@ -691,7 +691,7 @@ static int snd_es18xx_playback2_trigger(struct snd_es18xx *chip,
snd_es18xx_write(chip, 0xB8, 0x05);
#ifdef AVOID_POPS
/* Avoid pops */
- udelay(100000);
+ mdelay(100);
/* Enable Audio 1 */
snd_es18xx_dsp_command(chip, 0xD1);
#endif
@@ -705,7 +705,7 @@ static int snd_es18xx_playback2_trigger(struct snd_es18xx *chip,
snd_es18xx_write(chip, 0xB8, 0x00);
#ifdef AVOID_POPS
/* Avoid pops */
- udelay(25000);
+ mdelay(25);
/* Disable Audio 1 */
snd_es18xx_dsp_command(chip, 0xD3);
#endif
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 248b90abb882..480bbddbd801 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -1059,24 +1059,26 @@ static void azx_init_cmd_io(struct azx *chip)
/* reset the corb hw read pointer */
azx_writew(chip, CORBRP, ICH6_CORBRP_RST);
- for (timeout = 1000; timeout > 0; timeout--) {
- if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST)
- break;
- udelay(1);
- }
- if (timeout <= 0)
- dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n",
- azx_readw(chip, CORBRP));
+ if (!(chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)) {
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST)
+ break;
+ udelay(1);
+ }
+ if (timeout <= 0)
+ dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n",
+ azx_readw(chip, CORBRP));
- azx_writew(chip, CORBRP, 0);
- for (timeout = 1000; timeout > 0; timeout--) {
- if (azx_readw(chip, CORBRP) == 0)
- break;
- udelay(1);
+ azx_writew(chip, CORBRP, 0);
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if (azx_readw(chip, CORBRP) == 0)
+ break;
+ udelay(1);
+ }
+ if (timeout <= 0)
+ dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n",
+ azx_readw(chip, CORBRP));
}
- if (timeout <= 0)
- dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n",
- azx_readw(chip, CORBRP));
/* enable corb dma */
azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index d6bca62ef387..b540ad71eb0d 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -249,7 +249,8 @@ enum {
/* quirks for Nvidia */
#define AZX_DCAPS_PRESET_NVIDIA \
(AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\
- AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT)
+ AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT |\
+ AZX_DCAPS_CORBRP_SELF_CLEAR)
#define AZX_DCAPS_PRESET_CTHDA \
(AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY)
diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h
index ba38b819f984..4a7cb01fa912 100644
--- a/sound/pci/hda/hda_priv.h
+++ b/sound/pci/hda/hda_priv.h
@@ -189,6 +189,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */
#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */
+#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */
/* position fix mode */
enum {
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 0cb5b89cd0c8..1edbb9c47c2d 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1127,8 +1127,10 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
AMP_OUT_UNMUTE);
eld = &per_pin->sink_eld;
- if (!eld->monitor_present)
+ if (!eld->monitor_present) {
+ hdmi_set_channel_count(codec, per_pin->cvt_nid, channels);
return;
+ }
if (!non_pcm && per_pin->chmap_set)
ca = hdmi_manual_channel_allocation(channels, per_pin->chmap);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 14ae979a92ea..5f7c765391f1 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -4621,6 +4621,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0667, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0674, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x067e, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x067f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -4912,6 +4915,7 @@ static int patch_alc269(struct hda_codec *codec)
spec->codec_variant = ALC269_TYPE_ALC285;
break;
case 0x10ec0286:
+ case 0x10ec0288:
spec->codec_variant = ALC269_TYPE_ALC286;
break;
case 0x10ec0255:
@@ -5539,6 +5543,8 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_AUTO_MUTE),
SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_AUTO_MUTE),
+ SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A),
SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
@@ -5781,6 +5787,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0284, .name = "ALC284", .patch = patch_alc269 },
{ .id = 0x10ec0285, .name = "ALC285", .patch = patch_alc269 },
{ .id = 0x10ec0286, .name = "ALC286", .patch = patch_alc269 },
+ { .id = 0x10ec0288, .name = "ALC288", .patch = patch_alc269 },
{ .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 },
{ .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 },
{ .id = 0x10ec0293, .name = "ALC293", .patch = patch_alc269 },
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 4789619a52d8..27e3fc4a536b 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -35,7 +35,7 @@ config SND_AT91_SOC_SAM9G20_WM8731
config SND_ATMEL_SOC_WM8904
tristate "Atmel ASoC driver for boards using WM8904 codec"
- depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC
+ depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC && I2C
select SND_ATMEL_SOC_SSC
select SND_ATMEL_SOC_DMA
select SND_SOC_WM8904
diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c
index 33ec592ecd75..a366b3503c28 100644
--- a/sound/soc/atmel/atmel-pcm-pdc.c
+++ b/sound/soc/atmel/atmel-pcm-pdc.c
@@ -76,12 +76,6 @@ struct atmel_runtime_data {
size_t period_size;
dma_addr_t period_ptr; /* physical address of next period */
-
- /* PDC register save */
- u32 pdc_xpr_save;
- u32 pdc_xcr_save;
- u32 pdc_xnpr_save;
- u32 pdc_xncr_save;
};
/*--------------------------------------------------------------------------*\
@@ -320,67 +314,10 @@ static struct snd_pcm_ops atmel_pcm_ops = {
.mmap = atmel_pcm_mmap,
};
-
-/*--------------------------------------------------------------------------*\
- * ASoC platform driver
-\*--------------------------------------------------------------------------*/
-#ifdef CONFIG_PM
-static int atmel_pcm_suspend(struct snd_soc_dai *dai)
-{
- struct snd_pcm_runtime *runtime = dai->runtime;
- struct atmel_runtime_data *prtd;
- struct atmel_pcm_dma_params *params;
-
- if (!runtime)
- return 0;
-
- prtd = runtime->private_data;
- params = prtd->params;
-
- /* disable the PDC and save the PDC registers */
-
- ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable);
-
- prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr);
- prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr);
- prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr);
- prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr);
-
- return 0;
-}
-
-static int atmel_pcm_resume(struct snd_soc_dai *dai)
-{
- struct snd_pcm_runtime *runtime = dai->runtime;
- struct atmel_runtime_data *prtd;
- struct atmel_pcm_dma_params *params;
-
- if (!runtime)
- return 0;
-
- prtd = runtime->private_data;
- params = prtd->params;
-
- /* restore the PDC registers and enable the PDC */
- ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save);
- ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save);
- ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save);
- ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save);
-
- ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable);
- return 0;
-}
-#else
-#define atmel_pcm_suspend NULL
-#define atmel_pcm_resume NULL
-#endif
-
static struct snd_soc_platform_driver atmel_soc_platform = {
.ops = &atmel_pcm_ops,
.pcm_new = atmel_pcm_new,
.pcm_free = atmel_pcm_free,
- .suspend = atmel_pcm_suspend,
- .resume = atmel_pcm_resume,
};
int atmel_pcm_pdc_platform_register(struct device *dev)
diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c
index f65f08beac31..9579799ace54 100644
--- a/sound/soc/atmel/snd-soc-afeb9260.c
+++ b/sound/soc/atmel/snd-soc-afeb9260.c
@@ -80,17 +80,6 @@ static const struct snd_soc_dapm_route afeb9260_audio_map[] = {
{"MICIN", NULL, "Mic Jack"},
};
-static int afeb9260_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_enable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_enable_pin(dapm, "Line In");
- snd_soc_dapm_enable_pin(dapm, "Mic Jack");
-
- return 0;
-}
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link afeb9260_dai = {
@@ -100,7 +89,6 @@ static struct snd_soc_dai_link afeb9260_dai = {
.codec_dai_name = "tlv320aic23-hifi",
.platform_name = "atmel_pcm-audio",
.codec_name = "tlv320aic23-codec.0-001a",
- .init = afeb9260_tlv320aic23_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
SND_SOC_DAIFMT_CBM_CFM,
.ops = &afeb9260_ops,
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index 6347d5910138..6410aa2cc2cf 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -43,6 +43,32 @@ config SND_SOC_BFIN_EVAL_ADAU1373
Note: This driver assumes that first ADAU1373 DAI is connected to the
first SPORT port on the BF5XX board.
+config SND_SOC_BFIN_EVAL_ADAU1X61
+ tristate "Support for the EVAL-ADAU1X61 board on Blackfin eval boards"
+ depends on SND_BF5XX_I2S && I2C
+ select SND_BF5XX_SOC_I2S
+ select SND_SOC_ADAU1761_I2C
+ help
+ Say Y if you want to add support for the Analog Devices EVAL-ADAU1X61
+ board connected to one of the Blackfin evaluation boards like the
+ BF5XX-STAMP or BF5XX-EZKIT.
+
+ Note: This driver assumes that the ADAU1X61 is connected to the
+ first SPORT port on the BF5XX board.
+
+config SND_SOC_BFIN_EVAL_ADAU1X81
+ tristate "Support for the EVAL-ADAU1X81 boards on Blackfin eval boards"
+ depends on SND_BF5XX_I2S && I2C
+ select SND_BF5XX_SOC_I2S
+ select SND_SOC_ADAU1781_I2C
+ help
+ Say Y if you want to add support for the Analog Devices EVAL-ADAU1X81
+ board connected to one of the Blackfin evaluation boards like the
+ BF5XX-STAMP or BF5XX-EZKIT.
+
+ Note: This driver assumes that the ADAU1X81 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 && SND_SOC_I2C_AND_SPI
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile
index ad0a6e99bc5d..f21e948b2e9b 100644
--- a/sound/soc/blackfin/Makefile
+++ b/sound/soc/blackfin/Makefile
@@ -22,6 +22,8 @@ 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-adau1x61-objs := bfin-eval-adau1x61.o
+snd-soc-bfin-eval-adau1x81-objs := bfin-eval-adau1x81.o
snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o
snd-soc-bfin-eval-adav80x-objs := bfin-eval-adav80x.o
@@ -31,5 +33,7 @@ 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_ADAU1X61) += snd-soc-bfin-eval-adau1x61.o
+obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X81) += snd-soc-bfin-eval-adau1x81.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/bfin-eval-adau1x61.c b/sound/soc/blackfin/bfin-eval-adau1x61.c
new file mode 100644
index 000000000000..3011906f9d3b
--- /dev/null
+++ b/sound/soc/blackfin/bfin-eval-adau1x61.c
@@ -0,0 +1,142 @@
+/*
+ * Machine driver for EVAL-ADAU1x61MINIZ on Analog Devices bfin
+ * evaluation boards.
+ *
+ * Copyright 2011-2014 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 <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+#include "../codecs/adau17x1.h"
+
+static const struct snd_soc_dapm_widget bfin_eval_adau1x61_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("In 1", NULL),
+ SND_SOC_DAPM_LINE("In 2", NULL),
+ SND_SOC_DAPM_LINE("In 3-4", NULL),
+
+ SND_SOC_DAPM_LINE("Diff Out L", NULL),
+ SND_SOC_DAPM_LINE("Diff Out R", NULL),
+ SND_SOC_DAPM_LINE("Stereo Out", NULL),
+ SND_SOC_DAPM_HP("Capless HP Out", NULL),
+};
+
+static const struct snd_soc_dapm_route bfin_eval_adau1x61_dapm_routes[] = {
+ { "LAUX", NULL, "In 3-4" },
+ { "RAUX", NULL, "In 3-4" },
+ { "LINP", NULL, "In 1" },
+ { "LINN", NULL, "In 1"},
+ { "RINP", NULL, "In 2" },
+ { "RINN", NULL, "In 2" },
+
+ { "In 1", NULL, "MICBIAS" },
+ { "In 2", NULL, "MICBIAS" },
+
+ { "Capless HP Out", NULL, "LHP" },
+ { "Capless HP Out", NULL, "RHP" },
+ { "Diff Out L", NULL, "LOUT" },
+ { "Diff Out R", NULL, "ROUT" },
+ { "Stereo Out", NULL, "LOUT" },
+ { "Stereo Out", NULL, "ROUT" },
+};
+
+static int bfin_eval_adau1x61_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;
+ int pll_rate;
+ int ret;
+
+ switch (params_rate(params)) {
+ case 48000:
+ case 8000:
+ case 12000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 96000:
+ pll_rate = 48000 * 1024;
+ break;
+ case 44100:
+ case 7350:
+ case 11025:
+ case 14700:
+ case 22050:
+ case 29400:
+ case 88200:
+ pll_rate = 44100 * 1024;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, ADAU17X1_PLL,
+ ADAU17X1_PLL_SRC_MCLK, 12288000, pll_rate);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, ADAU17X1_CLK_SRC_PLL, pll_rate,
+ SND_SOC_CLOCK_IN);
+
+ return ret;
+}
+
+static const struct snd_soc_ops bfin_eval_adau1x61_ops = {
+ .hw_params = bfin_eval_adau1x61_hw_params,
+};
+
+static struct snd_soc_dai_link bfin_eval_adau1x61_dai = {
+ .name = "adau1x61",
+ .stream_name = "adau1x61",
+ .cpu_dai_name = "bfin-i2s.0",
+ .codec_dai_name = "adau-hifi",
+ .platform_name = "bfin-i2s-pcm-audio",
+ .codec_name = "adau1761.0-0038",
+ .ops = &bfin_eval_adau1x61_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
+};
+
+static struct snd_soc_card bfin_eval_adau1x61 = {
+ .name = "bfin-eval-adau1x61",
+ .driver_name = "eval-adau1x61",
+ .dai_link = &bfin_eval_adau1x61_dai,
+ .num_links = 1,
+
+ .dapm_widgets = bfin_eval_adau1x61_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1x61_dapm_widgets),
+ .dapm_routes = bfin_eval_adau1x61_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1x61_dapm_routes),
+ .fully_routed = true,
+};
+
+static int bfin_eval_adau1x61_probe(struct platform_device *pdev)
+{
+ bfin_eval_adau1x61.dev = &pdev->dev;
+
+ return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1x61);
+}
+
+static struct platform_driver bfin_eval_adau1x61_driver = {
+ .driver = {
+ .name = "bfin-eval-adau1x61",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = bfin_eval_adau1x61_probe,
+};
+module_platform_driver(bfin_eval_adau1x61_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ALSA SoC bfin adau1x61 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bfin-eval-adau1x61");
diff --git a/sound/soc/blackfin/bfin-eval-adau1x81.c b/sound/soc/blackfin/bfin-eval-adau1x81.c
new file mode 100644
index 000000000000..5c380f6aed1a
--- /dev/null
+++ b/sound/soc/blackfin/bfin-eval-adau1x81.c
@@ -0,0 +1,130 @@
+/*
+ * Machine driver for EVAL-ADAU1x81 on Analog Devices bfin
+ * evaluation boards.
+ *
+ * Copyright 2011-2014 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 <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+#include "../codecs/adau17x1.h"
+
+static const struct snd_soc_dapm_widget bfin_eval_adau1x81_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("Stereo In", NULL),
+ SND_SOC_DAPM_LINE("Beep", NULL),
+
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+};
+
+static const struct snd_soc_dapm_route bfin_eval_adau1x81_dapm_routes[] = {
+ { "BEEP", NULL, "Beep" },
+ { "LMIC", NULL, "Stereo In" },
+ { "LMIC", NULL, "Stereo In" },
+
+ { "Headphone", NULL, "AOUTL" },
+ { "Headphone", NULL, "AOUTR" },
+ { "Speaker", NULL, "SP" },
+};
+
+static int bfin_eval_adau1x81_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;
+ int pll_rate;
+ int ret;
+
+ switch (params_rate(params)) {
+ case 48000:
+ case 8000:
+ case 12000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 96000:
+ pll_rate = 48000 * 1024;
+ break;
+ case 44100:
+ case 7350:
+ case 11025:
+ case 14700:
+ case 22050:
+ case 29400:
+ case 88200:
+ pll_rate = 44100 * 1024;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, ADAU17X1_PLL,
+ ADAU17X1_PLL_SRC_MCLK, 12288000, pll_rate);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, ADAU17X1_CLK_SRC_PLL, pll_rate,
+ SND_SOC_CLOCK_IN);
+
+ return ret;
+}
+
+static const struct snd_soc_ops bfin_eval_adau1x81_ops = {
+ .hw_params = bfin_eval_adau1x81_hw_params,
+};
+
+static struct snd_soc_dai_link bfin_eval_adau1x81_dai = {
+ .name = "adau1x81",
+ .stream_name = "adau1x81",
+ .cpu_dai_name = "bfin-i2s.0",
+ .codec_dai_name = "adau-hifi",
+ .platform_name = "bfin-i2s-pcm-audio",
+ .codec_name = "adau1781.0-0038",
+ .ops = &bfin_eval_adau1x81_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
+};
+
+static struct snd_soc_card bfin_eval_adau1x81 = {
+ .name = "bfin-eval-adau1x81",
+ .driver_name = "eval-adau1x81",
+ .dai_link = &bfin_eval_adau1x81_dai,
+ .num_links = 1,
+
+ .dapm_widgets = bfin_eval_adau1x81_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1x81_dapm_widgets),
+ .dapm_routes = bfin_eval_adau1x81_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1x81_dapm_routes),
+ .fully_routed = true,
+};
+
+static int bfin_eval_adau1x81_probe(struct platform_device *pdev)
+{
+ bfin_eval_adau1x81.dev = &pdev->dev;
+
+ return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1x81);
+}
+
+static struct platform_driver bfin_eval_adau1x81_driver = {
+ .driver = {
+ .name = "bfin-eval-adau1x81",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = bfin_eval_adau1x81_probe,
+};
+module_platform_driver(bfin_eval_adau1x81_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ALSA SoC bfin adau1x81 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bfin-eval-adau1x81");
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index b07e17160f94..3c4b10ff48c1 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -276,7 +276,7 @@ static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
int val[2], val2[2], i;
@@ -300,7 +300,7 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
int err;
@@ -333,7 +333,7 @@ static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
@@ -353,7 +353,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
@@ -1327,10 +1327,6 @@ static int pm860x_probe(struct snd_soc_codec *codec)
pm860x->codec = codec;
- ret = snd_soc_codec_set_cache_io(codec, pm860x->regmap);
- if (ret)
- return ret;
-
for (i = 0; i < 4; i++) {
ret = request_threaded_irq(pm860x->irq[i], NULL,
pm860x_codec_handler, IRQF_ONESHOT,
@@ -1362,10 +1358,18 @@ static int pm860x_remove(struct snd_soc_codec *codec)
return 0;
}
+static struct regmap *pm860x_get_regmap(struct device *dev)
+{
+ struct pm860x_priv *pm860x = dev_get_drvdata(dev);
+
+ return pm860x->regmap;
+}
+
static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
.probe = pm860x_probe,
.remove = pm860x_remove,
.set_bias_level = pm860x_set_bias_level,
+ .get_regmap = pm860x_get_regmap,
.controls = pm860x_snd_controls,
.num_controls = ARRAY_SIZE(pm860x_snd_controls),
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index f0e840137887..66f4b6ec12cf 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -23,6 +23,10 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
select SND_SOC_AD73311
select SND_SOC_ADAU1373 if I2C
+ select SND_SOC_ADAU1761_I2C if I2C
+ select SND_SOC_ADAU1761_SPI if SPI
+ select SND_SOC_ADAU1781_I2C if I2C
+ select SND_SOC_ADAU1781_SPI if SPI
select SND_SOC_ADAV801 if SPI_MASTER
select SND_SOC_ADAV803 if I2C
select SND_SOC_ADAU1977_SPI if SPI_MASTER
@@ -39,8 +43,9 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ALC5623 if I2C
select SND_SOC_ALC5632 if I2C
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
- select SND_SOC_CS42L51 if I2C
- select SND_SOC_CS42L52 if I2C
+ select SND_SOC_CS42L51_I2C if I2C
+ select SND_SOC_CS42L52 if I2C && INPUT
+ select SND_SOC_CS42L56 if I2C && INPUT
select SND_SOC_CS42L73 if I2C
select SND_SOC_CS4270 if I2C
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
@@ -71,6 +76,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM512x_SPI if SPI_MASTER
select SND_SOC_RT5631 if I2C
select SND_SOC_RT5640 if I2C
+ select SND_SOC_RT5645 if I2C
+ select SND_SOC_RT5651 if I2C
select SND_SOC_SGTL5000 if I2C
select SND_SOC_SI476X if MFD_SI476X_CORE
select SND_SOC_SIRF_AUDIO_CODEC
@@ -80,6 +87,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_SSM2602_SPI if SPI_MASTER
select SND_SOC_SSM2602_I2C if I2C
select SND_SOC_STA32X if I2C
+ select SND_SOC_STA350 if I2C
select SND_SOC_STA529 if I2C
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_TAS5086 if I2C
@@ -127,7 +135,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8955 if I2C
select SND_SOC_WM8960 if I2C
select SND_SOC_WM8961 if I2C
- select SND_SOC_WM8962 if I2C
+ select SND_SOC_WM8962 if I2C && INPUT
select SND_SOC_WM8971 if I2C
select SND_SOC_WM8974 if I2C
select SND_SOC_WM8978 if I2C
@@ -210,13 +218,45 @@ config SND_SOC_AD1980
config SND_SOC_AD73311
tristate
+config SND_SOC_ADAU1373
+ tristate
+
config SND_SOC_ADAU1701
tristate "Analog Devices ADAU1701 CODEC"
depends on I2C
select SND_SOC_SIGMADSP
-config SND_SOC_ADAU1373
+config SND_SOC_ADAU17X1
tristate
+ select SND_SOC_SIGMADSP
+
+config SND_SOC_ADAU1761
+ tristate
+ select SND_SOC_ADAU17X1
+
+config SND_SOC_ADAU1761_I2C
+ tristate
+ select SND_SOC_ADAU1761
+ select REGMAP_I2C
+
+config SND_SOC_ADAU1761_SPI
+ tristate
+ select SND_SOC_ADAU1761
+ select REGMAP_SPI
+
+config SND_SOC_ADAU1781
+ select SND_SOC_ADAU17X1
+ tristate
+
+config SND_SOC_ADAU1781_I2C
+ tristate
+ select SND_SOC_ADAU1781
+ select REGMAP_I2C
+
+config SND_SOC_ADAU1781_SPI
+ tristate
+ select SND_SOC_ADAU1781
+ select REGMAP_SPI
config SND_SOC_ADAU1977
tristate
@@ -269,7 +309,7 @@ config SND_SOC_AK5386
tristate "AKM AK5638 CODEC"
config SND_SOC_ALC5623
- tristate
+ tristate "Realtek ALC5623 CODEC"
config SND_SOC_ALC5632
tristate
@@ -280,9 +320,17 @@ config SND_SOC_CQ0093VC
config SND_SOC_CS42L51
tristate
+config SND_SOC_CS42L51_I2C
+ tristate
+ select SND_SOC_CS42L51
+
config SND_SOC_CS42L52
tristate "Cirrus Logic CS42L52 CODEC"
- depends on I2C
+ depends on I2C && INPUT
+
+config SND_SOC_CS42L56
+ tristate "Cirrus Logic CS42L56 CODEC"
+ depends on I2C && INPUT
config SND_SOC_CS42L73
tristate "Cirrus Logic CS42L73 CODEC"
@@ -396,6 +444,12 @@ config SND_SOC_RT5631
config SND_SOC_RT5640
tristate
+config SND_SOC_RT5645
+ tristate
+
+config SND_SOC_RT5651
+ tristate
+
#Freescale sgtl5000 codec
config SND_SOC_SGTL5000
tristate "Freescale SGTL5000 CODEC"
@@ -435,6 +489,10 @@ config SND_SOC_SSM2602_I2C
config SND_SOC_STA32X
tristate
+config SND_SOC_STA350
+ tristate "STA350 speaker amplifier"
+ depends on I2C
+
config SND_SOC_STA529
tristate
@@ -598,7 +656,7 @@ config SND_SOC_WM8961
config SND_SOC_WM8962
tristate "Wolfson Microelectronics WM8962 CODEC"
- depends on I2C
+ depends on I2C && INPUT
config SND_SOC_WM8971
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 3c4d275d064b..bed0d984c97c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -7,8 +7,15 @@ snd-soc-ad193x-spi-objs := ad193x-spi.o
snd-soc-ad193x-i2c-objs := ad193x-i2c.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-adau1701-objs := adau1701.o
+snd-soc-adau17x1-objs := adau17x1.o
+snd-soc-adau1761-objs := adau1761.o
+snd-soc-adau1761-i2c-objs := adau1761-i2c.o
+snd-soc-adau1761-spi-objs := adau1761-spi.o
+snd-soc-adau1781-objs := adau1781.o
+snd-soc-adau1781-i2c-objs := adau1781-i2c.o
+snd-soc-adau1781-spi-objs := adau1781-spi.o
snd-soc-adau1977-objs := adau1977.o
snd-soc-adau1977-spi-objs := adau1977-spi.o
snd-soc-adau1977-i2c-objs := adau1977-i2c.o
@@ -26,7 +33,9 @@ snd-soc-ak5386-objs := ak5386.o
snd-soc-arizona-objs := arizona.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs42l51-objs := cs42l51.o
+snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
snd-soc-cs42l52-objs := cs42l52.o
+snd-soc-cs42l56-objs := cs42l56.o
snd-soc-cs42l73-objs := cs42l73.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cs4271-objs := cs4271.o
@@ -60,6 +69,8 @@ snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
snd-soc-rt5631-objs := rt5631.o
snd-soc-rt5640-objs := rt5640.o
+snd-soc-rt5645-objs := rt5645.o
+snd-soc-rt5651-objs := rt5651.o
snd-soc-sgtl5000-objs := sgtl5000.o
snd-soc-alc5623-objs := alc5623.o
snd-soc-alc5632-objs := alc5632.o
@@ -74,6 +85,7 @@ snd-soc-ssm2602-objs := ssm2602.o
snd-soc-ssm2602-spi-objs := ssm2602-spi.o
snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o
snd-soc-sta32x-objs := sta32x.o
+snd-soc-sta350-objs := sta350.o
snd-soc-sta529-objs := sta529.o
snd-soc-stac9766-objs := stac9766.o
snd-soc-tas5086-objs := tas5086.o
@@ -157,10 +169,17 @@ obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.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_ADAU17X1) += snd-soc-adau17x1.o
+obj-$(CONFIG_SND_SOC_ADAU1761) += snd-soc-adau1761.o
+obj-$(CONFIG_SND_SOC_ADAU1761_I2C) += snd-soc-adau1761-i2c.o
+obj-$(CONFIG_SND_SOC_ADAU1761_SPI) += snd-soc-adau1761-spi.o
+obj-$(CONFIG_SND_SOC_ADAU1781) += snd-soc-adau1781.o
+obj-$(CONFIG_SND_SOC_ADAU1781_I2C) += snd-soc-adau1781-i2c.o
+obj-$(CONFIG_SND_SOC_ADAU1781_SPI) += snd-soc-adau1781-spi.o
obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o
obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o
obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o
-obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o
obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o
@@ -177,7 +196,9 @@ obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o
obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
+obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
+obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o
obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
@@ -211,6 +232,8 @@ obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
+obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
+obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o
@@ -221,6 +244,7 @@ obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o
obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o
obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o
+obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o
obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 1ad92cbf0b24..1fb4402bf72d 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -1139,7 +1139,7 @@ static void anc_configure(struct snd_soc_codec *codec,
static int sid_status_control_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
mutex_lock(&codec->mutex);
@@ -1153,7 +1153,7 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol,
static int sid_status_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
unsigned int param, sidconf, val;
int status = 1;
@@ -1208,7 +1208,7 @@ out:
static int anc_status_control_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
mutex_lock(&codec->mutex);
@@ -1221,7 +1221,7 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol,
static int anc_status_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
struct device *dev = codec->dev;
bool apply_fir, apply_iir;
@@ -1306,7 +1306,7 @@ static int filter_control_info(struct snd_kcontrol *kcontrol,
static int filter_control_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct filter_control *fc =
(struct filter_control *)kcontrol->private_value;
unsigned int i;
@@ -1322,7 +1322,7 @@ static int filter_control_get(struct snd_kcontrol *kcontrol,
static int filter_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct filter_control *fc =
(struct filter_control *)kcontrol->private_value;
unsigned int i;
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 34d965a4a040..304d3003339a 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -189,28 +189,27 @@ static struct snd_soc_dai_driver ad1980_dai = {
static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
{
- u16 retry_cnt = 0;
+ unsigned int retry_cnt = 0;
-retry:
- if (try_warm && soc_ac97_ops->warm_reset) {
- soc_ac97_ops->warm_reset(codec->ac97);
- if (ac97_read(codec, AC97_RESET) == 0x0090)
- return 1;
- }
-
- soc_ac97_ops->reset(codec->ac97);
- /* Set bit 16slot in register 74h, then every slot will has only 16
- * bits. This command is sent out in 20bit mode, in which case the
- * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/
- ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
-
- if (ac97_read(codec, AC97_RESET) != 0x0090)
- goto err;
- return 0;
+ do {
+ if (try_warm && soc_ac97_ops->warm_reset) {
+ soc_ac97_ops->warm_reset(codec->ac97);
+ if (ac97_read(codec, AC97_RESET) == 0x0090)
+ return 1;
+ }
-err:
- while (retry_cnt++ < 10)
- goto retry;
+ soc_ac97_ops->reset(codec->ac97);
+ /*
+ * Set bit 16slot in register 74h, then every slot will has only
+ * 16 bits. This command is sent out in 20bit mode, in which
+ * case the first nibble of data is eaten by the addr. (Tag is
+ * always 16 bit)
+ */
+ ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
+
+ if (ac97_read(codec, AC97_RESET) == 0x0090)
+ return 0;
+ } while (retry_cnt++ < 10);
printk(KERN_ERR "AD1980 AC97 reset failed\n");
return -EIO;
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 877f5737bb6b..1ff7d4d027e9 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -519,8 +519,7 @@ static const struct snd_kcontrol_new adau1373_controls[] = {
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 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,
@@ -580,7 +579,7 @@ static SOC_ENUM_SINGLE_VIRT_DECL(adau1373_decimator_enum,
adau1373_decimator_text);
static const struct snd_kcontrol_new adau1373_decimator_mux =
- SOC_DAPM_ENUM_VIRT("Decimator Mux", adau1373_decimator_enum);
+ SOC_DAPM_ENUM("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),
@@ -694,7 +693,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = {
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,
+ SND_SOC_DAPM_MUX("Decimator Mux", SND_SOC_NOPM, 0, 0,
&adau1373_decimator_mux),
SND_SOC_DAPM_SUPPLY("MICBIAS2", ADAU1373_PWDN_CTRL1, 5, 0, NULL, 0),
diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c
new file mode 100644
index 000000000000..862796dec693
--- /dev/null
+++ b/sound/soc/codecs/adau1761-i2c.c
@@ -0,0 +1,60 @@
+/*
+ * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
+ *
+ * Copyright 2014 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "adau1761.h"
+
+static int adau1761_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regmap_config config;
+
+ config = adau1761_regmap_config;
+ config.val_bits = 8;
+ config.reg_bits = 16;
+
+ return adau1761_probe(&client->dev,
+ devm_regmap_init_i2c(client, &config),
+ id->driver_data, NULL);
+}
+
+static int adau1761_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id adau1761_i2c_ids[] = {
+ { "adau1361", ADAU1361 },
+ { "adau1461", ADAU1761 },
+ { "adau1761", ADAU1761 },
+ { "adau1961", ADAU1361 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adau1761_i2c_ids);
+
+static struct i2c_driver adau1761_i2c_driver = {
+ .driver = {
+ .name = "adau1761",
+ .owner = THIS_MODULE,
+ },
+ .probe = adau1761_i2c_probe,
+ .remove = adau1761_i2c_remove,
+ .id_table = adau1761_i2c_ids,
+};
+module_i2c_driver(adau1761_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC I2C driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1761-spi.c b/sound/soc/codecs/adau1761-spi.c
new file mode 100644
index 000000000000..cce2f11f1ffb
--- /dev/null
+++ b/sound/soc/codecs/adau1761-spi.c
@@ -0,0 +1,77 @@
+/*
+ * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
+ *
+ * Copyright 2014 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "adau1761.h"
+
+static void adau1761_spi_switch_mode(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+
+ /*
+ * To get the device into SPI mode CLATCH has to be pulled low three
+ * times. Do this by issuing three dummy reads.
+ */
+ spi_w8r8(spi, 0x00);
+ spi_w8r8(spi, 0x00);
+ spi_w8r8(spi, 0x00);
+}
+
+static int adau1761_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct regmap_config config;
+
+ if (!id)
+ return -EINVAL;
+
+ config = adau1761_regmap_config;
+ config.val_bits = 8;
+ config.reg_bits = 24;
+ config.read_flag_mask = 0x1;
+
+ return adau1761_probe(&spi->dev,
+ devm_regmap_init_spi(spi, &config),
+ id->driver_data, adau1761_spi_switch_mode);
+}
+
+static int adau1761_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ return 0;
+}
+
+static const struct spi_device_id adau1761_spi_id[] = {
+ { "adau1361", ADAU1361 },
+ { "adau1461", ADAU1761 },
+ { "adau1761", ADAU1761 },
+ { "adau1961", ADAU1361 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, adau1761_spi_id);
+
+static struct spi_driver adau1761_spi_driver = {
+ .driver = {
+ .name = "adau1761",
+ .owner = THIS_MODULE,
+ },
+ .probe = adau1761_spi_probe,
+ .remove = adau1761_spi_remove,
+ .id_table = adau1761_spi_id,
+};
+module_spi_driver(adau1761_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC SPI driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
new file mode 100644
index 000000000000..848cab839553
--- /dev/null
+++ b/sound/soc/codecs/adau1761.c
@@ -0,0 +1,803 @@
+/*
+ * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
+ *
+ * Copyright 2011-2013 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/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/platform_data/adau17x1.h>
+
+#include "adau17x1.h"
+#include "adau1761.h"
+
+#define ADAU1761_DIGMIC_JACKDETECT 0x4008
+#define ADAU1761_REC_MIXER_LEFT0 0x400a
+#define ADAU1761_REC_MIXER_LEFT1 0x400b
+#define ADAU1761_REC_MIXER_RIGHT0 0x400c
+#define ADAU1761_REC_MIXER_RIGHT1 0x400d
+#define ADAU1761_LEFT_DIFF_INPUT_VOL 0x400e
+#define ADAU1761_RIGHT_DIFF_INPUT_VOL 0x400f
+#define ADAU1761_PLAY_LR_MIXER_LEFT 0x4020
+#define ADAU1761_PLAY_MIXER_LEFT0 0x401c
+#define ADAU1761_PLAY_MIXER_LEFT1 0x401d
+#define ADAU1761_PLAY_MIXER_RIGHT0 0x401e
+#define ADAU1761_PLAY_MIXER_RIGHT1 0x401f
+#define ADAU1761_PLAY_LR_MIXER_RIGHT 0x4021
+#define ADAU1761_PLAY_MIXER_MONO 0x4022
+#define ADAU1761_PLAY_HP_LEFT_VOL 0x4023
+#define ADAU1761_PLAY_HP_RIGHT_VOL 0x4024
+#define ADAU1761_PLAY_LINE_LEFT_VOL 0x4025
+#define ADAU1761_PLAY_LINE_RIGHT_VOL 0x4026
+#define ADAU1761_PLAY_MONO_OUTPUT_VOL 0x4027
+#define ADAU1761_POP_CLICK_SUPPRESS 0x4028
+#define ADAU1761_JACK_DETECT_PIN 0x4031
+#define ADAU1761_DEJITTER 0x4036
+#define ADAU1761_CLK_ENABLE0 0x40f9
+#define ADAU1761_CLK_ENABLE1 0x40fa
+
+#define ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW BIT(0)
+#define ADAU1761_DIGMIC_JACKDETECT_DIGMIC BIT(5)
+
+#define ADAU1761_DIFF_INPUT_VOL_LDEN BIT(0)
+
+#define ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP BIT(0)
+#define ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE BIT(1)
+
+#define ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP BIT(0)
+
+#define ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP BIT(0)
+
+#define ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP BIT(0)
+
+
+#define ADAU1761_FIRMWARE "adau1761.bin"
+
+static const struct reg_default adau1761_reg_defaults[] = {
+ { ADAU1761_DEJITTER, 0x03 },
+ { ADAU1761_DIGMIC_JACKDETECT, 0x00 },
+ { ADAU1761_REC_MIXER_LEFT0, 0x00 },
+ { ADAU1761_REC_MIXER_LEFT1, 0x00 },
+ { ADAU1761_REC_MIXER_RIGHT0, 0x00 },
+ { ADAU1761_REC_MIXER_RIGHT1, 0x00 },
+ { ADAU1761_LEFT_DIFF_INPUT_VOL, 0x00 },
+ { ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 },
+ { ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 },
+ { ADAU1761_PLAY_MIXER_LEFT0, 0x00 },
+ { ADAU1761_PLAY_MIXER_LEFT1, 0x00 },
+ { ADAU1761_PLAY_MIXER_RIGHT0, 0x00 },
+ { ADAU1761_PLAY_MIXER_RIGHT1, 0x00 },
+ { ADAU1761_PLAY_LR_MIXER_RIGHT, 0x00 },
+ { ADAU1761_PLAY_MIXER_MONO, 0x00 },
+ { ADAU1761_PLAY_HP_LEFT_VOL, 0x00 },
+ { ADAU1761_PLAY_HP_RIGHT_VOL, 0x00 },
+ { ADAU1761_PLAY_LINE_LEFT_VOL, 0x00 },
+ { ADAU1761_PLAY_LINE_RIGHT_VOL, 0x00 },
+ { ADAU1761_PLAY_MONO_OUTPUT_VOL, 0x00 },
+ { ADAU1761_POP_CLICK_SUPPRESS, 0x00 },
+ { ADAU1761_JACK_DETECT_PIN, 0x00 },
+ { ADAU1761_CLK_ENABLE0, 0x00 },
+ { ADAU1761_CLK_ENABLE1, 0x00 },
+ { ADAU17X1_CLOCK_CONTROL, 0x00 },
+ { ADAU17X1_PLL_CONTROL, 0x00 },
+ { ADAU17X1_REC_POWER_MGMT, 0x00 },
+ { ADAU17X1_MICBIAS, 0x00 },
+ { ADAU17X1_SERIAL_PORT0, 0x00 },
+ { ADAU17X1_SERIAL_PORT1, 0x00 },
+ { ADAU17X1_CONVERTER0, 0x00 },
+ { ADAU17X1_CONVERTER1, 0x00 },
+ { ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 },
+ { ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 },
+ { ADAU17X1_ADC_CONTROL, 0x00 },
+ { ADAU17X1_PLAY_POWER_MGMT, 0x00 },
+ { ADAU17X1_DAC_CONTROL0, 0x00 },
+ { ADAU17X1_DAC_CONTROL1, 0x00 },
+ { ADAU17X1_DAC_CONTROL2, 0x00 },
+ { ADAU17X1_SERIAL_PORT_PAD, 0xaa },
+ { ADAU17X1_CONTROL_PORT_PAD0, 0xaa },
+ { ADAU17X1_CONTROL_PORT_PAD1, 0x00 },
+ { ADAU17X1_DSP_SAMPLING_RATE, 0x01 },
+ { ADAU17X1_SERIAL_INPUT_ROUTE, 0x00 },
+ { ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x00 },
+ { ADAU17X1_DSP_ENABLE, 0x00 },
+ { ADAU17X1_DSP_RUN, 0x00 },
+ { ADAU17X1_SERIAL_SAMPLING_RATE, 0x00 },
+};
+
+static const DECLARE_TLV_DB_SCALE(adau1761_sing_in_tlv, -1500, 300, 1);
+static const DECLARE_TLV_DB_SCALE(adau1761_diff_in_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adau1761_out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(adau1761_sidetone_tlv, -1800, 300, 1);
+static const DECLARE_TLV_DB_SCALE(adau1761_boost_tlv, -600, 600, 1);
+static const DECLARE_TLV_DB_SCALE(adau1761_pga_boost_tlv, -2000, 2000, 1);
+
+static const unsigned int adau1761_bias_select_values[] = {
+ 0, 2, 3,
+};
+
+static const char * const adau1761_bias_select_text[] = {
+ "Normal operation", "Enhanced performance", "Power saving",
+};
+
+static const char * const adau1761_bias_select_extreme_text[] = {
+ "Normal operation", "Extreme power saving", "Enhanced performance",
+ "Power saving",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1761_adc_bias_enum,
+ ADAU17X1_REC_POWER_MGMT, 3, adau1761_bias_select_extreme_text);
+static SOC_ENUM_SINGLE_DECL(adau1761_hp_bias_enum,
+ ADAU17X1_PLAY_POWER_MGMT, 6, adau1761_bias_select_extreme_text);
+static SOC_ENUM_SINGLE_DECL(adau1761_dac_bias_enum,
+ ADAU17X1_PLAY_POWER_MGMT, 4, adau1761_bias_select_extreme_text);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_playback_bias_enum,
+ ADAU17X1_PLAY_POWER_MGMT, 2, 0x3, adau1761_bias_select_text,
+ adau1761_bias_select_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_capture_bias_enum,
+ ADAU17X1_REC_POWER_MGMT, 1, 0x3, adau1761_bias_select_text,
+ adau1761_bias_select_values);
+
+static const struct snd_kcontrol_new adau1761_jack_detect_controls[] = {
+ SOC_SINGLE("Speaker Auto-mute Switch", ADAU1761_DIGMIC_JACKDETECT,
+ 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new adau1761_differential_mode_controls[] = {
+ SOC_DOUBLE_R_TLV("Capture Volume", ADAU1761_LEFT_DIFF_INPUT_VOL,
+ ADAU1761_RIGHT_DIFF_INPUT_VOL, 2, 0x3f, 0,
+ adau1761_diff_in_tlv),
+ SOC_DOUBLE_R("Capture Switch", ADAU1761_LEFT_DIFF_INPUT_VOL,
+ ADAU1761_RIGHT_DIFF_INPUT_VOL, 1, 1, 0),
+
+ SOC_DOUBLE_R_TLV("PGA Boost Capture Volume", ADAU1761_REC_MIXER_LEFT1,
+ ADAU1761_REC_MIXER_RIGHT1, 3, 2, 0, adau1761_pga_boost_tlv),
+};
+
+static const struct snd_kcontrol_new adau1761_single_mode_controls[] = {
+ SOC_SINGLE_TLV("Input 1 Capture Volume", ADAU1761_REC_MIXER_LEFT0,
+ 4, 7, 0, adau1761_sing_in_tlv),
+ SOC_SINGLE_TLV("Input 2 Capture Volume", ADAU1761_REC_MIXER_LEFT0,
+ 1, 7, 0, adau1761_sing_in_tlv),
+ SOC_SINGLE_TLV("Input 3 Capture Volume", ADAU1761_REC_MIXER_RIGHT0,
+ 4, 7, 0, adau1761_sing_in_tlv),
+ SOC_SINGLE_TLV("Input 4 Capture Volume", ADAU1761_REC_MIXER_RIGHT0,
+ 1, 7, 0, adau1761_sing_in_tlv),
+};
+
+static const struct snd_kcontrol_new adau1761_controls[] = {
+ SOC_DOUBLE_R_TLV("Aux Capture Volume", ADAU1761_REC_MIXER_LEFT1,
+ ADAU1761_REC_MIXER_RIGHT1, 0, 7, 0, adau1761_sing_in_tlv),
+
+ SOC_DOUBLE_R_TLV("Headphone Playback Volume", ADAU1761_PLAY_HP_LEFT_VOL,
+ ADAU1761_PLAY_HP_RIGHT_VOL, 2, 0x3f, 0, adau1761_out_tlv),
+ SOC_DOUBLE_R("Headphone Playback Switch", ADAU1761_PLAY_HP_LEFT_VOL,
+ ADAU1761_PLAY_HP_RIGHT_VOL, 1, 1, 0),
+ SOC_DOUBLE_R_TLV("Lineout Playback Volume", ADAU1761_PLAY_LINE_LEFT_VOL,
+ ADAU1761_PLAY_LINE_RIGHT_VOL, 2, 0x3f, 0, adau1761_out_tlv),
+ SOC_DOUBLE_R("Lineout Playback Switch", ADAU1761_PLAY_LINE_LEFT_VOL,
+ ADAU1761_PLAY_LINE_RIGHT_VOL, 1, 1, 0),
+
+ SOC_ENUM("ADC Bias", adau1761_adc_bias_enum),
+ SOC_ENUM("DAC Bias", adau1761_dac_bias_enum),
+ SOC_ENUM("Capture Bias", adau1761_capture_bias_enum),
+ SOC_ENUM("Playback Bias", adau1761_playback_bias_enum),
+ SOC_ENUM("Headphone Bias", adau1761_hp_bias_enum),
+};
+
+static const struct snd_kcontrol_new adau1761_mono_controls[] = {
+ SOC_SINGLE_TLV("Mono Playback Volume", ADAU1761_PLAY_MONO_OUTPUT_VOL,
+ 2, 0x3f, 0, adau1761_out_tlv),
+ SOC_SINGLE("Mono Playback Switch", ADAU1761_PLAY_MONO_OUTPUT_VOL,
+ 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new adau1761_left_mixer_controls[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("Left DAC Switch",
+ ADAU1761_PLAY_MIXER_LEFT0, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("Right DAC Switch",
+ ADAU1761_PLAY_MIXER_LEFT0, 6, 1, 0),
+ SOC_DAPM_SINGLE_TLV("Aux Bypass Volume",
+ ADAU1761_PLAY_MIXER_LEFT0, 1, 8, 0, adau1761_sidetone_tlv),
+ SOC_DAPM_SINGLE_TLV("Right Bypass Volume",
+ ADAU1761_PLAY_MIXER_LEFT1, 4, 8, 0, adau1761_sidetone_tlv),
+ SOC_DAPM_SINGLE_TLV("Left Bypass Volume",
+ ADAU1761_PLAY_MIXER_LEFT1, 0, 8, 0, adau1761_sidetone_tlv),
+};
+
+static const struct snd_kcontrol_new adau1761_right_mixer_controls[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("Left DAC Switch",
+ ADAU1761_PLAY_MIXER_RIGHT0, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("Right DAC Switch",
+ ADAU1761_PLAY_MIXER_RIGHT0, 6, 1, 0),
+ SOC_DAPM_SINGLE_TLV("Aux Bypass Volume",
+ ADAU1761_PLAY_MIXER_RIGHT0, 1, 8, 0, adau1761_sidetone_tlv),
+ SOC_DAPM_SINGLE_TLV("Right Bypass Volume",
+ ADAU1761_PLAY_MIXER_RIGHT1, 4, 8, 0, adau1761_sidetone_tlv),
+ SOC_DAPM_SINGLE_TLV("Left Bypass Volume",
+ ADAU1761_PLAY_MIXER_RIGHT1, 0, 8, 0, adau1761_sidetone_tlv),
+};
+
+static const struct snd_kcontrol_new adau1761_left_lr_mixer_controls[] = {
+ SOC_DAPM_SINGLE_TLV("Left Volume",
+ ADAU1761_PLAY_LR_MIXER_LEFT, 1, 2, 0, adau1761_boost_tlv),
+ SOC_DAPM_SINGLE_TLV("Right Volume",
+ ADAU1761_PLAY_LR_MIXER_LEFT, 3, 2, 0, adau1761_boost_tlv),
+};
+
+static const struct snd_kcontrol_new adau1761_right_lr_mixer_controls[] = {
+ SOC_DAPM_SINGLE_TLV("Left Volume",
+ ADAU1761_PLAY_LR_MIXER_RIGHT, 1, 2, 0, adau1761_boost_tlv),
+ SOC_DAPM_SINGLE_TLV("Right Volume",
+ ADAU1761_PLAY_LR_MIXER_RIGHT, 3, 2, 0, adau1761_boost_tlv),
+};
+
+static const char * const adau1761_input_mux_text[] = {
+ "ADC", "DMIC",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1761_input_mux_enum,
+ ADAU17X1_ADC_CONTROL, 2, adau1761_input_mux_text);
+
+static const struct snd_kcontrol_new adau1761_input_mux_control =
+ SOC_DAPM_ENUM("Input Select", adau1761_input_mux_enum);
+
+static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
+
+ /* After any power changes have been made the dejitter circuit
+ * has to be reinitialized. */
+ regmap_write(adau->regmap, ADAU1761_DEJITTER, 0);
+ if (!adau->master)
+ regmap_write(adau->regmap, ADAU1761_DEJITTER, 3);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget adau1x61_dapm_widgets[] = {
+ SND_SOC_DAPM_MIXER("Left Input Mixer", ADAU1761_REC_MIXER_LEFT0, 0, 0,
+ NULL, 0),
+ SND_SOC_DAPM_MIXER("Right Input Mixer", ADAU1761_REC_MIXER_RIGHT0, 0, 0,
+ NULL, 0),
+
+ SOC_MIXER_ARRAY("Left Playback Mixer", ADAU1761_PLAY_MIXER_LEFT0,
+ 0, 0, adau1761_left_mixer_controls),
+ SOC_MIXER_ARRAY("Right Playback Mixer", ADAU1761_PLAY_MIXER_RIGHT0,
+ 0, 0, adau1761_right_mixer_controls),
+ SOC_MIXER_ARRAY("Left LR Playback Mixer", ADAU1761_PLAY_LR_MIXER_LEFT,
+ 0, 0, adau1761_left_lr_mixer_controls),
+ SOC_MIXER_ARRAY("Right LR Playback Mixer", ADAU1761_PLAY_LR_MIXER_RIGHT,
+ 0, 0, adau1761_right_lr_mixer_controls),
+
+ SND_SOC_DAPM_SUPPLY("Headphone", ADAU1761_PLAY_HP_LEFT_VOL,
+ 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("SYSCLK", 2, SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_POST("Dejitter fixup", adau1761_dejitter_fixup),
+
+ SND_SOC_DAPM_INPUT("LAUX"),
+ SND_SOC_DAPM_INPUT("RAUX"),
+ SND_SOC_DAPM_INPUT("LINP"),
+ SND_SOC_DAPM_INPUT("LINN"),
+ SND_SOC_DAPM_INPUT("RINP"),
+ SND_SOC_DAPM_INPUT("RINN"),
+
+ SND_SOC_DAPM_OUTPUT("LOUT"),
+ SND_SOC_DAPM_OUTPUT("ROUT"),
+ SND_SOC_DAPM_OUTPUT("LHP"),
+ SND_SOC_DAPM_OUTPUT("RHP"),
+};
+
+static const struct snd_soc_dapm_widget adau1761_mono_dapm_widgets[] = {
+ SND_SOC_DAPM_MIXER("Mono Playback Mixer", ADAU1761_PLAY_MIXER_MONO,
+ 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_OUTPUT("MONOOUT"),
+};
+
+static const struct snd_soc_dapm_widget adau1761_capless_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY_S("Headphone VGND", 1, ADAU1761_PLAY_MIXER_MONO,
+ 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route adau1x61_dapm_routes[] = {
+ { "Left Input Mixer", NULL, "LINP" },
+ { "Left Input Mixer", NULL, "LINN" },
+ { "Left Input Mixer", NULL, "LAUX" },
+
+ { "Right Input Mixer", NULL, "RINP" },
+ { "Right Input Mixer", NULL, "RINN" },
+ { "Right Input Mixer", NULL, "RAUX" },
+
+ { "Left Playback Mixer", NULL, "Left Playback Enable"},
+ { "Right Playback Mixer", NULL, "Right Playback Enable"},
+ { "Left LR Playback Mixer", NULL, "Left Playback Enable"},
+ { "Right LR Playback Mixer", NULL, "Right Playback Enable"},
+
+ { "Left Playback Mixer", "Left DAC Switch", "Left DAC" },
+ { "Left Playback Mixer", "Right DAC Switch", "Right DAC" },
+
+ { "Right Playback Mixer", "Left DAC Switch", "Left DAC" },
+ { "Right Playback Mixer", "Right DAC Switch", "Right DAC" },
+
+ { "Left LR Playback Mixer", "Left Volume", "Left Playback Mixer" },
+ { "Left LR Playback Mixer", "Right Volume", "Right Playback Mixer" },
+
+ { "Right LR Playback Mixer", "Left Volume", "Left Playback Mixer" },
+ { "Right LR Playback Mixer", "Right Volume", "Right Playback Mixer" },
+
+ { "LHP", NULL, "Left Playback Mixer" },
+ { "RHP", NULL, "Right Playback Mixer" },
+
+ { "LHP", NULL, "Headphone" },
+ { "RHP", NULL, "Headphone" },
+
+ { "LOUT", NULL, "Left LR Playback Mixer" },
+ { "ROUT", NULL, "Right LR Playback Mixer" },
+
+ { "Left Playback Mixer", "Aux Bypass Volume", "LAUX" },
+ { "Left Playback Mixer", "Left Bypass Volume", "Left Input Mixer" },
+ { "Left Playback Mixer", "Right Bypass Volume", "Right Input Mixer" },
+ { "Right Playback Mixer", "Aux Bypass Volume", "RAUX" },
+ { "Right Playback Mixer", "Left Bypass Volume", "Left Input Mixer" },
+ { "Right Playback Mixer", "Right Bypass Volume", "Right Input Mixer" },
+};
+
+static const struct snd_soc_dapm_route adau1761_mono_dapm_routes[] = {
+ { "Mono Playback Mixer", NULL, "Left Playback Mixer" },
+ { "Mono Playback Mixer", NULL, "Right Playback Mixer" },
+
+ { "MONOOUT", NULL, "Mono Playback Mixer" },
+};
+
+static const struct snd_soc_dapm_route adau1761_capless_dapm_routes[] = {
+ { "Headphone", NULL, "Headphone VGND" },
+};
+
+static const struct snd_soc_dapm_widget adau1761_dmic_widgets[] = {
+ SND_SOC_DAPM_MUX("Left Decimator Mux", SND_SOC_NOPM, 0, 0,
+ &adau1761_input_mux_control),
+ SND_SOC_DAPM_MUX("Right Decimator Mux", SND_SOC_NOPM, 0, 0,
+ &adau1761_input_mux_control),
+
+ SND_SOC_DAPM_INPUT("DMIC"),
+};
+
+static const struct snd_soc_dapm_route adau1761_dmic_routes[] = {
+ { "Left Decimator Mux", "ADC", "Left Input Mixer" },
+ { "Left Decimator Mux", "DMIC", "DMIC" },
+ { "Right Decimator Mux", "ADC", "Right Input Mixer" },
+ { "Right Decimator Mux", "DMIC", "DMIC" },
+
+ { "Left Decimator", NULL, "Left Decimator Mux" },
+ { "Right Decimator", NULL, "Right Decimator Mux" },
+};
+
+static const struct snd_soc_dapm_route adau1761_no_dmic_routes[] = {
+ { "Left Decimator", NULL, "Left Input Mixer" },
+ { "Right Decimator", NULL, "Right Input Mixer" },
+};
+
+static const struct snd_soc_dapm_widget adau1761_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("Serial Port Clock", ADAU1761_CLK_ENABLE0,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Serial Input Routing Clock", ADAU1761_CLK_ENABLE0,
+ 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Serial Output Routing Clock", ADAU1761_CLK_ENABLE0,
+ 3, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("Decimator Resync Clock", ADAU1761_CLK_ENABLE0,
+ 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Interpolator Resync Clock", ADAU1761_CLK_ENABLE0,
+ 2, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("Slew Clock", ADAU1761_CLK_ENABLE0, 6, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("Digital Clock 0", 1, ADAU1761_CLK_ENABLE1,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("Digital Clock 1", 1, ADAU1761_CLK_ENABLE1,
+ 1, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route adau1761_dapm_routes[] = {
+ { "Left Decimator", NULL, "Digital Clock 0", },
+ { "Right Decimator", NULL, "Digital Clock 0", },
+ { "Left DAC", NULL, "Digital Clock 0", },
+ { "Right DAC", NULL, "Digital Clock 0", },
+
+ { "AIFCLK", NULL, "Digital Clock 1" },
+
+ { "Playback", NULL, "Serial Port Clock" },
+ { "Capture", NULL, "Serial Port Clock" },
+ { "Playback", NULL, "Serial Input Routing Clock" },
+ { "Capture", NULL, "Serial Output Routing Clock" },
+
+ { "Left Decimator", NULL, "Decimator Resync Clock" },
+ { "Right Decimator", NULL, "Decimator Resync Clock" },
+ { "Left DAC", NULL, "Interpolator Resync Clock" },
+ { "Right DAC", NULL, "Interpolator Resync Clock" },
+
+ { "DSP", NULL, "Digital Clock 0" },
+
+ { "Slew Clock", NULL, "Digital Clock 0" },
+ { "Right Playback Mixer", NULL, "Slew Clock" },
+ { "Left Playback Mixer", NULL, "Slew Clock" },
+
+ { "Digital Clock 0", NULL, "SYSCLK" },
+ { "Digital Clock 1", NULL, "SYSCLK" },
+};
+
+static int adau1761_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
+ ADAU17X1_CLOCK_CONTROL_SYSCLK_EN,
+ ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
+ break;
+ case SND_SOC_BIAS_OFF:
+ regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
+ ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0);
+ break;
+
+ }
+ codec->dapm.bias_level = level;
+ return 0;
+}
+
+static enum adau1761_output_mode adau1761_get_lineout_mode(
+ struct snd_soc_codec *codec)
+{
+ struct adau1761_platform_data *pdata = codec->dev->platform_data;
+
+ if (pdata)
+ return pdata->lineout_mode;
+
+ return ADAU1761_OUTPUT_MODE_LINE;
+}
+
+static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
+{
+ struct adau1761_platform_data *pdata = codec->dev->platform_data;
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+ enum adau1761_digmic_jackdet_pin_mode mode;
+ unsigned int val = 0;
+ int ret;
+
+ if (pdata)
+ mode = pdata->digmic_jackdetect_pin_mode;
+ else
+ mode = ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE;
+
+ switch (mode) {
+ case ADAU1761_DIGMIC_JACKDET_PIN_MODE_JACKDETECT:
+ switch (pdata->jackdetect_debounce_time) {
+ case ADAU1761_JACKDETECT_DEBOUNCE_5MS:
+ case ADAU1761_JACKDETECT_DEBOUNCE_10MS:
+ case ADAU1761_JACKDETECT_DEBOUNCE_20MS:
+ case ADAU1761_JACKDETECT_DEBOUNCE_40MS:
+ val |= pdata->jackdetect_debounce_time << 6;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (pdata->jackdetect_active_low)
+ val |= ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW;
+
+ ret = snd_soc_add_codec_controls(codec,
+ adau1761_jack_detect_controls,
+ ARRAY_SIZE(adau1761_jack_detect_controls));
+ if (ret)
+ return ret;
+ case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */
+ ret = snd_soc_dapm_add_routes(&codec->dapm,
+ adau1761_no_dmic_routes,
+ ARRAY_SIZE(adau1761_no_dmic_routes));
+ if (ret)
+ return ret;
+ break;
+ case ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC:
+ ret = snd_soc_dapm_new_controls(&codec->dapm,
+ adau1761_dmic_widgets,
+ ARRAY_SIZE(adau1761_dmic_widgets));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(&codec->dapm,
+ adau1761_dmic_routes,
+ ARRAY_SIZE(adau1761_dmic_routes));
+ if (ret)
+ return ret;
+
+ val |= ADAU1761_DIGMIC_JACKDETECT_DIGMIC;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_write(adau->regmap, ADAU1761_DIGMIC_JACKDETECT, val);
+
+ return 0;
+}
+
+static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+ struct adau1761_platform_data *pdata = codec->dev->platform_data;
+ enum adau1761_output_mode mode;
+ int ret;
+
+ if (pdata)
+ mode = pdata->headphone_mode;
+ else
+ mode = ADAU1761_OUTPUT_MODE_HEADPHONE;
+
+ switch (mode) {
+ case ADAU1761_OUTPUT_MODE_LINE:
+ break;
+ case ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS:
+ regmap_update_bits(adau->regmap, ADAU1761_PLAY_MONO_OUTPUT_VOL,
+ ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP |
+ ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE,
+ ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP |
+ ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE);
+ /* fallthrough */
+ case ADAU1761_OUTPUT_MODE_HEADPHONE:
+ regmap_update_bits(adau->regmap, ADAU1761_PLAY_HP_RIGHT_VOL,
+ ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP,
+ ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (mode == ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS) {
+ ret = snd_soc_dapm_new_controls(&codec->dapm,
+ adau1761_capless_dapm_widgets,
+ ARRAY_SIZE(adau1761_capless_dapm_widgets));
+ if (ret)
+ return ret;
+ ret = snd_soc_dapm_add_routes(&codec->dapm,
+ adau1761_capless_dapm_routes,
+ ARRAY_SIZE(adau1761_capless_dapm_routes));
+ } else {
+ ret = snd_soc_add_codec_controls(codec, adau1761_mono_controls,
+ ARRAY_SIZE(adau1761_mono_controls));
+ if (ret)
+ return ret;
+ ret = snd_soc_dapm_new_controls(&codec->dapm,
+ adau1761_mono_dapm_widgets,
+ ARRAY_SIZE(adau1761_mono_dapm_widgets));
+ if (ret)
+ return ret;
+ ret = snd_soc_dapm_add_routes(&codec->dapm,
+ adau1761_mono_dapm_routes,
+ ARRAY_SIZE(adau1761_mono_dapm_routes));
+ }
+
+ return ret;
+}
+
+static bool adau1761_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ADAU1761_DIGMIC_JACKDETECT:
+ case ADAU1761_REC_MIXER_LEFT0:
+ case ADAU1761_REC_MIXER_LEFT1:
+ case ADAU1761_REC_MIXER_RIGHT0:
+ case ADAU1761_REC_MIXER_RIGHT1:
+ case ADAU1761_LEFT_DIFF_INPUT_VOL:
+ case ADAU1761_RIGHT_DIFF_INPUT_VOL:
+ case ADAU1761_PLAY_LR_MIXER_LEFT:
+ case ADAU1761_PLAY_MIXER_LEFT0:
+ case ADAU1761_PLAY_MIXER_LEFT1:
+ case ADAU1761_PLAY_MIXER_RIGHT0:
+ case ADAU1761_PLAY_MIXER_RIGHT1:
+ case ADAU1761_PLAY_LR_MIXER_RIGHT:
+ case ADAU1761_PLAY_MIXER_MONO:
+ case ADAU1761_PLAY_HP_LEFT_VOL:
+ case ADAU1761_PLAY_HP_RIGHT_VOL:
+ case ADAU1761_PLAY_LINE_LEFT_VOL:
+ case ADAU1761_PLAY_LINE_RIGHT_VOL:
+ case ADAU1761_PLAY_MONO_OUTPUT_VOL:
+ case ADAU1761_POP_CLICK_SUPPRESS:
+ case ADAU1761_JACK_DETECT_PIN:
+ case ADAU1761_DEJITTER:
+ case ADAU1761_CLK_ENABLE0:
+ case ADAU1761_CLK_ENABLE1:
+ return true;
+ default:
+ break;
+ }
+
+ return adau17x1_readable_register(dev, reg);
+}
+
+static int adau1761_codec_probe(struct snd_soc_codec *codec)
+{
+ struct adau1761_platform_data *pdata = codec->dev->platform_data;
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = adau17x1_add_widgets(codec);
+ if (ret < 0)
+ return ret;
+
+ if (pdata && pdata->input_differential) {
+ regmap_update_bits(adau->regmap, ADAU1761_LEFT_DIFF_INPUT_VOL,
+ ADAU1761_DIFF_INPUT_VOL_LDEN,
+ ADAU1761_DIFF_INPUT_VOL_LDEN);
+ regmap_update_bits(adau->regmap, ADAU1761_RIGHT_DIFF_INPUT_VOL,
+ ADAU1761_DIFF_INPUT_VOL_LDEN,
+ ADAU1761_DIFF_INPUT_VOL_LDEN);
+ ret = snd_soc_add_codec_controls(codec,
+ adau1761_differential_mode_controls,
+ ARRAY_SIZE(adau1761_differential_mode_controls));
+ if (ret)
+ return ret;
+ } else {
+ ret = snd_soc_add_codec_controls(codec,
+ adau1761_single_mode_controls,
+ ARRAY_SIZE(adau1761_single_mode_controls));
+ if (ret)
+ return ret;
+ }
+
+ switch (adau1761_get_lineout_mode(codec)) {
+ case ADAU1761_OUTPUT_MODE_LINE:
+ break;
+ case ADAU1761_OUTPUT_MODE_HEADPHONE:
+ regmap_update_bits(adau->regmap, ADAU1761_PLAY_LINE_LEFT_VOL,
+ ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP,
+ ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP);
+ regmap_update_bits(adau->regmap, ADAU1761_PLAY_LINE_RIGHT_VOL,
+ ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP,
+ ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = adau1761_setup_headphone_mode(codec);
+ if (ret)
+ return ret;
+
+ ret = adau1761_setup_digmic_jackdetect(codec);
+ if (ret)
+ return ret;
+
+ if (adau->type == ADAU1761) {
+ ret = snd_soc_dapm_new_controls(&codec->dapm,
+ adau1761_dapm_widgets,
+ ARRAY_SIZE(adau1761_dapm_widgets));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(&codec->dapm,
+ adau1761_dapm_routes,
+ ARRAY_SIZE(adau1761_dapm_routes));
+ if (ret)
+ return ret;
+
+ ret = adau17x1_load_firmware(adau, codec->dev,
+ ADAU1761_FIRMWARE);
+ if (ret)
+ dev_warn(codec->dev, "Failed to firmware\n");
+ }
+
+ ret = adau17x1_add_routes(codec);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct snd_soc_codec_driver adau1761_codec_driver = {
+ .probe = adau1761_codec_probe,
+ .suspend = adau17x1_suspend,
+ .resume = adau17x1_resume,
+ .set_bias_level = adau1761_set_bias_level,
+
+ .controls = adau1761_controls,
+ .num_controls = ARRAY_SIZE(adau1761_controls),
+ .dapm_widgets = adau1x61_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(adau1x61_dapm_widgets),
+ .dapm_routes = adau1x61_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(adau1x61_dapm_routes),
+};
+
+#define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver adau1361_dai_driver = {
+ .name = "adau-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 4,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = ADAU1761_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 4,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = ADAU1761_FORMATS,
+ },
+ .ops = &adau17x1_dai_ops,
+};
+
+static struct snd_soc_dai_driver adau1761_dai_driver = {
+ .name = "adau-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = ADAU1761_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = ADAU1761_FORMATS,
+ },
+ .ops = &adau17x1_dai_ops,
+};
+
+int adau1761_probe(struct device *dev, struct regmap *regmap,
+ enum adau17x1_type type, void (*switch_mode)(struct device *dev))
+{
+ struct snd_soc_dai_driver *dai_drv;
+ int ret;
+
+ ret = adau17x1_probe(dev, regmap, type, switch_mode);
+ if (ret)
+ return ret;
+
+ if (type == ADAU1361)
+ dai_drv = &adau1361_dai_driver;
+ else
+ dai_drv = &adau1761_dai_driver;
+
+ return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1);
+}
+EXPORT_SYMBOL_GPL(adau1761_probe);
+
+const struct regmap_config adau1761_regmap_config = {
+ .val_bits = 8,
+ .reg_bits = 16,
+ .max_register = 0x40fa,
+ .reg_defaults = adau1761_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults),
+ .readable_reg = adau1761_readable_register,
+ .volatile_reg = adau17x1_volatile_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(adau1761_regmap_config);
+
+MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1761.h b/sound/soc/codecs/adau1761.h
new file mode 100644
index 000000000000..a9e0d288301e
--- /dev/null
+++ b/sound/soc/codecs/adau1761.h
@@ -0,0 +1,23 @@
+/*
+ * ADAU1361/ADAU1461/ADAU1761/ADAU1961 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __SOUND_SOC_CODECS_ADAU1761_H__
+#define __SOUND_SOC_CODECS_ADAU1761_H__
+
+#include <linux/regmap.h>
+#include "adau17x1.h"
+
+struct device;
+
+int adau1761_probe(struct device *dev, struct regmap *regmap,
+ enum adau17x1_type type, void (*switch_mode)(struct device *dev));
+
+extern const struct regmap_config adau1761_regmap_config;
+
+#endif
diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c
new file mode 100644
index 000000000000..2ce4362ccec1
--- /dev/null
+++ b/sound/soc/codecs/adau1781-i2c.c
@@ -0,0 +1,58 @@
+/*
+ * Driver for ADAU1381/ADAU1781 CODEC
+ *
+ * Copyright 2014 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "adau1781.h"
+
+static int adau1781_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regmap_config config;
+
+ config = adau1781_regmap_config;
+ config.val_bits = 8;
+ config.reg_bits = 16;
+
+ return adau1781_probe(&client->dev,
+ devm_regmap_init_i2c(client, &config),
+ id->driver_data, NULL);
+}
+
+static int adau1781_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id adau1781_i2c_ids[] = {
+ { "adau1381", ADAU1381 },
+ { "adau1781", ADAU1781 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adau1781_i2c_ids);
+
+static struct i2c_driver adau1781_i2c_driver = {
+ .driver = {
+ .name = "adau1781",
+ .owner = THIS_MODULE,
+ },
+ .probe = adau1781_i2c_probe,
+ .remove = adau1781_i2c_remove,
+ .id_table = adau1781_i2c_ids,
+};
+module_i2c_driver(adau1781_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 CODEC I2C driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1781-spi.c b/sound/soc/codecs/adau1781-spi.c
new file mode 100644
index 000000000000..194686716bbe
--- /dev/null
+++ b/sound/soc/codecs/adau1781-spi.c
@@ -0,0 +1,75 @@
+/*
+ * Driver for ADAU1381/ADAU1781 CODEC
+ *
+ * Copyright 2014 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "adau1781.h"
+
+static void adau1781_spi_switch_mode(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+
+ /*
+ * To get the device into SPI mode CLATCH has to be pulled low three
+ * times. Do this by issuing three dummy reads.
+ */
+ spi_w8r8(spi, 0x00);
+ spi_w8r8(spi, 0x00);
+ spi_w8r8(spi, 0x00);
+}
+
+static int adau1781_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct regmap_config config;
+
+ if (!id)
+ return -EINVAL;
+
+ config = adau1781_regmap_config;
+ config.val_bits = 8;
+ config.reg_bits = 24;
+ config.read_flag_mask = 0x1;
+
+ return adau1781_probe(&spi->dev,
+ devm_regmap_init_spi(spi, &config),
+ id->driver_data, adau1781_spi_switch_mode);
+}
+
+static int adau1781_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ return 0;
+}
+
+static const struct spi_device_id adau1781_spi_id[] = {
+ { "adau1381", ADAU1381 },
+ { "adau1781", ADAU1781 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, adau1781_spi_id);
+
+static struct spi_driver adau1781_spi_driver = {
+ .driver = {
+ .name = "adau1781",
+ .owner = THIS_MODULE,
+ },
+ .probe = adau1781_spi_probe,
+ .remove = adau1781_spi_remove,
+ .id_table = adau1781_spi_id,
+};
+module_spi_driver(adau1781_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 CODEC SPI driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c
new file mode 100644
index 000000000000..045a61413840
--- /dev/null
+++ b/sound/soc/codecs/adau1781.c
@@ -0,0 +1,511 @@
+/*
+ * Driver for ADAU1781/ADAU1781 codec
+ *
+ * Copyright 2011-2013 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/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/platform_data/adau17x1.h>
+
+#include "adau17x1.h"
+#include "adau1781.h"
+
+#define ADAU1781_DMIC_BEEP_CTRL 0x4008
+#define ADAU1781_LEFT_PGA 0x400e
+#define ADAU1781_RIGHT_PGA 0x400f
+#define ADAU1781_LEFT_PLAYBACK_MIXER 0x401c
+#define ADAU1781_RIGHT_PLAYBACK_MIXER 0x401e
+#define ADAU1781_MONO_PLAYBACK_MIXER 0x401f
+#define ADAU1781_LEFT_LINEOUT 0x4025
+#define ADAU1781_RIGHT_LINEOUT 0x4026
+#define ADAU1781_SPEAKER 0x4027
+#define ADAU1781_BEEP_ZC 0x4028
+#define ADAU1781_DEJITTER 0x4032
+#define ADAU1781_DIG_PWDN0 0x4080
+#define ADAU1781_DIG_PWDN1 0x4081
+
+#define ADAU1781_INPUT_DIFFERNTIAL BIT(3)
+
+#define ADAU1381_FIRMWARE "adau1381.bin"
+#define ADAU1781_FIRMWARE "adau1781.bin"
+
+static const struct reg_default adau1781_reg_defaults[] = {
+ { ADAU1781_DMIC_BEEP_CTRL, 0x00 },
+ { ADAU1781_LEFT_PGA, 0xc7 },
+ { ADAU1781_RIGHT_PGA, 0xc7 },
+ { ADAU1781_LEFT_PLAYBACK_MIXER, 0x00 },
+ { ADAU1781_RIGHT_PLAYBACK_MIXER, 0x00 },
+ { ADAU1781_MONO_PLAYBACK_MIXER, 0x00 },
+ { ADAU1781_LEFT_LINEOUT, 0x00 },
+ { ADAU1781_RIGHT_LINEOUT, 0x00 },
+ { ADAU1781_SPEAKER, 0x00 },
+ { ADAU1781_BEEP_ZC, 0x19 },
+ { ADAU1781_DEJITTER, 0x60 },
+ { ADAU1781_DIG_PWDN1, 0x0c },
+ { ADAU1781_DIG_PWDN1, 0x00 },
+ { ADAU17X1_CLOCK_CONTROL, 0x00 },
+ { ADAU17X1_PLL_CONTROL, 0x00 },
+ { ADAU17X1_REC_POWER_MGMT, 0x00 },
+ { ADAU17X1_MICBIAS, 0x04 },
+ { ADAU17X1_SERIAL_PORT0, 0x00 },
+ { ADAU17X1_SERIAL_PORT1, 0x00 },
+ { ADAU17X1_CONVERTER0, 0x00 },
+ { ADAU17X1_CONVERTER1, 0x00 },
+ { ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 },
+ { ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 },
+ { ADAU17X1_ADC_CONTROL, 0x00 },
+ { ADAU17X1_PLAY_POWER_MGMT, 0x00 },
+ { ADAU17X1_DAC_CONTROL0, 0x00 },
+ { ADAU17X1_DAC_CONTROL1, 0x00 },
+ { ADAU17X1_DAC_CONTROL2, 0x00 },
+ { ADAU17X1_SERIAL_PORT_PAD, 0x00 },
+ { ADAU17X1_CONTROL_PORT_PAD0, 0x00 },
+ { ADAU17X1_CONTROL_PORT_PAD1, 0x00 },
+ { ADAU17X1_DSP_SAMPLING_RATE, 0x01 },
+ { ADAU17X1_SERIAL_INPUT_ROUTE, 0x00 },
+ { ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x00 },
+ { ADAU17X1_DSP_ENABLE, 0x00 },
+ { ADAU17X1_DSP_RUN, 0x00 },
+ { ADAU17X1_SERIAL_SAMPLING_RATE, 0x00 },
+};
+
+static const DECLARE_TLV_DB_SCALE(adau1781_speaker_tlv, 0, 200, 0);
+
+static const DECLARE_TLV_DB_RANGE(adau1781_pga_tlv,
+ 0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
+ 2, 3, TLV_DB_SCALE_ITEM(1000, 400, 0),
+ 4, 4, TLV_DB_SCALE_ITEM(1700, 0, 0),
+ 5, 7, TLV_DB_SCALE_ITEM(2000, 600, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(adau1781_beep_tlv,
+ 0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
+ 2, 3, TLV_DB_SCALE_ITEM(1000, 400, 0),
+ 4, 4, TLV_DB_SCALE_ITEM(-2300, 0, 0),
+ 5, 7, TLV_DB_SCALE_ITEM(2000, 600, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(adau1781_sidetone_tlv, -1800, 300, 1);
+
+static const char * const adau1781_speaker_bias_select_text[] = {
+ "Normal operation", "Power saving", "Enhanced performance",
+};
+
+static const char * const adau1781_bias_select_text[] = {
+ "Normal operation", "Extreme power saving", "Power saving",
+ "Enhanced performance",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1781_adc_bias_enum,
+ ADAU17X1_REC_POWER_MGMT, 3, adau1781_bias_select_text);
+static SOC_ENUM_SINGLE_DECL(adau1781_speaker_bias_enum,
+ ADAU17X1_PLAY_POWER_MGMT, 6, adau1781_speaker_bias_select_text);
+static SOC_ENUM_SINGLE_DECL(adau1781_dac_bias_enum,
+ ADAU17X1_PLAY_POWER_MGMT, 4, adau1781_bias_select_text);
+static SOC_ENUM_SINGLE_DECL(adau1781_playback_bias_enum,
+ ADAU17X1_PLAY_POWER_MGMT, 2, adau1781_bias_select_text);
+static SOC_ENUM_SINGLE_DECL(adau1781_capture_bias_enum,
+ ADAU17X1_REC_POWER_MGMT, 1, adau1781_bias_select_text);
+
+static const struct snd_kcontrol_new adau1781_controls[] = {
+ SOC_SINGLE_TLV("Beep Capture Volume", ADAU1781_DMIC_BEEP_CTRL, 0, 7, 0,
+ adau1781_beep_tlv),
+ SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAU1781_LEFT_PGA,
+ ADAU1781_RIGHT_PGA, 5, 7, 0, adau1781_pga_tlv),
+ SOC_DOUBLE_R("PGA Capture Switch", ADAU1781_LEFT_PGA,
+ ADAU1781_RIGHT_PGA, 1, 1, 0),
+
+ SOC_DOUBLE_R("Lineout Playback Switch", ADAU1781_LEFT_LINEOUT,
+ ADAU1781_RIGHT_LINEOUT, 1, 1, 0),
+ SOC_SINGLE("Beep ZC Switch", ADAU1781_BEEP_ZC, 0, 1, 0),
+
+ SOC_SINGLE("Mono Playback Switch", ADAU1781_MONO_PLAYBACK_MIXER,
+ 0, 1, 0),
+ SOC_SINGLE_TLV("Mono Playback Volume", ADAU1781_SPEAKER, 6, 3, 0,
+ adau1781_speaker_tlv),
+
+ SOC_ENUM("ADC Bias", adau1781_adc_bias_enum),
+ SOC_ENUM("DAC Bias", adau1781_dac_bias_enum),
+ SOC_ENUM("Capture Bias", adau1781_capture_bias_enum),
+ SOC_ENUM("Playback Bias", adau1781_playback_bias_enum),
+ SOC_ENUM("Speaker Bias", adau1781_speaker_bias_enum),
+};
+
+static const struct snd_kcontrol_new adau1781_beep_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Beep Capture Switch", ADAU1781_DMIC_BEEP_CTRL,
+ 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new adau1781_left_mixer_controls[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+ ADAU1781_LEFT_PLAYBACK_MIXER, 5, 1, 0),
+ SOC_DAPM_SINGLE_TLV("Beep Playback Volume",
+ ADAU1781_LEFT_PLAYBACK_MIXER, 1, 8, 0, adau1781_sidetone_tlv),
+};
+
+static const struct snd_kcontrol_new adau1781_right_mixer_controls[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+ ADAU1781_RIGHT_PLAYBACK_MIXER, 6, 1, 0),
+ SOC_DAPM_SINGLE_TLV("Beep Playback Volume",
+ ADAU1781_LEFT_PLAYBACK_MIXER, 1, 8, 0, adau1781_sidetone_tlv),
+};
+
+static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("Left Switch",
+ ADAU1781_MONO_PLAYBACK_MIXER, 7, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("Right Switch",
+ ADAU1781_MONO_PLAYBACK_MIXER, 6, 1, 0),
+ SOC_DAPM_SINGLE_TLV("Beep Playback Volume",
+ ADAU1781_MONO_PLAYBACK_MIXER, 2, 8, 0, adau1781_sidetone_tlv),
+};
+
+static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+
+ /* After any power changes have been made the dejitter circuit
+ * has to be reinitialized. */
+ regmap_write(adau->regmap, ADAU1781_DEJITTER, 0);
+ if (!adau->master)
+ regmap_write(adau->regmap, ADAU1781_DEJITTER, 5);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget adau1781_dapm_widgets[] = {
+ SND_SOC_DAPM_PGA("Left PGA", ADAU1781_LEFT_PGA, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right PGA", ADAU1781_RIGHT_PGA, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_OUT_DRV("Speaker", ADAU1781_SPEAKER, 0, 0, NULL, 0),
+
+ SOC_MIXER_NAMED_CTL_ARRAY("Beep Mixer", ADAU17X1_MICBIAS, 4, 0,
+ adau1781_beep_mixer_controls),
+
+ SOC_MIXER_ARRAY("Left Lineout Mixer", SND_SOC_NOPM, 0, 0,
+ adau1781_left_mixer_controls),
+ SOC_MIXER_ARRAY("Right Lineout Mixer", SND_SOC_NOPM, 0, 0,
+ adau1781_right_mixer_controls),
+ SOC_MIXER_ARRAY("Mono Mixer", SND_SOC_NOPM, 0, 0,
+ adau1781_mono_mixer_controls),
+
+ SND_SOC_DAPM_SUPPLY("Serial Input Routing", ADAU1781_DIG_PWDN0,
+ 2, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Serial Output Routing", ADAU1781_DIG_PWDN0,
+ 3, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Clock Domain Transfer", ADAU1781_DIG_PWDN0,
+ 5, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Serial Ports", ADAU1781_DIG_PWDN0, 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC Engine", ADAU1781_DIG_PWDN0, 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC Engine", ADAU1781_DIG_PWDN1, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Digital Mic", ADAU1781_DIG_PWDN1, 1, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("Sound Engine", ADAU1781_DIG_PWDN0, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, ADAU1781_DIG_PWDN0, 1, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("Zero Crossing Detector", ADAU1781_DIG_PWDN1, 2, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_POST("Dejitter fixup", adau1781_dejitter_fixup),
+
+ SND_SOC_DAPM_INPUT("BEEP"),
+
+ SND_SOC_DAPM_OUTPUT("AOUTL"),
+ SND_SOC_DAPM_OUTPUT("AOUTR"),
+ SND_SOC_DAPM_OUTPUT("SP"),
+ SND_SOC_DAPM_INPUT("LMIC"),
+ SND_SOC_DAPM_INPUT("RMIC"),
+};
+
+static const struct snd_soc_dapm_route adau1781_dapm_routes[] = {
+ { "Left Lineout Mixer", NULL, "Left Playback Enable" },
+ { "Right Lineout Mixer", NULL, "Right Playback Enable" },
+
+ { "Left Lineout Mixer", "Beep Playback Volume", "Beep Mixer" },
+ { "Left Lineout Mixer", "Switch", "Left DAC" },
+
+ { "Right Lineout Mixer", "Beep Playback Volume", "Beep Mixer" },
+ { "Right Lineout Mixer", "Switch", "Right DAC" },
+
+ { "Mono Mixer", "Beep Playback Volume", "Beep Mixer" },
+ { "Mono Mixer", "Right Switch", "Right DAC" },
+ { "Mono Mixer", "Left Switch", "Left DAC" },
+ { "Speaker", NULL, "Mono Mixer" },
+
+ { "Mono Mixer", NULL, "SYSCLK" },
+ { "Left Lineout Mixer", NULL, "SYSCLK" },
+ { "Left Lineout Mixer", NULL, "SYSCLK" },
+
+ { "Beep Mixer", "Beep Capture Switch", "BEEP" },
+ { "Beep Mixer", NULL, "Zero Crossing Detector" },
+
+ { "Left DAC", NULL, "DAC Engine" },
+ { "Right DAC", NULL, "DAC Engine" },
+
+ { "Sound Engine", NULL, "SYSCLK" },
+ { "DSP", NULL, "Sound Engine" },
+
+ { "Left Decimator", NULL, "ADC Engine" },
+ { "Right Decimator", NULL, "ADC Engine" },
+
+ { "AIFCLK", NULL, "SYSCLK" },
+
+ { "Playback", NULL, "Serial Input Routing" },
+ { "Playback", NULL, "Serial Ports" },
+ { "Playback", NULL, "Clock Domain Transfer" },
+ { "Capture", NULL, "Serial Output Routing" },
+ { "Capture", NULL, "Serial Ports" },
+ { "Capture", NULL, "Clock Domain Transfer" },
+
+ { "AOUTL", NULL, "Left Lineout Mixer" },
+ { "AOUTR", NULL, "Right Lineout Mixer" },
+ { "SP", NULL, "Speaker" },
+};
+
+static const struct snd_soc_dapm_route adau1781_adc_dapm_routes[] = {
+ { "Left PGA", NULL, "LMIC" },
+ { "Right PGA", NULL, "RMIC" },
+
+ { "Left Decimator", NULL, "Left PGA" },
+ { "Right Decimator", NULL, "Right PGA" },
+};
+
+static const char * const adau1781_dmic_select_text[] = {
+ "DMIC1", "DMIC2",
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(adau1781_dmic_select_enum,
+ adau1781_dmic_select_text);
+
+static const struct snd_kcontrol_new adau1781_dmic_mux =
+ SOC_DAPM_ENUM("DMIC Select", adau1781_dmic_select_enum);
+
+static const struct snd_soc_dapm_widget adau1781_dmic_dapm_widgets[] = {
+ SND_SOC_DAPM_MUX("DMIC Select", SND_SOC_NOPM, 0, 0, &adau1781_dmic_mux),
+
+ SND_SOC_DAPM_ADC("DMIC1", NULL, ADAU1781_DMIC_BEEP_CTRL, 4, 0),
+ SND_SOC_DAPM_ADC("DMIC2", NULL, ADAU1781_DMIC_BEEP_CTRL, 5, 0),
+};
+
+static const struct snd_soc_dapm_route adau1781_dmic_dapm_routes[] = {
+ { "DMIC1", NULL, "LMIC" },
+ { "DMIC2", NULL, "RMIC" },
+
+ { "DMIC1", NULL, "Digital Mic" },
+ { "DMIC2", NULL, "Digital Mic" },
+
+ { "DMIC Select", "DMIC1", "DMIC1" },
+ { "DMIC Select", "DMIC2", "DMIC2" },
+
+ { "Left Decimator", NULL, "DMIC Select" },
+ { "Right Decimator", NULL, "DMIC Select" },
+};
+
+static int adau1781_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
+ ADAU17X1_CLOCK_CONTROL_SYSCLK_EN,
+ ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
+
+ /* Precharge */
+ regmap_update_bits(adau->regmap, ADAU1781_DIG_PWDN1, 0x8, 0x8);
+ break;
+ case SND_SOC_BIAS_OFF:
+ regmap_update_bits(adau->regmap, ADAU1781_DIG_PWDN1, 0xc, 0x0);
+ regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
+ ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0);
+ break;
+ }
+
+ codec->dapm.bias_level = level;
+ return 0;
+}
+
+static bool adau1781_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ADAU1781_DMIC_BEEP_CTRL:
+ case ADAU1781_LEFT_PGA:
+ case ADAU1781_RIGHT_PGA:
+ case ADAU1781_LEFT_PLAYBACK_MIXER:
+ case ADAU1781_RIGHT_PLAYBACK_MIXER:
+ case ADAU1781_MONO_PLAYBACK_MIXER:
+ case ADAU1781_LEFT_LINEOUT:
+ case ADAU1781_RIGHT_LINEOUT:
+ case ADAU1781_SPEAKER:
+ case ADAU1781_BEEP_ZC:
+ case ADAU1781_DEJITTER:
+ case ADAU1781_DIG_PWDN0:
+ case ADAU1781_DIG_PWDN1:
+ return true;
+ default:
+ break;
+ }
+
+ return adau17x1_readable_register(dev, reg);
+}
+
+static int adau1781_set_input_mode(struct adau *adau, unsigned int reg,
+ bool differential)
+{
+ unsigned int val;
+
+ if (differential)
+ val = ADAU1781_INPUT_DIFFERNTIAL;
+ else
+ val = 0;
+
+ return regmap_update_bits(adau->regmap, reg,
+ ADAU1781_INPUT_DIFFERNTIAL, val);
+}
+
+static int adau1781_codec_probe(struct snd_soc_codec *codec)
+{
+ struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+ const char *firmware;
+ int ret;
+
+ ret = adau17x1_add_widgets(codec);
+ if (ret)
+ return ret;
+
+ if (pdata) {
+ ret = adau1781_set_input_mode(adau, ADAU1781_LEFT_PGA,
+ pdata->left_input_differential);
+ if (ret)
+ return ret;
+ ret = adau1781_set_input_mode(adau, ADAU1781_RIGHT_PGA,
+ pdata->right_input_differential);
+ if (ret)
+ return ret;
+ }
+
+ if (pdata && pdata->use_dmic) {
+ ret = snd_soc_dapm_new_controls(&codec->dapm,
+ adau1781_dmic_dapm_widgets,
+ ARRAY_SIZE(adau1781_dmic_dapm_widgets));
+ if (ret)
+ return ret;
+ ret = snd_soc_dapm_add_routes(&codec->dapm,
+ adau1781_dmic_dapm_routes,
+ ARRAY_SIZE(adau1781_dmic_dapm_routes));
+ if (ret)
+ return ret;
+ } else {
+ ret = snd_soc_dapm_add_routes(&codec->dapm,
+ adau1781_adc_dapm_routes,
+ ARRAY_SIZE(adau1781_adc_dapm_routes));
+ if (ret)
+ return ret;
+ }
+
+ switch (adau->type) {
+ case ADAU1381:
+ firmware = ADAU1381_FIRMWARE;
+ break;
+ case ADAU1781:
+ firmware = ADAU1781_FIRMWARE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = adau17x1_add_routes(codec);
+ if (ret < 0)
+ return ret;
+
+ ret = adau17x1_load_firmware(adau, codec->dev, firmware);
+ if (ret)
+ dev_warn(codec->dev, "Failed to load firmware\n");
+
+ return 0;
+}
+
+static const struct snd_soc_codec_driver adau1781_codec_driver = {
+ .probe = adau1781_codec_probe,
+ .suspend = adau17x1_suspend,
+ .resume = adau17x1_resume,
+ .set_bias_level = adau1781_set_bias_level,
+
+ .controls = adau1781_controls,
+ .num_controls = ARRAY_SIZE(adau1781_controls),
+ .dapm_widgets = adau1781_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(adau1781_dapm_widgets),
+ .dapm_routes = adau1781_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(adau1781_dapm_routes),
+};
+
+#define ADAU1781_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver adau1781_dai_driver = {
+ .name = "adau-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = ADAU1781_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = ADAU1781_FORMATS,
+ },
+ .ops = &adau17x1_dai_ops,
+};
+
+const struct regmap_config adau1781_regmap_config = {
+ .val_bits = 8,
+ .reg_bits = 16,
+ .max_register = 0x40f8,
+ .reg_defaults = adau1781_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(adau1781_reg_defaults),
+ .readable_reg = adau1781_readable_register,
+ .volatile_reg = adau17x1_volatile_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(adau1781_regmap_config);
+
+int adau1781_probe(struct device *dev, struct regmap *regmap,
+ enum adau17x1_type type, void (*switch_mode)(struct device *dev))
+{
+ int ret;
+
+ ret = adau17x1_probe(dev, regmap, type, switch_mode);
+ if (ret)
+ return ret;
+
+ return snd_soc_register_codec(dev, &adau1781_codec_driver,
+ &adau1781_dai_driver, 1);
+}
+EXPORT_SYMBOL_GPL(adau1781_probe);
+
+MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1781.h b/sound/soc/codecs/adau1781.h
new file mode 100644
index 000000000000..2b96e0a9ff2e
--- /dev/null
+++ b/sound/soc/codecs/adau1781.h
@@ -0,0 +1,23 @@
+/*
+ * ADAU1381/ADAU1781 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __SOUND_SOC_CODECS_ADAU1781_H__
+#define __SOUND_SOC_CODECS_ADAU1781_H__
+
+#include <linux/regmap.h>
+#include "adau17x1.h"
+
+struct device;
+
+int adau1781_probe(struct device *dev, struct regmap *regmap,
+ enum adau17x1_type type, void (*switch_mode)(struct device *dev));
+
+extern const struct regmap_config adau1781_regmap_config;
+
+#endif
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
new file mode 100644
index 000000000000..2961fae9670a
--- /dev/null
+++ b/sound/soc/codecs/adau17x1.c
@@ -0,0 +1,866 @@
+/*
+ * Common code for ADAU1X61 and ADAU1X81 codecs
+ *
+ * Copyright 2011-2014 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/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/gcd.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include "sigmadsp.h"
+#include "adau17x1.h"
+
+static const char * const adau17x1_capture_mixer_boost_text[] = {
+ "Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau17x1_capture_boost_enum,
+ ADAU17X1_REC_POWER_MGMT, 5, adau17x1_capture_mixer_boost_text);
+
+static const char * const adau17x1_mic_bias_mode_text[] = {
+ "Normal operation", "High performance",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau17x1_mic_bias_mode_enum,
+ ADAU17X1_MICBIAS, 3, adau17x1_mic_bias_mode_text);
+
+static const DECLARE_TLV_DB_MINMAX(adau17x1_digital_tlv, -9563, 0);
+
+static const struct snd_kcontrol_new adau17x1_controls[] = {
+ SOC_DOUBLE_R_TLV("Digital Capture Volume",
+ ADAU17X1_LEFT_INPUT_DIGITAL_VOL,
+ ADAU17X1_RIGHT_INPUT_DIGITAL_VOL,
+ 0, 0xff, 1, adau17x1_digital_tlv),
+ SOC_DOUBLE_R_TLV("Digital Playback Volume", ADAU17X1_DAC_CONTROL1,
+ ADAU17X1_DAC_CONTROL2, 0, 0xff, 1, adau17x1_digital_tlv),
+
+ SOC_SINGLE("ADC High Pass Filter Switch", ADAU17X1_ADC_CONTROL,
+ 5, 1, 0),
+ SOC_SINGLE("Playback De-emphasis Switch", ADAU17X1_DAC_CONTROL0,
+ 2, 1, 0),
+
+ SOC_ENUM("Capture Boost", adau17x1_capture_boost_enum),
+
+ SOC_ENUM("Mic Bias Mode", adau17x1_mic_bias_mode_enum),
+};
+
+static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
+ int ret;
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ adau->pll_regs[5] = 1;
+ } else {
+ adau->pll_regs[5] = 0;
+ /* Bypass the PLL when disabled, otherwise registers will become
+ * inaccessible. */
+ regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
+ ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL, 0);
+ }
+
+ /* The PLL register is 6 bytes long and can only be written at once. */
+ ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
+ adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ mdelay(5);
+ regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
+ ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL,
+ ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL);
+ }
+
+ return 0;
+}
+
+static const char * const adau17x1_mono_stereo_text[] = {
+ "Stereo",
+ "Mono Left Channel (L+R)",
+ "Mono Right Channel (L+R)",
+ "Mono (L+R)",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau17x1_dac_mode_enum,
+ ADAU17X1_DAC_CONTROL0, 6, adau17x1_mono_stereo_text);
+
+static const struct snd_kcontrol_new adau17x1_dac_mode_mux =
+ SOC_DAPM_ENUM("DAC Mono-Stereo-Mode", adau17x1_dac_mode_enum);
+
+static const struct snd_soc_dapm_widget adau17x1_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY_S("PLL", 3, SND_SOC_NOPM, 0, 0, adau17x1_pll_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY("AIFCLK", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU17X1_MICBIAS, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("Left Playback Enable", ADAU17X1_PLAY_POWER_MGMT,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Right Playback Enable", ADAU17X1_PLAY_POWER_MGMT,
+ 1, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("Left DAC Mode Mux", SND_SOC_NOPM, 0, 0,
+ &adau17x1_dac_mode_mux),
+ SND_SOC_DAPM_MUX("Right DAC Mode Mux", SND_SOC_NOPM, 0, 0,
+ &adau17x1_dac_mode_mux),
+
+ SND_SOC_DAPM_ADC("Left Decimator", NULL, ADAU17X1_ADC_CONTROL, 0, 0),
+ SND_SOC_DAPM_ADC("Right Decimator", NULL, ADAU17X1_ADC_CONTROL, 1, 0),
+ SND_SOC_DAPM_DAC("Left DAC", NULL, ADAU17X1_DAC_CONTROL0, 0, 0),
+ SND_SOC_DAPM_DAC("Right DAC", NULL, ADAU17X1_DAC_CONTROL0, 1, 0),
+};
+
+static const struct snd_soc_dapm_route adau17x1_dapm_routes[] = {
+ { "Left Decimator", NULL, "SYSCLK" },
+ { "Right Decimator", NULL, "SYSCLK" },
+ { "Left DAC", NULL, "SYSCLK" },
+ { "Right DAC", NULL, "SYSCLK" },
+ { "Capture", NULL, "SYSCLK" },
+ { "Playback", NULL, "SYSCLK" },
+
+ { "Left DAC", NULL, "Left DAC Mode Mux" },
+ { "Right DAC", NULL, "Right DAC Mode Mux" },
+
+ { "Capture", NULL, "AIFCLK" },
+ { "Playback", NULL, "AIFCLK" },
+};
+
+static const struct snd_soc_dapm_route adau17x1_dapm_pll_route = {
+ "SYSCLK", NULL, "PLL",
+};
+
+/*
+ * The MUX register for the Capture and Playback MUXs selects either DSP as
+ * source/destination or one of the TDM slots. The TDM slot is selected via
+ * snd_soc_dai_set_tdm_slot(), so we only expose whether to go to the DSP or
+ * directly to the DAI interface with this control.
+ */
+static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_dapm_update update;
+ unsigned int stream = e->shift_l;
+ unsigned int val, change;
+ int reg;
+
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
+ switch (ucontrol->value.enumerated.item[0]) {
+ case 0:
+ val = 0;
+ adau->dsp_bypass[stream] = false;
+ break;
+ default:
+ val = (adau->tdm_slot[stream] * 2) + 1;
+ adau->dsp_bypass[stream] = true;
+ break;
+ }
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ reg = ADAU17X1_SERIAL_INPUT_ROUTE;
+ else
+ reg = ADAU17X1_SERIAL_OUTPUT_ROUTE;
+
+ change = snd_soc_test_bits(codec, reg, 0xff, val);
+ if (change) {
+ update.kcontrol = kcontrol;
+ update.mask = 0xff;
+ update.reg = reg;
+ update.val = val;
+
+ snd_soc_dapm_mux_update_power(&codec->dapm, kcontrol,
+ ucontrol->value.enumerated.item[0], e, &update);
+ }
+
+ return change;
+}
+
+static int adau17x1_dsp_mux_enum_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int stream = e->shift_l;
+ unsigned int reg, val;
+ int ret;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ reg = ADAU17X1_SERIAL_INPUT_ROUTE;
+ else
+ reg = ADAU17X1_SERIAL_OUTPUT_ROUTE;
+
+ ret = regmap_read(adau->regmap, reg, &val);
+ if (ret)
+ return ret;
+
+ if (val != 0)
+ val = 1;
+ ucontrol->value.enumerated.item[0] = val;
+
+ return 0;
+}
+
+#define DECLARE_ADAU17X1_DSP_MUX_CTRL(_name, _label, _stream, _text) \
+ const struct snd_kcontrol_new _name = \
+ SOC_DAPM_ENUM_EXT(_label, (const struct soc_enum)\
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, _stream, \
+ ARRAY_SIZE(_text), _text), \
+ adau17x1_dsp_mux_enum_get, adau17x1_dsp_mux_enum_put)
+
+static const char * const adau17x1_dac_mux_text[] = {
+ "DSP",
+ "AIFIN",
+};
+
+static const char * const adau17x1_capture_mux_text[] = {
+ "DSP",
+ "Decimator",
+};
+
+static DECLARE_ADAU17X1_DSP_MUX_CTRL(adau17x1_dac_mux, "DAC Playback Mux",
+ SNDRV_PCM_STREAM_PLAYBACK, adau17x1_dac_mux_text);
+
+static DECLARE_ADAU17X1_DSP_MUX_CTRL(adau17x1_capture_mux, "Capture Mux",
+ SNDRV_PCM_STREAM_CAPTURE, adau17x1_capture_mux_text);
+
+static const struct snd_soc_dapm_widget adau17x1_dsp_dapm_widgets[] = {
+ SND_SOC_DAPM_PGA("DSP", ADAU17X1_DSP_RUN, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SIGGEN("DSP Siggen"),
+
+ SND_SOC_DAPM_MUX("DAC Playback Mux", SND_SOC_NOPM, 0, 0,
+ &adau17x1_dac_mux),
+ SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0,
+ &adau17x1_capture_mux),
+};
+
+static const struct snd_soc_dapm_route adau17x1_dsp_dapm_routes[] = {
+ { "DAC Playback Mux", "DSP", "DSP" },
+ { "DAC Playback Mux", "AIFIN", "Playback" },
+
+ { "Left DAC Mode Mux", "Stereo", "DAC Playback Mux" },
+ { "Left DAC Mode Mux", "Mono (L+R)", "DAC Playback Mux" },
+ { "Left DAC Mode Mux", "Mono Left Channel (L+R)", "DAC Playback Mux" },
+ { "Right DAC Mode Mux", "Stereo", "DAC Playback Mux" },
+ { "Right DAC Mode Mux", "Mono (L+R)", "DAC Playback Mux" },
+ { "Right DAC Mode Mux", "Mono Right Channel (L+R)", "DAC Playback Mux" },
+
+ { "Capture Mux", "DSP", "DSP" },
+ { "Capture Mux", "Decimator", "Left Decimator" },
+ { "Capture Mux", "Decimator", "Right Decimator" },
+
+ { "Capture", NULL, "Capture Mux" },
+
+ { "DSP", NULL, "DSP Siggen" },
+
+ { "DSP", NULL, "Left Decimator" },
+ { "DSP", NULL, "Right Decimator" },
+};
+
+static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = {
+ { "Left DAC Mode Mux", "Stereo", "Playback" },
+ { "Left DAC Mode Mux", "Mono (L+R)", "Playback" },
+ { "Left DAC Mode Mux", "Mono Left Channel (L+R)", "Playback" },
+ { "Right DAC Mode Mux", "Stereo", "Playback" },
+ { "Right DAC Mode Mux", "Mono (L+R)", "Playback" },
+ { "Right DAC Mode Mux", "Mono Right Channel (L+R)", "Playback" },
+ { "Capture", NULL, "Left Decimator" },
+ { "Capture", NULL, "Right Decimator" },
+};
+
+bool adau17x1_has_dsp(struct adau *adau)
+{
+ switch (adau->type) {
+ case ADAU1761:
+ case ADAU1381:
+ case ADAU1781:
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL_GPL(adau17x1_has_dsp);
+
+static int adau17x1_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 adau *adau = snd_soc_codec_get_drvdata(codec);
+ unsigned int val, div, dsp_div;
+ unsigned int freq;
+
+ if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
+ freq = adau->pll_freq;
+ else
+ freq = adau->sysclk;
+
+ if (freq % params_rate(params) != 0)
+ return -EINVAL;
+
+ switch (freq / params_rate(params)) {
+ case 1024: /* fs */
+ div = 0;
+ dsp_div = 1;
+ break;
+ case 6144: /* fs / 6 */
+ div = 1;
+ dsp_div = 6;
+ break;
+ case 4096: /* fs / 4 */
+ div = 2;
+ dsp_div = 5;
+ break;
+ case 3072: /* fs / 3 */
+ div = 3;
+ dsp_div = 4;
+ break;
+ case 2048: /* fs / 2 */
+ div = 4;
+ dsp_div = 3;
+ break;
+ case 1536: /* fs / 1.5 */
+ div = 5;
+ dsp_div = 2;
+ break;
+ case 512: /* fs / 0.5 */
+ div = 6;
+ dsp_div = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
+ ADAU17X1_CONVERTER0_CONVSR_MASK, div);
+ if (adau17x1_has_dsp(adau)) {
+ regmap_write(adau->regmap, ADAU17X1_SERIAL_SAMPLING_RATE, div);
+ regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div);
+ }
+
+ if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
+ return 0;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ val = ADAU17X1_SERIAL_PORT1_DELAY16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ val = ADAU17X1_SERIAL_PORT1_DELAY8;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ val = ADAU17X1_SERIAL_PORT1_DELAY0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1,
+ ADAU17X1_SERIAL_PORT1_DELAY_MASK, val);
+}
+
+static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+ unsigned int r, n, m, i, j;
+ unsigned int div;
+ int ret;
+
+ if (freq_in < 8000000 || freq_in > 27000000)
+ return -EINVAL;
+
+ if (!freq_out) {
+ r = 0;
+ n = 0;
+ m = 0;
+ div = 0;
+ } else {
+ if (freq_out % freq_in != 0) {
+ div = DIV_ROUND_UP(freq_in, 13500000);
+ freq_in /= div;
+ r = freq_out / freq_in;
+ i = freq_out % freq_in;
+ j = gcd(i, freq_in);
+ n = i / j;
+ m = freq_in / j;
+ div--;
+ } else {
+ r = freq_out / freq_in;
+ n = 0;
+ m = 0;
+ div = 0;
+ }
+ if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2)
+ return -EINVAL;
+ }
+
+ adau->pll_regs[0] = m >> 8;
+ adau->pll_regs[1] = m & 0xff;
+ adau->pll_regs[2] = n >> 8;
+ adau->pll_regs[3] = n & 0xff;
+ adau->pll_regs[4] = (r << 3) | (div << 1);
+ if (m != 0)
+ adau->pll_regs[4] |= 1; /* Fractional mode */
+
+ /* The PLL register is 6 bytes long and can only be written at once. */
+ ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
+ adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
+ if (ret)
+ return ret;
+
+ adau->pll_freq = freq_out;
+
+ return 0;
+}
+
+static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
+ struct snd_soc_dapm_context *dapm = &dai->codec->dapm;
+
+ switch (clk_id) {
+ case ADAU17X1_CLK_SRC_MCLK:
+ case ADAU17X1_CLK_SRC_PLL:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ adau->sysclk = freq;
+
+ if (adau->clk_src != clk_id) {
+ if (clk_id == ADAU17X1_CLK_SRC_PLL) {
+ snd_soc_dapm_add_routes(dapm,
+ &adau17x1_dapm_pll_route, 1);
+ } else {
+ snd_soc_dapm_del_routes(dapm,
+ &adau17x1_dapm_pll_route, 1);
+ }
+ }
+
+ adau->clk_src = clk_id;
+
+ return 0;
+}
+
+static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
+ unsigned int ctrl0, ctrl1;
+ int lrclk_pol;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ ctrl0 = ADAU17X1_SERIAL_PORT0_MASTER;
+ adau->master = true;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ ctrl0 = 0;
+ adau->master = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ lrclk_pol = 0;
+ ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY1;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ lrclk_pol = 1;
+ ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY0;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ lrclk_pol = 1;
+ ctrl0 |= ADAU17X1_SERIAL_PORT0_PULSE_MODE;
+ ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY1;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ lrclk_pol = 1;
+ ctrl0 |= ADAU17X1_SERIAL_PORT0_PULSE_MODE;
+ ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ ctrl0 |= ADAU17X1_SERIAL_PORT0_BCLK_POL;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ lrclk_pol = !lrclk_pol;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ ctrl0 |= ADAU17X1_SERIAL_PORT0_BCLK_POL;
+ lrclk_pol = !lrclk_pol;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (lrclk_pol)
+ ctrl0 |= ADAU17X1_SERIAL_PORT0_LRCLK_POL;
+
+ regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT0, ctrl0);
+ regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT1, ctrl1);
+
+ adau->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+ return 0;
+}
+
+static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
+ unsigned int ser_ctrl0, ser_ctrl1;
+ unsigned int conv_ctrl0, conv_ctrl1;
+
+ /* I2S mode */
+ if (slots == 0) {
+ slots = 2;
+ rx_mask = 3;
+ tx_mask = 3;
+ slot_width = 32;
+ }
+
+ switch (slots) {
+ case 2:
+ ser_ctrl0 = ADAU17X1_SERIAL_PORT0_STEREO;
+ break;
+ case 4:
+ ser_ctrl0 = ADAU17X1_SERIAL_PORT0_TDM4;
+ break;
+ case 8:
+ if (adau->type == ADAU1361)
+ return -EINVAL;
+
+ ser_ctrl0 = ADAU17X1_SERIAL_PORT0_TDM8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (slot_width * slots) {
+ case 32:
+ if (adau->type == ADAU1761)
+ return -EINVAL;
+
+ ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK32;
+ break;
+ case 64:
+ ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK64;
+ break;
+ case 48:
+ ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK48;
+ break;
+ case 128:
+ ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK128;
+ break;
+ case 256:
+ if (adau->type == ADAU1361)
+ return -EINVAL;
+
+ ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK256;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (rx_mask) {
+ case 0x03:
+ conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(1);
+ adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 0;
+ break;
+ case 0x0c:
+ conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(2);
+ adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 1;
+ break;
+ case 0x30:
+ conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(3);
+ adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 2;
+ break;
+ case 0xc0:
+ conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(4);
+ adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (tx_mask) {
+ case 0x03:
+ conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(1);
+ adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 0;
+ break;
+ case 0x0c:
+ conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(2);
+ adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 1;
+ break;
+ case 0x30:
+ conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(3);
+ adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 2;
+ break;
+ case 0xc0:
+ conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(4);
+ adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
+ ADAU17X1_CONVERTER0_DAC_PAIR_MASK, conv_ctrl0);
+ regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER1,
+ ADAU17X1_CONVERTER1_ADC_PAIR_MASK, conv_ctrl1);
+ regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT0,
+ ADAU17X1_SERIAL_PORT0_TDM_MASK, ser_ctrl0);
+ regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1,
+ ADAU17X1_SERIAL_PORT1_BCLK_MASK, ser_ctrl1);
+
+ if (!adau17x1_has_dsp(adau))
+ return 0;
+
+ if (adau->dsp_bypass[SNDRV_PCM_STREAM_PLAYBACK]) {
+ regmap_write(adau->regmap, ADAU17X1_SERIAL_INPUT_ROUTE,
+ (adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] * 2) + 1);
+ }
+
+ if (adau->dsp_bypass[SNDRV_PCM_STREAM_CAPTURE]) {
+ regmap_write(adau->regmap, ADAU17X1_SERIAL_OUTPUT_ROUTE,
+ (adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] * 2) + 1);
+ }
+
+ return 0;
+}
+
+const struct snd_soc_dai_ops adau17x1_dai_ops = {
+ .hw_params = adau17x1_hw_params,
+ .set_sysclk = adau17x1_set_dai_sysclk,
+ .set_fmt = adau17x1_set_dai_fmt,
+ .set_pll = adau17x1_set_dai_pll,
+ .set_tdm_slot = adau17x1_set_dai_tdm_slot,
+};
+EXPORT_SYMBOL_GPL(adau17x1_dai_ops);
+
+int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
+ enum adau17x1_micbias_voltage micbias)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+
+ switch (micbias) {
+ case ADAU17X1_MICBIAS_0_90_AVDD:
+ case ADAU17X1_MICBIAS_0_65_AVDD:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_write(adau->regmap, ADAU17X1_MICBIAS, micbias << 2);
+}
+EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage);
+
+bool adau17x1_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ADAU17X1_CLOCK_CONTROL:
+ case ADAU17X1_PLL_CONTROL:
+ case ADAU17X1_REC_POWER_MGMT:
+ case ADAU17X1_MICBIAS:
+ case ADAU17X1_SERIAL_PORT0:
+ case ADAU17X1_SERIAL_PORT1:
+ case ADAU17X1_CONVERTER0:
+ case ADAU17X1_CONVERTER1:
+ case ADAU17X1_LEFT_INPUT_DIGITAL_VOL:
+ case ADAU17X1_RIGHT_INPUT_DIGITAL_VOL:
+ case ADAU17X1_ADC_CONTROL:
+ case ADAU17X1_PLAY_POWER_MGMT:
+ case ADAU17X1_DAC_CONTROL0:
+ case ADAU17X1_DAC_CONTROL1:
+ case ADAU17X1_DAC_CONTROL2:
+ case ADAU17X1_SERIAL_PORT_PAD:
+ case ADAU17X1_CONTROL_PORT_PAD0:
+ case ADAU17X1_CONTROL_PORT_PAD1:
+ case ADAU17X1_DSP_SAMPLING_RATE:
+ case ADAU17X1_SERIAL_INPUT_ROUTE:
+ case ADAU17X1_SERIAL_OUTPUT_ROUTE:
+ case ADAU17X1_DSP_ENABLE:
+ case ADAU17X1_DSP_RUN:
+ case ADAU17X1_SERIAL_SAMPLING_RATE:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+EXPORT_SYMBOL_GPL(adau17x1_readable_register);
+
+bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
+{
+ /* SigmaDSP parameter and program memory */
+ if (reg < 0x4000)
+ return true;
+
+ switch (reg) {
+ /* The PLL register is 6 bytes long */
+ case ADAU17X1_PLL_CONTROL:
+ case ADAU17X1_PLL_CONTROL + 1:
+ case ADAU17X1_PLL_CONTROL + 2:
+ case ADAU17X1_PLL_CONTROL + 3:
+ case ADAU17X1_PLL_CONTROL + 4:
+ case ADAU17X1_PLL_CONTROL + 5:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
+
+int adau17x1_load_firmware(struct adau *adau, struct device *dev,
+ const char *firmware)
+{
+ int ret;
+ int dspsr;
+
+ ret = regmap_read(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, &dspsr);
+ if (ret)
+ return ret;
+
+ regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1);
+ regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf);
+
+ ret = process_sigma_firmware_regmap(dev, adau->regmap, firmware);
+ if (ret) {
+ regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0);
+ return ret;
+ }
+ regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dspsr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adau17x1_load_firmware);
+
+int adau17x1_add_widgets(struct snd_soc_codec *codec)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = snd_soc_add_codec_controls(codec, adau17x1_controls,
+ ARRAY_SIZE(adau17x1_controls));
+ if (ret)
+ return ret;
+ ret = snd_soc_dapm_new_controls(&codec->dapm, adau17x1_dapm_widgets,
+ ARRAY_SIZE(adau17x1_dapm_widgets));
+ if (ret)
+ return ret;
+
+ if (adau17x1_has_dsp(adau)) {
+ ret = snd_soc_dapm_new_controls(&codec->dapm,
+ adau17x1_dsp_dapm_widgets,
+ ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
+
+int adau17x1_add_routes(struct snd_soc_codec *codec)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = snd_soc_dapm_add_routes(&codec->dapm, adau17x1_dapm_routes,
+ ARRAY_SIZE(adau17x1_dapm_routes));
+ if (ret)
+ return ret;
+
+ if (adau17x1_has_dsp(adau)) {
+ ret = snd_soc_dapm_add_routes(&codec->dapm,
+ adau17x1_dsp_dapm_routes,
+ ARRAY_SIZE(adau17x1_dsp_dapm_routes));
+ } else {
+ ret = snd_soc_dapm_add_routes(&codec->dapm,
+ adau17x1_no_dsp_dapm_routes,
+ ARRAY_SIZE(adau17x1_no_dsp_dapm_routes));
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(adau17x1_add_routes);
+
+int adau17x1_suspend(struct snd_soc_codec *codec)
+{
+ codec->driver->set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adau17x1_suspend);
+
+int adau17x1_resume(struct snd_soc_codec *codec)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
+
+ if (adau->switch_mode)
+ adau->switch_mode(codec->dev);
+
+ codec->driver->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ regcache_sync(adau->regmap);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adau17x1_resume);
+
+int adau17x1_probe(struct device *dev, struct regmap *regmap,
+ enum adau17x1_type type, void (*switch_mode)(struct device *dev))
+{
+ struct adau *adau;
+
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ adau = devm_kzalloc(dev, sizeof(*adau), GFP_KERNEL);
+ if (!adau)
+ return -ENOMEM;
+
+ adau->regmap = regmap;
+ adau->switch_mode = switch_mode;
+ adau->type = type;
+
+ dev_set_drvdata(dev, adau);
+
+ if (switch_mode)
+ switch_mode(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adau17x1_probe);
+
+MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h
new file mode 100644
index 000000000000..3ffabaf4c7a8
--- /dev/null
+++ b/sound/soc/codecs/adau17x1.h
@@ -0,0 +1,124 @@
+#ifndef __ADAU17X1_H__
+#define __ADAU17X1_H__
+
+#include <linux/regmap.h>
+#include <linux/platform_data/adau17x1.h>
+
+enum adau17x1_type {
+ ADAU1361,
+ ADAU1761,
+ ADAU1381,
+ ADAU1781,
+};
+
+enum adau17x1_pll {
+ ADAU17X1_PLL,
+};
+
+enum adau17x1_pll_src {
+ ADAU17X1_PLL_SRC_MCLK,
+};
+
+enum adau17x1_clk_src {
+ ADAU17X1_CLK_SRC_MCLK,
+ ADAU17X1_CLK_SRC_PLL,
+};
+
+struct adau {
+ unsigned int sysclk;
+ unsigned int pll_freq;
+
+ enum adau17x1_clk_src clk_src;
+ enum adau17x1_type type;
+ void (*switch_mode)(struct device *dev);
+
+ unsigned int dai_fmt;
+
+ uint8_t pll_regs[6];
+
+ bool master;
+
+ unsigned int tdm_slot[2];
+ bool dsp_bypass[2];
+
+ struct regmap *regmap;
+};
+
+int adau17x1_add_widgets(struct snd_soc_codec *codec);
+int adau17x1_add_routes(struct snd_soc_codec *codec);
+int adau17x1_probe(struct device *dev, struct regmap *regmap,
+ enum adau17x1_type type, void (*switch_mode)(struct device *dev));
+int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
+ enum adau17x1_micbias_voltage micbias);
+bool adau17x1_readable_register(struct device *dev, unsigned int reg);
+bool adau17x1_volatile_register(struct device *dev, unsigned int reg);
+int adau17x1_suspend(struct snd_soc_codec *codec);
+int adau17x1_resume(struct snd_soc_codec *codec);
+
+extern const struct snd_soc_dai_ops adau17x1_dai_ops;
+
+int adau17x1_load_firmware(struct adau *adau, struct device *dev,
+ const char *firmware);
+bool adau17x1_has_dsp(struct adau *adau);
+
+#define ADAU17X1_CLOCK_CONTROL 0x4000
+#define ADAU17X1_PLL_CONTROL 0x4002
+#define ADAU17X1_REC_POWER_MGMT 0x4009
+#define ADAU17X1_MICBIAS 0x4010
+#define ADAU17X1_SERIAL_PORT0 0x4015
+#define ADAU17X1_SERIAL_PORT1 0x4016
+#define ADAU17X1_CONVERTER0 0x4017
+#define ADAU17X1_CONVERTER1 0x4018
+#define ADAU17X1_LEFT_INPUT_DIGITAL_VOL 0x401a
+#define ADAU17X1_RIGHT_INPUT_DIGITAL_VOL 0x401b
+#define ADAU17X1_ADC_CONTROL 0x4019
+#define ADAU17X1_PLAY_POWER_MGMT 0x4029
+#define ADAU17X1_DAC_CONTROL0 0x402a
+#define ADAU17X1_DAC_CONTROL1 0x402b
+#define ADAU17X1_DAC_CONTROL2 0x402c
+#define ADAU17X1_SERIAL_PORT_PAD 0x402d
+#define ADAU17X1_CONTROL_PORT_PAD0 0x402f
+#define ADAU17X1_CONTROL_PORT_PAD1 0x4030
+#define ADAU17X1_DSP_SAMPLING_RATE 0x40eb
+#define ADAU17X1_SERIAL_INPUT_ROUTE 0x40f2
+#define ADAU17X1_SERIAL_OUTPUT_ROUTE 0x40f3
+#define ADAU17X1_DSP_ENABLE 0x40f5
+#define ADAU17X1_DSP_RUN 0x40f6
+#define ADAU17X1_SERIAL_SAMPLING_RATE 0x40f8
+
+#define ADAU17X1_SERIAL_PORT0_BCLK_POL BIT(4)
+#define ADAU17X1_SERIAL_PORT0_LRCLK_POL BIT(3)
+#define ADAU17X1_SERIAL_PORT0_MASTER BIT(0)
+
+#define ADAU17X1_SERIAL_PORT1_DELAY1 0x00
+#define ADAU17X1_SERIAL_PORT1_DELAY0 0x01
+#define ADAU17X1_SERIAL_PORT1_DELAY8 0x02
+#define ADAU17X1_SERIAL_PORT1_DELAY16 0x03
+#define ADAU17X1_SERIAL_PORT1_DELAY_MASK 0x03
+
+#define ADAU17X1_CLOCK_CONTROL_INFREQ_MASK 0x6
+#define ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL BIT(3)
+#define ADAU17X1_CLOCK_CONTROL_SYSCLK_EN BIT(0)
+
+#define ADAU17X1_SERIAL_PORT1_BCLK32 (0x0 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK48 (0x1 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK64 (0x2 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK128 (0x3 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK256 (0x4 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK_MASK (0x7 << 5)
+
+#define ADAU17X1_SERIAL_PORT0_STEREO (0x0 << 1)
+#define ADAU17X1_SERIAL_PORT0_TDM4 (0x1 << 1)
+#define ADAU17X1_SERIAL_PORT0_TDM8 (0x2 << 1)
+#define ADAU17X1_SERIAL_PORT0_TDM_MASK (0x3 << 1)
+#define ADAU17X1_SERIAL_PORT0_PULSE_MODE BIT(5)
+
+#define ADAU17X1_CONVERTER0_DAC_PAIR(x) (((x) - 1) << 5)
+#define ADAU17X1_CONVERTER0_DAC_PAIR_MASK (0x3 << 5)
+#define ADAU17X1_CONVERTER1_ADC_PAIR(x) ((x) - 1)
+#define ADAU17X1_CONVERTER1_ADC_PAIR_MASK 0x3
+
+#define ADAU17X1_CONVERTER0_CONVSR_MASK 0x7
+
+
+#endif
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index 5062e34ee8dc..c43b93fdf0df 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -172,14 +172,14 @@ static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3);
static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3);
static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl =
- SOC_DAPM_VALUE_ENUM("Route", adav80x_aux_capture_enum);
+ SOC_DAPM_ENUM("Route", adav80x_aux_capture_enum);
static const struct snd_kcontrol_new adav80x_capture_mux_ctrl =
- SOC_DAPM_VALUE_ENUM("Route", adav80x_capture_enum);
+ SOC_DAPM_ENUM("Route", adav80x_capture_enum);
static const struct snd_kcontrol_new adav80x_dac_mux_ctrl =
- SOC_DAPM_VALUE_ENUM("Route", adav80x_dac_enum);
+ SOC_DAPM_ENUM("Route", adav80x_dac_enum);
#define ADAV80X_MUX(name, ctrl) \
- SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+ SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1),
@@ -315,7 +315,7 @@ static int adav80x_set_deemph(struct snd_soc_codec *codec)
static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
unsigned int deemph = ucontrol->value.enumerated.item[0];
@@ -330,7 +330,7 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
static int adav80x_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = adav80x->deemph;
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 10adf25d4c14..1fd7f72b2a62 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -11,13 +11,14 @@
#include <linux/module.h>
#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/initval.h>
#include <linux/spi/spi.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
/* AK4104 registers addresses */
#define AK4104_REG_CONTROL1 0x00
@@ -47,6 +48,7 @@
struct ak4104_private {
struct regmap *regmap;
+ struct regulator *regulator;
};
static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = {
@@ -174,20 +176,30 @@ static int ak4104_probe(struct snd_soc_codec *codec)
struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
int ret;
+ ret = regulator_enable(ak4104->regulator);
+ if (ret < 0) {
+ dev_err(codec->dev, "Unable to enable regulator: %d\n", ret);
+ return ret;
+ }
+
/* set power-up and non-reset bits */
ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
if (ret < 0)
- return ret;
+ goto exit_disable_regulator;
/* enable transmitter */
ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
AK4104_TX_TXE, AK4104_TX_TXE);
if (ret < 0)
- return ret;
+ goto exit_disable_regulator;
return 0;
+
+exit_disable_regulator:
+ regulator_disable(ak4104->regulator);
+ return ret;
}
static int ak4104_remove(struct snd_soc_codec *codec)
@@ -196,13 +208,42 @@ static int ak4104_remove(struct snd_soc_codec *codec)
regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
+ regulator_disable(ak4104->regulator);
return 0;
}
+#ifdef CONFIG_PM
+static int ak4104_soc_suspend(struct snd_soc_codec *codec)
+{
+ struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec);
+
+ regulator_disable(priv->regulator);
+
+ return 0;
+}
+
+static int ak4104_soc_resume(struct snd_soc_codec *codec)
+{
+ struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = regulator_enable(priv->regulator);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+#else
+#define ak4104_soc_suspend NULL
+#define ak4104_soc_resume NULL
+#endif /* CONFIG_PM */
+
static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
- .probe = ak4104_probe,
- .remove = ak4104_remove,
+ .probe = ak4104_probe,
+ .remove = ak4104_remove,
+ .suspend = ak4104_soc_suspend,
+ .resume = ak4104_soc_resume,
.dapm_widgets = ak4104_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets),
@@ -239,6 +280,13 @@ static int ak4104_spi_probe(struct spi_device *spi)
if (ak4104 == NULL)
return -ENOMEM;
+ ak4104->regulator = devm_regulator_get(&spi->dev, "vdd");
+ if (IS_ERR(ak4104->regulator)) {
+ ret = PTR_ERR(ak4104->regulator);
+ dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret);
+ return ret;
+ }
+
ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap);
if (IS_ERR(ak4104->regmap)) {
ret = PTR_ERR(ak4104->regmap);
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index 868c0e2da1ec..7afe8f482088 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -74,7 +74,7 @@ static int ak4641_set_deemph(struct snd_soc_codec *codec)
static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
int deemph = ucontrol->value.enumerated.item[0];
@@ -89,7 +89,7 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = ak4641->deemph;
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 92655cc189ae..3ba4c0f11418 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -98,7 +98,7 @@
#define MGAIN0 (1 << 0) /* MIC amp gain*/
/* TIMER */
-#define ZTM(param) ((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */
+#define ZTM(param) ((param & 0x3) << 4) /* ALC Zero Crossing TimeOut */
#define WTM(param) (((param & 0x4) << 4) | ((param & 0x3) << 2))
/* ALC_CTL1 */
@@ -134,6 +134,15 @@
/* MD_CTL4 */
#define DACH (1 << 0)
+struct ak4642_drvdata {
+ const struct regmap_config *regmap_config;
+ int extended_frequencies;
+};
+
+struct ak4642_priv {
+ const struct ak4642_drvdata *drvdata;
+};
+
/*
* Playback Volume (table 39)
*
@@ -148,6 +157,8 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC,
0, 0xFF, 1, out_tlv),
+ SOC_SINGLE("ALC Capture Switch", ALC_CTL1, 5, 1, 0),
+ SOC_SINGLE("ALC Capture ZC Switch", ALC_CTL1, 4, 1, 1),
};
static const struct snd_kcontrol_new ak4642_headphone_control =
@@ -287,7 +298,9 @@ static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
+ struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec);
u8 pll;
+ int extended_freq = 0;
switch (freq) {
case 11289600:
@@ -308,9 +321,25 @@ static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai,
case 27000000:
pll = PLL3 | PLL2 | PLL0;
break;
+ case 19200000:
+ pll = PLL3;
+ extended_freq = 1;
+ break;
+ case 13000000:
+ pll = PLL3 | PLL2 | PLL1;
+ extended_freq = 1;
+ break;
+ case 26000000:
+ pll = PLL3 | PLL2 | PLL1 | PLL0;
+ extended_freq = 1;
+ break;
default:
return -EINVAL;
}
+
+ if (extended_freq && !priv->drvdata->extended_frequencies)
+ return -EINVAL;
+
snd_soc_update_bits(codec, MD_CTL1, PLL_MASK, pll);
return 0;
@@ -505,30 +534,52 @@ static const struct regmap_config ak4648_regmap = {
.num_reg_defaults = ARRAY_SIZE(ak4648_reg),
};
+static const struct ak4642_drvdata ak4642_drvdata = {
+ .regmap_config = &ak4642_regmap,
+};
+
+static const struct ak4642_drvdata ak4643_drvdata = {
+ .regmap_config = &ak4642_regmap,
+};
+
+static const struct ak4642_drvdata ak4648_drvdata = {
+ .regmap_config = &ak4648_regmap,
+ .extended_frequencies = 1,
+};
+
static struct of_device_id ak4642_of_match[];
static int ak4642_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct device_node *np = i2c->dev.of_node;
- const struct regmap_config *regmap_config = NULL;
+ const struct ak4642_drvdata *drvdata = NULL;
struct regmap *regmap;
+ struct ak4642_priv *priv;
if (np) {
const struct of_device_id *of_id;
of_id = of_match_device(ak4642_of_match, &i2c->dev);
if (of_id)
- regmap_config = of_id->data;
+ drvdata = of_id->data;
} else {
- regmap_config = (const struct regmap_config *)id->driver_data;
+ drvdata = (const struct ak4642_drvdata *)id->driver_data;
}
- if (!regmap_config) {
+ if (!drvdata) {
dev_err(&i2c->dev, "Unknown device type\n");
return -EINVAL;
}
- regmap = devm_regmap_init_i2c(i2c, regmap_config);
+ priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->drvdata = drvdata;
+
+ i2c_set_clientdata(i2c, priv);
+
+ regmap = devm_regmap_init_i2c(i2c, drvdata->regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
@@ -543,17 +594,17 @@ static int ak4642_i2c_remove(struct i2c_client *client)
}
static struct of_device_id ak4642_of_match[] = {
- { .compatible = "asahi-kasei,ak4642", .data = &ak4642_regmap},
- { .compatible = "asahi-kasei,ak4643", .data = &ak4642_regmap},
- { .compatible = "asahi-kasei,ak4648", .data = &ak4648_regmap},
+ { .compatible = "asahi-kasei,ak4642", .data = &ak4642_drvdata},
+ { .compatible = "asahi-kasei,ak4643", .data = &ak4643_drvdata},
+ { .compatible = "asahi-kasei,ak4648", .data = &ak4648_drvdata},
{},
};
MODULE_DEVICE_TABLE(of, ak4642_of_match);
static const struct i2c_device_id ak4642_i2c_id[] = {
- { "ak4642", (kernel_ulong_t)&ak4642_regmap },
- { "ak4643", (kernel_ulong_t)&ak4642_regmap },
- { "ak4648", (kernel_ulong_t)&ak4648_regmap },
+ { "ak4642", (kernel_ulong_t)&ak4642_drvdata },
+ { "ak4643", (kernel_ulong_t)&ak4643_drvdata },
+ { "ak4648", (kernel_ulong_t)&ak4648_drvdata },
{ }
};
MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index f500905e9373..9d0755aa1d16 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -23,6 +23,7 @@
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -998,8 +999,10 @@ static int alc5623_i2c_probe(struct i2c_client *client,
{
struct alc5623_platform_data *pdata;
struct alc5623_priv *alc5623;
+ struct device_node *np;
unsigned int vid1, vid2;
int ret;
+ u32 val32;
alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv),
GFP_KERNEL);
@@ -1018,13 +1021,13 @@ static int alc5623_i2c_probe(struct i2c_client *client,
dev_err(&client->dev, "failed to read vendor ID1: %d\n", ret);
return ret;
}
- vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8);
ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID2, &vid2);
if (ret < 0) {
dev_err(&client->dev, "failed to read vendor ID2: %d\n", ret);
return ret;
}
+ vid2 >>= 8;
if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) {
dev_err(&client->dev, "unknown or wrong codec\n");
@@ -1040,6 +1043,16 @@ static int alc5623_i2c_probe(struct i2c_client *client,
if (pdata) {
alc5623->add_ctrl = pdata->add_ctrl;
alc5623->jack_det_ctrl = pdata->jack_det_ctrl;
+ } else {
+ if (client->dev.of_node) {
+ np = client->dev.of_node;
+ ret = of_property_read_u32(np, "add-ctrl", &val32);
+ if (!ret)
+ alc5623->add_ctrl = val32;
+ ret = of_property_read_u32(np, "jack-det-ctrl", &val32);
+ if (!ret)
+ alc5623->jack_det_ctrl = val32;
+ }
}
alc5623->id = vid2;
@@ -1081,11 +1094,18 @@ static const struct i2c_device_id alc5623_i2c_table[] = {
};
MODULE_DEVICE_TABLE(i2c, alc5623_i2c_table);
+static const struct of_device_id alc5623_of_match[] = {
+ { .compatible = "realtek,alc5623", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, alc5623_of_match);
+
/* i2c codec control layer */
static struct i2c_driver alc5623_i2c_driver = {
.driver = {
.name = "alc562x-codec",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(alc5623_of_match),
},
.probe = alc5623_i2c_probe,
.remove = alc5623_i2c_remove,
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 16df0f913353..05ae17f5bca3 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -107,7 +107,7 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
#define ARIZONA_MUX_CTL_DECL(name) \
const struct snd_kcontrol_new name##_mux = \
- SOC_DAPM_VALUE_ENUM("Route", name##_enum)
+ SOC_DAPM_ENUM("Route", name##_enum)
#define ARIZONA_MUX_ENUMS(name, base_reg) \
static ARIZONA_MUX_ENUM_DECL(name##_enum, base_reg); \
@@ -128,7 +128,7 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
ARIZONA_MUX_ENUMS(name##_aux6, base_reg + 40)
#define ARIZONA_MUX(name, ctrl) \
- SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+ SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
#define ARIZONA_MUX_WIDGETS(name, name_str) \
ARIZONA_MUX(name_str " Input", &name##_mux)
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index 1e25c7af853b..537327c7f7f1 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -139,8 +139,6 @@ static int cq93vc_probe(struct snd_soc_codec *codec)
davinci_vc->cq93vc.codec = codec;
- snd_soc_codec_set_cache_io(codec, davinci_vc->regmap);
-
/* Off, with power on */
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -154,11 +152,19 @@ static int cq93vc_remove(struct snd_soc_codec *codec)
return 0;
}
+static struct regmap *cq93vc_get_regmap(struct device *dev)
+{
+ struct davinci_vc *davinci_vc = dev->platform_data;
+
+ return davinci_vc->regmap;
+}
+
static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
.set_bias_level = cq93vc_set_bias_level,
.probe = cq93vc_probe,
.remove = cq93vc_remove,
.resume = cq93vc_resume,
+ .get_regmap = cq93vc_get_regmap,
.controls = cq93vc_snd_controls,
.num_controls = ARRAY_SIZE(cq93vc_snd_controls),
};
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 3920e6264948..9947a9583679 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -438,7 +438,7 @@ static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute)
static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int left = !ucontrol->value.integer.value[0];
int right = !ucontrol->value.integer.value[1];
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index aef4965750c7..93cec52f4733 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -284,7 +284,7 @@ static int cs4271_set_deemph(struct snd_soc_codec *codec)
static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = cs4271->deemph;
@@ -294,7 +294,7 @@ static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
cs4271->deemph = ucontrol->value.enumerated.item[0];
diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c
new file mode 100644
index 000000000000..cee51ae177c1
--- /dev/null
+++ b/sound/soc/codecs/cs42l51-i2c.c
@@ -0,0 +1,59 @@
+/*
+ * cs42l56.c -- CS42L51 ALSA SoC I2C audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.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/i2c.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "cs42l51.h"
+
+static struct i2c_device_id cs42l51_i2c_id[] = {
+ {"cs42l51", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id);
+
+static int cs42l51_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct regmap_config config;
+
+ config = cs42l51_regmap;
+ config.val_bits = 8;
+ config.reg_bits = 8;
+
+ return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config));
+}
+
+static int cs42l51_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_codec(&i2c->dev);
+
+ return 0;
+}
+
+static struct i2c_driver cs42l51_i2c_driver = {
+ .driver = {
+ .name = "cs42l51",
+ .owner = THIS_MODULE,
+ },
+ .probe = cs42l51_i2c_probe,
+ .remove = cs42l51_i2c_remove,
+ .id_table = cs42l51_i2c_id,
+};
+
+module_i2c_driver(cs42l51_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L51 I2C Driver");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 6c0da2baa154..09488d97de60 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -29,7 +29,6 @@
#include <sound/initval.h>
#include <sound/pcm_params.h>
#include <sound/pcm.h>
-#include <linux/i2c.h>
#include <linux/regmap.h>
#include "cs42l51.h"
@@ -55,7 +54,7 @@ struct cs42l51_private {
static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;
switch (value) {
@@ -83,7 +82,7 @@ static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned char val;
switch (ucontrol->value.integer.value[0]) {
@@ -483,7 +482,7 @@ static struct snd_soc_dai_driver cs42l51_dai = {
.ops = &cs42l51_dai_ops,
};
-static int cs42l51_probe(struct snd_soc_codec *codec)
+static int cs42l51_codec_probe(struct snd_soc_codec *codec)
{
int ret, reg;
@@ -504,7 +503,7 @@ static int cs42l51_probe(struct snd_soc_codec *codec)
}
static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
- .probe = cs42l51_probe,
+ .probe = cs42l51_codec_probe,
.controls = cs42l51_snd_controls,
.num_controls = ARRAY_SIZE(cs42l51_snd_controls),
@@ -514,91 +513,56 @@ static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
.num_dapm_routes = ARRAY_SIZE(cs42l51_routes),
};
-static const struct regmap_config cs42l51_regmap = {
- .reg_bits = 8,
- .val_bits = 8,
-
+const struct regmap_config cs42l51_regmap = {
.max_register = CS42L51_CHARGE_FREQ,
.cache_type = REGCACHE_RBTREE,
};
+EXPORT_SYMBOL_GPL(cs42l51_regmap);
-static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
- const struct i2c_device_id *id)
+int cs42l51_probe(struct device *dev, struct regmap *regmap)
{
struct cs42l51_private *cs42l51;
- struct regmap *regmap;
unsigned int val;
int ret;
- regmap = devm_regmap_init_i2c(i2c_client, &cs42l51_regmap);
- if (IS_ERR(regmap)) {
- ret = PTR_ERR(regmap);
- dev_err(&i2c_client->dev, "Failed to create regmap: %d\n",
- ret);
- return ret;
- }
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ cs42l51 = devm_kzalloc(dev, sizeof(struct cs42l51_private),
+ GFP_KERNEL);
+ if (!cs42l51)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, cs42l51);
/* Verify that we have a CS42L51 */
ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
if (ret < 0) {
- dev_err(&i2c_client->dev, "failed to read I2C\n");
+ dev_err(dev, "failed to read I2C\n");
goto error;
}
if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
(val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
- dev_err(&i2c_client->dev, "Invalid chip id: %x\n", val);
+ dev_err(dev, "Invalid chip id: %x\n", val);
ret = -ENODEV;
goto error;
}
+ dev_info(dev, "Cirrus Logic CS42L51, Revision: %02X\n",
+ val & CS42L51_CHIP_REV_MASK);
- dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
- val & 7);
-
- cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private),
- GFP_KERNEL);
- if (!cs42l51)
- return -ENOMEM;
-
- i2c_set_clientdata(i2c_client, cs42l51);
-
- ret = snd_soc_register_codec(&i2c_client->dev,
+ ret = snd_soc_register_codec(dev,
&soc_codec_device_cs42l51, &cs42l51_dai, 1);
error:
return ret;
}
-
-static int cs42l51_i2c_remove(struct i2c_client *client)
-{
- snd_soc_unregister_codec(&client->dev);
- return 0;
-}
-
-static const struct i2c_device_id cs42l51_id[] = {
- {"cs42l51", 0},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, cs42l51_id);
+EXPORT_SYMBOL_GPL(cs42l51_probe);
static const struct of_device_id cs42l51_of_match[] = {
{ .compatible = "cirrus,cs42l51", },
{ }
};
MODULE_DEVICE_TABLE(of, cs42l51_of_match);
-
-static struct i2c_driver cs42l51_i2c_driver = {
- .driver = {
- .name = "cs42l51-codec",
- .owner = THIS_MODULE,
- .of_match_table = cs42l51_of_match,
- },
- .id_table = cs42l51_id,
- .probe = cs42l51_i2c_probe,
- .remove = cs42l51_i2c_remove,
-};
-
-module_i2c_driver(cs42l51_i2c_driver);
-
MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h
index 2beeb171db4b..8c55bf384bc6 100644
--- a/sound/soc/codecs/cs42l51.h
+++ b/sound/soc/codecs/cs42l51.h
@@ -18,9 +18,15 @@
#ifndef _CS42L51_H
#define _CS42L51_H
+struct device;
+
+extern const struct regmap_config cs42l51_regmap;
+int cs42l51_probe(struct device *dev, struct regmap *regmap);
+
#define CS42L51_CHIP_ID 0x1B
#define CS42L51_CHIP_REV_A 0x00
#define CS42L51_CHIP_REV_B 0x01
+#define CS42L51_CHIP_REV_MASK 0x07
#define CS42L51_CHIP_REV_ID 0x01
#define CS42L51_MK_CHIP_REV(a, b) ((a)<<3|(b))
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 460d35547a68..071fc77f2f06 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -50,11 +50,9 @@ struct cs42l52_private {
u8 mclksel;
u32 mclk;
u8 flags;
-#if IS_ENABLED(CONFIG_INPUT)
struct input_dev *beep;
struct work_struct beep_work;
int beep_rate;
-#endif
};
static const struct reg_default cs42l52_reg_defaults[] = {
@@ -962,7 +960,6 @@ static int cs42l52_resume(struct snd_soc_codec *codec)
return 0;
}
-#if IS_ENABLED(CONFIG_INPUT)
static int beep_rates[] = {
261, 522, 585, 667, 706, 774, 889, 1000,
1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
@@ -1096,15 +1093,6 @@ static void cs42l52_free_beep(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, CS42L52_BEEP_TONE_CTL,
CS42L52_BEEP_EN_MASK, 0);
}
-#else
-static void cs42l52_init_beep(struct snd_soc_codec *codec)
-{
-}
-
-static void cs42l52_free_beep(struct snd_soc_codec *codec)
-{
-}
-#endif
static int cs42l52_probe(struct snd_soc_codec *codec)
{
@@ -1229,8 +1217,10 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
}
if (cs42l52->pdata.reset_gpio) {
- ret = gpio_request_one(cs42l52->pdata.reset_gpio,
- GPIOF_OUT_INIT_HIGH, "CS42L52 /RST");
+ ret = devm_gpio_request_one(&i2c_client->dev,
+ cs42l52->pdata.reset_gpio,
+ GPIOF_OUT_INIT_HIGH,
+ "CS42L52 /RST");
if (ret < 0) {
dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
cs42l52->pdata.reset_gpio, ret);
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
new file mode 100644
index 000000000000..5bb134b4ab9b
--- /dev/null
+++ b/sound/soc/codecs/cs42l56.c
@@ -0,0 +1,1427 @@
+/*
+ * cs42l56.c -- CS42L56 ALSA SoC audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.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/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.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 <sound/cs42l56.h>
+#include "cs42l56.h"
+
+#define CS42L56_NUM_SUPPLIES 3
+static const char *const cs42l56_supply_names[CS42L56_NUM_SUPPLIES] = {
+ "VA",
+ "VCP",
+ "VLDO",
+};
+
+struct cs42l56_private {
+ struct regmap *regmap;
+ struct snd_soc_codec *codec;
+ struct device *dev;
+ struct cs42l56_platform_data pdata;
+ struct regulator_bulk_data supplies[CS42L56_NUM_SUPPLIES];
+ u32 mclk;
+ u8 mclk_prediv;
+ u8 mclk_div2;
+ u8 mclk_ratio;
+ u8 iface;
+ u8 iface_fmt;
+ u8 iface_inv;
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ struct input_dev *beep;
+ struct work_struct beep_work;
+ int beep_rate;
+#endif
+};
+
+static const struct reg_default cs42l56_reg_defaults[] = {
+ { 1, 0x56 }, /* r01 - ID 1 */
+ { 2, 0x04 }, /* r02 - ID 2 */
+ { 3, 0x7f }, /* r03 - Power Ctl 1 */
+ { 4, 0xff }, /* r04 - Power Ctl 2 */
+ { 5, 0x00 }, /* ro5 - Clocking Ctl 1 */
+ { 6, 0x0b }, /* r06 - Clocking Ctl 2 */
+ { 7, 0x00 }, /* r07 - Serial Format */
+ { 8, 0x05 }, /* r08 - Class H Ctl */
+ { 9, 0x0c }, /* r09 - Misc Ctl */
+ { 10, 0x80 }, /* r0a - INT Status */
+ { 11, 0x00 }, /* r0b - Playback Ctl */
+ { 12, 0x0c }, /* r0c - DSP Mute Ctl */
+ { 13, 0x00 }, /* r0d - ADCA Mixer Volume */
+ { 14, 0x00 }, /* r0e - ADCB Mixer Volume */
+ { 15, 0x00 }, /* r0f - PCMA Mixer Volume */
+ { 16, 0x00 }, /* r10 - PCMB Mixer Volume */
+ { 17, 0x00 }, /* r11 - Analog Input Advisory Volume */
+ { 18, 0x00 }, /* r12 - Digital Input Advisory Volume */
+ { 19, 0x00 }, /* r13 - Master A Volume */
+ { 20, 0x00 }, /* r14 - Master B Volume */
+ { 21, 0x00 }, /* r15 - Beep Freq / On Time */
+ { 22, 0x00 }, /* r16 - Beep Volume / Off Time */
+ { 23, 0x00 }, /* r17 - Beep Tone Ctl */
+ { 24, 0x88 }, /* r18 - Tone Ctl */
+ { 25, 0x00 }, /* r19 - Channel Mixer & Swap */
+ { 26, 0x00 }, /* r1a - AIN Ref Config / ADC Mux */
+ { 27, 0xa0 }, /* r1b - High-Pass Filter Ctl */
+ { 28, 0x00 }, /* r1c - Misc ADC Ctl */
+ { 29, 0x00 }, /* r1d - Gain & Bias Ctl */
+ { 30, 0x00 }, /* r1e - PGAA Mux & Volume */
+ { 31, 0x00 }, /* r1f - PGAB Mux & Volume */
+ { 32, 0x00 }, /* r20 - ADCA Attenuator */
+ { 33, 0x00 }, /* r21 - ADCB Attenuator */
+ { 34, 0x00 }, /* r22 - ALC Enable & Attack Rate */
+ { 35, 0xbf }, /* r23 - ALC Release Rate */
+ { 36, 0x00 }, /* r24 - ALC Threshold */
+ { 37, 0x00 }, /* r25 - Noise Gate Ctl */
+ { 38, 0x00 }, /* r26 - ALC, Limiter, SFT, ZeroCross */
+ { 39, 0x00 }, /* r27 - Analog Mute, LO & HP Mux */
+ { 40, 0x00 }, /* r28 - HP A Volume */
+ { 41, 0x00 }, /* r29 - HP B Volume */
+ { 42, 0x00 }, /* r2a - LINEOUT A Volume */
+ { 43, 0x00 }, /* r2b - LINEOUT B Volume */
+ { 44, 0x00 }, /* r2c - Limit Threshold Ctl */
+ { 45, 0x7f }, /* r2d - Limiter Ctl & Release Rate */
+ { 46, 0x00 }, /* r2e - Limiter Attack Rate */
+};
+
+static bool cs42l56_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42L56_CHIP_ID_1:
+ case CS42L56_CHIP_ID_2:
+ case CS42L56_PWRCTL_1:
+ case CS42L56_PWRCTL_2:
+ case CS42L56_CLKCTL_1:
+ case CS42L56_CLKCTL_2:
+ case CS42L56_SERIAL_FMT:
+ case CS42L56_CLASSH_CTL:
+ case CS42L56_MISC_CTL:
+ case CS42L56_INT_STATUS:
+ case CS42L56_PLAYBACK_CTL:
+ case CS42L56_DSP_MUTE_CTL:
+ case CS42L56_ADCA_MIX_VOLUME:
+ case CS42L56_ADCB_MIX_VOLUME:
+ case CS42L56_PCMA_MIX_VOLUME:
+ case CS42L56_PCMB_MIX_VOLUME:
+ case CS42L56_ANAINPUT_ADV_VOLUME:
+ case CS42L56_DIGINPUT_ADV_VOLUME:
+ case CS42L56_MASTER_A_VOLUME:
+ case CS42L56_MASTER_B_VOLUME:
+ case CS42L56_BEEP_FREQ_ONTIME:
+ case CS42L56_BEEP_FREQ_OFFTIME:
+ case CS42L56_BEEP_TONE_CFG:
+ case CS42L56_TONE_CTL:
+ case CS42L56_CHAN_MIX_SWAP:
+ case CS42L56_AIN_REFCFG_ADC_MUX:
+ case CS42L56_HPF_CTL:
+ case CS42L56_MISC_ADC_CTL:
+ case CS42L56_GAIN_BIAS_CTL:
+ case CS42L56_PGAA_MUX_VOLUME:
+ case CS42L56_PGAB_MUX_VOLUME:
+ case CS42L56_ADCA_ATTENUATOR:
+ case CS42L56_ADCB_ATTENUATOR:
+ case CS42L56_ALC_EN_ATTACK_RATE:
+ case CS42L56_ALC_RELEASE_RATE:
+ case CS42L56_ALC_THRESHOLD:
+ case CS42L56_NOISE_GATE_CTL:
+ case CS42L56_ALC_LIM_SFT_ZC:
+ case CS42L56_AMUTE_HPLO_MUX:
+ case CS42L56_HPA_VOLUME:
+ case CS42L56_HPB_VOLUME:
+ case CS42L56_LOA_VOLUME:
+ case CS42L56_LOB_VOLUME:
+ case CS42L56_LIM_THRESHOLD_CTL:
+ case CS42L56_LIM_CTL_RELEASE_RATE:
+ case CS42L56_LIM_ATTACK_RATE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs42l56_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42L56_INT_STATUS:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static DECLARE_TLV_DB_SCALE(beep_tlv, -5000, 200, 0);
+static DECLARE_TLV_DB_SCALE(hl_tlv, -6000, 50, 0);
+static DECLARE_TLV_DB_SCALE(adv_tlv, -10200, 50, 0);
+static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, 0);
+static DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
+static DECLARE_TLV_DB_SCALE(preamp_tlv, 0, 1000, 0);
+static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
+
+static const unsigned int ngnb_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0, 1, TLV_DB_SCALE_ITEM(-8200, 600, 0),
+ 2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0),
+};
+static const unsigned int ngb_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0, 2, TLV_DB_SCALE_ITEM(-6400, 600, 0),
+ 3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0),
+};
+static const unsigned int alc_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
+ 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0),
+};
+
+static const char * const beep_config_text[] = {
+ "Off", "Single", "Multiple", "Continuous"
+};
+
+static const struct soc_enum beep_config_enum =
+ SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 6,
+ ARRAY_SIZE(beep_config_text), beep_config_text);
+
+static const char * const beep_pitch_text[] = {
+ "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
+ "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
+};
+
+static const struct soc_enum beep_pitch_enum =
+ SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 4,
+ ARRAY_SIZE(beep_pitch_text), beep_pitch_text);
+
+static const char * const beep_ontime_text[] = {
+ "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
+ "1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s",
+ "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
+};
+
+static const struct soc_enum beep_ontime_enum =
+ SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 0,
+ ARRAY_SIZE(beep_ontime_text), beep_ontime_text);
+
+static const char * const beep_offtime_text[] = {
+ "1.23 s", "2.58 s", "3.90 s", "5.20 s",
+ "6.60 s", "8.05 s", "9.35 s", "10.80 s"
+};
+
+static const struct soc_enum beep_offtime_enum =
+ SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_OFFTIME, 5,
+ ARRAY_SIZE(beep_offtime_text), beep_offtime_text);
+
+static const char * const beep_treble_text[] = {
+ "5kHz", "7kHz", "10kHz", "15kHz"
+};
+
+static const struct soc_enum beep_treble_enum =
+ SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 3,
+ ARRAY_SIZE(beep_treble_text), beep_treble_text);
+
+static const char * const beep_bass_text[] = {
+ "50Hz", "100Hz", "200Hz", "250Hz"
+};
+
+static const struct soc_enum beep_bass_enum =
+ SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1,
+ ARRAY_SIZE(beep_bass_text), beep_bass_text);
+
+static const char * const adc_swap_text[] = {
+ "None", "A+B/2", "A-B/2", "Swap"
+};
+
+static const struct soc_enum adc_swap_enum =
+ SOC_ENUM_SINGLE(CS42L56_MISC_ADC_CTL, 3,
+ ARRAY_SIZE(adc_swap_text), adc_swap_text);
+
+static const char * const pgaa_mux_text[] = {
+ "AIN1A", "AIN2A", "AIN3A"};
+
+static const struct soc_enum pgaa_mux_enum =
+ SOC_ENUM_SINGLE(CS42L56_PGAA_MUX_VOLUME, 0,
+ ARRAY_SIZE(pgaa_mux_text),
+ pgaa_mux_text);
+
+static const struct snd_kcontrol_new pgaa_mux =
+ SOC_DAPM_ENUM("Route", pgaa_mux_enum);
+
+static const char * const pgab_mux_text[] = {
+ "AIN1B", "AIN2B", "AIN3B"};
+
+static const struct soc_enum pgab_mux_enum =
+ SOC_ENUM_SINGLE(CS42L56_PGAB_MUX_VOLUME, 0,
+ ARRAY_SIZE(pgab_mux_text),
+ pgab_mux_text);
+
+static const struct snd_kcontrol_new pgab_mux =
+ SOC_DAPM_ENUM("Route", pgab_mux_enum);
+
+static const char * const adca_mux_text[] = {
+ "PGAA", "AIN1A", "AIN2A", "AIN3A"};
+
+static const struct soc_enum adca_mux_enum =
+ SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 0,
+ ARRAY_SIZE(adca_mux_text),
+ adca_mux_text);
+
+static const struct snd_kcontrol_new adca_mux =
+ SOC_DAPM_ENUM("Route", adca_mux_enum);
+
+static const char * const adcb_mux_text[] = {
+ "PGAB", "AIN1B", "AIN2B", "AIN3B"};
+
+static const struct soc_enum adcb_mux_enum =
+ SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 2,
+ ARRAY_SIZE(adcb_mux_text),
+ adcb_mux_text);
+
+static const struct snd_kcontrol_new adcb_mux =
+ SOC_DAPM_ENUM("Route", adcb_mux_enum);
+
+static const char * const left_swap_text[] = {
+ "Left", "LR 2", "Right"};
+
+static const char * const right_swap_text[] = {
+ "Right", "LR 2", "Left"};
+
+static const unsigned int swap_values[] = { 0, 1, 3 };
+
+static const struct soc_enum adca_swap_enum =
+ SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 0, 3,
+ ARRAY_SIZE(left_swap_text),
+ left_swap_text,
+ swap_values);
+
+static const struct soc_enum pcma_swap_enum =
+ SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3,
+ ARRAY_SIZE(left_swap_text),
+ left_swap_text,
+ swap_values);
+
+static const struct soc_enum adcb_swap_enum =
+ SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3,
+ ARRAY_SIZE(right_swap_text),
+ right_swap_text,
+ swap_values);
+
+static const struct soc_enum pcmb_swap_enum =
+ SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3,
+ ARRAY_SIZE(right_swap_text),
+ right_swap_text,
+ swap_values);
+
+static const struct snd_kcontrol_new hpa_switch =
+ SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1);
+
+static const struct snd_kcontrol_new hpb_switch =
+ SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 4, 1, 1);
+
+static const struct snd_kcontrol_new loa_switch =
+ SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 2, 1, 1);
+
+static const struct snd_kcontrol_new lob_switch =
+ SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 0, 1, 1);
+
+static const char * const hploa_input_text[] = {
+ "DACA", "PGAA"};
+
+static const struct soc_enum lineouta_input_enum =
+ SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 2,
+ ARRAY_SIZE(hploa_input_text),
+ hploa_input_text);
+
+static const struct snd_kcontrol_new lineouta_input =
+ SOC_DAPM_ENUM("Route", lineouta_input_enum);
+
+static const struct soc_enum hpa_input_enum =
+ SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 0,
+ ARRAY_SIZE(hploa_input_text),
+ hploa_input_text);
+
+static const struct snd_kcontrol_new hpa_input =
+ SOC_DAPM_ENUM("Route", hpa_input_enum);
+
+static const char * const hplob_input_text[] = {
+ "DACB", "PGAB"};
+
+static const struct soc_enum lineoutb_input_enum =
+ SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 3,
+ ARRAY_SIZE(hplob_input_text),
+ hplob_input_text);
+
+static const struct snd_kcontrol_new lineoutb_input =
+ SOC_DAPM_ENUM("Route", lineoutb_input_enum);
+
+static const struct soc_enum hpb_input_enum =
+ SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 1,
+ ARRAY_SIZE(hplob_input_text),
+ hplob_input_text);
+
+static const struct snd_kcontrol_new hpb_input =
+ SOC_DAPM_ENUM("Route", hpb_input_enum);
+
+static const char * const dig_mux_text[] = {
+ "ADC", "DSP"};
+
+static const struct soc_enum dig_mux_enum =
+ SOC_ENUM_SINGLE(CS42L56_MISC_CTL, 7,
+ ARRAY_SIZE(dig_mux_text),
+ dig_mux_text);
+
+static const struct snd_kcontrol_new dig_mux =
+ SOC_DAPM_ENUM("Route", dig_mux_enum);
+
+static const char * const hpf_freq_text[] = {
+ "1.8Hz", "119Hz", "236Hz", "464Hz"
+};
+
+static const struct soc_enum hpfa_freq_enum =
+ SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 0,
+ ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
+
+static const struct soc_enum hpfb_freq_enum =
+ SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 2,
+ ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
+
+static const char * const ng_delay_text[] = {
+ "50ms", "100ms", "150ms", "200ms"
+};
+
+static const struct soc_enum ng_delay_enum =
+ SOC_ENUM_SINGLE(CS42L56_NOISE_GATE_CTL, 0,
+ ARRAY_SIZE(ng_delay_text), ng_delay_text);
+
+static const struct snd_kcontrol_new cs42l56_snd_controls[] = {
+
+ SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME,
+ CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xfd, adv_tlv),
+ SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1),
+
+ SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME,
+ CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv),
+ SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1),
+
+ SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME,
+ CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0xa9, hl_tlv),
+ SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1),
+
+ SOC_SINGLE_TLV("Analog Advisory Volume",
+ CS42L56_ANAINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
+ SOC_SINGLE_TLV("Digital Advisory Volume",
+ CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
+
+ SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME,
+ CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0xfd, pga_tlv),
+ SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR,
+ CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv),
+ SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1),
+ SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1),
+
+ SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME,
+ CS42L56_HPA_VOLUME, 0, 0x44, 0x55, hl_tlv),
+ SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME,
+ CS42L56_LOA_VOLUME, 0, 0x44, 0x55, hl_tlv),
+
+ SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL,
+ 0, 0x00, 1, tone_tlv),
+ SOC_SINGLE_TLV("Treble Shelving Volume", CS42L56_TONE_CTL,
+ 4, 0x00, 1, tone_tlv),
+
+ SOC_DOUBLE_TLV("PGA Preamp Volume", CS42L56_GAIN_BIAS_CTL,
+ 4, 6, 0x02, 1, preamp_tlv),
+
+ SOC_SINGLE("DSP Switch", CS42L56_PLAYBACK_CTL, 7, 1, 1),
+ SOC_SINGLE("Gang Playback Switch", CS42L56_PLAYBACK_CTL, 4, 1, 1),
+ SOC_SINGLE("Gang ADC Switch", CS42L56_MISC_ADC_CTL, 7, 1, 1),
+ SOC_SINGLE("Gang PGA Switch", CS42L56_MISC_ADC_CTL, 6, 1, 1),
+
+ SOC_SINGLE("PCMA Invert", CS42L56_PLAYBACK_CTL, 2, 1, 1),
+ SOC_SINGLE("PCMB Invert", CS42L56_PLAYBACK_CTL, 3, 1, 1),
+ SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1),
+ SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1),
+
+ SOC_ENUM("PCMA Swap", pcma_swap_enum),
+ SOC_ENUM("PCMB Swap", pcmb_swap_enum),
+ SOC_ENUM("ADCA Swap", adca_swap_enum),
+ SOC_ENUM("ADCB Swap", adcb_swap_enum),
+
+ SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1),
+ SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1),
+ SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum),
+ SOC_ENUM("HPFB Corner Freq", hpfb_freq_enum),
+
+ SOC_SINGLE("Analog Soft Ramp", CS42L56_MISC_CTL, 4, 1, 1),
+ SOC_DOUBLE("Analog Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
+ 7, 5, 1, 1),
+ SOC_SINGLE("Analog Zero Cross", CS42L56_MISC_CTL, 3, 1, 1),
+ SOC_DOUBLE("Analog Zero Cross Disable", CS42L56_ALC_LIM_SFT_ZC,
+ 6, 4, 1, 1),
+ SOC_SINGLE("Digital Soft Ramp", CS42L56_MISC_CTL, 2, 1, 1),
+ SOC_SINGLE("Digital Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
+ 3, 1, 1),
+
+ SOC_SINGLE("HL Deemphasis", CS42L56_PLAYBACK_CTL, 6, 1, 1),
+
+ SOC_SINGLE("ALC Switch", CS42L56_ALC_EN_ATTACK_RATE, 6, 1, 1),
+ SOC_SINGLE("ALC Limit All Switch", CS42L56_ALC_RELEASE_RATE, 7, 1, 1),
+ SOC_SINGLE_RANGE("ALC Attack", CS42L56_ALC_EN_ATTACK_RATE,
+ 0, 0, 0x3f, 0),
+ SOC_SINGLE_RANGE("ALC Release", CS42L56_ALC_RELEASE_RATE,
+ 0, 0x3f, 0, 0),
+ SOC_SINGLE_TLV("ALC MAX", CS42L56_ALC_THRESHOLD,
+ 5, 0x07, 1, alc_tlv),
+ SOC_SINGLE_TLV("ALC MIN", CS42L56_ALC_THRESHOLD,
+ 2, 0x07, 1, alc_tlv),
+
+ SOC_SINGLE("Limiter Switch", CS42L56_LIM_CTL_RELEASE_RATE, 7, 1, 1),
+ SOC_SINGLE("Limit All Switch", CS42L56_LIM_CTL_RELEASE_RATE, 6, 1, 1),
+ SOC_SINGLE_RANGE("Limiter Attack", CS42L56_LIM_ATTACK_RATE,
+ 0, 0, 0x3f, 0),
+ SOC_SINGLE_RANGE("Limiter Release", CS42L56_LIM_CTL_RELEASE_RATE,
+ 0, 0x3f, 0, 0),
+ SOC_SINGLE_TLV("Limiter MAX", CS42L56_LIM_THRESHOLD_CTL,
+ 5, 0x07, 1, alc_tlv),
+ SOC_SINGLE_TLV("Limiter Cushion", CS42L56_ALC_THRESHOLD,
+ 2, 0x07, 1, alc_tlv),
+
+ SOC_SINGLE("NG Switch", CS42L56_NOISE_GATE_CTL, 6, 1, 1),
+ SOC_SINGLE("NG All Switch", CS42L56_NOISE_GATE_CTL, 7, 1, 1),
+ SOC_SINGLE("NG Boost Switch", CS42L56_NOISE_GATE_CTL, 5, 1, 1),
+ SOC_SINGLE_TLV("NG Unboost Threshold", CS42L56_NOISE_GATE_CTL,
+ 2, 0x07, 1, ngnb_tlv),
+ SOC_SINGLE_TLV("NG Boost Threshold", CS42L56_NOISE_GATE_CTL,
+ 2, 0x07, 1, ngb_tlv),
+ SOC_ENUM("NG Delay", ng_delay_enum),
+
+ SOC_ENUM("Beep Config", beep_config_enum),
+ SOC_ENUM("Beep Pitch", beep_pitch_enum),
+ SOC_ENUM("Beep on Time", beep_ontime_enum),
+ SOC_ENUM("Beep off Time", beep_offtime_enum),
+ SOC_SINGLE_SX_TLV("Beep Volume", CS42L56_BEEP_FREQ_OFFTIME,
+ 0, 0x07, 0x23, beep_tlv),
+ SOC_SINGLE("Beep Tone Ctl Switch", CS42L56_BEEP_TONE_CFG, 0, 1, 1),
+ SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
+ SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
+
+};
+
+static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SIGGEN("Beep"),
+ SND_SOC_DAPM_SUPPLY("VBUF", CS42L56_PWRCTL_1, 5, 1, NULL, 0),
+ SND_SOC_DAPM_MICBIAS("MIC1 Bias", CS42L56_PWRCTL_1, 4, 1),
+ SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L56_PWRCTL_1, 3, 1, NULL, 0),
+
+ SND_SOC_DAPM_INPUT("AIN1A"),
+ SND_SOC_DAPM_INPUT("AIN2A"),
+ SND_SOC_DAPM_INPUT("AIN1B"),
+ SND_SOC_DAPM_INPUT("AIN2B"),
+ SND_SOC_DAPM_INPUT("AIN3A"),
+ SND_SOC_DAPM_INPUT("AIN3B"),
+
+ SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0,
+ SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0,
+ SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_MUX("Digital Output Mux", SND_SOC_NOPM,
+ 0, 0, &dig_mux),
+
+ SND_SOC_DAPM_PGA("PGAA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PGAB", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MUX("PGAA Input Mux",
+ SND_SOC_NOPM, 0, 0, &pgaa_mux),
+ SND_SOC_DAPM_MUX("PGAB Input Mux",
+ SND_SOC_NOPM, 0, 0, &pgab_mux),
+
+ SND_SOC_DAPM_MUX("ADCA Mux", SND_SOC_NOPM,
+ 0, 0, &adca_mux),
+ SND_SOC_DAPM_MUX("ADCB Mux", SND_SOC_NOPM,
+ 0, 0, &adcb_mux),
+
+ SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1),
+ SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1),
+
+ SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_OUTPUT("HPA"),
+ SND_SOC_DAPM_OUTPUT("LOA"),
+ SND_SOC_DAPM_OUTPUT("HPB"),
+ SND_SOC_DAPM_OUTPUT("LOB"),
+
+ SND_SOC_DAPM_SWITCH("Headphone Right",
+ CS42L56_PWRCTL_2, 4, 1, &hpb_switch),
+ SND_SOC_DAPM_SWITCH("Headphone Left",
+ CS42L56_PWRCTL_2, 6, 1, &hpa_switch),
+
+ SND_SOC_DAPM_SWITCH("Lineout Right",
+ CS42L56_PWRCTL_2, 0, 1, &lob_switch),
+ SND_SOC_DAPM_SWITCH("Lineout Left",
+ CS42L56_PWRCTL_2, 2, 1, &loa_switch),
+
+ SND_SOC_DAPM_MUX("LINEOUTA Input Mux", SND_SOC_NOPM,
+ 0, 0, &lineouta_input),
+ SND_SOC_DAPM_MUX("LINEOUTB Input Mux", SND_SOC_NOPM,
+ 0, 0, &lineoutb_input),
+ SND_SOC_DAPM_MUX("HPA Input Mux", SND_SOC_NOPM,
+ 0, 0, &hpa_input),
+ SND_SOC_DAPM_MUX("HPB Input Mux", SND_SOC_NOPM,
+ 0, 0, &hpb_input),
+
+};
+
+static const struct snd_soc_dapm_route cs42l56_audio_map[] = {
+
+ {"HiFi Capture", "DSP", "Digital Output Mux"},
+ {"HiFi Capture", "ADC", "Digital Output Mux"},
+
+ {"Digital Output Mux", NULL, "ADCA"},
+ {"Digital Output Mux", NULL, "ADCB"},
+
+ {"ADCB", NULL, "ADCB Mux"},
+ {"ADCA", NULL, "ADCA Mux"},
+
+ {"ADCA Mux", NULL, "AIN3A"},
+ {"ADCA Mux", NULL, "AIN2A"},
+ {"ADCA Mux", NULL, "AIN1A"},
+ {"ADCA Mux", NULL, "PGAA"},
+ {"ADCB Mux", NULL, "AIN3B"},
+ {"ADCB Mux", NULL, "AIN2B"},
+ {"ADCB Mux", NULL, "AIN1B"},
+ {"ADCB Mux", NULL, "PGAB"},
+
+ {"PGAA", "AIN1A", "PGAA Input Mux"},
+ {"PGAA", "AIN2A", "PGAA Input Mux"},
+ {"PGAA", "AIN3A", "PGAA Input Mux"},
+ {"PGAB", "AIN1B", "PGAB Input Mux"},
+ {"PGAB", "AIN2B", "PGAB Input Mux"},
+ {"PGAB", "AIN3B", "PGAB Input Mux"},
+
+ {"PGAA Input Mux", NULL, "AIN1A"},
+ {"PGAA Input Mux", NULL, "AIN2A"},
+ {"PGAA Input Mux", NULL, "AIN3A"},
+ {"PGAB Input Mux", NULL, "AIN1B"},
+ {"PGAB Input Mux", NULL, "AIN2B"},
+ {"PGAB Input Mux", NULL, "AIN3B"},
+
+ {"LOB", NULL, "Lineout Right"},
+ {"LOA", NULL, "Lineout Left"},
+
+ {"Lineout Right", "Switch", "LINEOUTB Input Mux"},
+ {"Lineout Left", "Switch", "LINEOUTA Input Mux"},
+
+ {"LINEOUTA Input Mux", "PGAA", "PGAA"},
+ {"LINEOUTB Input Mux", "PGAB", "PGAB"},
+ {"LINEOUTA Input Mux", "DACA", "DACA"},
+ {"LINEOUTB Input Mux", "DACB", "DACB"},
+
+ {"HPA", NULL, "Headphone Left"},
+ {"HPB", NULL, "Headphone Right"},
+
+ {"Headphone Right", "Switch", "HPB Input Mux"},
+ {"Headphone Left", "Switch", "HPA Input Mux"},
+
+ {"HPA Input Mux", "PGAA", "PGAA"},
+ {"HPB Input Mux", "PGAB", "PGAB"},
+ {"HPA Input Mux", "DACA", "DACA"},
+ {"HPB Input Mux", "DACB", "DACB"},
+
+ {"DACB", NULL, "HiFi Playback"},
+ {"DACA", NULL, "HiFi Playback"},
+
+};
+
+struct cs42l56_clk_para {
+ u32 mclk;
+ u32 srate;
+ u8 ratio;
+};
+
+static const struct cs42l56_clk_para clk_ratio_table[] = {
+ /* 8k */
+ { 6000000, 8000, CS42L56_MCLK_LRCLK_768 },
+ { 6144000, 8000, CS42L56_MCLK_LRCLK_750 },
+ { 12000000, 8000, CS42L56_MCLK_LRCLK_768 },
+ { 12288000, 8000, CS42L56_MCLK_LRCLK_750 },
+ { 24000000, 8000, CS42L56_MCLK_LRCLK_768 },
+ { 24576000, 8000, CS42L56_MCLK_LRCLK_750 },
+ /* 11.025k */
+ { 5644800, 11025, CS42L56_MCLK_LRCLK_512},
+ { 11289600, 11025, CS42L56_MCLK_LRCLK_512},
+ { 22579200, 11025, CS42L56_MCLK_LRCLK_512 },
+ /* 11.0294k */
+ { 6000000, 110294, CS42L56_MCLK_LRCLK_544 },
+ { 12000000, 110294, CS42L56_MCLK_LRCLK_544 },
+ { 24000000, 110294, CS42L56_MCLK_LRCLK_544 },
+ /* 12k */
+ { 6000000, 12000, CS42L56_MCLK_LRCLK_500 },
+ { 6144000, 12000, CS42L56_MCLK_LRCLK_512 },
+ { 12000000, 12000, CS42L56_MCLK_LRCLK_500 },
+ { 12288000, 12000, CS42L56_MCLK_LRCLK_512 },
+ { 24000000, 12000, CS42L56_MCLK_LRCLK_500 },
+ { 24576000, 12000, CS42L56_MCLK_LRCLK_512 },
+ /* 16k */
+ { 6000000, 16000, CS42L56_MCLK_LRCLK_375 },
+ { 6144000, 16000, CS42L56_MCLK_LRCLK_384 },
+ { 12000000, 16000, CS42L56_MCLK_LRCLK_375 },
+ { 12288000, 16000, CS42L56_MCLK_LRCLK_384 },
+ { 24000000, 16000, CS42L56_MCLK_LRCLK_375 },
+ { 24576000, 16000, CS42L56_MCLK_LRCLK_384 },
+ /* 22.050k */
+ { 5644800, 22050, CS42L56_MCLK_LRCLK_256 },
+ { 11289600, 22050, CS42L56_MCLK_LRCLK_256 },
+ { 22579200, 22050, CS42L56_MCLK_LRCLK_256 },
+ /* 22.0588k */
+ { 6000000, 220588, CS42L56_MCLK_LRCLK_272 },
+ { 12000000, 220588, CS42L56_MCLK_LRCLK_272 },
+ { 24000000, 220588, CS42L56_MCLK_LRCLK_272 },
+ /* 24k */
+ { 6000000, 24000, CS42L56_MCLK_LRCLK_250 },
+ { 6144000, 24000, CS42L56_MCLK_LRCLK_256 },
+ { 12000000, 24000, CS42L56_MCLK_LRCLK_250 },
+ { 12288000, 24000, CS42L56_MCLK_LRCLK_256 },
+ { 24000000, 24000, CS42L56_MCLK_LRCLK_250 },
+ { 24576000, 24000, CS42L56_MCLK_LRCLK_256 },
+ /* 32k */
+ { 6000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
+ { 6144000, 32000, CS42L56_MCLK_LRCLK_192 },
+ { 12000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
+ { 12288000, 32000, CS42L56_MCLK_LRCLK_192 },
+ { 24000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
+ { 24576000, 32000, CS42L56_MCLK_LRCLK_192 },
+ /* 44.118k */
+ { 6000000, 44118, CS42L56_MCLK_LRCLK_136 },
+ { 12000000, 44118, CS42L56_MCLK_LRCLK_136 },
+ { 24000000, 44118, CS42L56_MCLK_LRCLK_136 },
+ /* 44.1k */
+ { 5644800, 44100, CS42L56_MCLK_LRCLK_128 },
+ { 11289600, 44100, CS42L56_MCLK_LRCLK_128 },
+ { 22579200, 44100, CS42L56_MCLK_LRCLK_128 },
+ /* 48k */
+ { 6000000, 48000, CS42L56_MCLK_LRCLK_125 },
+ { 6144000, 48000, CS42L56_MCLK_LRCLK_128 },
+ { 12000000, 48000, CS42L56_MCLK_LRCLK_125 },
+ { 12288000, 48000, CS42L56_MCLK_LRCLK_128 },
+ { 24000000, 48000, CS42L56_MCLK_LRCLK_125 },
+ { 24576000, 48000, CS42L56_MCLK_LRCLK_128 },
+};
+
+static int cs42l56_get_mclk_ratio(int mclk, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clk_ratio_table); i++) {
+ if (clk_ratio_table[i].mclk == mclk &&
+ clk_ratio_table[i].srate == rate)
+ return clk_ratio_table[i].ratio;
+ }
+ return -EINVAL;
+}
+
+static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+
+ switch (freq) {
+ case CS42L56_MCLK_5P6448MHZ:
+ case CS42L56_MCLK_6MHZ:
+ case CS42L56_MCLK_6P144MHZ:
+ cs42l56->mclk_div2 = 0;
+ cs42l56->mclk_prediv = 0;
+ break;
+ case CS42L56_MCLK_11P2896MHZ:
+ case CS42L56_MCLK_12MHZ:
+ case CS42L56_MCLK_12P288MHZ:
+ cs42l56->mclk_div2 = 1;
+ cs42l56->mclk_prediv = 0;
+ break;
+ case CS42L56_MCLK_22P5792MHZ:
+ case CS42L56_MCLK_24MHZ:
+ case CS42L56_MCLK_24P576MHZ:
+ cs42l56->mclk_div2 = 1;
+ cs42l56->mclk_prediv = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ cs42l56->mclk = freq;
+
+ snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
+ CS42L56_MCLK_PREDIV_MASK,
+ cs42l56->mclk_prediv);
+ snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
+ CS42L56_MCLK_DIV2_MASK,
+ cs42l56->mclk_div2);
+
+ return 0;
+}
+
+static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ cs42l56->iface = CS42L56_MASTER_MODE;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ cs42l56->iface = CS42L56_SLAVE_MODE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ cs42l56->iface_fmt = CS42L56_DIG_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ cs42l56->iface_fmt = CS42L56_DIG_FMT_LEFT_J;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* sclk inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ cs42l56->iface_inv = 0;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ cs42l56->iface_inv = CS42L56_SCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
+ CS42L56_MS_MODE_MASK, cs42l56->iface);
+ snd_soc_update_bits(codec, CS42L56_SERIAL_FMT,
+ CS42L56_DIG_FMT_MASK, cs42l56->iface_fmt);
+ snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
+ CS42L56_SCLK_INV_MASK, cs42l56->iface_inv);
+ return 0;
+}
+
+static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ if (mute) {
+ /* Hit the DSP Mixer first */
+ snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL,
+ CS42L56_ADCAMIX_MUTE_MASK |
+ CS42L56_ADCBMIX_MUTE_MASK |
+ CS42L56_PCMAMIX_MUTE_MASK |
+ CS42L56_PCMBMIX_MUTE_MASK |
+ CS42L56_MSTB_MUTE_MASK |
+ CS42L56_MSTA_MUTE_MASK,
+ CS42L56_MUTE);
+ /* Mute ADC's */
+ snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL,
+ CS42L56_ADCA_MUTE_MASK |
+ CS42L56_ADCB_MUTE_MASK,
+ CS42L56_MUTE);
+ /* HP And LO */
+ snd_soc_update_bits(codec, CS42L56_HPA_VOLUME,
+ CS42L56_HP_MUTE_MASK,
+ CS42L56_MUTE);
+ snd_soc_update_bits(codec, CS42L56_HPB_VOLUME,
+ CS42L56_HP_MUTE_MASK,
+ CS42L56_MUTE);
+ snd_soc_update_bits(codec, CS42L56_LOA_VOLUME,
+ CS42L56_LO_MUTE_MASK,
+ CS42L56_MUTE);
+ snd_soc_update_bits(codec, CS42L56_LOB_VOLUME,
+ CS42L56_LO_MUTE_MASK,
+ CS42L56_MUTE);
+
+
+ } else {
+ snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL,
+ CS42L56_ADCAMIX_MUTE_MASK |
+ CS42L56_ADCBMIX_MUTE_MASK |
+ CS42L56_PCMAMIX_MUTE_MASK |
+ CS42L56_PCMBMIX_MUTE_MASK |
+ CS42L56_MSTB_MUTE_MASK |
+ CS42L56_MSTA_MUTE_MASK,
+ CS42L56_UNMUTE);
+ snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL,
+ CS42L56_ADCA_MUTE_MASK |
+ CS42L56_ADCB_MUTE_MASK,
+ CS42L56_UNMUTE);
+ snd_soc_update_bits(codec, CS42L56_HPA_VOLUME,
+ CS42L56_HP_MUTE_MASK,
+ CS42L56_UNMUTE);
+ snd_soc_update_bits(codec, CS42L56_HPB_VOLUME,
+ CS42L56_HP_MUTE_MASK,
+ CS42L56_UNMUTE);
+ snd_soc_update_bits(codec, CS42L56_LOA_VOLUME,
+ CS42L56_LO_MUTE_MASK,
+ CS42L56_UNMUTE);
+ snd_soc_update_bits(codec, CS42L56_LOB_VOLUME,
+ CS42L56_LO_MUTE_MASK,
+ CS42L56_UNMUTE);
+ }
+ return 0;
+}
+
+static int cs42l56_pcm_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 cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+ int ratio;
+
+ ratio = cs42l56_get_mclk_ratio(cs42l56->mclk, params_rate(params));
+ if (ratio >= 0) {
+ snd_soc_update_bits(codec, CS42L56_CLKCTL_2,
+ CS42L56_CLK_RATIO_MASK, ratio);
+ } else {
+ dev_err(codec->dev, "unsupported mclk/sclk/lrclk ratio\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
+ CS42L56_MCLK_DIS_MASK, 0);
+ snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
+ CS42L56_PDN_ALL_MASK, 0);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ regcache_cache_only(cs42l56->regmap, false);
+ regcache_sync(cs42l56->regmap);
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
+ cs42l56->supplies);
+ if (ret != 0) {
+ dev_err(cs42l56->dev,
+ "Failed to enable regulators: %d\n",
+ ret);
+ return ret;
+ }
+ }
+ snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
+ CS42L56_PDN_ALL_MASK, 1);
+ break;
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
+ CS42L56_PDN_ALL_MASK, 1);
+ snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
+ CS42L56_MCLK_DIS_MASK, 1);
+ regcache_cache_only(cs42l56->regmap, true);
+ regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
+ cs42l56->supplies);
+ break;
+ }
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+#define CS42L56_RATES (SNDRV_PCM_RATE_8000_48000)
+
+#define CS42L56_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static struct snd_soc_dai_ops cs42l56_ops = {
+ .hw_params = cs42l56_pcm_hw_params,
+ .digital_mute = cs42l56_digital_mute,
+ .set_fmt = cs42l56_set_dai_fmt,
+ .set_sysclk = cs42l56_set_sysclk,
+};
+
+static struct snd_soc_dai_driver cs42l56_dai = {
+ .name = "cs42l56",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = CS42L56_RATES,
+ .formats = CS42L56_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = CS42L56_RATES,
+ .formats = CS42L56_FORMATS,
+ },
+ .ops = &cs42l56_ops,
+};
+
+static int cs42l56_suspend(struct snd_soc_codec *codec)
+{
+ cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int cs42l56_resume(struct snd_soc_codec *codec)
+{
+ cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+
+static int beep_freq[] = {
+ 261, 522, 585, 667, 706, 774, 889, 1000,
+ 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
+};
+
+static void cs42l56_beep_work(struct work_struct *work)
+{
+ struct cs42l56_private *cs42l56 =
+ container_of(work, struct cs42l56_private, beep_work);
+ struct snd_soc_codec *codec = cs42l56->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int i;
+ int val = 0;
+ int best = 0;
+
+ if (cs42l56->beep_rate) {
+ for (i = 0; i < ARRAY_SIZE(beep_freq); i++) {
+ if (abs(cs42l56->beep_rate - beep_freq[i]) <
+ abs(cs42l56->beep_rate - beep_freq[best]))
+ best = i;
+ }
+
+ dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
+ beep_freq[best], cs42l56->beep_rate);
+
+ val = (best << CS42L56_BEEP_RATE_SHIFT);
+
+ snd_soc_dapm_enable_pin(dapm, "Beep");
+ } else {
+ dev_dbg(codec->dev, "Disabling beep\n");
+ snd_soc_dapm_disable_pin(dapm, "Beep");
+ }
+
+ snd_soc_update_bits(codec, CS42L56_BEEP_FREQ_ONTIME,
+ CS42L56_BEEP_FREQ_MASK, val);
+
+ snd_soc_dapm_sync(dapm);
+}
+
+/* For usability define a way of injecting beep events for the device -
+ * many systems will not have a keyboard.
+ */
+static int cs42l56_beep_event(struct input_dev *dev, unsigned int type,
+ unsigned int code, int hz)
+{
+ struct snd_soc_codec *codec = input_get_drvdata(dev);
+ struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
+
+ switch (code) {
+ case SND_BELL:
+ if (hz)
+ hz = 261;
+ case SND_TONE:
+ break;
+ default:
+ return -1;
+ }
+
+ /* Kick the beep from a workqueue */
+ cs42l56->beep_rate = hz;
+ schedule_work(&cs42l56->beep_work);
+ return 0;
+}
+
+static ssize_t cs42l56_beep_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cs42l56_private *cs42l56 = dev_get_drvdata(dev);
+ long int time;
+ int ret;
+
+ ret = kstrtol(buf, 10, &time);
+ if (ret != 0)
+ return ret;
+
+ input_event(cs42l56->beep, EV_SND, SND_TONE, time);
+
+ return count;
+}
+
+static DEVICE_ATTR(beep, 0200, NULL, cs42l56_beep_set);
+
+static void cs42l56_init_beep(struct snd_soc_codec *codec)
+{
+ struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ cs42l56->beep = devm_input_allocate_device(codec->dev);
+ if (!cs42l56->beep) {
+ dev_err(codec->dev, "Failed to allocate beep device\n");
+ return;
+ }
+
+ INIT_WORK(&cs42l56->beep_work, cs42l56_beep_work);
+ cs42l56->beep_rate = 0;
+
+ cs42l56->beep->name = "CS42L56 Beep Generator";
+ cs42l56->beep->phys = dev_name(codec->dev);
+ cs42l56->beep->id.bustype = BUS_I2C;
+
+ cs42l56->beep->evbit[0] = BIT_MASK(EV_SND);
+ cs42l56->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+ cs42l56->beep->event = cs42l56_beep_event;
+ cs42l56->beep->dev.parent = codec->dev;
+ input_set_drvdata(cs42l56->beep, codec);
+
+ ret = input_register_device(cs42l56->beep);
+ if (ret != 0) {
+ cs42l56->beep = NULL;
+ dev_err(codec->dev, "Failed to register beep device\n");
+ }
+
+ ret = device_create_file(codec->dev, &dev_attr_beep);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to create keyclick file: %d\n",
+ ret);
+ }
+}
+
+static void cs42l56_free_beep(struct snd_soc_codec *codec)
+{
+ struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+
+ device_remove_file(codec->dev, &dev_attr_beep);
+ cancel_work_sync(&cs42l56->beep_work);
+ cs42l56->beep = NULL;
+
+ snd_soc_update_bits(codec, CS42L56_BEEP_TONE_CFG,
+ CS42L56_BEEP_EN_MASK, 0);
+}
+
+static int cs42l56_probe(struct snd_soc_codec *codec)
+{
+ cs42l56_init_beep(codec);
+
+ cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+
+static int cs42l56_remove(struct snd_soc_codec *codec)
+{
+ struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
+
+ cs42l56_free_beep(codec);
+ cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ regulator_bulk_free(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
+ .probe = cs42l56_probe,
+ .remove = cs42l56_remove,
+ .suspend = cs42l56_suspend,
+ .resume = cs42l56_resume,
+ .set_bias_level = cs42l56_set_bias_level,
+
+ .dapm_widgets = cs42l56_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets),
+ .dapm_routes = cs42l56_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(cs42l56_audio_map),
+
+ .controls = cs42l56_snd_controls,
+ .num_controls = ARRAY_SIZE(cs42l56_snd_controls),
+};
+
+static struct regmap_config cs42l56_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = CS42L56_MAX_REGISTER,
+ .reg_defaults = cs42l56_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults),
+ .readable_reg = cs42l56_readable_register,
+ .volatile_reg = cs42l56_volatile_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int cs42l56_handle_of_data(struct i2c_client *i2c_client,
+ struct cs42l56_platform_data *pdata)
+{
+ struct device_node *np = i2c_client->dev.of_node;
+ u32 val32;
+
+ if (of_property_read_bool(np, "cirrus,ain1a-reference-cfg"))
+ pdata->ain1a_ref_cfg = true;
+
+ if (of_property_read_bool(np, "cirrus,ain2a-reference-cfg"))
+ pdata->ain2a_ref_cfg = true;
+
+ if (of_property_read_bool(np, "cirrus,ain1b-reference-cfg"))
+ pdata->ain1b_ref_cfg = true;
+
+ if (of_property_read_bool(np, "cirrus,ain2b-reference-cfg"))
+ pdata->ain2b_ref_cfg = true;
+
+ if (of_property_read_u32(np, "cirrus,micbias-lvl", &val32) >= 0)
+ pdata->micbias_lvl = val32;
+
+ if (of_property_read_u32(np, "cirrus,chgfreq-divisor", &val32) >= 0)
+ pdata->chgfreq = val32;
+
+ if (of_property_read_u32(np, "cirrus,adaptive-pwr-cfg", &val32) >= 0)
+ pdata->adaptive_pwr = val32;
+
+ if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
+ pdata->hpfa_freq = val32;
+
+ if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
+ pdata->hpfb_freq = val32;
+
+ pdata->gpio_nreset = of_get_named_gpio(np, "cirrus,gpio-nreset", 0);
+
+ return 0;
+}
+
+static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct cs42l56_private *cs42l56;
+ struct cs42l56_platform_data *pdata =
+ dev_get_platdata(&i2c_client->dev);
+ int ret, i;
+ unsigned int devid = 0;
+ unsigned int alpha_rev, metal_rev;
+ unsigned int reg;
+
+ cs42l56 = devm_kzalloc(&i2c_client->dev,
+ sizeof(struct cs42l56_private),
+ GFP_KERNEL);
+ if (cs42l56 == NULL)
+ return -ENOMEM;
+ cs42l56->dev = &i2c_client->dev;
+
+ cs42l56->regmap = devm_regmap_init_i2c(i2c_client, &cs42l56_regmap);
+ if (IS_ERR(cs42l56->regmap)) {
+ ret = PTR_ERR(cs42l56->regmap);
+ dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ if (pdata) {
+ cs42l56->pdata = *pdata;
+ } else {
+ pdata = devm_kzalloc(&i2c_client->dev,
+ sizeof(struct cs42l56_platform_data),
+ GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&i2c_client->dev,
+ "could not allocate pdata\n");
+ return -ENOMEM;
+ }
+ if (i2c_client->dev.of_node) {
+ ret = cs42l56_handle_of_data(i2c_client,
+ &cs42l56->pdata);
+ if (ret != 0)
+ return ret;
+ }
+ cs42l56->pdata = *pdata;
+ }
+
+ if (cs42l56->pdata.gpio_nreset) {
+ ret = gpio_request_one(cs42l56->pdata.gpio_nreset,
+ GPIOF_OUT_INIT_HIGH, "CS42L56 /RST");
+ if (ret < 0) {
+ dev_err(&i2c_client->dev,
+ "Failed to request /RST %d: %d\n",
+ cs42l56->pdata.gpio_nreset, ret);
+ return ret;
+ }
+ gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 0);
+ gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 1);
+ }
+
+
+ i2c_set_clientdata(i2c_client, cs42l56);
+
+ for (i = 0; i < ARRAY_SIZE(cs42l56->supplies); i++)
+ cs42l56->supplies[i].supply = cs42l56_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c_client->dev,
+ ARRAY_SIZE(cs42l56->supplies),
+ cs42l56->supplies);
+ if (ret != 0) {
+ dev_err(&i2c_client->dev,
+ "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
+ cs42l56->supplies);
+ if (ret != 0) {
+ dev_err(&i2c_client->dev,
+ "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ regcache_cache_bypass(cs42l56->regmap, true);
+
+ ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, &reg);
+ devid = reg & CS42L56_CHIP_ID_MASK;
+ if (devid != CS42L56_DEVID) {
+ dev_err(&i2c_client->dev,
+ "CS42L56 Device ID (%X). Expected %X\n",
+ devid, CS42L56_DEVID);
+ goto err_enable;
+ }
+ alpha_rev = reg & CS42L56_AREV_MASK;
+ metal_rev = reg & CS42L56_MTLREV_MASK;
+
+ dev_info(&i2c_client->dev, "Cirrus Logic CS42L56 ");
+ dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n",
+ alpha_rev, metal_rev);
+
+ regcache_cache_bypass(cs42l56->regmap, false);
+
+ if (cs42l56->pdata.ain1a_ref_cfg)
+ regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
+ CS42L56_AIN1A_REF_MASK, 1);
+
+ if (cs42l56->pdata.ain1b_ref_cfg)
+ regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
+ CS42L56_AIN1B_REF_MASK, 1);
+
+ if (cs42l56->pdata.ain2a_ref_cfg)
+ regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
+ CS42L56_AIN2A_REF_MASK, 1);
+
+ if (cs42l56->pdata.ain2b_ref_cfg)
+ regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
+ CS42L56_AIN2B_REF_MASK, 1);
+
+ if (cs42l56->pdata.micbias_lvl)
+ regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL,
+ CS42L56_MIC_BIAS_MASK,
+ cs42l56->pdata.micbias_lvl);
+
+ if (cs42l56->pdata.chgfreq)
+ regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
+ CS42L56_CHRG_FREQ_MASK,
+ cs42l56->pdata.chgfreq);
+
+ if (cs42l56->pdata.hpfb_freq)
+ regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
+ CS42L56_HPFB_FREQ_MASK,
+ cs42l56->pdata.hpfb_freq);
+
+ if (cs42l56->pdata.hpfa_freq)
+ regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
+ CS42L56_HPFA_FREQ_MASK,
+ cs42l56->pdata.hpfa_freq);
+
+ if (cs42l56->pdata.adaptive_pwr)
+ regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
+ CS42L56_ADAPT_PWR_MASK,
+ cs42l56->pdata.adaptive_pwr);
+
+ ret = snd_soc_register_codec(&i2c_client->dev,
+ &soc_codec_dev_cs42l56, &cs42l56_dai, 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
+ cs42l56->supplies);
+ return ret;
+}
+
+static int cs42l56_i2c_remove(struct i2c_client *client)
+{
+ struct cs42l56_private *cs42l56 = i2c_get_clientdata(client);
+
+ snd_soc_unregister_codec(&client->dev);
+ regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
+ cs42l56->supplies);
+ return 0;
+}
+
+static const struct of_device_id cs42l56_of_match[] = {
+ { .compatible = "cirrus,cs42l56", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cs42l56_of_match);
+
+
+static const struct i2c_device_id cs42l56_id[] = {
+ { "cs42l56", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cs42l56_id);
+
+static struct i2c_driver cs42l56_i2c_driver = {
+ .driver = {
+ .name = "cs42l56",
+ .owner = THIS_MODULE,
+ .of_match_table = cs42l56_of_match,
+ },
+ .id_table = cs42l56_id,
+ .probe = cs42l56_i2c_probe,
+ .remove = cs42l56_i2c_remove,
+};
+
+module_i2c_driver(cs42l56_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L56 driver");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l56.h b/sound/soc/codecs/cs42l56.h
new file mode 100644
index 000000000000..ad2b50a90b16
--- /dev/null
+++ b/sound/soc/codecs/cs42l56.h
@@ -0,0 +1,175 @@
+/*
+ * cs42l52.h -- CS42L56 ALSA SoC audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.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 __CS42L56_H__
+#define __CS42L56_H__
+
+#define CS42L56_CHIP_ID_1 0x01
+#define CS42L56_CHIP_ID_2 0x02
+#define CS42L56_PWRCTL_1 0x03
+#define CS42L56_PWRCTL_2 0x04
+#define CS42L56_CLKCTL_1 0x05
+#define CS42L56_CLKCTL_2 0x06
+#define CS42L56_SERIAL_FMT 0x07
+#define CS42L56_CLASSH_CTL 0x08
+#define CS42L56_MISC_CTL 0x09
+#define CS42L56_INT_STATUS 0x0a
+#define CS42L56_PLAYBACK_CTL 0x0b
+#define CS42L56_DSP_MUTE_CTL 0x0c
+#define CS42L56_ADCA_MIX_VOLUME 0x0d
+#define CS42L56_ADCB_MIX_VOLUME 0x0e
+#define CS42L56_PCMA_MIX_VOLUME 0x0f
+#define CS42L56_PCMB_MIX_VOLUME 0x10
+#define CS42L56_ANAINPUT_ADV_VOLUME 0x11
+#define CS42L56_DIGINPUT_ADV_VOLUME 0x12
+#define CS42L56_MASTER_A_VOLUME 0x13
+#define CS42L56_MASTER_B_VOLUME 0x14
+#define CS42L56_BEEP_FREQ_ONTIME 0x15
+#define CS42L56_BEEP_FREQ_OFFTIME 0x16
+#define CS42L56_BEEP_TONE_CFG 0x17
+#define CS42L56_TONE_CTL 0x18
+#define CS42L56_CHAN_MIX_SWAP 0x19
+#define CS42L56_AIN_REFCFG_ADC_MUX 0x1a
+#define CS42L56_HPF_CTL 0x1b
+#define CS42L56_MISC_ADC_CTL 0x1c
+#define CS42L56_GAIN_BIAS_CTL 0x1d
+#define CS42L56_PGAA_MUX_VOLUME 0x1e
+#define CS42L56_PGAB_MUX_VOLUME 0x1f
+#define CS42L56_ADCA_ATTENUATOR 0x20
+#define CS42L56_ADCB_ATTENUATOR 0x21
+#define CS42L56_ALC_EN_ATTACK_RATE 0x22
+#define CS42L56_ALC_RELEASE_RATE 0x23
+#define CS42L56_ALC_THRESHOLD 0x24
+#define CS42L56_NOISE_GATE_CTL 0x25
+#define CS42L56_ALC_LIM_SFT_ZC 0x26
+#define CS42L56_AMUTE_HPLO_MUX 0x27
+#define CS42L56_HPA_VOLUME 0x28
+#define CS42L56_HPB_VOLUME 0x29
+#define CS42L56_LOA_VOLUME 0x2a
+#define CS42L56_LOB_VOLUME 0x2b
+#define CS42L56_LIM_THRESHOLD_CTL 0x2c
+#define CS42L56_LIM_CTL_RELEASE_RATE 0x2d
+#define CS42L56_LIM_ATTACK_RATE 0x2e
+
+/* Device ID and Rev ID Masks */
+#define CS42L56_DEVID 0x56
+#define CS42L56_CHIP_ID_MASK 0xff
+#define CS42L56_AREV_MASK 0x1c
+#define CS42L56_MTLREV_MASK 0x03
+
+/* Power bit masks */
+#define CS42L56_PDN_ALL_MASK 0x01
+#define CS42L56_PDN_ADCA_MASK 0x02
+#define CS42L56_PDN_ADCB_MASK 0x04
+#define CS42L56_PDN_CHRG_MASK 0x08
+#define CS42L56_PDN_BIAS_MASK 0x10
+#define CS42L56_PDN_VBUF_MASK 0x20
+#define CS42L56_PDN_LOA_MASK 0x03
+#define CS42L56_PDN_LOB_MASK 0x0c
+#define CS42L56_PDN_HPA_MASK 0x30
+#define CS42L56_PDN_HPB_MASK 0xc0
+
+/* serial port and clk masks */
+#define CS42L56_MASTER_MODE 1
+#define CS42L56_SLAVE_MODE 0
+#define CS42L56_MS_MODE_MASK 0x40
+#define CS42L56_SCLK_INV 1
+#define CS42L56_SCLK_INV_MASK 0x20
+#define CS42L56_SCLK_MCLK_MASK 0x18
+#define CS42L56_MCLK_PREDIV_MASK 0x04
+#define CS42L56_MCLK_DIV2_MASK 0x02
+#define CS42L56_MCLK_DIS_MASK 0x01
+#define CS42L56_CLK_AUTO_MASK 0x20
+#define CS42L56_CLK_RATIO_MASK 0x1f
+#define CS42L56_DIG_FMT_I2S 0
+#define CS42L56_DIG_FMT_LEFT_J 1
+#define CS42L56_DIG_FMT_MASK 0x08
+
+/* Class H and misc ctl masks */
+#define CS42L56_ADAPT_PWR_MASK 0xc0
+#define CS42L56_CHRG_FREQ_MASK 0x0f
+#define CS42L56_DIG_MUX_MASK 0x80
+#define CS42L56_ANLGSFT_MASK 0x10
+#define CS42L56_ANLGZC_MASK 0x08
+#define CS42L56_DIGSFT_MASK 0x04
+#define CS42L56_FREEZE_MASK 0x01
+#define CS42L56_MIC_BIAS_MASK 0x03
+#define CS42L56_HPFA_FREQ_MASK 0x03
+#define CS42L56_HPFB_FREQ_MASK 0xc0
+#define CS42L56_AIN1A_REF_MASK 0x10
+#define CS42L56_AIN2A_REF_MASK 0x40
+#define CS42L56_AIN1B_REF_MASK 0x20
+#define CS42L56_AIN2B_REF_MASK 0x80
+
+/* Playback Capture ctl masks */
+#define CS42L56_PDN_DSP_MASK 0x80
+#define CS42L56_DEEMPH_MASK 0x40
+#define CS42L56_PLYBCK_GANG_MASK 0x10
+#define CS42L56_PCM_INV_MASK 0x0c
+#define CS42L56_MUTE 1
+#define CS42L56_UNMUTE 0
+#define CS42L56_ADCAMIX_MUTE_MASK 0x40
+#define CS42L56_ADCBMIX_MUTE_MASK 0x80
+#define CS42L56_PCMAMIX_MUTE_MASK 0x10
+#define CS42L56_PCMBMIX_MUTE_MASK 0x20
+#define CS42L56_MSTB_MUTE_MASK 0x02
+#define CS42L56_MSTA_MUTE_MASK 0x01
+#define CS42L56_ADCA_MUTE_MASK 0x01
+#define CS42L56_ADCB_MUTE_MASK 0x02
+#define CS42L56_HP_MUTE_MASK 0x80
+#define CS42L56_LO_MUTE_MASK 0x80
+
+/* Beep masks */
+#define CS42L56_BEEP_FREQ_MASK 0xf0
+#define CS42L56_BEEP_ONTIME_MASK 0x0f
+#define CS42L56_BEEP_OFFTIME_MASK 0xe0
+#define CS42L56_BEEP_CFG_MASK 0xc0
+#define CS42L56_BEEP_TREBCF_MASK 0x18
+#define CS42L56_BEEP_BASSCF_MASK 0x06
+#define CS42L56_BEEP_TCEN_MASK 0x01
+#define CS42L56_BEEP_RATE_SHIFT 4
+#define CS42L56_BEEP_EN_MASK 0x3f
+
+
+/* Supported MCLKS */
+#define CS42L56_MCLK_5P6448MHZ 5644800
+#define CS42L56_MCLK_6MHZ 6000000
+#define CS42L56_MCLK_6P144MHZ 6144000
+#define CS42L56_MCLK_11P2896MHZ 11289600
+#define CS42L56_MCLK_12MHZ 12000000
+#define CS42L56_MCLK_12P288MHZ 12288000
+#define CS42L56_MCLK_22P5792MHZ 22579200
+#define CS42L56_MCLK_24MHZ 24000000
+#define CS42L56_MCLK_24P576MHZ 24576000
+
+/* Clock ratios */
+#define CS42L56_MCLK_LRCLK_128 0x08
+#define CS42L56_MCLK_LRCLK_125 0x09
+#define CS42L56_MCLK_LRCLK_136 0x0b
+#define CS42L56_MCLK_LRCLK_192 0x0c
+#define CS42L56_MCLK_LRCLK_187P5 0x0d
+#define CS42L56_MCLK_LRCLK_256 0x10
+#define CS42L56_MCLK_LRCLK_250 0x11
+#define CS42L56_MCLK_LRCLK_272 0x13
+#define CS42L56_MCLK_LRCLK_384 0x14
+#define CS42L56_MCLK_LRCLK_375 0x15
+#define CS42L56_MCLK_LRCLK_512 0x18
+#define CS42L56_MCLK_LRCLK_500 0x19
+#define CS42L56_MCLK_LRCLK_544 0x1b
+#define CS42L56_MCLK_LRCLK_750 0x1c
+#define CS42L56_MCLK_LRCLK_768 0x1d
+
+
+#define CS42L56_MAX_REGISTER 0x34
+
+#endif
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 0ee60a19a263..ae3717992d56 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -1443,8 +1443,10 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
i2c_set_clientdata(i2c_client, cs42l73);
if (cs42l73->pdata.reset_gpio) {
- ret = gpio_request_one(cs42l73->pdata.reset_gpio,
- GPIOF_OUT_INIT_HIGH, "CS42L73 /RST");
+ ret = devm_gpio_request_one(&i2c_client->dev,
+ cs42l73->pdata.reset_gpio,
+ GPIOF_OUT_INIT_HIGH,
+ "CS42L73 /RST");
if (ret < 0) {
dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
cs42l73->pdata.reset_gpio, ret);
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
index 85020322eee7..a25bc6061a30 100644
--- a/sound/soc/codecs/cs42xx8.c
+++ b/sound/soc/codecs/cs42xx8.c
@@ -248,8 +248,7 @@ static int cs42xx8_hw_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 snd_soc_codec *codec = dai->codec;
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
u32 ratio = cs42xx8->sysclk / params_rate(params);
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 137e8ebc092c..21810e5f3321 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -335,7 +335,7 @@ static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel,
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);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
if (ucontrol->value.integer.value[0]) {
/* Check if noise suppression is enabled */
@@ -358,7 +358,7 @@ static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
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);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
u8 val;
if (ucontrol->value.integer.value[0]) {
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 738fa18a50d2..9ec577f0edb4 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -345,7 +345,7 @@ static void da7213_alc_calib(struct snd_soc_codec *codec)
static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
int ret;
@@ -361,7 +361,7 @@ static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol,
static int da7213_put_alc_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
/* Force ALC offset calibration if enabling ALC */
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index 48f3fef68484..2fae31cb0067 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -332,7 +332,7 @@ static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum,
static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
unsigned int reg = enum_ctrl->reg;
unsigned int sel = ucontrol->value.integer.value[0];
@@ -360,7 +360,7 @@ static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
static int da732x_hpf_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
unsigned int reg = enum_ctrl->reg;
int val;
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index 4ff06b50fbba..ad19cc56702b 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -484,7 +484,7 @@ static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)
static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
u8 reg_val, adc_left, adc_right, mic_left, mic_right;
int avg_left_data, avg_right_data, offset_l, offset_r;
diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c
index 9cb1c7d3e1dc..1087fd5f9917 100644
--- a/sound/soc/codecs/hdmi.c
+++ b/sound/soc/codecs/hdmi.c
@@ -20,6 +20,7 @@
*/
#include <linux/module.h>
#include <sound/soc.h>
+#include <linux/of.h>
#include <linux/of_device.h>
#define DRV_NAME "hdmi-audio-codec"
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
index 4f048db9f55f..a924bb9d7886 100644
--- a/sound/soc/codecs/lm4857.c
+++ b/sound/soc/codecs/lm4857.c
@@ -49,7 +49,7 @@ static const struct reg_default lm4857_default_regs[] = {
static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = lm4857->mode;
@@ -60,7 +60,7 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
uint8_t value = ucontrol->value.integer.value[0];
diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c
index ec481fc428c7..e1c196a41930 100644
--- a/sound/soc/codecs/max9768.c
+++ b/sound/soc/codecs/max9768.c
@@ -43,7 +43,7 @@ static struct reg_default max9768_default_regs[] = {
static int max9768_get_gpio(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
int val = gpio_get_value_cansleep(max9768->mute_gpio);
@@ -55,7 +55,7 @@ static int max9768_get_gpio(struct snd_kcontrol *kcontrol,
static int max9768_set_gpio(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]);
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index ef7cf89f5623..9134982807b5 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -635,7 +635,7 @@ static SOC_ENUM_SINGLE_DECL(max98088_dai1_adc_filter_enum,
static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
unsigned int sel = ucontrol->value.integer.value[0];
@@ -649,7 +649,7 @@ static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = max98088->mic1pre;
@@ -659,7 +659,7 @@ static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
unsigned int sel = ucontrol->value.integer.value[0];
@@ -673,7 +673,7 @@ static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = max98088->mic2pre;
@@ -1750,7 +1750,7 @@ static void max98088_setup_eq2(struct snd_soc_codec *codec)
static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
struct max98088_pdata *pdata = max98088->pdata;
int channel = max98088_get_channel(codec, kcontrol->id.name);
@@ -1782,7 +1782,7 @@ static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
int channel = max98088_get_channel(codec, kcontrol->id.name);
struct max98088_cdata *cdata;
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index f7b0b37aa858..9b76f5a45115 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -11,10 +11,12 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/acpi.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -255,6 +257,7 @@ static struct reg_default max98090_reg[] = {
static bool max98090_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case M98090_REG_SOFTWARE_RESET:
case M98090_REG_DEVICE_STATUS:
case M98090_REG_JACK_STATUS:
case M98090_REG_REVISION_ID:
@@ -389,6 +392,7 @@ static const DECLARE_TLV_DB_SCALE(max98090_alc_tlv, -1500, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98090_alcmakeup_tlv, 0, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98090_alccomp_tlv, -3100, 100, 0);
static const DECLARE_TLV_DB_SCALE(max98090_drcexp_tlv, -6600, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98090_sdg_tlv, 50, 200, 0);
static const unsigned int max98090_mixout_tlv[] = {
TLV_DB_RANGE_HEAD(2),
@@ -426,7 +430,7 @@ static const unsigned int max98090_rcv_lout_tlv[] = {
static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -466,7 +470,7 @@ static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -665,7 +669,7 @@ static const struct snd_kcontrol_new max98090_snd_controls[] = {
SOC_SINGLE_EXT_TLV("Digital Sidetone Volume",
M98090_REG_ADC_SIDETONE, M98090_DVST_SHIFT,
M98090_DVST_NUM - 1, 1, max98090_get_enab_tlv,
- max98090_put_enab_tlv, max98090_micboost_tlv),
+ max98090_put_enab_tlv, max98090_sdg_tlv),
SOC_SINGLE_TLV("Digital Coarse Volume", M98090_REG_DAI_PLAYBACK_LEVEL,
M98090_DVG_SHIFT, M98090_DVG_NUM - 1, 0,
max98090_dvg_tlv),
@@ -875,7 +879,7 @@ static const char *dmic_mux_text[] = { "ADC", "DMIC" };
static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text);
static const struct snd_kcontrol_new max98090_dmic_mux =
- SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum);
+ SOC_DAPM_ENUM("DMIC Mux", dmic_mux_enum);
static const char *max98090_micpre_text[] = { "Off", "On" };
@@ -1175,8 +1179,7 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
SND_SOC_DAPM_MUX("MIC2 Mux", SND_SOC_NOPM,
0, 0, &max98090_mic2_mux),
- SND_SOC_DAPM_VIRT_MUX("DMIC Mux", SND_SOC_NOPM,
- 0, 0, &max98090_dmic_mux),
+ SND_SOC_DAPM_MUX("DMIC Mux", SND_SOC_NOPM, 0, 0, &max98090_dmic_mux),
SND_SOC_DAPM_PGA_E("MIC1 Input", M98090_REG_MIC1_INPUT_LEVEL,
M98090_MIC_PA1EN_SHIFT, 0, NULL, 0, max98090_micinput_event,
@@ -1673,6 +1676,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
M98090_REG_CLOCK_RATIO_NI_LSB, 0x00);
snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
M98090_USE_M1_MASK, 0);
+ max98090->master = false;
break;
case SND_SOC_DAIFMT_CBM_CFM:
/* Set to master mode */
@@ -1689,6 +1693,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
regval |= M98090_MAS_MASK |
M98090_BSEL_32;
}
+ max98090->master = true;
break;
case SND_SOC_DAIFMT_CBS_CFM:
case SND_SOC_DAIFMT_CBM_CFS:
@@ -1792,13 +1797,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
- if (max98090->jack_state == M98090_JACK_STATE_HEADSET) {
- /*
- * Set to normal bias level.
- */
- snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
- M98090_MBVSEL_MASK, M98090_MBVSEL_2V8);
- }
break;
case SND_SOC_BIAS_PREPARE:
@@ -1872,7 +1870,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- max98090_configure_bclk(codec);
+ if (max98090->master)
+ max98090_configure_bclk(codec);
cdata->rate = max98090->lrclk;
@@ -1951,8 +1950,6 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
max98090->sysclk = freq;
- max98090_configure_bclk(codec);
-
return 0;
}
@@ -2224,6 +2221,7 @@ static int max98090_probe(struct snd_soc_codec *codec)
/* Initialize private data */
max98090->sysclk = (unsigned)-1;
+ max98090->master = false;
cdata = &max98090->dai[0];
cdata->rate = (unsigned)-1;
@@ -2293,6 +2291,9 @@ static int max98090_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, M98090_REG_BIAS_CONTROL,
M98090_VCM_MODE_MASK);
+ snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
+ M98090_MBVSEL_MASK, M98090_MBVSEL_2V8);
+
max98090_handle_pdata(codec);
max98090_add_widgets(codec);
@@ -2329,9 +2330,11 @@ static const struct regmap_config max98090_regmap = {
};
static int max98090_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *i2c_id)
{
struct max98090_priv *max98090;
+ const struct acpi_device_id *acpi_id;
+ kernel_ulong_t driver_data = 0;
int ret;
pr_debug("max98090_i2c_probe\n");
@@ -2341,7 +2344,19 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
if (max98090 == NULL)
return -ENOMEM;
- max98090->devtype = id->driver_data;
+ if (ACPI_HANDLE(&i2c->dev)) {
+ acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table,
+ &i2c->dev);
+ if (!acpi_id) {
+ dev_err(&i2c->dev, "No driver data\n");
+ return -EINVAL;
+ }
+ driver_data = acpi_id->driver_data;
+ } else if (i2c_id) {
+ driver_data = i2c_id->driver_data;
+ }
+
+ max98090->devtype = driver_data;
i2c_set_clientdata(i2c, max98090);
max98090->pdata = i2c->dev.platform_data;
max98090->irq = i2c->irq;
@@ -2373,6 +2388,8 @@ static int max98090_runtime_resume(struct device *dev)
regcache_cache_only(max98090->regmap, false);
+ max98090_reset(max98090);
+
regcache_sync(max98090->regmap);
return 0;
@@ -2388,9 +2405,34 @@ static int max98090_runtime_suspend(struct device *dev)
}
#endif
+#ifdef CONFIG_PM
+static int max98090_resume(struct device *dev)
+{
+ struct max98090_priv *max98090 = dev_get_drvdata(dev);
+ unsigned int status;
+
+ regcache_mark_dirty(max98090->regmap);
+
+ max98090_reset(max98090);
+
+ /* clear IRQ status */
+ regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status);
+
+ regcache_sync(max98090->regmap);
+
+ return 0;
+}
+
+static int max98090_suspend(struct device *dev)
+{
+ return 0;
+}
+#endif
+
static const struct dev_pm_ops max98090_pm = {
SET_RUNTIME_PM_OPS(max98090_runtime_suspend,
max98090_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(max98090_suspend, max98090_resume)
};
static const struct i2c_device_id max98090_i2c_id[] = {
@@ -2405,12 +2447,21 @@ static const struct of_device_id max98090_of_match[] = {
};
MODULE_DEVICE_TABLE(of, max98090_of_match);
+#ifdef CONFIG_ACPI
+static struct acpi_device_id max98090_acpi_match[] = {
+ { "193C9890", MAX98090 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, max98090_acpi_match);
+#endif
+
static struct i2c_driver max98090_i2c_driver = {
.driver = {
.name = "max98090",
.owner = THIS_MODULE,
.pm = &max98090_pm,
.of_match_table = of_match_ptr(max98090_of_match),
+ .acpi_match_table = ACPI_PTR(max98090_acpi_match),
},
.probe = max98090_i2c_probe,
.remove = max98090_i2c_remove,
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
index 1a4e2334a7b2..5a3c8d0613cb 100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
@@ -1540,6 +1540,7 @@ struct max98090_priv {
unsigned int pa2en;
unsigned int extmic_mux;
unsigned int sidetone;
+ bool master;
};
int max98090_mic_detect(struct snd_soc_codec *codec,
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 03f0536e6f61..d6c1e4c19a5a 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -612,7 +612,7 @@ static SOC_ENUM_SINGLE_DECL(max98095_dai3_dac_filter_enum,
static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
unsigned int sel = ucontrol->value.integer.value[0];
@@ -626,7 +626,7 @@ static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = max98095->mic1pre;
@@ -636,7 +636,7 @@ static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,
static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
unsigned int sel = ucontrol->value.integer.value[0];
@@ -650,7 +650,7 @@ static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,
static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = max98095->mic2pre;
@@ -1737,7 +1737,7 @@ static int max98095_get_eq_channel(const char *name)
static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
struct max98095_pdata *pdata = max98095->pdata;
int channel = max98095_get_eq_channel(kcontrol->id.name);
@@ -1801,7 +1801,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
int channel = max98095_get_eq_channel(kcontrol->id.name);
struct max98095_cdata *cdata;
@@ -1891,7 +1891,7 @@ static int max98095_get_bq_channel(struct snd_soc_codec *codec,
static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
struct max98095_pdata *pdata = max98095->pdata;
int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
@@ -1952,7 +1952,7 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
struct max98095_cdata *cdata;
@@ -2399,10 +2399,17 @@ static const struct i2c_device_id max98095_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max98095_i2c_id);
+static const struct of_device_id max98095_of_match[] = {
+ { .compatible = "maxim,max98095", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max98095_of_match);
+
static struct i2c_driver max98095_i2c_driver = {
.driver = {
.name = "max98095",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(max98095_of_match),
},
.probe = max98095_i2c_probe,
.remove = max98095_i2c_remove,
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 2c59b1fb69dc..9965277b595a 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -22,6 +22,7 @@
*/
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/of.h>
#include <linux/mfd/mc13xxx.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -409,7 +410,7 @@ static const char * const adcl_enum_text[] = {
static SOC_ENUM_SINGLE_VIRT_DECL(adcl_enum, adcl_enum_text);
static const struct snd_kcontrol_new left_input_mux =
- SOC_DAPM_ENUM_VIRT("Route", adcl_enum);
+ SOC_DAPM_ENUM("Route", adcl_enum);
static const char * const adcr_enum_text[] = {
"MC1R", "MC2", "RXINR", "TXIN",
@@ -418,7 +419,7 @@ static const char * const adcr_enum_text[] = {
static SOC_ENUM_SINGLE_VIRT_DECL(adcr_enum, adcr_enum_text);
static const struct snd_kcontrol_new right_input_mux =
- SOC_DAPM_ENUM_VIRT("Route", adcr_enum);
+ SOC_DAPM_ENUM("Route", adcr_enum);
static const struct snd_kcontrol_new samp_ctl =
SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0);
@@ -478,9 +479,9 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
SND_SOC_DAPM_SWITCH("MC2 Amp", MC13783_AUDIO_TX, 9, 0, &mc2_amp_ctl),
SND_SOC_DAPM_SWITCH("TXIN Amp", MC13783_AUDIO_TX, 11, 0, &atx_amp_ctl),
- SND_SOC_DAPM_VIRT_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,
+ SND_SOC_DAPM_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,
&left_input_mux),
- SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,
+ SND_SOC_DAPM_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,
&right_input_mux),
SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0,
@@ -608,14 +609,6 @@ static struct snd_kcontrol_new mc13783_control_list[] = {
static int mc13783_probe(struct snd_soc_codec *codec)
{
struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- ret = snd_soc_codec_set_cache_io(codec,
- dev_get_regmap(codec->dev->parent, NULL));
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
/* these are the reset values */
mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);
@@ -735,9 +728,15 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = {
}
};
+static struct regmap *mc13783_get_regmap(struct device *dev)
+{
+ return dev_get_regmap(dev->parent, NULL);
+}
+
static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
.probe = mc13783_probe,
.remove = mc13783_remove,
+ .get_regmap = mc13783_get_regmap,
.controls = mc13783_control_list,
.num_controls = ARRAY_SIZE(mc13783_control_list),
.dapm_widgets = mc13783_dapm_widgets,
@@ -750,6 +749,7 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
{
struct mc13783_priv *priv;
struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
+ struct device_node *np;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -760,7 +760,17 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
priv->adc_ssi_port = pdata->adc_ssi_port;
priv->dac_ssi_port = pdata->dac_ssi_port;
} else {
- return -ENOSYS;
+ np = of_get_child_by_name(pdev->dev.parent->of_node, "codec");
+ if (!np)
+ return -ENOSYS;
+
+ ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port);
+ if (ret)
+ return ret;
}
dev_set_drvdata(&pdev->dev, priv);
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index e427544183d7..a722a023c262 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -115,7 +115,7 @@ static int pcm1681_set_deemph(struct snd_soc_codec *codec)
static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = priv->deemph;
@@ -126,7 +126,7 @@ static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
priv->deemph = ucontrol->value.enumerated.item[0];
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 4b4c0c7bb918..163ec3855fd4 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -269,7 +269,7 @@ SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
PCM512x_RQMR_SHIFT, 1, 1),
SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
-SOC_VALUE_ENUM("DSP Program", pcm512x_dsp_program),
+SOC_ENUM("DSP Program", pcm512x_dsp_program),
SOC_ENUM("Clock Missing Period", pcm512x_clk_missing),
SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l),
@@ -517,6 +517,7 @@ void pcm512x_remove(struct device *dev)
}
EXPORT_SYMBOL_GPL(pcm512x_remove);
+#ifdef CONFIG_PM_RUNTIME
static int pcm512x_suspend(struct device *dev)
{
struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
@@ -578,6 +579,7 @@ static int pcm512x_resume(struct device *dev)
return 0;
}
+#endif
const struct dev_pm_ops pcm512x_pm_ops = {
SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL)
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index d4c229f0233f..30e234708579 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -188,7 +188,7 @@ static unsigned int mic_bst_tlv[] = {
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 snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = rt5631->dmic_used_flag;
@@ -199,7 +199,7 @@ static int rt5631_dmic_get(struct snd_kcontrol *kcontrol,
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 snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
rt5631->dmic_used_flag = ucontrol->value.integer.value[0];
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 68b4dd622b87..9e0d48f98927 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -1,5 +1,5 @@
/*
- * rt5640.c -- RT5640 ALSA SoC audio codec driver
+ * rt5640.c -- RT5640/RT5639 ALSA SoC audio codec driver
*
* Copyright 2011 Realtek Semiconductor Corp.
* Author: Johnny Hsu <johnnyhsu@realtek.com>
@@ -18,6 +18,7 @@
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
+#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
@@ -59,7 +60,7 @@ static struct reg_default init_list[] = {
};
#define RT5640_INIT_REG_LEN ARRAY_SIZE(init_list)
-static const struct reg_default rt5640_reg[RT5640_VENDOR_ID2 + 1] = {
+static const struct reg_default rt5640_reg[] = {
{ 0x00, 0x000e },
{ 0x01, 0xc8c8 },
{ 0x02, 0xc8c8 },
@@ -398,18 +399,13 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {
RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
SOC_DOUBLE_TLV("OUT Playback Volume", RT5640_OUTPUT,
RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
- /* MONO Output Control */
- SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT,
- RT5640_L_MUTE_SFT, 1, 1),
+
/* DAC Digital Volume */
SOC_DOUBLE("DAC2 Playback Switch", RT5640_DAC2_CTRL,
RT5640_M_DAC_L2_VOL_SFT, RT5640_M_DAC_R2_VOL_SFT, 1, 1),
SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5640_DAC1_DIG_VOL,
RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
175, 0, dac_vol_tlv),
- SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL,
- RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
- 175, 0, dac_vol_tlv),
/* IN1/IN2 Control */
SOC_SINGLE_TLV("IN1 Boost", RT5640_IN1_IN2,
RT5640_BST_SFT1, 8, 0, bst_tlv),
@@ -441,6 +437,15 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {
SOC_ENUM("DAC IF2 Data Switch", rt5640_if2_dac_enum),
};
+static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = {
+ /* MONO Output Control */
+ SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT, RT5640_L_MUTE_SFT,
+ 1, 1),
+
+ SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL,
+ RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 175, 0, dac_vol_tlv),
+};
+
/**
* set_dmic_clk - Set parameter of dmic.
*
@@ -480,14 +485,14 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
return idx;
}
-static int check_sysclk1_source(struct snd_soc_dapm_widget *source,
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
unsigned int val;
val = snd_soc_read(source->codec, RT5640_GLB_CLK);
val &= RT5640_SCLK_SRC_MASK;
- if (val == RT5640_SCLK_SRC_PLL1 || val == RT5640_SCLK_SRC_PLL1T)
+ if (val == RT5640_SCLK_SRC_PLL1)
return 1;
else
return 0;
@@ -554,6 +559,20 @@ static const struct snd_kcontrol_new rt5640_sto_dac_r_mix[] = {
RT5640_M_ANC_DAC_R_SFT, 1, 1),
};
+static const struct snd_kcontrol_new rt5639_sto_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_STO_DAC_MIXER,
+ RT5640_M_DAC_L1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_STO_DAC_MIXER,
+ RT5640_M_DAC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5639_sto_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_STO_DAC_MIXER,
+ RT5640_M_DAC_R1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_STO_DAC_MIXER,
+ RT5640_M_DAC_R2_SFT, 1, 1),
+};
+
static const struct snd_kcontrol_new rt5640_mono_dac_l_mix[] = {
SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_MONO_DAC_MIXER,
RT5640_M_DAC_L1_MONO_L_SFT, 1, 1),
@@ -676,6 +695,30 @@ static const struct snd_kcontrol_new rt5640_out_r_mix[] = {
RT5640_M_DAC_R1_OM_R_SFT, 1, 1),
};
+static const struct snd_kcontrol_new rt5639_out_l_mix[] = {
+ SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_L3_MIXER,
+ RT5640_M_BST1_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INL Switch", RT5640_OUT_L3_MIXER,
+ RT5640_M_IN_L_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("REC MIXL Switch", RT5640_OUT_L3_MIXER,
+ RT5640_M_RM_L_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_OUT_L3_MIXER,
+ RT5640_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5639_out_r_mix[] = {
+ SOC_DAPM_SINGLE("BST2 Switch", RT5640_OUT_R3_MIXER,
+ RT5640_M_BST4_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_R3_MIXER,
+ RT5640_M_BST1_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INR Switch", RT5640_OUT_R3_MIXER,
+ RT5640_M_IN_R_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("REC MIXR Switch", RT5640_OUT_R3_MIXER,
+ RT5640_M_RM_R_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_OUT_R3_MIXER,
+ RT5640_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
static const struct snd_kcontrol_new rt5640_spo_l_mix[] = {
SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPO_L_MIXER,
RT5640_M_DAC_R1_SPM_L_SFT, 1, 1),
@@ -707,6 +750,13 @@ static const struct snd_kcontrol_new rt5640_hpo_mix[] = {
RT5640_M_HPVOL_HM_SFT, 1, 1),
};
+static const struct snd_kcontrol_new rt5639_hpo_mix[] = {
+ SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5640_HPO_MIXER,
+ RT5640_M_DAC1_HM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5640_HPO_MIXER,
+ RT5640_M_HPVOL_HM_SFT, 1, 1),
+};
+
static const struct snd_kcontrol_new rt5640_lout_mix[] = {
SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_LOUT_MIXER,
RT5640_M_DAC_L1_LM_SFT, 1, 1),
@@ -824,7 +874,7 @@ static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_l2_enum,
0x3, rt5640_dac_l2_src, rt5640_dac_l2_values);
static const struct snd_kcontrol_new rt5640_dac_l2_mux =
- SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum);
+ SOC_DAPM_ENUM("DAC2 left channel source", rt5640_dac_l2_enum);
static const char * const rt5640_dac_r2_src[] = {
"IF2",
@@ -859,7 +909,7 @@ static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dai_iis_map_enum,
rt5640_dai_iis_map_values);
static const struct snd_kcontrol_new rt5640_dai_mux =
- SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum);
+ SOC_DAPM_ENUM("DAI select", rt5640_dai_iis_map_enum);
/* SDI select */
static const char * const rt5640_sdi_sel[] = {
@@ -872,54 +922,6 @@ static SOC_ENUM_SINGLE_DECL(rt5640_sdi_sel_enum, RT5640_I2S2_SDP,
static const struct snd_kcontrol_new rt5640_sdi_mux =
SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
-static int rt5640_set_dmic1_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:
- snd_soc_update_bits(codec, RT5640_GPIO_CTRL1,
- RT5640_GP2_PIN_MASK | RT5640_GP3_PIN_MASK,
- RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP3_PIN_DMIC1_SDA);
- snd_soc_update_bits(codec, RT5640_DMIC,
- RT5640_DMIC_1L_LH_MASK | RT5640_DMIC_1R_LH_MASK |
- RT5640_DMIC_1_DP_MASK,
- RT5640_DMIC_1L_LH_FALLING | RT5640_DMIC_1R_LH_RISING |
- RT5640_DMIC_1_DP_IN1P);
- break;
-
- default:
- return 0;
- }
-
- return 0;
-}
-
-static int rt5640_set_dmic2_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:
- snd_soc_update_bits(codec, RT5640_GPIO_CTRL1,
- RT5640_GP2_PIN_MASK | RT5640_GP4_PIN_MASK,
- RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP4_PIN_DMIC2_SDA);
- snd_soc_update_bits(codec, RT5640_DMIC,
- RT5640_DMIC_2L_LH_MASK | RT5640_DMIC_2R_LH_MASK |
- RT5640_DMIC_2_DP_MASK,
- RT5640_DMIC_2L_LH_FALLING | RT5640_DMIC_2R_LH_RISING |
- RT5640_DMIC_2_DP_IN1N);
- break;
-
- default:
- return 0;
- }
-
- return 0;
-}
-
static void hp_amp_power_on(struct snd_soc_codec *codec)
{
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
@@ -1054,12 +1056,10 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC,
- RT5640_DMIC_1_EN_SFT, 0, rt5640_set_dmic1_event,
- SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC,
- RT5640_DMIC_2_EN_SFT, 0, rt5640_set_dmic2_event,
- SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC, RT5640_DMIC_1_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC, RT5640_DMIC_2_EN_SFT, 0,
+ NULL, 0),
/* Boost */
SND_SOC_DAPM_PGA("BST1", RT5640_PWR_ANLG2,
RT5640_PWR_BST1_BIT, 0, NULL, 0),
@@ -1146,26 +1146,15 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
- /* Audio DSP */
- SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
- /* ANC */
- SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
/* Output Side */
/* DAC mixer before sound effect */
SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
rt5640_dac_l_mix, ARRAY_SIZE(rt5640_dac_l_mix)),
SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
rt5640_dac_r_mix, ARRAY_SIZE(rt5640_dac_r_mix)),
- /* DAC2 channel Mux */
- SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0,
- &rt5640_dac_l2_mux),
- SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0,
- &rt5640_dac_r2_mux),
+
/* DAC Mixer */
- SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
- rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)),
- SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
- rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)),
SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
rt5640_mono_dac_l_mix, ARRAY_SIZE(rt5640_mono_dac_l_mix)),
SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
@@ -1177,21 +1166,14 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
/* DACs */
SND_SOC_DAPM_DAC("DAC L1", NULL, RT5640_PWR_DIG1,
RT5640_PWR_DAC_L1_BIT, 0),
- SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1,
- RT5640_PWR_DAC_L2_BIT, 0),
SND_SOC_DAPM_DAC("DAC R1", NULL, RT5640_PWR_DIG1,
RT5640_PWR_DAC_R1_BIT, 0),
- SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1,
- RT5640_PWR_DAC_R2_BIT, 0),
+
/* SPK/OUT Mixer */
SND_SOC_DAPM_MIXER("SPK MIXL", RT5640_PWR_MIXER, RT5640_PWR_SM_L_BIT,
0, rt5640_spk_l_mix, ARRAY_SIZE(rt5640_spk_l_mix)),
SND_SOC_DAPM_MIXER("SPK MIXR", RT5640_PWR_MIXER, RT5640_PWR_SM_R_BIT,
0, rt5640_spk_r_mix, ARRAY_SIZE(rt5640_spk_r_mix)),
- SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT,
- 0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)),
- SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT,
- 0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)),
/* Ouput Volume */
SND_SOC_DAPM_PGA("SPKVOL L", RT5640_PWR_VOL,
RT5640_PWR_SV_L_BIT, 0, NULL, 0),
@@ -1210,16 +1192,8 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
0, rt5640_spo_l_mix, ARRAY_SIZE(rt5640_spo_l_mix)),
SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0,
0, rt5640_spo_r_mix, ARRAY_SIZE(rt5640_spo_r_mix)),
- SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0,
- rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
- SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0,
- rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
SND_SOC_DAPM_MIXER("LOUT MIX", RT5640_PWR_ANLG1, RT5640_PWR_LM_BIT, 0,
rt5640_lout_mix, ARRAY_SIZE(rt5640_lout_mix)),
- SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0,
- rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)),
- SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1,
- RT5640_PWR_MA_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM,
0, 0, rt5640_hp_power_event, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0,
@@ -1251,10 +1225,69 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("HPOR"),
SND_SOC_DAPM_OUTPUT("LOUTL"),
SND_SOC_DAPM_OUTPUT("LOUTR"),
+};
+
+static const struct snd_soc_dapm_widget rt5640_specific_dapm_widgets[] = {
+ /* Audio DSP */
+ SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+ /* ANC */
+ SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* DAC2 channel Mux */
+ SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dac_l2_mux),
+ SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dac_r2_mux),
+
+ SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)),
+
+ SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_R2_BIT,
+ 0),
+ SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_L2_BIT,
+ 0),
+
+ SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT,
+ 0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)),
+ SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT,
+ 0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)),
+
+ SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0,
+ rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
+ SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0,
+ rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
+
+ SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0,
+ rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)),
+ SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1,
+ RT5640_PWR_MA_BIT, 0, NULL, 0),
+
SND_SOC_DAPM_OUTPUT("MONOP"),
SND_SOC_DAPM_OUTPUT("MONON"),
};
+static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = {
+ SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5639_sto_dac_l_mix, ARRAY_SIZE(rt5639_sto_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5639_sto_dac_r_mix, ARRAY_SIZE(rt5639_sto_dac_r_mix)),
+
+ SND_SOC_DAPM_SUPPLY("DAC L2 Filter", RT5640_PWR_DIG1,
+ RT5640_PWR_DAC_L2_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC R2 Filter", RT5640_PWR_DIG1,
+ RT5640_PWR_DAC_R2_BIT, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT,
+ 0, rt5639_out_l_mix, ARRAY_SIZE(rt5639_out_l_mix)),
+ SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT,
+ 0, rt5639_out_r_mix, ARRAY_SIZE(rt5639_out_r_mix)),
+
+ SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0,
+ rt5639_hpo_mix, ARRAY_SIZE(rt5639_hpo_mix)),
+ SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0,
+ rt5639_hpo_mix, ARRAY_SIZE(rt5639_hpo_mix)),
+};
+
static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"IN1P", NULL, "LDO2"},
{"IN2P", NULL, "LDO2"},
@@ -1323,22 +1356,22 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"Stereo ADC MIXL", "ADC1 Switch", "Stereo ADC L1 Mux"},
{"Stereo ADC MIXL", "ADC2 Switch", "Stereo ADC L2 Mux"},
{"Stereo ADC MIXL", NULL, "Stereo Filter"},
- {"Stereo Filter", NULL, "PLL1", check_sysclk1_source},
+ {"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"Stereo ADC MIXR", "ADC1 Switch", "Stereo ADC R1 Mux"},
{"Stereo ADC MIXR", "ADC2 Switch", "Stereo ADC R2 Mux"},
{"Stereo ADC MIXR", NULL, "Stereo Filter"},
- {"Stereo Filter", NULL, "PLL1", check_sysclk1_source},
+ {"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"},
{"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"},
{"Mono ADC MIXL", NULL, "Mono Left Filter"},
- {"Mono Left Filter", NULL, "PLL1", check_sysclk1_source},
+ {"Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"},
{"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"},
{"Mono ADC MIXR", NULL, "Mono Right Filter"},
- {"Mono Right Filter", NULL, "PLL1", check_sysclk1_source},
+ {"Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"IF2 ADC L", NULL, "Mono ADC MIXL"},
{"IF2 ADC R", NULL, "Mono ADC MIXR"},
@@ -1396,71 +1429,38 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"DAC MIXR", "Stereo ADC Switch", "Stereo ADC MIXR"},
{"DAC MIXR", "INF1 Switch", "IF1 DAC R"},
- {"ANC", NULL, "Stereo ADC MIXL"},
- {"ANC", NULL, "Stereo ADC MIXR"},
-
- {"Audio DSP", NULL, "DAC MIXL"},
- {"Audio DSP", NULL, "DAC MIXR"},
-
- {"DAC L2 Mux", "IF2", "IF2 DAC L"},
- {"DAC L2 Mux", "Base L/R", "Audio DSP"},
-
- {"DAC R2 Mux", "IF2", "IF2 DAC R"},
-
{"Stereo DAC MIXL", "DAC L1 Switch", "DAC MIXL"},
- {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
- {"Stereo DAC MIXL", "ANC Switch", "ANC"},
{"Stereo DAC MIXR", "DAC R1 Switch", "DAC MIXR"},
- {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
- {"Stereo DAC MIXR", "ANC Switch", "ANC"},
{"Mono DAC MIXL", "DAC L1 Switch", "DAC MIXL"},
- {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
- {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},
{"Mono DAC MIXR", "DAC R1 Switch", "DAC MIXR"},
- {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
- {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},
{"DIG MIXL", "DAC L1 Switch", "DAC MIXL"},
- {"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},
{"DIG MIXR", "DAC R1 Switch", "DAC MIXR"},
- {"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"},
{"DAC L1", NULL, "Stereo DAC MIXL"},
- {"DAC L1", NULL, "PLL1", check_sysclk1_source},
+ {"DAC L1", NULL, "PLL1", is_sys_clk_from_pll},
{"DAC R1", NULL, "Stereo DAC MIXR"},
- {"DAC R1", NULL, "PLL1", check_sysclk1_source},
- {"DAC L2", NULL, "Mono DAC MIXL"},
- {"DAC L2", NULL, "PLL1", check_sysclk1_source},
- {"DAC R2", NULL, "Mono DAC MIXR"},
- {"DAC R2", NULL, "PLL1", check_sysclk1_source},
+ {"DAC R1", NULL, "PLL1", is_sys_clk_from_pll},
{"SPK MIXL", "REC MIXL Switch", "RECMIXL"},
{"SPK MIXL", "INL Switch", "INL VOL"},
{"SPK MIXL", "DAC L1 Switch", "DAC L1"},
- {"SPK MIXL", "DAC L2 Switch", "DAC L2"},
{"SPK MIXL", "OUT MIXL Switch", "OUT MIXL"},
{"SPK MIXR", "REC MIXR Switch", "RECMIXR"},
{"SPK MIXR", "INR Switch", "INR VOL"},
{"SPK MIXR", "DAC R1 Switch", "DAC R1"},
- {"SPK MIXR", "DAC R2 Switch", "DAC R2"},
{"SPK MIXR", "OUT MIXR Switch", "OUT MIXR"},
- {"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"},
{"OUT MIXL", "BST1 Switch", "BST1"},
{"OUT MIXL", "INL Switch", "INL VOL"},
{"OUT MIXL", "REC MIXL Switch", "RECMIXL"},
- {"OUT MIXL", "DAC R2 Switch", "DAC R2"},
- {"OUT MIXL", "DAC L2 Switch", "DAC L2"},
{"OUT MIXL", "DAC L1 Switch", "DAC L1"},
- {"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"},
{"OUT MIXR", "BST2 Switch", "BST2"},
{"OUT MIXR", "BST1 Switch", "BST1"},
{"OUT MIXR", "INR Switch", "INR VOL"},
{"OUT MIXR", "REC MIXR Switch", "RECMIXR"},
- {"OUT MIXR", "DAC L2 Switch", "DAC L2"},
- {"OUT MIXR", "DAC R2 Switch", "DAC R2"},
{"OUT MIXR", "DAC R1 Switch", "DAC R1"},
{"SPKVOL L", NULL, "SPK MIXL"},
@@ -1479,11 +1479,9 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"SPOR MIX", "SPKVOL R Switch", "SPKVOL R"},
{"SPOR MIX", "BST1 Switch", "BST1"},
- {"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"},
{"HPO MIX L", "HPO MIX DAC1 Switch", "DAC L1"},
{"HPO MIX L", "HPO MIX HPVOL Switch", "HPOVOL L"},
{"HPO MIX L", NULL, "HP L Amp"},
- {"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"},
{"HPO MIX R", "HPO MIX DAC1 Switch", "DAC R1"},
{"HPO MIX R", "HPO MIX HPVOL Switch", "HPOVOL R"},
{"HPO MIX R", NULL, "HP R Amp"},
@@ -1493,12 +1491,6 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},
{"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"},
- {"Mono MIX", "DAC R2 Switch", "DAC R2"},
- {"Mono MIX", "DAC L2 Switch", "DAC L2"},
- {"Mono MIX", "OUTVOL R Switch", "OUTVOL R"},
- {"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
- {"Mono MIX", "BST1 Switch", "BST1"},
-
{"HP Amp", NULL, "HPO MIX L"},
{"HP Amp", NULL, "HPO MIX R"},
@@ -1523,11 +1515,82 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"HPOR", NULL, "HP R Playback"},
{"LOUTL", NULL, "LOUT MIX"},
{"LOUTR", NULL, "LOUT MIX"},
+};
+
+static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = {
+ {"ANC", NULL, "Stereo ADC MIXL"},
+ {"ANC", NULL, "Stereo ADC MIXR"},
+
+ {"Audio DSP", NULL, "DAC MIXL"},
+ {"Audio DSP", NULL, "DAC MIXR"},
+
+ {"DAC L2 Mux", "IF2", "IF2 DAC L"},
+ {"DAC L2 Mux", "Base L/R", "Audio DSP"},
+
+ {"DAC R2 Mux", "IF2", "IF2 DAC R"},
+
+ {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+ {"Stereo DAC MIXL", "ANC Switch", "ANC"},
+ {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+ {"Stereo DAC MIXR", "ANC Switch", "ANC"},
+
+ {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+ {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},
+
+ {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+ {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},
+
+ {"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+ {"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+
+ {"DAC L2", NULL, "Mono DAC MIXL"},
+ {"DAC L2", NULL, "PLL1", is_sys_clk_from_pll},
+ {"DAC R2", NULL, "Mono DAC MIXR"},
+ {"DAC R2", NULL, "PLL1", is_sys_clk_from_pll},
+
+ {"SPK MIXL", "DAC L2 Switch", "DAC L2"},
+ {"SPK MIXR", "DAC R2 Switch", "DAC R2"},
+
+ {"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"},
+ {"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"},
+
+ {"OUT MIXL", "DAC R2 Switch", "DAC R2"},
+ {"OUT MIXL", "DAC L2 Switch", "DAC L2"},
+
+ {"OUT MIXR", "DAC L2 Switch", "DAC L2"},
+ {"OUT MIXR", "DAC R2 Switch", "DAC R2"},
+
+ {"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"},
+ {"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"},
+
+ {"Mono MIX", "DAC R2 Switch", "DAC R2"},
+ {"Mono MIX", "DAC L2 Switch", "DAC L2"},
+ {"Mono MIX", "OUTVOL R Switch", "OUTVOL R"},
+ {"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
+ {"Mono MIX", "BST1 Switch", "BST1"},
+
{"MONOP", NULL, "Mono MIX"},
{"MONON", NULL, "Mono MIX"},
{"MONOP", NULL, "Improve MONO Amp Drv"},
};
+static const struct snd_soc_dapm_route rt5639_specific_dapm_routes[] = {
+ {"Stereo DAC MIXL", "DAC L2 Switch", "IF2 DAC L"},
+ {"Stereo DAC MIXR", "DAC R2 Switch", "IF2 DAC R"},
+
+ {"Mono DAC MIXL", "DAC L2 Switch", "IF2 DAC L"},
+ {"Mono DAC MIXL", "DAC R2 Switch", "IF2 DAC R"},
+
+ {"Mono DAC MIXR", "DAC R2 Switch", "IF2 DAC R"},
+ {"Mono DAC MIXR", "DAC L2 Switch", "IF2 DAC L"},
+
+ {"DIG MIXL", "DAC L2 Switch", "IF2 DAC L"},
+ {"DIG MIXR", "DAC R2 Switch", "IF2 DAC R"},
+
+ {"IF2 DAC L", NULL, "DAC L2 Filter"},
+ {"IF2 DAC R", NULL, "DAC R2 Filter"},
+};
+
static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)
{
int ret = 0, val;
@@ -1622,16 +1685,16 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
bclk_ms, pre_div, dai->id);
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
val_len |= RT5640_I2S_DL_20;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
val_len |= RT5640_I2S_DL_24;
break;
- case SNDRV_PCM_FORMAT_S8:
+ case 8:
val_len |= RT5640_I2S_DL_8;
break;
default:
@@ -1744,12 +1807,6 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
case RT5640_SCLK_S_PLL1:
reg_val |= RT5640_SCLK_SRC_PLL1;
break;
- case RT5640_SCLK_S_PLL1_TK:
- reg_val |= RT5640_SCLK_SRC_PLL1T;
- break;
- case RT5640_SCLK_S_RCCLK:
- reg_val |= RT5640_SCLK_SRC_RCCLK;
- break;
default:
dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
return -EINVAL;
@@ -1890,11 +1947,9 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
static int rt5640_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
switch (level) {
case SND_SOC_BIAS_STANDBY:
if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
- regcache_cache_only(rt5640->regmap, false);
snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
RT5640_PWR_VREF1 | RT5640_PWR_MB |
RT5640_PWR_BG | RT5640_PWR_VREF2,
@@ -1904,7 +1959,6 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
RT5640_PWR_FV1 | RT5640_PWR_FV2,
RT5640_PWR_FV1 | RT5640_PWR_FV2);
- regcache_sync(rt5640->regmap);
snd_soc_update_bits(codec, RT5640_DUMMY1,
0x0301, 0x0301);
snd_soc_update_bits(codec, RT5640_MICBIAS,
@@ -1938,13 +1992,39 @@ static int rt5640_probe(struct snd_soc_codec *codec)
rt5640->codec = codec;
- codec->dapm.idle_bias_off = 1;
rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
+ switch (snd_soc_read(codec, RT5640_RESET) & RT5640_ID_MASK) {
+ case RT5640_ID_5640:
+ case RT5640_ID_5642:
+ snd_soc_add_codec_controls(codec,
+ rt5640_specific_snd_controls,
+ ARRAY_SIZE(rt5640_specific_snd_controls));
+ snd_soc_dapm_new_controls(&codec->dapm,
+ rt5640_specific_dapm_widgets,
+ ARRAY_SIZE(rt5640_specific_dapm_widgets));
+ snd_soc_dapm_add_routes(&codec->dapm,
+ rt5640_specific_dapm_routes,
+ ARRAY_SIZE(rt5640_specific_dapm_routes));
+ break;
+ case RT5640_ID_5639:
+ snd_soc_dapm_new_controls(&codec->dapm,
+ rt5639_specific_dapm_widgets,
+ ARRAY_SIZE(rt5639_specific_dapm_widgets));
+ snd_soc_dapm_add_routes(&codec->dapm,
+ rt5639_specific_dapm_routes,
+ ARRAY_SIZE(rt5639_specific_dapm_routes));
+ break;
+ default:
+ dev_err(codec->dev,
+ "The driver is for RT5639 RT5640 or RT5642 only\n");
+ return -ENODEV;
+ }
+
return 0;
}
@@ -1979,6 +2059,9 @@ static int rt5640_resume(struct snd_soc_codec *codec)
msleep(400);
}
+ regcache_cache_only(rt5640->regmap, false);
+ regcache_sync(rt5640->regmap);
+
return 0;
}
#else
@@ -2044,6 +2127,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
.suspend = rt5640_suspend,
.resume = rt5640_resume,
.set_bias_level = rt5640_set_bias_level,
+ .idle_bias_off = true,
.controls = rt5640_snd_controls,
.num_controls = ARRAY_SIZE(rt5640_snd_controls),
.dapm_widgets = rt5640_dapm_widgets,
@@ -2070,12 +2154,15 @@ static const struct regmap_config rt5640_regmap = {
static const struct i2c_device_id rt5640_i2c_id[] = {
{ "rt5640", 0 },
+ { "rt5639", 0 },
+ { "rt5642", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
#if defined(CONFIG_OF)
static const struct of_device_id rt5640_of_match[] = {
+ { .compatible = "realtek,rt5639", },
{ .compatible = "realtek,rt5640", },
{},
};
@@ -2166,7 +2253,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
}
regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val);
- if ((val != RT5640_DEVICE_ID)) {
+ if (val != RT5640_DEVICE_ID) {
dev_err(&i2c->dev,
"Device with ID register %x is not rt5640/39\n", val);
return -ENODEV;
@@ -2187,6 +2274,25 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
RT5640_IN_DF2, RT5640_IN_DF2);
+ if (rt5640->pdata.dmic_en) {
+ regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+ RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
+
+ if (rt5640->pdata.dmic1_data_pin) {
+ regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+ RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
+ regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+ RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
+ }
+
+ if (rt5640->pdata.dmic2_data_pin) {
+ regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+ RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
+ regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+ RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
+ }
+ }
+
rt5640->hp_mute = 1;
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
@@ -2219,6 +2325,6 @@ static struct i2c_driver rt5640_i2c_driver = {
};
module_i2c_driver(rt5640_i2c_driver);
-MODULE_DESCRIPTION("ASoC RT5640 driver");
+MODULE_DESCRIPTION("ASoC RT5640/RT5639 driver");
MODULE_AUTHOR("Johnny Hsu <johnnyhsu@realtek.com>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index 5e8df25a13f3..895ca149db2e 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -192,6 +192,13 @@
#define RT5640_R_VOL_MASK (0x3f)
#define RT5640_R_VOL_SFT 0
+/* SW Reset & Device ID (0x00) */
+#define RT5640_ID_MASK (0x3 << 1)
+#define RT5640_ID_5639 (0x0 << 1)
+#define RT5640_ID_5640 (0x2 << 1)
+#define RT5640_ID_5642 (0x3 << 1)
+
+
/* IN1 and IN2 Control (0x0d) */
/* IN3 and IN4 Control (0x0e) */
#define RT5640_BST_SFT1 12
@@ -976,8 +983,6 @@
#define RT5640_SCLK_SRC_SFT 14
#define RT5640_SCLK_SRC_MCLK (0x0 << 14)
#define RT5640_SCLK_SRC_PLL1 (0x1 << 14)
-#define RT5640_SCLK_SRC_PLL1T (0x2 << 14)
-#define RT5640_SCLK_SRC_RCCLK (0x3 << 14) /* 15MHz */
#define RT5640_PLL1_SRC_MASK (0x3 << 12)
#define RT5640_PLL1_SRC_SFT 12
#define RT5640_PLL1_SRC_MCLK (0x0 << 12)
@@ -2097,7 +2102,6 @@ struct rt5640_priv {
int pll_in;
int pll_out;
- int dmic_en;
bool hp_mute;
};
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
new file mode 100644
index 000000000000..ab97d722e15d
--- /dev/null
+++ b/sound/soc/codecs/rt5645.c
@@ -0,0 +1,2475 @@
+/*
+ * rt5645.c -- RT5645 ALSA SoC audio codec driver
+ *
+ * Copyright 2013 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.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/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/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt5645.h"
+
+#define RT5645_DEVICE_ID 0x6308
+
+#define RT5645_PR_RANGE_BASE (0xff + 1)
+#define RT5645_PR_SPACING 0x100
+
+#define RT5645_PR_BASE (RT5645_PR_RANGE_BASE + (0 * RT5645_PR_SPACING))
+
+static const struct regmap_range_cfg rt5645_ranges[] = {
+ {
+ .name = "PR",
+ .range_min = RT5645_PR_BASE,
+ .range_max = RT5645_PR_BASE + 0xf8,
+ .selector_reg = RT5645_PRIV_INDEX,
+ .selector_mask = 0xff,
+ .selector_shift = 0x0,
+ .window_start = RT5645_PRIV_DATA,
+ .window_len = 0x1,
+ },
+};
+
+static const struct reg_default init_list[] = {
+ {RT5645_PR_BASE + 0x3d, 0x3600},
+ {RT5645_PR_BASE + 0x1c, 0xfd20},
+ {RT5645_PR_BASE + 0x20, 0x611f},
+ {RT5645_PR_BASE + 0x21, 0x4040},
+ {RT5645_PR_BASE + 0x23, 0x0004},
+};
+#define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static const struct reg_default rt5645_reg[] = {
+ { 0x00, 0x0000 },
+ { 0x01, 0xc8c8 },
+ { 0x02, 0xc8c8 },
+ { 0x03, 0xc8c8 },
+ { 0x0a, 0x0002 },
+ { 0x0b, 0x2827 },
+ { 0x0c, 0xe000 },
+ { 0x0d, 0x0000 },
+ { 0x0e, 0x0000 },
+ { 0x0f, 0x0808 },
+ { 0x14, 0x3333 },
+ { 0x16, 0x4b00 },
+ { 0x18, 0x018b },
+ { 0x19, 0xafaf },
+ { 0x1a, 0xafaf },
+ { 0x1b, 0x0001 },
+ { 0x1c, 0x2f2f },
+ { 0x1d, 0x2f2f },
+ { 0x1e, 0x0000 },
+ { 0x20, 0x0000 },
+ { 0x27, 0x7060 },
+ { 0x28, 0x7070 },
+ { 0x29, 0x8080 },
+ { 0x2a, 0x5656 },
+ { 0x2b, 0x5454 },
+ { 0x2c, 0xaaa0 },
+ { 0x2f, 0x1002 },
+ { 0x31, 0x5000 },
+ { 0x32, 0x0000 },
+ { 0x33, 0x0000 },
+ { 0x34, 0x0000 },
+ { 0x35, 0x0000 },
+ { 0x3b, 0x0000 },
+ { 0x3c, 0x007f },
+ { 0x3d, 0x0000 },
+ { 0x3e, 0x007f },
+ { 0x3f, 0x0000 },
+ { 0x40, 0x001f },
+ { 0x41, 0x0000 },
+ { 0x42, 0x001f },
+ { 0x45, 0x6000 },
+ { 0x46, 0x003e },
+ { 0x47, 0x003e },
+ { 0x48, 0xf807 },
+ { 0x4a, 0x0004 },
+ { 0x4d, 0x0000 },
+ { 0x4e, 0x0000 },
+ { 0x4f, 0x01ff },
+ { 0x50, 0x0000 },
+ { 0x51, 0x0000 },
+ { 0x52, 0x01ff },
+ { 0x53, 0xf000 },
+ { 0x56, 0x0111 },
+ { 0x57, 0x0064 },
+ { 0x58, 0xef0e },
+ { 0x59, 0xf0f0 },
+ { 0x5a, 0xef0e },
+ { 0x5b, 0xf0f0 },
+ { 0x5c, 0xef0e },
+ { 0x5d, 0xf0f0 },
+ { 0x5e, 0xf000 },
+ { 0x5f, 0x0000 },
+ { 0x61, 0x0300 },
+ { 0x62, 0x0000 },
+ { 0x63, 0x00c2 },
+ { 0x64, 0x0000 },
+ { 0x65, 0x0000 },
+ { 0x66, 0x0000 },
+ { 0x6a, 0x0000 },
+ { 0x6c, 0x0aaa },
+ { 0x70, 0x8000 },
+ { 0x71, 0x8000 },
+ { 0x72, 0x8000 },
+ { 0x73, 0x7770 },
+ { 0x74, 0x3e00 },
+ { 0x75, 0x2409 },
+ { 0x76, 0x000a },
+ { 0x77, 0x0c00 },
+ { 0x78, 0x0000 },
+ { 0x80, 0x0000 },
+ { 0x81, 0x0000 },
+ { 0x82, 0x0000 },
+ { 0x83, 0x0000 },
+ { 0x84, 0x0000 },
+ { 0x85, 0x0000 },
+ { 0x8a, 0x0000 },
+ { 0x8e, 0x0004 },
+ { 0x8f, 0x1100 },
+ { 0x90, 0x0646 },
+ { 0x91, 0x0c06 },
+ { 0x93, 0x0000 },
+ { 0x94, 0x0200 },
+ { 0x95, 0x0000 },
+ { 0x9a, 0x2184 },
+ { 0x9b, 0x010a },
+ { 0x9c, 0x0aea },
+ { 0x9d, 0x000c },
+ { 0x9e, 0x0400 },
+ { 0xa0, 0xa0a8 },
+ { 0xa1, 0x0059 },
+ { 0xa2, 0x0001 },
+ { 0xae, 0x6000 },
+ { 0xaf, 0x0000 },
+ { 0xb0, 0x6000 },
+ { 0xb1, 0x0000 },
+ { 0xb2, 0x0000 },
+ { 0xb3, 0x001f },
+ { 0xb4, 0x020c },
+ { 0xb5, 0x1f00 },
+ { 0xb6, 0x0000 },
+ { 0xbb, 0x0000 },
+ { 0xbc, 0x0000 },
+ { 0xbd, 0x0000 },
+ { 0xbe, 0x0000 },
+ { 0xbf, 0x3100 },
+ { 0xc0, 0x0000 },
+ { 0xc1, 0x0000 },
+ { 0xc2, 0x0000 },
+ { 0xc3, 0x2000 },
+ { 0xcd, 0x0000 },
+ { 0xce, 0x0000 },
+ { 0xcf, 0x1813 },
+ { 0xd0, 0x0690 },
+ { 0xd1, 0x1c17 },
+ { 0xd3, 0xb320 },
+ { 0xd4, 0x0000 },
+ { 0xd6, 0x0400 },
+ { 0xd9, 0x0809 },
+ { 0xda, 0x0000 },
+ { 0xdb, 0x0003 },
+ { 0xdc, 0x0049 },
+ { 0xdd, 0x001b },
+ { 0xe6, 0x8000 },
+ { 0xe7, 0x0200 },
+ { 0xec, 0xb300 },
+ { 0xed, 0x0000 },
+ { 0xf0, 0x001f },
+ { 0xf1, 0x020c },
+ { 0xf2, 0x1f00 },
+ { 0xf3, 0x0000 },
+ { 0xf4, 0x4000 },
+ { 0xf8, 0x0000 },
+ { 0xf9, 0x0000 },
+ { 0xfa, 0x2060 },
+ { 0xfb, 0x4040 },
+ { 0xfc, 0x0000 },
+ { 0xfd, 0x0002 },
+ { 0xfe, 0x10ec },
+ { 0xff, 0x6308 },
+};
+
+static int rt5645_reset(struct snd_soc_codec *codec)
+{
+ return snd_soc_write(codec, RT5645_RESET, 0);
+}
+
+static bool rt5645_volatile_register(struct device *dev, unsigned int reg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rt5645_ranges); i++) {
+ if (reg >= rt5645_ranges[i].range_min &&
+ reg <= rt5645_ranges[i].range_max) {
+ return true;
+ }
+ }
+
+ switch (reg) {
+ case RT5645_RESET:
+ case RT5645_PRIV_DATA:
+ case RT5645_IN1_CTRL1:
+ case RT5645_IN1_CTRL2:
+ case RT5645_IN1_CTRL3:
+ case RT5645_A_JD_CTRL1:
+ case RT5645_ADC_EQ_CTRL1:
+ case RT5645_EQ_CTRL1:
+ case RT5645_ALC_CTRL_1:
+ case RT5645_IRQ_CTRL2:
+ case RT5645_IRQ_CTRL3:
+ case RT5645_INT_IRQ_ST:
+ case RT5645_IL_CMD:
+ case RT5645_VENDOR_ID:
+ case RT5645_VENDOR_ID1:
+ case RT5645_VENDOR_ID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt5645_readable_register(struct device *dev, unsigned int reg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rt5645_ranges); i++) {
+ if (reg >= rt5645_ranges[i].range_min &&
+ reg <= rt5645_ranges[i].range_max) {
+ return true;
+ }
+ }
+
+ switch (reg) {
+ case RT5645_RESET:
+ case RT5645_SPK_VOL:
+ case RT5645_HP_VOL:
+ case RT5645_LOUT1:
+ case RT5645_IN1_CTRL1:
+ case RT5645_IN1_CTRL2:
+ case RT5645_IN1_CTRL3:
+ case RT5645_IN2_CTRL:
+ case RT5645_INL1_INR1_VOL:
+ case RT5645_SPK_FUNC_LIM:
+ case RT5645_ADJ_HPF_CTRL:
+ case RT5645_DAC1_DIG_VOL:
+ case RT5645_DAC2_DIG_VOL:
+ case RT5645_DAC_CTRL:
+ case RT5645_STO1_ADC_DIG_VOL:
+ case RT5645_MONO_ADC_DIG_VOL:
+ case RT5645_ADC_BST_VOL1:
+ case RT5645_ADC_BST_VOL2:
+ case RT5645_STO1_ADC_MIXER:
+ case RT5645_MONO_ADC_MIXER:
+ case RT5645_AD_DA_MIXER:
+ case RT5645_STO_DAC_MIXER:
+ case RT5645_MONO_DAC_MIXER:
+ case RT5645_DIG_MIXER:
+ case RT5645_DIG_INF1_DATA:
+ case RT5645_PDM_OUT_CTRL:
+ case RT5645_REC_L1_MIXER:
+ case RT5645_REC_L2_MIXER:
+ case RT5645_REC_R1_MIXER:
+ case RT5645_REC_R2_MIXER:
+ case RT5645_HPMIXL_CTRL:
+ case RT5645_HPOMIXL_CTRL:
+ case RT5645_HPMIXR_CTRL:
+ case RT5645_HPOMIXR_CTRL:
+ case RT5645_HPO_MIXER:
+ case RT5645_SPK_L_MIXER:
+ case RT5645_SPK_R_MIXER:
+ case RT5645_SPO_MIXER:
+ case RT5645_SPO_CLSD_RATIO:
+ case RT5645_OUT_L1_MIXER:
+ case RT5645_OUT_R1_MIXER:
+ case RT5645_OUT_L_GAIN1:
+ case RT5645_OUT_L_GAIN2:
+ case RT5645_OUT_R_GAIN1:
+ case RT5645_OUT_R_GAIN2:
+ case RT5645_LOUT_MIXER:
+ case RT5645_HAPTIC_CTRL1:
+ case RT5645_HAPTIC_CTRL2:
+ case RT5645_HAPTIC_CTRL3:
+ case RT5645_HAPTIC_CTRL4:
+ case RT5645_HAPTIC_CTRL5:
+ case RT5645_HAPTIC_CTRL6:
+ case RT5645_HAPTIC_CTRL7:
+ case RT5645_HAPTIC_CTRL8:
+ case RT5645_HAPTIC_CTRL9:
+ case RT5645_HAPTIC_CTRL10:
+ case RT5645_PWR_DIG1:
+ case RT5645_PWR_DIG2:
+ case RT5645_PWR_ANLG1:
+ case RT5645_PWR_ANLG2:
+ case RT5645_PWR_MIXER:
+ case RT5645_PWR_VOL:
+ case RT5645_PRIV_INDEX:
+ case RT5645_PRIV_DATA:
+ case RT5645_I2S1_SDP:
+ case RT5645_I2S2_SDP:
+ case RT5645_ADDA_CLK1:
+ case RT5645_ADDA_CLK2:
+ case RT5645_DMIC_CTRL1:
+ case RT5645_DMIC_CTRL2:
+ case RT5645_TDM_CTRL_1:
+ case RT5645_TDM_CTRL_2:
+ case RT5645_GLB_CLK:
+ case RT5645_PLL_CTRL1:
+ case RT5645_PLL_CTRL2:
+ case RT5645_ASRC_1:
+ case RT5645_ASRC_2:
+ case RT5645_ASRC_3:
+ case RT5645_ASRC_4:
+ case RT5645_DEPOP_M1:
+ case RT5645_DEPOP_M2:
+ case RT5645_DEPOP_M3:
+ case RT5645_MICBIAS:
+ case RT5645_A_JD_CTRL1:
+ case RT5645_VAD_CTRL4:
+ case RT5645_CLSD_OUT_CTRL:
+ case RT5645_ADC_EQ_CTRL1:
+ case RT5645_ADC_EQ_CTRL2:
+ case RT5645_EQ_CTRL1:
+ case RT5645_EQ_CTRL2:
+ case RT5645_ALC_CTRL_1:
+ case RT5645_ALC_CTRL_2:
+ case RT5645_ALC_CTRL_3:
+ case RT5645_ALC_CTRL_4:
+ case RT5645_ALC_CTRL_5:
+ case RT5645_JD_CTRL:
+ case RT5645_IRQ_CTRL1:
+ case RT5645_IRQ_CTRL2:
+ case RT5645_IRQ_CTRL3:
+ case RT5645_INT_IRQ_ST:
+ case RT5645_GPIO_CTRL1:
+ case RT5645_GPIO_CTRL2:
+ case RT5645_GPIO_CTRL3:
+ case RT5645_BASS_BACK:
+ case RT5645_MP3_PLUS1:
+ case RT5645_MP3_PLUS2:
+ case RT5645_ADJ_HPF1:
+ case RT5645_ADJ_HPF2:
+ case RT5645_HP_CALIB_AMP_DET:
+ case RT5645_SV_ZCD1:
+ case RT5645_SV_ZCD2:
+ case RT5645_IL_CMD:
+ case RT5645_IL_CMD2:
+ case RT5645_IL_CMD3:
+ case RT5645_DRC1_HL_CTRL1:
+ case RT5645_DRC2_HL_CTRL1:
+ case RT5645_ADC_MONO_HP_CTRL1:
+ case RT5645_ADC_MONO_HP_CTRL2:
+ case RT5645_DRC2_CTRL1:
+ case RT5645_DRC2_CTRL2:
+ case RT5645_DRC2_CTRL3:
+ case RT5645_DRC2_CTRL4:
+ case RT5645_DRC2_CTRL5:
+ case RT5645_JD_CTRL3:
+ case RT5645_JD_CTRL4:
+ case RT5645_GEN_CTRL1:
+ case RT5645_GEN_CTRL2:
+ case RT5645_GEN_CTRL3:
+ case RT5645_VENDOR_ID:
+ case RT5645_VENDOR_ID1:
+ case RT5645_VENDOR_ID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static unsigned int bst_tlv[] = {
+ TLV_DB_RANGE_HEAD(7),
+ 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 const char * const rt5645_tdm_data_swap_select[] = {
+ "L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot0_1_enum,
+ RT5645_TDM_CTRL_1, 6, rt5645_tdm_data_swap_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot2_3_enum,
+ RT5645_TDM_CTRL_1, 4, rt5645_tdm_data_swap_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot4_5_enum,
+ RT5645_TDM_CTRL_1, 2, rt5645_tdm_data_swap_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot6_7_enum,
+ RT5645_TDM_CTRL_1, 0, rt5645_tdm_data_swap_select);
+
+static const char * const rt5645_tdm_adc_data_select[] = {
+ "1/2/R", "2/1/R", "R/1/2", "R/2/1"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_sel_enum,
+ RT5645_TDM_CTRL_1, 8,
+ rt5645_tdm_adc_data_select);
+
+static const struct snd_kcontrol_new rt5645_snd_controls[] = {
+ /* Speaker Output Volume */
+ SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL,
+ RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1),
+ SOC_DOUBLE_TLV("Speaker Playback Volume", RT5645_SPK_VOL,
+ RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+ /* Headphone Output Volume */
+ SOC_DOUBLE("HP Channel Switch", RT5645_HP_VOL,
+ RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1),
+ SOC_DOUBLE_TLV("HP Playback Volume", RT5645_HP_VOL,
+ RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+ /* OUTPUT Control */
+ SOC_DOUBLE("OUT Playback Switch", RT5645_LOUT1,
+ RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE("OUT Channel Switch", RT5645_LOUT1,
+ RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1),
+ SOC_DOUBLE_TLV("OUT Playback Volume", RT5645_LOUT1,
+ RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+ /* DAC Digital Volume */
+ SOC_DOUBLE("DAC2 Playback Switch", RT5645_DAC_CTRL,
+ RT5645_M_DAC_L2_VOL_SFT, RT5645_M_DAC_R2_VOL_SFT, 1, 1),
+ SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5645_DAC1_DIG_VOL,
+ RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv),
+ SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5645_DAC2_DIG_VOL,
+ RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv),
+
+ /* IN1/IN2 Control */
+ SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1,
+ RT5645_BST_SFT1, 8, 0, bst_tlv),
+ SOC_SINGLE_TLV("IN2 Boost", RT5645_IN2_CTRL,
+ RT5645_BST_SFT2, 8, 0, bst_tlv),
+
+ /* INL/INR Volume Control */
+ SOC_DOUBLE_TLV("IN Capture Volume", RT5645_INL1_INR1_VOL,
+ RT5645_INL_VOL_SFT, RT5645_INR_VOL_SFT, 31, 1, in_vol_tlv),
+
+ /* ADC Digital Volume Control */
+ SOC_DOUBLE("ADC Capture Switch", RT5645_STO1_ADC_DIG_VOL,
+ RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_TLV("ADC Capture Volume", RT5645_STO1_ADC_DIG_VOL,
+ RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv),
+ SOC_DOUBLE("Mono ADC Capture Switch", RT5645_MONO_ADC_DIG_VOL,
+ RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5645_MONO_ADC_DIG_VOL,
+ RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv),
+
+ /* ADC Boost Volume Control */
+ SOC_DOUBLE_TLV("STO1 ADC Boost Gain", RT5645_ADC_BST_VOL1,
+ RT5645_STO1_ADC_L_BST_SFT, RT5645_STO1_ADC_R_BST_SFT, 3, 0,
+ adc_bst_tlv),
+ SOC_DOUBLE_TLV("STO2 ADC Boost Gain", RT5645_ADC_BST_VOL1,
+ RT5645_STO2_ADC_L_BST_SFT, RT5645_STO2_ADC_R_BST_SFT, 3, 0,
+ adc_bst_tlv),
+
+ /* I2S2 function select */
+ SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT,
+ 1, 1),
+
+ /* TDM */
+ SOC_ENUM("TDM Adc Slot0 1 Data", rt5645_tdm_adc_slot0_1_enum),
+ SOC_ENUM("TDM Adc Slot2 3 Data", rt5645_tdm_adc_slot2_3_enum),
+ SOC_ENUM("TDM Adc Slot4 5 Data", rt5645_tdm_adc_slot4_5_enum),
+ SOC_ENUM("TDM Adc Slot6 7 Data", rt5645_tdm_adc_slot6_7_enum),
+ SOC_ENUM("TDM IF1 ADC DATA Sel", rt5645_tdm_adc_sel_enum),
+ SOC_SINGLE("TDM IF1_DAC1_L Sel", RT5645_TDM_CTRL_3, 12, 7, 0),
+ SOC_SINGLE("TDM IF1_DAC1_R Sel", RT5645_TDM_CTRL_3, 8, 7, 0),
+ SOC_SINGLE("TDM IF1_DAC2_L Sel", RT5645_TDM_CTRL_3, 4, 7, 0),
+ SOC_SINGLE("TDM IF1_DAC2_R Sel", RT5645_TDM_CTRL_3, 0, 7, 0),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+ int div[] = {2, 3, 4, 6, 8, 12};
+ int idx = -EINVAL, i;
+ int rate, red, bound, temp;
+
+ rate = rt5645->sysclk;
+ red = 3000000 * 12;
+ for (i = 0; i < ARRAY_SIZE(div); i++) {
+ bound = div[i] * 3000000;
+ if (rate > bound)
+ continue;
+ temp = bound - rate;
+ if (temp < red) {
+ red = temp;
+ idx = i;
+ }
+ }
+
+ if (idx < 0)
+ dev_err(codec->dev, "Failed to set DMIC clock\n");
+ else
+ snd_soc_update_bits(codec, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_CLK_MASK, idx << RT5645_DMIC_CLK_SFT);
+ return idx;
+}
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int val;
+
+ val = snd_soc_read(source->codec, RT5645_GLB_CLK);
+ val &= RT5645_SCLK_SRC_MASK;
+ if (val == RT5645_SCLK_SRC_PLL1)
+ return 1;
+ else
+ return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
+ RT5645_M_ADC_L1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5645_STO1_ADC_MIXER,
+ RT5645_M_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_sto1_adc_r_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
+ RT5645_M_ADC_R1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5645_STO1_ADC_MIXER,
+ RT5645_M_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_mono_adc_l_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5645_MONO_ADC_MIXER,
+ RT5645_M_MONO_ADC_L1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5645_MONO_ADC_MIXER,
+ RT5645_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_mono_adc_r_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5645_MONO_ADC_MIXER,
+ RT5645_M_MONO_ADC_R1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5645_MONO_ADC_MIXER,
+ RT5645_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("Stereo ADC Switch", RT5645_AD_DA_MIXER,
+ RT5645_M_ADCMIX_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC1 Switch", RT5645_AD_DA_MIXER,
+ RT5645_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("Stereo ADC Switch", RT5645_AD_DA_MIXER,
+ RT5645_M_ADCMIX_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC1 Switch", RT5645_AD_DA_MIXER,
+ RT5645_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_sto_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_STO_DAC_MIXER,
+ RT5645_M_DAC_L1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_STO_DAC_MIXER,
+ RT5645_M_DAC_L2_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_STO_DAC_MIXER,
+ RT5645_M_DAC_R1_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_sto_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_STO_DAC_MIXER,
+ RT5645_M_DAC_R1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_STO_DAC_MIXER,
+ RT5645_M_DAC_R2_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_STO_DAC_MIXER,
+ RT5645_M_DAC_L1_STO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_mono_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_MONO_DAC_MIXER,
+ RT5645_M_DAC_L1_MONO_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_MONO_DAC_MIXER,
+ RT5645_M_DAC_L2_MONO_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_MONO_DAC_MIXER,
+ RT5645_M_DAC_R2_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_mono_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_MONO_DAC_MIXER,
+ RT5645_M_DAC_R1_MONO_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_MONO_DAC_MIXER,
+ RT5645_M_DAC_R2_MONO_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_MONO_DAC_MIXER,
+ RT5645_M_DAC_L2_MONO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_dig_l_mix[] = {
+ SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5645_DIG_MIXER,
+ RT5645_M_STO_L_DAC_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_DIG_MIXER,
+ RT5645_M_DAC_L2_DAC_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_DIG_MIXER,
+ RT5645_M_DAC_R2_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_dig_r_mix[] = {
+ SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5645_DIG_MIXER,
+ RT5645_M_STO_R_DAC_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_DIG_MIXER,
+ RT5645_M_DAC_R2_DAC_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_DIG_MIXER,
+ RT5645_M_DAC_L2_DAC_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5645_rec_l_mix[] = {
+ SOC_DAPM_SINGLE("HPOL Switch", RT5645_REC_L2_MIXER,
+ RT5645_M_HP_L_RM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INL Switch", RT5645_REC_L2_MIXER,
+ RT5645_M_IN_L_RM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5645_REC_L2_MIXER,
+ RT5645_M_BST2_RM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5645_REC_L2_MIXER,
+ RT5645_M_BST1_RM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("OUT MIXL Switch", RT5645_REC_L2_MIXER,
+ RT5645_M_OM_L_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_rec_r_mix[] = {
+ SOC_DAPM_SINGLE("HPOR Switch", RT5645_REC_R2_MIXER,
+ RT5645_M_HP_R_RM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INR Switch", RT5645_REC_R2_MIXER,
+ RT5645_M_IN_R_RM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5645_REC_R2_MIXER,
+ RT5645_M_BST2_RM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5645_REC_R2_MIXER,
+ RT5645_M_BST1_RM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("OUT MIXR Switch", RT5645_REC_R2_MIXER,
+ RT5645_M_OM_R_RM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_spk_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_SPK_L_MIXER,
+ RT5645_M_DAC_L1_SM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_SPK_L_MIXER,
+ RT5645_M_DAC_L2_SM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INL Switch", RT5645_SPK_L_MIXER,
+ RT5645_M_IN_L_SM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5645_SPK_L_MIXER,
+ RT5645_M_BST1_L_SM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_spk_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_SPK_R_MIXER,
+ RT5645_M_DAC_R1_SM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_SPK_R_MIXER,
+ RT5645_M_DAC_R2_SM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INR Switch", RT5645_SPK_R_MIXER,
+ RT5645_M_IN_R_SM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5645_SPK_R_MIXER,
+ RT5645_M_BST2_R_SM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_out_l_mix[] = {
+ SOC_DAPM_SINGLE("BST1 Switch", RT5645_OUT_L1_MIXER,
+ RT5645_M_BST1_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INL Switch", RT5645_OUT_L1_MIXER,
+ RT5645_M_IN_L_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_OUT_L1_MIXER,
+ RT5645_M_DAC_L2_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_OUT_L1_MIXER,
+ RT5645_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_out_r_mix[] = {
+ SOC_DAPM_SINGLE("BST2 Switch", RT5645_OUT_R1_MIXER,
+ RT5645_M_BST2_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INR Switch", RT5645_OUT_R1_MIXER,
+ RT5645_M_IN_R_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_OUT_R1_MIXER,
+ RT5645_M_DAC_R2_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_OUT_R1_MIXER,
+ RT5645_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_spo_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_SPO_MIXER,
+ RT5645_M_DAC_R1_SPM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_SPO_MIXER,
+ RT5645_M_DAC_L1_SPM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("SPKVOL R Switch", RT5645_SPO_MIXER,
+ RT5645_M_SV_R_SPM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("SPKVOL L Switch", RT5645_SPO_MIXER,
+ RT5645_M_SV_L_SPM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_spo_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_SPO_MIXER,
+ RT5645_M_DAC_R1_SPM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("SPKVOL R Switch", RT5645_SPO_MIXER,
+ RT5645_M_SV_R_SPM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_hpo_mix[] = {
+ SOC_DAPM_SINGLE("DAC1 Switch", RT5645_HPO_MIXER,
+ RT5645_M_DAC1_HM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("HPVOL Switch", RT5645_HPO_MIXER,
+ RT5645_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_hpvoll_mix[] = {
+ SOC_DAPM_SINGLE("DAC1 Switch", RT5645_HPOMIXL_CTRL,
+ RT5645_M_DAC1_HV_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC2 Switch", RT5645_HPOMIXL_CTRL,
+ RT5645_M_DAC2_HV_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INL Switch", RT5645_HPOMIXL_CTRL,
+ RT5645_M_IN_HV_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5645_HPOMIXL_CTRL,
+ RT5645_M_BST1_HV_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_hpvolr_mix[] = {
+ SOC_DAPM_SINGLE("DAC1 Switch", RT5645_HPOMIXR_CTRL,
+ RT5645_M_DAC1_HV_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC2 Switch", RT5645_HPOMIXR_CTRL,
+ RT5645_M_DAC2_HV_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INR Switch", RT5645_HPOMIXR_CTRL,
+ RT5645_M_IN_HV_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5645_HPOMIXR_CTRL,
+ RT5645_M_BST2_HV_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_lout_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_LOUT_MIXER,
+ RT5645_M_DAC_L1_LM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_LOUT_MIXER,
+ RT5645_M_DAC_R1_LM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("OUTMIX L Switch", RT5645_LOUT_MIXER,
+ RT5645_M_OV_L_LM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("OUTMIX R Switch", RT5645_LOUT_MIXER,
+ RT5645_M_OV_R_LM_SFT, 1, 1),
+};
+
+/*DAC1 L/R source*/ /* MX-29 [9:8] [11:10] */
+static const char * const rt5645_dac1_src[] = {
+ "IF1 DAC", "IF2 DAC", "IF3 DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_dac1l_enum, RT5645_AD_DA_MIXER,
+ RT5645_DAC1_L_SEL_SFT, rt5645_dac1_src);
+
+static const struct snd_kcontrol_new rt5645_dac1l_mux =
+ SOC_DAPM_ENUM("DAC1 L source", rt5645_dac1l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_dac1r_enum, RT5645_AD_DA_MIXER,
+ RT5645_DAC1_R_SEL_SFT, rt5645_dac1_src);
+
+static const struct snd_kcontrol_new rt5645_dac1r_mux =
+ SOC_DAPM_ENUM("DAC1 R source", rt5645_dac1r_enum);
+
+/*DAC2 L/R source*/ /* MX-1B [6:4] [2:0] */
+static const char * const rt5645_dac12_src[] = {
+ "IF1 DAC", "IF2 DAC", "IF3 DAC", "Mono ADC", "VAD_ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_dac2l_enum, RT5645_DAC_CTRL,
+ RT5645_DAC2_L_SEL_SFT, rt5645_dac12_src);
+
+static const struct snd_kcontrol_new rt5645_dac_l2_mux =
+ SOC_DAPM_ENUM("DAC2 L source", rt5645_dac2l_enum);
+
+static const char * const rt5645_dacr2_src[] = {
+ "IF1 DAC", "IF2 DAC", "IF3 DAC", "Mono ADC", "Haptic"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_dac2r_enum, RT5645_DAC_CTRL,
+ RT5645_DAC2_R_SEL_SFT, rt5645_dacr2_src);
+
+static const struct snd_kcontrol_new rt5645_dac_r2_mux =
+ SOC_DAPM_ENUM("DAC2 R source", rt5645_dac2r_enum);
+
+
+/* INL/R source */
+static const char * const rt5645_inl_src[] = {
+ "IN2P", "MonoP"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_inl_enum, RT5645_INL1_INR1_VOL,
+ RT5645_INL_SEL_SFT, rt5645_inl_src);
+
+static const struct snd_kcontrol_new rt5645_inl_mux =
+ SOC_DAPM_ENUM("INL source", rt5645_inl_enum);
+
+static const char * const rt5645_inr_src[] = {
+ "IN2N", "MonoN"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_inr_enum, RT5645_INL1_INR1_VOL,
+ RT5645_INR_SEL_SFT, rt5645_inr_src);
+
+static const struct snd_kcontrol_new rt5645_inr_mux =
+ SOC_DAPM_ENUM("INR source", rt5645_inr_enum);
+
+/* Stereo1 ADC source */
+/* MX-27 [12] */
+static const char * const rt5645_stereo_adc1_src[] = {
+ "DAC MIX", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_stereo1_adc1_enum, RT5645_STO1_ADC_MIXER,
+ RT5645_ADC_1_SRC_SFT, rt5645_stereo_adc1_src);
+
+static const struct snd_kcontrol_new rt5645_sto_adc1_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC1 Mux", rt5645_stereo1_adc1_enum);
+
+/* MX-27 [11] */
+static const char * const rt5645_stereo_adc2_src[] = {
+ "DAC MIX", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_stereo1_adc2_enum, RT5645_STO1_ADC_MIXER,
+ RT5645_ADC_2_SRC_SFT, rt5645_stereo_adc2_src);
+
+static const struct snd_kcontrol_new rt5645_sto_adc2_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC2 Mux", rt5645_stereo1_adc2_enum);
+
+/* MX-27 [8] */
+static const char * const rt5645_stereo_dmic_src[] = {
+ "DMIC1", "DMIC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_stereo1_dmic_enum, RT5645_STO1_ADC_MIXER,
+ RT5645_DMIC_SRC_SFT, rt5645_stereo_dmic_src);
+
+static const struct snd_kcontrol_new rt5645_sto1_dmic_mux =
+ SOC_DAPM_ENUM("Stereo1 DMIC source", rt5645_stereo1_dmic_enum);
+
+/* Mono ADC source */
+/* MX-28 [12] */
+static const char * const rt5645_mono_adc_l1_src[] = {
+ "Mono DAC MIXL", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_mono_adc_l1_enum, RT5645_MONO_ADC_MIXER,
+ RT5645_MONO_ADC_L1_SRC_SFT, rt5645_mono_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5645_mono_adc_l1_mux =
+ SOC_DAPM_ENUM("Mono ADC1 left source", rt5645_mono_adc_l1_enum);
+/* MX-28 [11] */
+static const char * const rt5645_mono_adc_l2_src[] = {
+ "Mono DAC MIXL", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_mono_adc_l2_enum, RT5645_MONO_ADC_MIXER,
+ RT5645_MONO_ADC_L2_SRC_SFT, rt5645_mono_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5645_mono_adc_l2_mux =
+ SOC_DAPM_ENUM("Mono ADC2 left source", rt5645_mono_adc_l2_enum);
+
+/* MX-28 [8] */
+static const char * const rt5645_mono_dmic_src[] = {
+ "DMIC1", "DMIC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_mono_dmic_l_enum, RT5645_MONO_ADC_MIXER,
+ RT5645_MONO_DMIC_L_SRC_SFT, rt5645_mono_dmic_src);
+
+static const struct snd_kcontrol_new rt5645_mono_dmic_l_mux =
+ SOC_DAPM_ENUM("Mono DMIC left source", rt5645_mono_dmic_l_enum);
+/* MX-28 [1:0] */
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_mono_dmic_r_enum, RT5645_MONO_ADC_MIXER,
+ RT5645_MONO_DMIC_R_SRC_SFT, rt5645_mono_dmic_src);
+
+static const struct snd_kcontrol_new rt5645_mono_dmic_r_mux =
+ SOC_DAPM_ENUM("Mono DMIC Right source", rt5645_mono_dmic_r_enum);
+/* MX-28 [4] */
+static const char * const rt5645_mono_adc_r1_src[] = {
+ "Mono DAC MIXR", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_mono_adc_r1_enum, RT5645_MONO_ADC_MIXER,
+ RT5645_MONO_ADC_R1_SRC_SFT, rt5645_mono_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5645_mono_adc_r1_mux =
+ SOC_DAPM_ENUM("Mono ADC1 right source", rt5645_mono_adc_r1_enum);
+/* MX-28 [3] */
+static const char * const rt5645_mono_adc_r2_src[] = {
+ "Mono DAC MIXR", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_mono_adc_r2_enum, RT5645_MONO_ADC_MIXER,
+ RT5645_MONO_ADC_R2_SRC_SFT, rt5645_mono_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5645_mono_adc_r2_mux =
+ SOC_DAPM_ENUM("Mono ADC2 right source", rt5645_mono_adc_r2_enum);
+
+/* MX-77 [9:8] */
+static const char * const rt5645_if1_adc_in_src[] = {
+ "IF_ADC1", "IF_ADC2", "VAD_ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_if1_adc_in_enum, RT5645_TDM_CTRL_1,
+ RT5645_IF1_ADC_IN_SFT, rt5645_if1_adc_in_src);
+
+static const struct snd_kcontrol_new rt5645_if1_adc_in_mux =
+ SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum);
+
+/* MX-2F [13:12] */
+static const char * const rt5645_if2_adc_in_src[] = {
+ "IF_ADC1", "IF_ADC2", "VAD_ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_if2_adc_in_enum, RT5645_DIG_INF1_DATA,
+ RT5645_IF2_ADC_IN_SFT, rt5645_if2_adc_in_src);
+
+static const struct snd_kcontrol_new rt5645_if2_adc_in_mux =
+ SOC_DAPM_ENUM("IF2 ADC IN source", rt5645_if2_adc_in_enum);
+
+/* MX-2F [1:0] */
+static const char * const rt5645_if3_adc_in_src[] = {
+ "IF_ADC1", "IF_ADC2", "VAD_ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_if3_adc_in_enum, RT5645_DIG_INF1_DATA,
+ RT5645_IF3_ADC_IN_SFT, rt5645_if3_adc_in_src);
+
+static const struct snd_kcontrol_new rt5645_if3_adc_in_mux =
+ SOC_DAPM_ENUM("IF3 ADC IN source", rt5645_if3_adc_in_enum);
+
+/* MX-31 [15] [13] [11] [9] */
+static const char * const rt5645_pdm_src[] = {
+ "Mono DAC", "Stereo DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_pdm1_l_enum, RT5645_PDM_OUT_CTRL,
+ RT5645_PDM1_L_SFT, rt5645_pdm_src);
+
+static const struct snd_kcontrol_new rt5645_pdm1_l_mux =
+ SOC_DAPM_ENUM("PDM1 L source", rt5645_pdm1_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_pdm1_r_enum, RT5645_PDM_OUT_CTRL,
+ RT5645_PDM1_R_SFT, rt5645_pdm_src);
+
+static const struct snd_kcontrol_new rt5645_pdm1_r_mux =
+ SOC_DAPM_ENUM("PDM1 R source", rt5645_pdm1_r_enum);
+
+/* MX-9D [9:8] */
+static const char * const rt5645_vad_adc_src[] = {
+ "Sto1 ADC L", "Mono ADC L", "Mono ADC R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5645_vad_adc_enum, RT5645_VAD_CTRL4,
+ RT5645_VAD_SEL_SFT, rt5645_vad_adc_src);
+
+static const struct snd_kcontrol_new rt5645_vad_adc_mux =
+ SOC_DAPM_ENUM("VAD ADC source", rt5645_vad_adc_enum);
+
+static const struct snd_kcontrol_new spk_l_vol_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_SPK_VOL,
+ RT5645_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new spk_r_vol_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_SPK_VOL,
+ RT5645_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hp_l_vol_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_HP_VOL,
+ RT5645_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hp_r_vol_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_HP_VOL,
+ RT5645_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new pdm1_l_vol_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_PDM_OUT_CTRL,
+ RT5645_M_PDM1_L, 1, 1);
+
+static const struct snd_kcontrol_new pdm1_r_vol_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_PDM_OUT_CTRL,
+ RT5645_M_PDM1_R, 1, 1);
+
+static void hp_amp_power(struct snd_soc_codec *codec, int on)
+{
+ static int hp_amp_power_count;
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+
+ if (on) {
+ if (hp_amp_power_count <= 0) {
+ /* depop parameters */
+ snd_soc_update_bits(codec, RT5645_DEPOP_M2,
+ RT5645_DEPOP_MASK, RT5645_DEPOP_MAN);
+ snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ RT5645_HP_DCC_INT1, 0x9f01);
+ mdelay(150);
+ /* headphone amp power on */
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_FV1 | RT5645_PWR_FV2 , 0);
+ snd_soc_update_bits(codec, RT5645_PWR_VOL,
+ RT5645_PWR_HV_L | RT5645_PWR_HV_R,
+ RT5645_PWR_HV_L | RT5645_PWR_HV_R);
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+ RT5645_PWR_HA,
+ RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+ RT5645_PWR_HA);
+ mdelay(5);
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_FV1 | RT5645_PWR_FV2,
+ RT5645_PWR_FV1 | RT5645_PWR_FV2);
+
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_HP_CO_MASK | RT5645_HP_SG_MASK,
+ RT5645_HP_CO_EN | RT5645_HP_SG_EN);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ 0x14, 0x1aaa);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ 0x24, 0x0430);
+ }
+ hp_amp_power_count++;
+ } else {
+ hp_amp_power_count--;
+ if (hp_amp_power_count <= 0) {
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
+ RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
+ RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
+ /* headphone amp power down */
+ snd_soc_write(codec, RT5645_DEPOP_M1, 0x0000);
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+ RT5645_PWR_HA, 0);
+ }
+ }
+}
+
+static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ hp_amp_power(codec, 1);
+ /* headphone unmute sequence */
+ snd_soc_update_bits(codec, RT5645_DEPOP_M3, RT5645_CP_FQ1_MASK |
+ RT5645_CP_FQ2_MASK | RT5645_CP_FQ3_MASK,
+ (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
+ (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
+ (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+ regmap_write(rt5645->regmap,
+ RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_RSTN_MASK, RT5645_RSTN_EN);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK |
+ RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS |
+ RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
+ msleep(40);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
+ RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
+ RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ /* headphone mute sequence */
+ snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+ RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+ RT5645_CP_FQ3_MASK,
+ (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
+ (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
+ (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+ regmap_write(rt5645->regmap,
+ RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_HP_SG_MASK, RT5645_HP_SG_EN);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_RSTP_MASK, RT5645_RSTP_EN);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK |
+ RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS |
+ RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
+ msleep(30);
+ hp_amp_power(codec, 0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5645_spk_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_POST_PMU:
+ snd_soc_update_bits(codec, RT5645_PWR_DIG1,
+ RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
+ RT5645_PWR_CLS_D_L,
+ RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
+ RT5645_PWR_CLS_D_L);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5645_PWR_DIG1,
+ RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
+ RT5645_PWR_CLS_D_L, 0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5645_lout_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_POST_PMU:
+ hp_amp_power(codec, 1);
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_LM, RT5645_PWR_LM);
+ snd_soc_update_bits(codec, RT5645_LOUT1,
+ RT5645_L_MUTE | RT5645_R_MUTE, 0);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5645_LOUT1,
+ RT5645_L_MUTE | RT5645_R_MUTE,
+ RT5645_L_MUTE | RT5645_R_MUTE);
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_LM, 0);
+ hp_amp_power(codec, 0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5645_bst2_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_POST_PMU:
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG2,
+ RT5645_PWR_BST2_P, RT5645_PWR_BST2_P);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG2,
+ RT5645_PWR_BST2_P, 0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("LDO2", RT5645_PWR_MIXER,
+ RT5645_PWR_LDO2_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLL1", RT5645_PWR_ANLG2,
+ RT5645_PWR_PLL_BIT, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("JD Power", RT5645_PWR_ANLG2,
+ RT5645_PWR_JD1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL,
+ RT5645_PWR_MIC_DET_BIT, 0, NULL, 0),
+
+ /* Input Side */
+ /* micbias */
+ SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2,
+ RT5645_PWR_MB1_BIT, 0),
+ SND_SOC_DAPM_MICBIAS("micbias2", RT5645_PWR_ANLG2,
+ RT5645_PWR_MB2_BIT, 0),
+ /* Input Lines */
+ SND_SOC_DAPM_INPUT("DMIC L1"),
+ SND_SOC_DAPM_INPUT("DMIC R1"),
+ SND_SOC_DAPM_INPUT("DMIC L2"),
+ SND_SOC_DAPM_INPUT("DMIC R2"),
+
+ SND_SOC_DAPM_INPUT("IN1P"),
+ SND_SOC_DAPM_INPUT("IN1N"),
+ SND_SOC_DAPM_INPUT("IN2P"),
+ SND_SOC_DAPM_INPUT("IN2N"),
+
+ SND_SOC_DAPM_INPUT("Haptic Generator"),
+
+ SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+ set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5645_DMIC_CTRL1,
+ RT5645_DMIC_1_EN_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5645_DMIC_CTRL1,
+ RT5645_DMIC_2_EN_SFT, 0, NULL, 0),
+ /* Boost */
+ SND_SOC_DAPM_PGA("BST1", RT5645_PWR_ANLG2,
+ RT5645_PWR_BST1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("BST2", RT5645_PWR_ANLG2,
+ RT5645_PWR_BST2_BIT, 0, NULL, 0, rt5645_bst2_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ /* Input Volume */
+ SND_SOC_DAPM_PGA("INL VOL", RT5645_PWR_VOL,
+ RT5645_PWR_IN_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INR VOL", RT5645_PWR_VOL,
+ RT5645_PWR_IN_R_BIT, 0, NULL, 0),
+ /* REC Mixer */
+ SND_SOC_DAPM_MIXER("RECMIXL", RT5645_PWR_MIXER, RT5645_PWR_RM_L_BIT,
+ 0, rt5645_rec_l_mix, ARRAY_SIZE(rt5645_rec_l_mix)),
+ SND_SOC_DAPM_MIXER("RECMIXR", RT5645_PWR_MIXER, RT5645_PWR_RM_R_BIT,
+ 0, rt5645_rec_r_mix, ARRAY_SIZE(rt5645_rec_r_mix)),
+ /* ADCs */
+ SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_SUPPLY("ADC L power", RT5645_PWR_DIG1,
+ RT5645_PWR_ADC_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC R power", RT5645_PWR_DIG1,
+ RT5645_PWR_ADC_R_BIT, 0, NULL, 0),
+
+ /* ADC Mux */
+ SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_sto1_dmic_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_sto_adc2_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_sto_adc2_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_sto_adc1_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_sto_adc1_mux),
+ SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_mono_dmic_l_mux),
+ SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_mono_dmic_r_mux),
+ SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_mono_adc_l2_mux),
+ SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_mono_adc_l1_mux),
+ SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_mono_adc_r1_mux),
+ SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_mono_adc_r2_mux),
+ /* ADC Mixer */
+
+ SND_SOC_DAPM_SUPPLY_S("adc stereo1 filter", 1, RT5645_PWR_DIG2,
+ RT5645_PWR_ADC_S1F_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("adc stereo2 filter", 1, RT5645_PWR_DIG2,
+ RT5645_PWR_ADC_S2F_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER_E("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5645_sto1_adc_l_mix, ARRAY_SIZE(rt5645_sto1_adc_l_mix),
+ NULL, 0),
+ SND_SOC_DAPM_MIXER_E("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5645_sto1_adc_r_mix, ARRAY_SIZE(rt5645_sto1_adc_r_mix),
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("adc mono left filter", 1, RT5645_PWR_DIG2,
+ RT5645_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER_E("Mono ADC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5645_mono_adc_l_mix, ARRAY_SIZE(rt5645_mono_adc_l_mix),
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("adc mono right filter", 1, RT5645_PWR_DIG2,
+ RT5645_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER_E("Mono ADC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5645_mono_adc_r_mix, ARRAY_SIZE(rt5645_mono_adc_r_mix),
+ NULL, 0),
+
+ /* ADC PGA */
+ SND_SOC_DAPM_PGA("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("VAD_ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* IF1 2 Mux */
+ SND_SOC_DAPM_MUX("IF1 ADC Mux", SND_SOC_NOPM,
+ 0, 0, &rt5645_if1_adc_in_mux),
+ SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM,
+ 0, 0, &rt5645_if2_adc_in_mux),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_SUPPLY("I2S1", RT5645_PWR_DIG1,
+ RT5645_PWR_I2S1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("I2S2", RT5645_PWR_DIG1,
+ RT5645_PWR_I2S2_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Digital Interface Select */
+ SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM,
+ 0, 0, &rt5645_vad_adc_mux),
+
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Output Side */
+ /* DAC mixer before sound effect */
+ SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+ rt5645_dac_l_mix, ARRAY_SIZE(rt5645_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+ rt5645_dac_r_mix, ARRAY_SIZE(rt5645_dac_r_mix)),
+
+ /* DAC2 channel Mux */
+ SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac_l2_mux),
+ SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac_r2_mux),
+ SND_SOC_DAPM_PGA("DAC L2 Volume", RT5645_PWR_DIG1,
+ RT5645_PWR_DAC_L2_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DAC R2 Volume", RT5645_PWR_DIG1,
+ RT5645_PWR_DAC_R2_BIT, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("DAC1 L Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac1l_mux),
+ SND_SOC_DAPM_MUX("DAC1 R Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac1r_mux),
+
+ /* DAC Mixer */
+ SND_SOC_DAPM_SUPPLY_S("dac stereo1 filter", 1, RT5645_PWR_DIG2,
+ RT5645_PWR_DAC_S1F_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("dac mono left filter", 1, RT5645_PWR_DIG2,
+ RT5645_PWR_DAC_MF_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("dac mono right filter", 1, RT5645_PWR_DIG2,
+ RT5645_PWR_DAC_MF_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5645_sto_dac_l_mix, ARRAY_SIZE(rt5645_sto_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5645_sto_dac_r_mix, ARRAY_SIZE(rt5645_sto_dac_r_mix)),
+ SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5645_mono_dac_l_mix, ARRAY_SIZE(rt5645_mono_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5645_mono_dac_r_mix, ARRAY_SIZE(rt5645_mono_dac_r_mix)),
+ SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5645_dig_l_mix, ARRAY_SIZE(rt5645_dig_l_mix)),
+ SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5645_dig_r_mix, ARRAY_SIZE(rt5645_dig_r_mix)),
+
+ /* DACs */
+ SND_SOC_DAPM_DAC("DAC L1", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_L1_BIT,
+ 0),
+ SND_SOC_DAPM_DAC("DAC L2", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_L2_BIT,
+ 0),
+ SND_SOC_DAPM_DAC("DAC R1", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_R1_BIT,
+ 0),
+ SND_SOC_DAPM_DAC("DAC R2", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_R2_BIT,
+ 0),
+ /* OUT Mixer */
+ SND_SOC_DAPM_MIXER("SPK MIXL", RT5645_PWR_MIXER, RT5645_PWR_SM_L_BIT,
+ 0, rt5645_spk_l_mix, ARRAY_SIZE(rt5645_spk_l_mix)),
+ SND_SOC_DAPM_MIXER("SPK MIXR", RT5645_PWR_MIXER, RT5645_PWR_SM_R_BIT,
+ 0, rt5645_spk_r_mix, ARRAY_SIZE(rt5645_spk_r_mix)),
+ SND_SOC_DAPM_MIXER("OUT MIXL", RT5645_PWR_MIXER, RT5645_PWR_OM_L_BIT,
+ 0, rt5645_out_l_mix, ARRAY_SIZE(rt5645_out_l_mix)),
+ SND_SOC_DAPM_MIXER("OUT MIXR", RT5645_PWR_MIXER, RT5645_PWR_OM_R_BIT,
+ 0, rt5645_out_r_mix, ARRAY_SIZE(rt5645_out_r_mix)),
+ /* Ouput Volume */
+ SND_SOC_DAPM_SWITCH("SPKVOL L", RT5645_PWR_VOL, RT5645_PWR_SV_L_BIT, 0,
+ &spk_l_vol_control),
+ SND_SOC_DAPM_SWITCH("SPKVOL R", RT5645_PWR_VOL, RT5645_PWR_SV_R_BIT, 0,
+ &spk_r_vol_control),
+ SND_SOC_DAPM_MIXER("HPOVOL MIXL", RT5645_PWR_VOL, RT5645_PWR_HV_L_BIT,
+ 0, rt5645_hpvoll_mix, ARRAY_SIZE(rt5645_hpvoll_mix)),
+ SND_SOC_DAPM_MIXER("HPOVOL MIXR", RT5645_PWR_VOL, RT5645_PWR_HV_R_BIT,
+ 0, rt5645_hpvolr_mix, ARRAY_SIZE(rt5645_hpvolr_mix)),
+ SND_SOC_DAPM_SUPPLY("HPOVOL MIXL Power", RT5645_PWR_MIXER,
+ RT5645_PWR_HM_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("HPOVOL MIXR Power", RT5645_PWR_MIXER,
+ RT5645_PWR_HM_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SWITCH("HPOVOL L", SND_SOC_NOPM, 0, 0, &hp_l_vol_control),
+ SND_SOC_DAPM_SWITCH("HPOVOL R", SND_SOC_NOPM, 0, 0, &hp_r_vol_control),
+
+ /* HPO/LOUT/Mono Mixer */
+ SND_SOC_DAPM_MIXER("SPOL MIX", SND_SOC_NOPM, 0, 0, rt5645_spo_l_mix,
+ ARRAY_SIZE(rt5645_spo_l_mix)),
+ SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0, 0, rt5645_spo_r_mix,
+ ARRAY_SIZE(rt5645_spo_r_mix)),
+ SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0, rt5645_hpo_mix,
+ ARRAY_SIZE(rt5645_hpo_mix)),
+ SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0, rt5645_lout_mix,
+ ARRAY_SIZE(rt5645_lout_mix)),
+
+ SND_SOC_DAPM_PGA_S("HP amp", 1, SND_SOC_NOPM, 0, 0, rt5645_hp_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0, rt5645_lout_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_S("SPK amp", 2, SND_SOC_NOPM, 0, 0, rt5645_spk_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+ /* PDM */
+ SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5645_PWR_DIG2, RT5645_PWR_PDM1_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_MUX("PDM1 L Mux", SND_SOC_NOPM, 0, 0, &rt5645_pdm1_l_mux),
+ SND_SOC_DAPM_MUX("PDM1 R Mux", SND_SOC_NOPM, 0, 0, &rt5645_pdm1_r_mux),
+
+ SND_SOC_DAPM_SWITCH("PDM1 L", SND_SOC_NOPM, 0, 0, &pdm1_l_vol_control),
+ SND_SOC_DAPM_SWITCH("PDM1 R", SND_SOC_NOPM, 0, 0, &pdm1_r_vol_control),
+
+ /* Output Lines */
+ SND_SOC_DAPM_OUTPUT("HPOL"),
+ SND_SOC_DAPM_OUTPUT("HPOR"),
+ SND_SOC_DAPM_OUTPUT("LOUTL"),
+ SND_SOC_DAPM_OUTPUT("LOUTR"),
+ SND_SOC_DAPM_OUTPUT("PDM1L"),
+ SND_SOC_DAPM_OUTPUT("PDM1R"),
+ SND_SOC_DAPM_OUTPUT("SPOL"),
+ SND_SOC_DAPM_OUTPUT("SPOR"),
+};
+
+static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
+ { "IN1P", NULL, "LDO2" },
+ { "IN2P", NULL, "LDO2" },
+
+ { "DMIC1", NULL, "DMIC L1" },
+ { "DMIC1", NULL, "DMIC R1" },
+ { "DMIC2", NULL, "DMIC L2" },
+ { "DMIC2", NULL, "DMIC R2" },
+
+ { "BST1", NULL, "IN1P" },
+ { "BST1", NULL, "IN1N" },
+ { "BST1", NULL, "JD Power" },
+ { "BST1", NULL, "Mic Det Power" },
+ { "BST2", NULL, "IN2P" },
+ { "BST2", NULL, "IN2N" },
+
+ { "INL VOL", NULL, "IN2P" },
+ { "INR VOL", NULL, "IN2N" },
+
+ { "RECMIXL", "HPOL Switch", "HPOL" },
+ { "RECMIXL", "INL Switch", "INL VOL" },
+ { "RECMIXL", "BST2 Switch", "BST2" },
+ { "RECMIXL", "BST1 Switch", "BST1" },
+ { "RECMIXL", "OUT MIXL Switch", "OUT MIXL" },
+
+ { "RECMIXR", "HPOR Switch", "HPOR" },
+ { "RECMIXR", "INR Switch", "INR VOL" },
+ { "RECMIXR", "BST2 Switch", "BST2" },
+ { "RECMIXR", "BST1 Switch", "BST1" },
+ { "RECMIXR", "OUT MIXR Switch", "OUT MIXR" },
+
+ { "ADC L", NULL, "RECMIXL" },
+ { "ADC L", NULL, "ADC L power" },
+ { "ADC R", NULL, "RECMIXR" },
+ { "ADC R", NULL, "ADC R power" },
+
+ {"DMIC L1", NULL, "DMIC CLK"},
+ {"DMIC L1", NULL, "DMIC1 Power"},
+ {"DMIC R1", NULL, "DMIC CLK"},
+ {"DMIC R1", NULL, "DMIC1 Power"},
+ {"DMIC L2", NULL, "DMIC CLK"},
+ {"DMIC L2", NULL, "DMIC2 Power"},
+ {"DMIC R2", NULL, "DMIC CLK"},
+ {"DMIC R2", NULL, "DMIC2 Power"},
+
+ { "Stereo1 DMIC Mux", "DMIC1", "DMIC1" },
+ { "Stereo1 DMIC Mux", "DMIC2", "DMIC2" },
+
+ { "Mono DMIC L Mux", "DMIC1", "DMIC L1" },
+ { "Mono DMIC L Mux", "DMIC2", "DMIC L2" },
+
+ { "Mono DMIC R Mux", "DMIC1", "DMIC R1" },
+ { "Mono DMIC R Mux", "DMIC2", "DMIC R2" },
+
+ { "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" },
+ { "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
+ { "Stereo1 ADC L1 Mux", "ADC", "ADC L" },
+ { "Stereo1 ADC L1 Mux", "DAC MIX", "DAC MIXL" },
+
+ { "Stereo1 ADC R1 Mux", "ADC", "ADC R" },
+ { "Stereo1 ADC R1 Mux", "DAC MIX", "DAC MIXR" },
+ { "Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC Mux" },
+ { "Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR" },
+
+ { "Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux" },
+ { "Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+ { "Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+ { "Mono ADC L1 Mux", "ADC", "ADC L" },
+
+ { "Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+ { "Mono ADC R1 Mux", "ADC", "ADC R" },
+ { "Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux" },
+ { "Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+
+ { "Sto1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux" },
+ { "Sto1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux" },
+ { "Sto1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux" },
+ { "Sto1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux" },
+
+ { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
+ { "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" },
+ { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+ { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
+ { "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" },
+ { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+ { "Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux" },
+ { "Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux" },
+ { "Mono ADC MIXL", NULL, "adc mono left filter" },
+ { "adc mono left filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+ { "Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux" },
+ { "Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux" },
+ { "Mono ADC MIXR", NULL, "adc mono right filter" },
+ { "adc mono right filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+ { "VAD ADC Mux", "Sto1 ADC L", "Stereo1 ADC MIXL" },
+ { "VAD ADC Mux", "Mono ADC L", "Mono ADC MIXL" },
+ { "VAD ADC Mux", "Mono ADC R", "Mono ADC MIXR" },
+
+ { "IF_ADC1", NULL, "Stereo1 ADC MIXL" },
+ { "IF_ADC1", NULL, "Stereo1 ADC MIXR" },
+ { "IF_ADC2", NULL, "Mono ADC MIXL" },
+ { "IF_ADC2", NULL, "Mono ADC MIXR" },
+ { "VAD_ADC", NULL, "VAD ADC Mux" },
+
+ { "IF1 ADC Mux", "IF_ADC1", "IF_ADC1" },
+ { "IF1 ADC Mux", "IF_ADC2", "IF_ADC2" },
+ { "IF1 ADC Mux", "VAD_ADC", "VAD_ADC" },
+
+ { "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" },
+ { "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" },
+ { "IF2 ADC Mux", "VAD_ADC", "VAD_ADC" },
+
+ { "IF1 ADC", NULL, "I2S1" },
+ { "IF1 ADC", NULL, "IF1 ADC Mux" },
+ { "IF2 ADC", NULL, "I2S2" },
+ { "IF2 ADC", NULL, "IF2 ADC Mux" },
+
+ { "AIF1TX", NULL, "IF1 ADC" },
+ { "AIF1TX", NULL, "IF2 ADC" },
+ { "AIF2TX", NULL, "IF2 ADC" },
+
+ { "IF1 DAC1", NULL, "AIF1RX" },
+ { "IF1 DAC2", NULL, "AIF1RX" },
+ { "IF2 DAC", NULL, "AIF2RX" },
+
+ { "IF1 DAC1", NULL, "I2S1" },
+ { "IF1 DAC2", NULL, "I2S1" },
+ { "IF2 DAC", NULL, "I2S2" },
+
+ { "IF1 DAC2 L", NULL, "IF1 DAC2" },
+ { "IF1 DAC2 R", NULL, "IF1 DAC2" },
+ { "IF1 DAC1 L", NULL, "IF1 DAC1" },
+ { "IF1 DAC1 R", NULL, "IF1 DAC1" },
+ { "IF2 DAC L", NULL, "IF2 DAC" },
+ { "IF2 DAC R", NULL, "IF2 DAC" },
+
+ { "DAC1 L Mux", "IF1 DAC", "IF1 DAC1 L" },
+ { "DAC1 L Mux", "IF2 DAC", "IF2 DAC L" },
+
+ { "DAC1 R Mux", "IF1 DAC", "IF1 DAC1 R" },
+ { "DAC1 R Mux", "IF2 DAC", "IF2 DAC R" },
+
+ { "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" },
+ { "DAC1 MIXL", "DAC1 Switch", "DAC1 L Mux" },
+ { "DAC1 MIXL", NULL, "dac stereo1 filter" },
+ { "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR" },
+ { "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" },
+ { "DAC1 MIXR", NULL, "dac stereo1 filter" },
+
+ { "DAC L2 Mux", "IF1 DAC", "IF1 DAC2 L" },
+ { "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" },
+ { "DAC L2 Mux", "Mono ADC", "Mono ADC MIXL" },
+ { "DAC L2 Mux", "VAD_ADC", "VAD_ADC" },
+ { "DAC L2 Volume", NULL, "DAC L2 Mux" },
+ { "DAC L2 Volume", NULL, "dac mono left filter" },
+
+ { "DAC R2 Mux", "IF1 DAC", "IF1 DAC2 R" },
+ { "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" },
+ { "DAC R2 Mux", "Mono ADC", "Mono ADC MIXR" },
+ { "DAC R2 Mux", "Haptic", "Haptic Generator" },
+ { "DAC R2 Volume", NULL, "DAC R2 Mux" },
+ { "DAC R2 Volume", NULL, "dac mono right filter" },
+
+ { "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+ { "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+ { "Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" },
+ { "Stereo DAC MIXL", NULL, "dac stereo1 filter" },
+ { "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+ { "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+ { "Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
+ { "Stereo DAC MIXR", NULL, "dac stereo1 filter" },
+
+ { "Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+ { "Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" },
+ { "Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Volume" },
+ { "Mono DAC MIXL", NULL, "dac mono left filter" },
+ { "Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+ { "Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
+ { "Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" },
+ { "Mono DAC MIXR", NULL, "dac mono right filter" },
+
+ { "DAC MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" },
+ { "DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" },
+ { "DAC MIXL", "DAC R2 Switch", "DAC R2 Volume" },
+ { "DAC MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" },
+ { "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
+ { "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" },
+
+ { "DAC L1", NULL, "Stereo DAC MIXL" },
+ { "DAC L1", NULL, "PLL1", is_sys_clk_from_pll },
+ { "DAC R1", NULL, "Stereo DAC MIXR" },
+ { "DAC R1", NULL, "PLL1", is_sys_clk_from_pll },
+ { "DAC L2", NULL, "Mono DAC MIXL" },
+ { "DAC L2", NULL, "PLL1", is_sys_clk_from_pll },
+ { "DAC R2", NULL, "Mono DAC MIXR" },
+ { "DAC R2", NULL, "PLL1", is_sys_clk_from_pll },
+
+ { "SPK MIXL", "BST1 Switch", "BST1" },
+ { "SPK MIXL", "INL Switch", "INL VOL" },
+ { "SPK MIXL", "DAC L1 Switch", "DAC L1" },
+ { "SPK MIXL", "DAC L2 Switch", "DAC L2" },
+ { "SPK MIXR", "BST2 Switch", "BST2" },
+ { "SPK MIXR", "INR Switch", "INR VOL" },
+ { "SPK MIXR", "DAC R1 Switch", "DAC R1" },
+ { "SPK MIXR", "DAC R2 Switch", "DAC R2" },
+
+ { "OUT MIXL", "BST1 Switch", "BST1" },
+ { "OUT MIXL", "INL Switch", "INL VOL" },
+ { "OUT MIXL", "DAC L2 Switch", "DAC L2" },
+ { "OUT MIXL", "DAC L1 Switch", "DAC L1" },
+
+ { "OUT MIXR", "BST2 Switch", "BST2" },
+ { "OUT MIXR", "INR Switch", "INR VOL" },
+ { "OUT MIXR", "DAC R2 Switch", "DAC R2" },
+ { "OUT MIXR", "DAC R1 Switch", "DAC R1" },
+
+ { "HPOVOL MIXL", "DAC1 Switch", "DAC L1" },
+ { "HPOVOL MIXL", "DAC2 Switch", "DAC L2" },
+ { "HPOVOL MIXL", "INL Switch", "INL VOL" },
+ { "HPOVOL MIXL", "BST1 Switch", "BST1" },
+ { "HPOVOL MIXL", NULL, "HPOVOL MIXL Power" },
+ { "HPOVOL MIXR", "DAC1 Switch", "DAC R1" },
+ { "HPOVOL MIXR", "DAC2 Switch", "DAC R2" },
+ { "HPOVOL MIXR", "INR Switch", "INR VOL" },
+ { "HPOVOL MIXR", "BST2 Switch", "BST2" },
+ { "HPOVOL MIXR", NULL, "HPOVOL MIXR Power" },
+
+ { "DAC 2", NULL, "DAC L2" },
+ { "DAC 2", NULL, "DAC R2" },
+ { "DAC 1", NULL, "DAC L1" },
+ { "DAC 1", NULL, "DAC R1" },
+ { "HPOVOL L", "Switch", "HPOVOL MIXL" },
+ { "HPOVOL R", "Switch", "HPOVOL MIXR" },
+ { "HPOVOL", NULL, "HPOVOL L" },
+ { "HPOVOL", NULL, "HPOVOL R" },
+ { "HPO MIX", "DAC1 Switch", "DAC 1" },
+ { "HPO MIX", "HPVOL Switch", "HPOVOL" },
+
+ { "SPKVOL L", "Switch", "SPK MIXL" },
+ { "SPKVOL R", "Switch", "SPK MIXR" },
+
+ { "SPOL MIX", "DAC R1 Switch", "DAC R1" },
+ { "SPOL MIX", "DAC L1 Switch", "DAC L1" },
+ { "SPOL MIX", "SPKVOL R Switch", "SPKVOL R" },
+ { "SPOL MIX", "SPKVOL L Switch", "SPKVOL L" },
+ { "SPOR MIX", "DAC R1 Switch", "DAC R1" },
+ { "SPOR MIX", "SPKVOL R Switch", "SPKVOL R" },
+
+ { "LOUT MIX", "DAC L1 Switch", "DAC L1" },
+ { "LOUT MIX", "DAC R1 Switch", "DAC R1" },
+ { "LOUT MIX", "OUTMIX L Switch", "OUT MIXL" },
+ { "LOUT MIX", "OUTMIX R Switch", "OUT MIXR" },
+
+ { "PDM1 L Mux", "Stereo DAC", "Stereo DAC MIXL" },
+ { "PDM1 L Mux", "Mono DAC", "Mono DAC MIXL" },
+ { "PDM1 L Mux", NULL, "PDM1 Power" },
+ { "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
+ { "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" },
+ { "PDM1 R Mux", NULL, "PDM1 Power" },
+
+ { "HP amp", NULL, "HPO MIX" },
+ { "HP amp", NULL, "JD Power" },
+ { "HP amp", NULL, "Mic Det Power" },
+ { "HP amp", NULL, "LDO2" },
+ { "HPOL", NULL, "HP amp" },
+ { "HPOR", NULL, "HP amp" },
+
+ { "LOUT amp", NULL, "LOUT MIX" },
+ { "LOUTL", NULL, "LOUT amp" },
+ { "LOUTR", NULL, "LOUT amp" },
+
+ { "PDM1 L", "Switch", "PDM1 L Mux" },
+ { "PDM1 R", "Switch", "PDM1 R Mux" },
+
+ { "PDM1L", NULL, "PDM1 L" },
+ { "PDM1R", NULL, "PDM1 R" },
+
+ { "SPK amp", NULL, "SPOL MIX" },
+ { "SPK amp", NULL, "SPOR MIX" },
+ { "SPOL", NULL, "SPK amp" },
+ { "SPOR", NULL, "SPK amp" },
+};
+
+static int get_clk_info(int sclk, int rate)
+{
+ int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
+
+ if (sclk <= 0 || rate <= 0)
+ return -EINVAL;
+
+ rate = rate << 8;
+ for (i = 0; i < ARRAY_SIZE(pd); i++)
+ if (sclk == rate * pd[i])
+ return i;
+
+ return -EINVAL;
+}
+
+static int rt5645_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 rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val_len = 0, val_clk, mask_clk;
+ int pre_div, bclk_ms, frame_size;
+
+ rt5645->lrck[dai->id] = params_rate(params);
+ pre_div = get_clk_info(rt5645->sysclk, rt5645->lrck[dai->id]);
+ if (pre_div < 0) {
+ dev_err(codec->dev, "Unsupported clock setting\n");
+ return -EINVAL;
+ }
+ frame_size = snd_soc_params_to_frame_size(params);
+ if (frame_size < 0) {
+ dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+ return -EINVAL;
+ }
+ bclk_ms = frame_size > 32;
+ rt5645->bclk[dai->id] = rt5645->lrck[dai->id] * (32 << bclk_ms);
+
+ dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+ rt5645->bclk[dai->id], rt5645->lrck[dai->id]);
+ dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+ bclk_ms, pre_div, dai->id);
+
+ switch (params_width(params)) {
+ case 16:
+ break;
+ case 20:
+ val_len |= RT5645_I2S_DL_20;
+ break;
+ case 24:
+ val_len |= RT5645_I2S_DL_24;
+ break;
+ case 8:
+ val_len |= RT5645_I2S_DL_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (dai->id) {
+ case RT5645_AIF1:
+ mask_clk = RT5645_I2S_BCLK_MS1_MASK | RT5645_I2S_PD1_MASK;
+ val_clk = bclk_ms << RT5645_I2S_BCLK_MS1_SFT |
+ pre_div << RT5645_I2S_PD1_SFT;
+ snd_soc_update_bits(codec, RT5645_I2S1_SDP,
+ RT5645_I2S_DL_MASK, val_len);
+ snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk);
+ break;
+ case RT5645_AIF2:
+ mask_clk = RT5645_I2S_BCLK_MS2_MASK | RT5645_I2S_PD2_MASK;
+ val_clk = bclk_ms << RT5645_I2S_BCLK_MS2_SFT |
+ pre_div << RT5645_I2S_PD2_SFT;
+ snd_soc_update_bits(codec, RT5645_I2S2_SDP,
+ RT5645_I2S_DL_MASK, val_len);
+ snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk);
+ break;
+ default:
+ dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rt5645_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+ unsigned int reg_val = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ rt5645->master[dai->id] = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ reg_val |= RT5645_I2S_MS_S;
+ rt5645->master[dai->id] = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg_val |= RT5645_I2S_BP_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg_val |= RT5645_I2S_DF_LEFT;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ reg_val |= RT5645_I2S_DF_PCM_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ reg_val |= RT5645_I2S_DF_PCM_B;
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (dai->id) {
+ case RT5645_AIF1:
+ snd_soc_update_bits(codec, RT5645_I2S1_SDP,
+ RT5645_I2S_MS_MASK | RT5645_I2S_BP_MASK |
+ RT5645_I2S_DF_MASK, reg_val);
+ break;
+ case RT5645_AIF2:
+ snd_soc_update_bits(codec, RT5645_I2S2_SDP,
+ RT5645_I2S_MS_MASK | RT5645_I2S_BP_MASK |
+ RT5645_I2S_DF_MASK, reg_val);
+ break;
+ default:
+ dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int rt5645_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+ unsigned int reg_val = 0;
+
+ if (freq == rt5645->sysclk && clk_id == rt5645->sysclk_src)
+ return 0;
+
+ switch (clk_id) {
+ case RT5645_SCLK_S_MCLK:
+ reg_val |= RT5645_SCLK_SRC_MCLK;
+ break;
+ case RT5645_SCLK_S_PLL1:
+ reg_val |= RT5645_SCLK_SRC_PLL1;
+ break;
+ case RT5645_SCLK_S_RCCLK:
+ reg_val |= RT5645_SCLK_SRC_RCCLK;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, RT5645_GLB_CLK,
+ RT5645_SCLK_SRC_MASK, reg_val);
+ rt5645->sysclk = freq;
+ rt5645->sysclk_src = clk_id;
+
+ dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+ return 0;
+}
+
+/**
+ * rt5645_pll_calc - Calcualte PLL M/N/K code.
+ * @freq_in: external clock provided to codec.
+ * @freq_out: target clock which codec works on.
+ * @pll_code: Pointer to structure with M, N, K and bypass flag.
+ *
+ * Calcualte M/N/K code to configure PLL for codec. And K is assigned to 2
+ * which make calculation more efficiently.
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5645_pll_calc(const unsigned int freq_in,
+ const unsigned int freq_out, struct rt5645_pll_code *pll_code)
+{
+ int max_n = RT5645_PLL_N_MAX, max_m = RT5645_PLL_M_MAX;
+ int k, n = 0, m = 0, red, n_t, m_t, pll_out, in_t, out_t;
+ int red_t = abs(freq_out - freq_in);
+ bool bypass = false;
+
+ if (RT5645_PLL_INP_MAX < freq_in || RT5645_PLL_INP_MIN > freq_in)
+ return -EINVAL;
+
+ k = 100000000 / freq_out - 2;
+ if (k > RT5645_PLL_K_MAX)
+ k = RT5645_PLL_K_MAX;
+ for (n_t = 0; n_t <= max_n; n_t++) {
+ in_t = freq_in / (k + 2);
+ pll_out = freq_out / (n_t + 2);
+ if (in_t < 0)
+ continue;
+ if (in_t == pll_out) {
+ bypass = true;
+ n = n_t;
+ goto code_find;
+ }
+ red = abs(in_t - pll_out);
+ if (red < red_t) {
+ bypass = true;
+ n = n_t;
+ m = m_t;
+ if (red == 0)
+ goto code_find;
+ red_t = red;
+ }
+ for (m_t = 0; m_t <= max_m; m_t++) {
+ out_t = in_t / (m_t + 2);
+ red = abs(out_t - pll_out);
+ if (red < red_t) {
+ bypass = false;
+ n = n_t;
+ m = m_t;
+ if (red == 0)
+ goto code_find;
+ red_t = red;
+ }
+ }
+ }
+ pr_debug("Only get approximation about PLL\n");
+
+code_find:
+
+ pll_code->m_bp = bypass;
+ pll_code->m_code = m;
+ pll_code->n_code = n;
+ pll_code->k_code = k;
+ return 0;
+}
+
+static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+ struct rt5645_pll_code pll_code;
+ int ret;
+
+ if (source == rt5645->pll_src && freq_in == rt5645->pll_in &&
+ freq_out == rt5645->pll_out)
+ return 0;
+
+ if (!freq_in || !freq_out) {
+ dev_dbg(codec->dev, "PLL disabled\n");
+
+ rt5645->pll_in = 0;
+ rt5645->pll_out = 0;
+ snd_soc_update_bits(codec, RT5645_GLB_CLK,
+ RT5645_SCLK_SRC_MASK, RT5645_SCLK_SRC_MCLK);
+ return 0;
+ }
+
+ switch (source) {
+ case RT5645_PLL1_S_MCLK:
+ snd_soc_update_bits(codec, RT5645_GLB_CLK,
+ RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_MCLK);
+ break;
+ case RT5645_PLL1_S_BCLK1:
+ case RT5645_PLL1_S_BCLK2:
+ switch (dai->id) {
+ case RT5645_AIF1:
+ snd_soc_update_bits(codec, RT5645_GLB_CLK,
+ RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_BCLK1);
+ break;
+ case RT5645_AIF2:
+ snd_soc_update_bits(codec, RT5645_GLB_CLK,
+ RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_BCLK2);
+ break;
+ default:
+ dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+ return -EINVAL;
+ }
+ break;
+ default:
+ dev_err(codec->dev, "Unknown PLL source %d\n", source);
+ return -EINVAL;
+ }
+
+ ret = rt5645_pll_calc(freq_in, freq_out, &pll_code);
+ if (ret < 0) {
+ dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+ return ret;
+ }
+
+ dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+ pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+ pll_code.n_code, pll_code.k_code);
+
+ snd_soc_write(codec, RT5645_PLL_CTRL1,
+ pll_code.n_code << RT5645_PLL_N_SFT | pll_code.k_code);
+ snd_soc_write(codec, RT5645_PLL_CTRL2,
+ (pll_code.m_bp ? 0 : pll_code.m_code) << RT5645_PLL_M_SFT |
+ pll_code.m_bp << RT5645_PLL_M_BP_SFT);
+
+ rt5645->pll_in = freq_in;
+ rt5645->pll_out = freq_out;
+ rt5645->pll_src = source;
+
+ return 0;
+}
+
+static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ unsigned int val = 0;
+
+ if (rx_mask || tx_mask)
+ val |= (1 << 14);
+
+ switch (slots) {
+ case 4:
+ val |= (1 << 12);
+ break;
+ case 6:
+ val |= (2 << 12);
+ break;
+ case 8:
+ val |= (3 << 12);
+ break;
+ case 2:
+ default:
+ break;
+ }
+
+ switch (slot_width) {
+ case 20:
+ val |= (1 << 10);
+ break;
+ case 24:
+ val |= (2 << 10);
+ break;
+ case 32:
+ val |= (3 << 10);
+ break;
+ case 16:
+ default:
+ break;
+ }
+
+ snd_soc_update_bits(codec, RT5645_TDM_CTRL_1, 0x7c00, val);
+
+ return 0;
+}
+
+static int rt5645_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_STANDBY:
+ if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_VREF1 | RT5645_PWR_MB |
+ RT5645_PWR_BG | RT5645_PWR_VREF2,
+ RT5645_PWR_VREF1 | RT5645_PWR_MB |
+ RT5645_PWR_BG | RT5645_PWR_VREF2);
+ mdelay(10);
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_FV1 | RT5645_PWR_FV2,
+ RT5645_PWR_FV1 | RT5645_PWR_FV2);
+ snd_soc_update_bits(codec, RT5645_GEN_CTRL1,
+ RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL);
+ }
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
+ snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128);
+ snd_soc_write(codec, RT5645_PWR_DIG1, 0x0000);
+ snd_soc_write(codec, RT5645_PWR_DIG2, 0x0000);
+ snd_soc_write(codec, RT5645_PWR_VOL, 0x0000);
+ snd_soc_write(codec, RT5645_PWR_MIXER, 0x0000);
+ snd_soc_write(codec, RT5645_PWR_ANLG1, 0x0000);
+ snd_soc_write(codec, RT5645_PWR_ANLG2, 0x0000);
+ break;
+
+ default:
+ break;
+ }
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+static int rt5645_probe(struct snd_soc_codec *codec)
+{
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+
+ rt5645->codec = codec;
+
+ rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
+
+ return 0;
+}
+
+static int rt5645_remove(struct snd_soc_codec *codec)
+{
+ rt5645_reset(codec);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5645_suspend(struct snd_soc_codec *codec)
+{
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(rt5645->regmap, true);
+ regcache_mark_dirty(rt5645->regmap);
+
+ return 0;
+}
+
+static int rt5645_resume(struct snd_soc_codec *codec)
+{
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(rt5645->regmap, false);
+ regcache_sync(rt5645->regmap);
+
+ return 0;
+}
+#else
+#define rt5645_suspend NULL
+#define rt5645_resume NULL
+#endif
+
+#define RT5645_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5645_FORMATS (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 rt5645_aif_dai_ops = {
+ .hw_params = rt5645_hw_params,
+ .set_fmt = rt5645_set_dai_fmt,
+ .set_sysclk = rt5645_set_dai_sysclk,
+ .set_tdm_slot = rt5645_set_tdm_slot,
+ .set_pll = rt5645_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5645_dai[] = {
+ {
+ .name = "rt5645-aif1",
+ .id = RT5645_AIF1,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5645_STEREO_RATES,
+ .formats = RT5645_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5645_STEREO_RATES,
+ .formats = RT5645_FORMATS,
+ },
+ .ops = &rt5645_aif_dai_ops,
+ },
+ {
+ .name = "rt5645-aif2",
+ .id = RT5645_AIF2,
+ .playback = {
+ .stream_name = "AIF2 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5645_STEREO_RATES,
+ .formats = RT5645_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5645_STEREO_RATES,
+ .formats = RT5645_FORMATS,
+ },
+ .ops = &rt5645_aif_dai_ops,
+ },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5645 = {
+ .probe = rt5645_probe,
+ .remove = rt5645_remove,
+ .suspend = rt5645_suspend,
+ .resume = rt5645_resume,
+ .set_bias_level = rt5645_set_bias_level,
+ .idle_bias_off = true,
+ .controls = rt5645_snd_controls,
+ .num_controls = ARRAY_SIZE(rt5645_snd_controls),
+ .dapm_widgets = rt5645_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt5645_dapm_widgets),
+ .dapm_routes = rt5645_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes),
+};
+
+static const struct regmap_config rt5645_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+
+ .max_register = RT5645_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5645_ranges) *
+ RT5645_PR_SPACING),
+ .volatile_reg = rt5645_volatile_register,
+ .readable_reg = rt5645_readable_register,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rt5645_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt5645_reg),
+ .ranges = rt5645_ranges,
+ .num_ranges = ARRAY_SIZE(rt5645_ranges),
+};
+
+static const struct i2c_device_id rt5645_i2c_id[] = {
+ { "rt5645", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
+
+static int rt5645_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt5645_platform_data *pdata = dev_get_platdata(&i2c->dev);
+ struct rt5645_priv *rt5645;
+ int ret;
+ unsigned int val;
+
+ rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv),
+ GFP_KERNEL);
+ if (rt5645 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt5645);
+
+ if (pdata)
+ rt5645->pdata = *pdata;
+
+ rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap);
+ if (IS_ERR(rt5645->regmap)) {
+ ret = PTR_ERR(rt5645->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val);
+ if (val != RT5645_DEVICE_ID) {
+ dev_err(&i2c->dev,
+ "Device with ID register %x is not rt5645\n", val);
+ return -ENODEV;
+ }
+
+ regmap_write(rt5645->regmap, RT5645_RESET, 0);
+
+ ret = regmap_register_patch(rt5645->regmap, init_list,
+ ARRAY_SIZE(init_list));
+ if (ret != 0)
+ dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+ if (rt5645->pdata.in2_diff)
+ regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL,
+ RT5645_IN_DF2, RT5645_IN_DF2);
+
+ if (rt5645->pdata.dmic_en) {
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP2_PIN_MASK, RT5645_GP2_PIN_DMIC1_SCL);
+
+ switch (rt5645->pdata.dmic1_data_pin) {
+ case RT5645_DMIC_DATA_IN2N:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_IN2N);
+ break;
+
+ case RT5645_DMIC_DATA_GPIO5:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5);
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP5_PIN_MASK, RT5645_GP5_PIN_DMIC1_SDA);
+ break;
+
+ case RT5645_DMIC_DATA_GPIO11:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO11);
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP11_PIN_MASK,
+ RT5645_GP11_PIN_DMIC1_SDA);
+ break;
+
+ default:
+ break;
+ }
+
+ switch (rt5645->pdata.dmic2_data_pin) {
+ case RT5645_DMIC_DATA_IN2P:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_IN2P);
+ break;
+
+ case RT5645_DMIC_DATA_GPIO6:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO6);
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP6_PIN_MASK, RT5645_GP6_PIN_DMIC2_SDA);
+ break;
+
+ case RT5645_DMIC_DATA_GPIO10:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO10);
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP10_PIN_MASK,
+ RT5645_GP10_PIN_DMIC2_SDA);
+ break;
+
+ case RT5645_DMIC_DATA_GPIO12:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_1_DP_MASK, RT5645_DMIC_2_DP_GPIO12);
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP12_PIN_MASK,
+ RT5645_GP12_PIN_DMIC2_SDA);
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
+ rt5645_dai, ARRAY_SIZE(rt5645_dai));
+ if (ret < 0)
+ goto err;
+
+ return 0;
+err:
+ return ret;
+}
+
+static int rt5645_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_codec(&i2c->dev);
+
+ return 0;
+}
+
+static struct i2c_driver rt5645_i2c_driver = {
+ .driver = {
+ .name = "rt5645",
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5645_i2c_probe,
+ .remove = rt5645_i2c_remove,
+ .id_table = rt5645_i2c_id,
+};
+module_i2c_driver(rt5645_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5645 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
new file mode 100644
index 000000000000..345aa3f5d14f
--- /dev/null
+++ b/sound/soc/codecs/rt5645.h
@@ -0,0 +1,2188 @@
+/*
+ * rt5645.h -- RT5645 ALSA SoC audio driver
+ *
+ * Copyright 2013 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.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 __RT5645_H__
+#define __RT5645_H__
+
+#include <sound/rt5645.h>
+
+/* Info */
+#define RT5645_RESET 0x00
+#define RT5645_VENDOR_ID 0xfd
+#define RT5645_VENDOR_ID1 0xfe
+#define RT5645_VENDOR_ID2 0xff
+/* I/O - Output */
+#define RT5645_SPK_VOL 0x01
+#define RT5645_HP_VOL 0x02
+#define RT5645_LOUT1 0x03
+#define RT5645_LOUT_CTRL 0x05
+/* I/O - Input */
+#define RT5645_IN1_CTRL1 0x0a
+#define RT5645_IN1_CTRL2 0x0b
+#define RT5645_IN1_CTRL3 0x0c
+#define RT5645_IN2_CTRL 0x0d
+#define RT5645_INL1_INR1_VOL 0x0f
+#define RT5645_SPK_FUNC_LIM 0x14
+#define RT5645_ADJ_HPF_CTRL 0x16
+/* I/O - ADC/DAC/DMIC */
+#define RT5645_DAC1_DIG_VOL 0x19
+#define RT5645_DAC2_DIG_VOL 0x1a
+#define RT5645_DAC_CTRL 0x1b
+#define RT5645_STO1_ADC_DIG_VOL 0x1c
+#define RT5645_MONO_ADC_DIG_VOL 0x1d
+#define RT5645_ADC_BST_VOL1 0x1e
+/* Mixer - D-D */
+#define RT5645_ADC_BST_VOL2 0x20
+#define RT5645_STO1_ADC_MIXER 0x27
+#define RT5645_MONO_ADC_MIXER 0x28
+#define RT5645_AD_DA_MIXER 0x29
+#define RT5645_STO_DAC_MIXER 0x2a
+#define RT5645_MONO_DAC_MIXER 0x2b
+#define RT5645_DIG_MIXER 0x2c
+#define RT5645_DIG_INF1_DATA 0x2f
+/* Mixer - PDM */
+#define RT5645_PDM_OUT_CTRL 0x31
+/* Mixer - ADC */
+#define RT5645_REC_L1_MIXER 0x3b
+#define RT5645_REC_L2_MIXER 0x3c
+#define RT5645_REC_R1_MIXER 0x3d
+#define RT5645_REC_R2_MIXER 0x3e
+/* Mixer - DAC */
+#define RT5645_HPMIXL_CTRL 0x3f
+#define RT5645_HPOMIXL_CTRL 0x40
+#define RT5645_HPMIXR_CTRL 0x41
+#define RT5645_HPOMIXR_CTRL 0x42
+#define RT5645_HPO_MIXER 0x45
+#define RT5645_SPK_L_MIXER 0x46
+#define RT5645_SPK_R_MIXER 0x47
+#define RT5645_SPO_MIXER 0x48
+#define RT5645_SPO_CLSD_RATIO 0x4a
+#define RT5645_OUT_L_GAIN1 0x4d
+#define RT5645_OUT_L_GAIN2 0x4e
+#define RT5645_OUT_L1_MIXER 0x4f
+#define RT5645_OUT_R_GAIN1 0x50
+#define RT5645_OUT_R_GAIN2 0x51
+#define RT5645_OUT_R1_MIXER 0x52
+#define RT5645_LOUT_MIXER 0x53
+/* Haptic */
+#define RT5645_HAPTIC_CTRL1 0x56
+#define RT5645_HAPTIC_CTRL2 0x57
+#define RT5645_HAPTIC_CTRL3 0x58
+#define RT5645_HAPTIC_CTRL4 0x59
+#define RT5645_HAPTIC_CTRL5 0x5a
+#define RT5645_HAPTIC_CTRL6 0x5b
+#define RT5645_HAPTIC_CTRL7 0x5c
+#define RT5645_HAPTIC_CTRL8 0x5d
+#define RT5645_HAPTIC_CTRL9 0x5e
+#define RT5645_HAPTIC_CTRL10 0x5f
+/* Power */
+#define RT5645_PWR_DIG1 0x61
+#define RT5645_PWR_DIG2 0x62
+#define RT5645_PWR_ANLG1 0x63
+#define RT5645_PWR_ANLG2 0x64
+#define RT5645_PWR_MIXER 0x65
+#define RT5645_PWR_VOL 0x66
+/* Private Register Control */
+#define RT5645_PRIV_INDEX 0x6a
+#define RT5645_PRIV_DATA 0x6c
+/* Format - ADC/DAC */
+#define RT5645_I2S1_SDP 0x70
+#define RT5645_I2S2_SDP 0x71
+#define RT5645_ADDA_CLK1 0x73
+#define RT5645_ADDA_CLK2 0x74
+#define RT5645_DMIC_CTRL1 0x75
+#define RT5645_DMIC_CTRL2 0x76
+/* Format - TDM Control */
+#define RT5645_TDM_CTRL_1 0x77
+#define RT5645_TDM_CTRL_2 0x78
+#define RT5645_TDM_CTRL_3 0x79
+
+/* Function - Analog */
+#define RT5645_GLB_CLK 0x80
+#define RT5645_PLL_CTRL1 0x81
+#define RT5645_PLL_CTRL2 0x82
+#define RT5645_ASRC_1 0x83
+#define RT5645_ASRC_2 0x84
+#define RT5645_ASRC_3 0x85
+#define RT5645_ASRC_4 0x8a
+#define RT5645_DEPOP_M1 0x8e
+#define RT5645_DEPOP_M2 0x8f
+#define RT5645_DEPOP_M3 0x90
+#define RT5645_CHARGE_PUMP 0x91
+#define RT5645_MICBIAS 0x93
+#define RT5645_A_JD_CTRL1 0x94
+#define RT5645_VAD_CTRL4 0x9d
+#define RT5645_CLSD_OUT_CTRL 0xa0
+/* Function - Digital */
+#define RT5645_ADC_EQ_CTRL1 0xae
+#define RT5645_ADC_EQ_CTRL2 0xaf
+#define RT5645_EQ_CTRL1 0xb0
+#define RT5645_EQ_CTRL2 0xb1
+#define RT5645_ALC_CTRL_1 0xb3
+#define RT5645_ALC_CTRL_2 0xb4
+#define RT5645_ALC_CTRL_3 0xb5
+#define RT5645_ALC_CTRL_4 0xb6
+#define RT5645_ALC_CTRL_5 0xb7
+#define RT5645_JD_CTRL 0xbb
+#define RT5645_IRQ_CTRL1 0xbc
+#define RT5645_IRQ_CTRL2 0xbd
+#define RT5645_IRQ_CTRL3 0xbe
+#define RT5645_INT_IRQ_ST 0xbf
+#define RT5645_GPIO_CTRL1 0xc0
+#define RT5645_GPIO_CTRL2 0xc1
+#define RT5645_GPIO_CTRL3 0xc2
+#define RT5645_BASS_BACK 0xcf
+#define RT5645_MP3_PLUS1 0xd0
+#define RT5645_MP3_PLUS2 0xd1
+#define RT5645_ADJ_HPF1 0xd3
+#define RT5645_ADJ_HPF2 0xd4
+#define RT5645_HP_CALIB_AMP_DET 0xd6
+#define RT5645_SV_ZCD1 0xd9
+#define RT5645_SV_ZCD2 0xda
+#define RT5645_IL_CMD 0xdb
+#define RT5645_IL_CMD2 0xdc
+#define RT5645_IL_CMD3 0xdd
+#define RT5645_DRC1_HL_CTRL1 0xe7
+#define RT5645_DRC2_HL_CTRL1 0xe9
+#define RT5645_MUTI_DRC_CTRL1 0xea
+#define RT5645_ADC_MONO_HP_CTRL1 0xec
+#define RT5645_ADC_MONO_HP_CTRL2 0xed
+#define RT5645_DRC2_CTRL1 0xf0
+#define RT5645_DRC2_CTRL2 0xf1
+#define RT5645_DRC2_CTRL3 0xf2
+#define RT5645_DRC2_CTRL4 0xf3
+#define RT5645_DRC2_CTRL5 0xf4
+#define RT5645_JD_CTRL3 0xf8
+#define RT5645_JD_CTRL4 0xf9
+/* General Control */
+#define RT5645_GEN_CTRL1 0xfa
+#define RT5645_GEN_CTRL2 0xfb
+#define RT5645_GEN_CTRL3 0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5645_DIG_VOL 0x00
+#define RT5645_PR_ALC_CTRL_1 0x01
+#define RT5645_PR_ALC_CTRL_2 0x02
+#define RT5645_PR_ALC_CTRL_3 0x03
+#define RT5645_PR_ALC_CTRL_4 0x04
+#define RT5645_PR_ALC_CTRL_5 0x05
+#define RT5645_PR_ALC_CTRL_6 0x06
+#define RT5645_BIAS_CUR1 0x12
+#define RT5645_BIAS_CUR3 0x14
+#define RT5645_CLSD_INT_REG1 0x1c
+#define RT5645_MAMP_INT_REG2 0x37
+#define RT5645_CHOP_DAC_ADC 0x3d
+#define RT5645_MIXER_INT_REG 0x3f
+#define RT5645_3D_SPK 0x63
+#define RT5645_WND_1 0x6c
+#define RT5645_WND_2 0x6d
+#define RT5645_WND_3 0x6e
+#define RT5645_WND_4 0x6f
+#define RT5645_WND_5 0x70
+#define RT5645_WND_8 0x73
+#define RT5645_DIP_SPK_INF 0x75
+#define RT5645_HP_DCC_INT1 0x77
+#define RT5645_EQ_BW_LOP 0xa0
+#define RT5645_EQ_GN_LOP 0xa1
+#define RT5645_EQ_FC_BP1 0xa2
+#define RT5645_EQ_BW_BP1 0xa3
+#define RT5645_EQ_GN_BP1 0xa4
+#define RT5645_EQ_FC_BP2 0xa5
+#define RT5645_EQ_BW_BP2 0xa6
+#define RT5645_EQ_GN_BP2 0xa7
+#define RT5645_EQ_FC_BP3 0xa8
+#define RT5645_EQ_BW_BP3 0xa9
+#define RT5645_EQ_GN_BP3 0xaa
+#define RT5645_EQ_FC_BP4 0xab
+#define RT5645_EQ_BW_BP4 0xac
+#define RT5645_EQ_GN_BP4 0xad
+#define RT5645_EQ_FC_HIP1 0xae
+#define RT5645_EQ_GN_HIP1 0xaf
+#define RT5645_EQ_FC_HIP2 0xb0
+#define RT5645_EQ_BW_HIP2 0xb1
+#define RT5645_EQ_GN_HIP2 0xb2
+#define RT5645_EQ_PRE_VOL 0xb3
+#define RT5645_EQ_PST_VOL 0xb4
+
+
+/* global definition */
+#define RT5645_L_MUTE (0x1 << 15)
+#define RT5645_L_MUTE_SFT 15
+#define RT5645_VOL_L_MUTE (0x1 << 14)
+#define RT5645_VOL_L_SFT 14
+#define RT5645_R_MUTE (0x1 << 7)
+#define RT5645_R_MUTE_SFT 7
+#define RT5645_VOL_R_MUTE (0x1 << 6)
+#define RT5645_VOL_R_SFT 6
+#define RT5645_L_VOL_MASK (0x3f << 8)
+#define RT5645_L_VOL_SFT 8
+#define RT5645_R_VOL_MASK (0x3f)
+#define RT5645_R_VOL_SFT 0
+
+/* IN1 Control 1 (0x0a) */
+#define RT5645_CBJ_BST1_MASK (0xf << 12)
+#define RT5645_CBJ_BST1_SFT (12)
+#define RT5645_CBJ_JD_HP_EN (0x1 << 9)
+#define RT5645_CBJ_JD_MIC_EN (0x1 << 8)
+#define RT5645_CBJ_JD_MIC_SW_EN (0x1 << 7)
+#define RT5645_CBJ_MIC_SEL_R (0x1 << 6)
+#define RT5645_CBJ_MIC_SEL_L (0x1 << 5)
+#define RT5645_CBJ_MIC_SW (0x1 << 4)
+#define RT5645_CBJ_BST1_EN (0x1 << 2)
+
+/* IN1 Control 2 (0x0b) */
+#define RT5645_CBJ_MN_JD (0x1 << 12)
+#define RT5645_CAPLESS_EN (0x1 << 11)
+#define RT5645_CBJ_DET_MODE (0x1 << 7)
+
+/* IN1 Control 3 (0x0c) */
+#define RT5645_CBJ_TIE_G_L (0x1 << 15)
+#define RT5645_CBJ_TIE_G_R (0x1 << 14)
+
+/* IN2 Control (0x0d) */
+#define RT5645_BST_MASK1 (0xf<<12)
+#define RT5645_BST_SFT1 12
+#define RT5645_BST_MASK2 (0xf<<8)
+#define RT5645_BST_SFT2 8
+#define RT5645_IN_DF2 (0x1 << 6)
+#define RT5645_IN_SFT2 6
+
+/* INL and INR Volume Control (0x0f) */
+#define RT5645_INL_SEL_MASK (0x1 << 15)
+#define RT5645_INL_SEL_SFT 15
+#define RT5645_INL_SEL_IN4P (0x0 << 15)
+#define RT5645_INL_SEL_MONOP (0x1 << 15)
+#define RT5645_INL_VOL_MASK (0x1f << 8)
+#define RT5645_INL_VOL_SFT 8
+#define RT5645_INR_SEL_MASK (0x1 << 7)
+#define RT5645_INR_SEL_SFT 7
+#define RT5645_INR_SEL_IN4N (0x0 << 7)
+#define RT5645_INR_SEL_MONON (0x1 << 7)
+#define RT5645_INR_VOL_MASK (0x1f)
+#define RT5645_INR_VOL_SFT 0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5645_DAC_L1_VOL_MASK (0xff << 8)
+#define RT5645_DAC_L1_VOL_SFT 8
+#define RT5645_DAC_R1_VOL_MASK (0xff)
+#define RT5645_DAC_R1_VOL_SFT 0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5645_DAC_L2_VOL_MASK (0xff << 8)
+#define RT5645_DAC_L2_VOL_SFT 8
+#define RT5645_DAC_R2_VOL_MASK (0xff)
+#define RT5645_DAC_R2_VOL_SFT 0
+
+/* DAC2 Control (0x1b) */
+#define RT5645_M_DAC_L2_VOL (0x1 << 13)
+#define RT5645_M_DAC_L2_VOL_SFT 13
+#define RT5645_M_DAC_R2_VOL (0x1 << 12)
+#define RT5645_M_DAC_R2_VOL_SFT 12
+#define RT5645_DAC2_L_SEL_MASK (0x7 << 4)
+#define RT5645_DAC2_L_SEL_SFT 4
+#define RT5645_DAC2_R_SEL_MASK (0x7 << 0)
+#define RT5645_DAC2_R_SEL_SFT 0
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5645_ADC_L_VOL_MASK (0x7f << 8)
+#define RT5645_ADC_L_VOL_SFT 8
+#define RT5645_ADC_R_VOL_MASK (0x7f)
+#define RT5645_ADC_R_VOL_SFT 0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5645_MONO_ADC_L_VOL_MASK (0x7f << 8)
+#define RT5645_MONO_ADC_L_VOL_SFT 8
+#define RT5645_MONO_ADC_R_VOL_MASK (0x7f)
+#define RT5645_MONO_ADC_R_VOL_SFT 0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5645_STO1_ADC_L_BST_MASK (0x3 << 14)
+#define RT5645_STO1_ADC_L_BST_SFT 14
+#define RT5645_STO1_ADC_R_BST_MASK (0x3 << 12)
+#define RT5645_STO1_ADC_R_BST_SFT 12
+#define RT5645_STO1_ADC_COMP_MASK (0x3 << 10)
+#define RT5645_STO1_ADC_COMP_SFT 10
+#define RT5645_STO2_ADC_L_BST_MASK (0x3 << 8)
+#define RT5645_STO2_ADC_L_BST_SFT 8
+#define RT5645_STO2_ADC_R_BST_MASK (0x3 << 6)
+#define RT5645_STO2_ADC_R_BST_SFT 6
+#define RT5645_STO2_ADC_COMP_MASK (0x3 << 4)
+#define RT5645_STO2_ADC_COMP_SFT 4
+
+/* Stereo2 ADC Mixer Control (0x26) */
+#define RT5645_STO2_ADC_SRC_MASK (0x1 << 15)
+#define RT5645_STO2_ADC_SRC_SFT 15
+
+/* Stereo ADC Mixer Control (0x27) */
+#define RT5645_M_ADC_L1 (0x1 << 14)
+#define RT5645_M_ADC_L1_SFT 14
+#define RT5645_M_ADC_L2 (0x1 << 13)
+#define RT5645_M_ADC_L2_SFT 13
+#define RT5645_ADC_1_SRC_MASK (0x1 << 12)
+#define RT5645_ADC_1_SRC_SFT 12
+#define RT5645_ADC_1_SRC_ADC (0x1 << 12)
+#define RT5645_ADC_1_SRC_DACMIX (0x0 << 12)
+#define RT5645_ADC_2_SRC_MASK (0x1 << 11)
+#define RT5645_ADC_2_SRC_SFT 11
+#define RT5645_DMIC_SRC_MASK (0x1 << 8)
+#define RT5645_DMIC_SRC_SFT 8
+#define RT5645_M_ADC_R1 (0x1 << 6)
+#define RT5645_M_ADC_R1_SFT 6
+#define RT5645_M_ADC_R2 (0x1 << 5)
+#define RT5645_M_ADC_R2_SFT 5
+#define RT5645_DMIC3_SRC_MASK (0x1 << 1)
+#define RT5645_DMIC3_SRC_SFT 0
+
+/* Mono ADC Mixer Control (0x28) */
+#define RT5645_M_MONO_ADC_L1 (0x1 << 14)
+#define RT5645_M_MONO_ADC_L1_SFT 14
+#define RT5645_M_MONO_ADC_L2 (0x1 << 13)
+#define RT5645_M_MONO_ADC_L2_SFT 13
+#define RT5645_MONO_ADC_L1_SRC_MASK (0x1 << 12)
+#define RT5645_MONO_ADC_L1_SRC_SFT 12
+#define RT5645_MONO_ADC_L1_SRC_DACMIXL (0x0 << 12)
+#define RT5645_MONO_ADC_L1_SRC_ADCL (0x1 << 12)
+#define RT5645_MONO_ADC_L2_SRC_MASK (0x1 << 11)
+#define RT5645_MONO_ADC_L2_SRC_SFT 11
+#define RT5645_MONO_DMIC_L_SRC_MASK (0x1 << 8)
+#define RT5645_MONO_DMIC_L_SRC_SFT 8
+#define RT5645_M_MONO_ADC_R1 (0x1 << 6)
+#define RT5645_M_MONO_ADC_R1_SFT 6
+#define RT5645_M_MONO_ADC_R2 (0x1 << 5)
+#define RT5645_M_MONO_ADC_R2_SFT 5
+#define RT5645_MONO_ADC_R1_SRC_MASK (0x1 << 4)
+#define RT5645_MONO_ADC_R1_SRC_SFT 4
+#define RT5645_MONO_ADC_R1_SRC_ADCR (0x1 << 4)
+#define RT5645_MONO_ADC_R1_SRC_DACMIXR (0x0 << 4)
+#define RT5645_MONO_ADC_R2_SRC_MASK (0x1 << 3)
+#define RT5645_MONO_ADC_R2_SRC_SFT 3
+#define RT5645_MONO_DMIC_R_SRC_MASK (0x3)
+#define RT5645_MONO_DMIC_R_SRC_SFT 0
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5645_M_ADCMIX_L (0x1 << 15)
+#define RT5645_M_ADCMIX_L_SFT 15
+#define RT5645_M_DAC1_L (0x1 << 14)
+#define RT5645_M_DAC1_L_SFT 14
+#define RT5645_DAC1_R_SEL_MASK (0x3 << 10)
+#define RT5645_DAC1_R_SEL_SFT 10
+#define RT5645_DAC1_R_SEL_IF1 (0x0 << 10)
+#define RT5645_DAC1_R_SEL_IF2 (0x1 << 10)
+#define RT5645_DAC1_R_SEL_IF3 (0x2 << 10)
+#define RT5645_DAC1_R_SEL_IF4 (0x3 << 10)
+#define RT5645_DAC1_L_SEL_MASK (0x3 << 8)
+#define RT5645_DAC1_L_SEL_SFT 8
+#define RT5645_DAC1_L_SEL_IF1 (0x0 << 8)
+#define RT5645_DAC1_L_SEL_IF2 (0x1 << 8)
+#define RT5645_DAC1_L_SEL_IF3 (0x2 << 8)
+#define RT5645_DAC1_L_SEL_IF4 (0x3 << 8)
+#define RT5645_M_ADCMIX_R (0x1 << 7)
+#define RT5645_M_ADCMIX_R_SFT 7
+#define RT5645_M_DAC1_R (0x1 << 6)
+#define RT5645_M_DAC1_R_SFT 6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5645_M_DAC_L1 (0x1 << 14)
+#define RT5645_M_DAC_L1_SFT 14
+#define RT5645_DAC_L1_STO_L_VOL_MASK (0x1 << 13)
+#define RT5645_DAC_L1_STO_L_VOL_SFT 13
+#define RT5645_M_DAC_L2 (0x1 << 12)
+#define RT5645_M_DAC_L2_SFT 12
+#define RT5645_DAC_L2_STO_L_VOL_MASK (0x1 << 11)
+#define RT5645_DAC_L2_STO_L_VOL_SFT 11
+#define RT5645_M_ANC_DAC_L (0x1 << 10)
+#define RT5645_M_ANC_DAC_L_SFT 10
+#define RT5645_M_DAC_R1_STO_L (0x1 << 9)
+#define RT5645_M_DAC_R1_STO_L_SFT 9
+#define RT5645_DAC_R1_STO_L_VOL_MASK (0x1 << 8)
+#define RT5645_DAC_R1_STO_L_VOL_SFT 8
+#define RT5645_M_DAC_R1 (0x1 << 6)
+#define RT5645_M_DAC_R1_SFT 6
+#define RT5645_DAC_R1_STO_R_VOL_MASK (0x1 << 5)
+#define RT5645_DAC_R1_STO_R_VOL_SFT 5
+#define RT5645_M_DAC_R2 (0x1 << 4)
+#define RT5645_M_DAC_R2_SFT 4
+#define RT5645_DAC_R2_STO_R_VOL_MASK (0x1 << 3)
+#define RT5645_DAC_R2_STO_R_VOL_SFT 3
+#define RT5645_M_ANC_DAC_R (0x1 << 2)
+#define RT5645_M_ANC_DAC_R_SFT 2
+#define RT5645_M_DAC_L1_STO_R (0x1 << 1)
+#define RT5645_M_DAC_L1_STO_R_SFT 1
+#define RT5645_DAC_L1_STO_R_VOL_MASK (0x1)
+#define RT5645_DAC_L1_STO_R_VOL_SFT 0
+
+/* Mono DAC Mixer Control (0x2b) */
+#define RT5645_M_DAC_L1_MONO_L (0x1 << 14)
+#define RT5645_M_DAC_L1_MONO_L_SFT 14
+#define RT5645_DAC_L1_MONO_L_VOL_MASK (0x1 << 13)
+#define RT5645_DAC_L1_MONO_L_VOL_SFT 13
+#define RT5645_M_DAC_L2_MONO_L (0x1 << 12)
+#define RT5645_M_DAC_L2_MONO_L_SFT 12
+#define RT5645_DAC_L2_MONO_L_VOL_MASK (0x1 << 11)
+#define RT5645_DAC_L2_MONO_L_VOL_SFT 11
+#define RT5645_M_DAC_R2_MONO_L (0x1 << 10)
+#define RT5645_M_DAC_R2_MONO_L_SFT 10
+#define RT5645_DAC_R2_MONO_L_VOL_MASK (0x1 << 9)
+#define RT5645_DAC_R2_MONO_L_VOL_SFT 9
+#define RT5645_M_DAC_R1_MONO_R (0x1 << 6)
+#define RT5645_M_DAC_R1_MONO_R_SFT 6
+#define RT5645_DAC_R1_MONO_R_VOL_MASK (0x1 << 5)
+#define RT5645_DAC_R1_MONO_R_VOL_SFT 5
+#define RT5645_M_DAC_R2_MONO_R (0x1 << 4)
+#define RT5645_M_DAC_R2_MONO_R_SFT 4
+#define RT5645_DAC_R2_MONO_R_VOL_MASK (0x1 << 3)
+#define RT5645_DAC_R2_MONO_R_VOL_SFT 3
+#define RT5645_M_DAC_L2_MONO_R (0x1 << 2)
+#define RT5645_M_DAC_L2_MONO_R_SFT 2
+#define RT5645_DAC_L2_MONO_R_VOL_MASK (0x1 << 1)
+#define RT5645_DAC_L2_MONO_R_VOL_SFT 1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5645_M_STO_L_DAC_L (0x1 << 15)
+#define RT5645_M_STO_L_DAC_L_SFT 15
+#define RT5645_STO_L_DAC_L_VOL_MASK (0x1 << 14)
+#define RT5645_STO_L_DAC_L_VOL_SFT 14
+#define RT5645_M_DAC_L2_DAC_L (0x1 << 13)
+#define RT5645_M_DAC_L2_DAC_L_SFT 13
+#define RT5645_DAC_L2_DAC_L_VOL_MASK (0x1 << 12)
+#define RT5645_DAC_L2_DAC_L_VOL_SFT 12
+#define RT5645_M_STO_R_DAC_R (0x1 << 11)
+#define RT5645_M_STO_R_DAC_R_SFT 11
+#define RT5645_STO_R_DAC_R_VOL_MASK (0x1 << 10)
+#define RT5645_STO_R_DAC_R_VOL_SFT 10
+#define RT5645_M_DAC_R2_DAC_R (0x1 << 9)
+#define RT5645_M_DAC_R2_DAC_R_SFT 9
+#define RT5645_DAC_R2_DAC_R_VOL_MASK (0x1 << 8)
+#define RT5645_DAC_R2_DAC_R_VOL_SFT 8
+#define RT5645_M_DAC_R2_DAC_L (0x1 << 7)
+#define RT5645_M_DAC_R2_DAC_L_SFT 7
+#define RT5645_DAC_R2_DAC_L_VOL_MASK (0x1 << 6)
+#define RT5645_DAC_R2_DAC_L_VOL_SFT 6
+#define RT5645_M_DAC_L2_DAC_R (0x1 << 5)
+#define RT5645_M_DAC_L2_DAC_R_SFT 5
+#define RT5645_DAC_L2_DAC_R_VOL_MASK (0x1 << 4)
+#define RT5645_DAC_L2_DAC_R_VOL_SFT 4
+
+/* Digital Interface Data Control (0x2f) */
+#define RT5645_IF1_ADC2_IN_SEL (0x1 << 15)
+#define RT5645_IF1_ADC2_IN_SFT 15
+#define RT5645_IF2_ADC_IN_MASK (0x7 << 12)
+#define RT5645_IF2_ADC_IN_SFT 12
+#define RT5645_IF2_DAC_SEL_MASK (0x3 << 10)
+#define RT5645_IF2_DAC_SEL_SFT 10
+#define RT5645_IF2_ADC_SEL_MASK (0x3 << 8)
+#define RT5645_IF2_ADC_SEL_SFT 8
+#define RT5645_IF3_DAC_SEL_MASK (0x3 << 6)
+#define RT5645_IF3_DAC_SEL_SFT 6
+#define RT5645_IF3_ADC_SEL_MASK (0x3 << 4)
+#define RT5645_IF3_ADC_SEL_SFT 4
+#define RT5645_IF3_ADC_IN_MASK (0x7)
+#define RT5645_IF3_ADC_IN_SFT 0
+
+/* PDM Output Control (0x31) */
+#define RT5645_PDM1_L_MASK (0x1 << 15)
+#define RT5645_PDM1_L_SFT 15
+#define RT5645_M_PDM1_L (0x1 << 14)
+#define RT5645_M_PDM1_L_SFT 14
+#define RT5645_PDM1_R_MASK (0x1 << 13)
+#define RT5645_PDM1_R_SFT 13
+#define RT5645_M_PDM1_R (0x1 << 12)
+#define RT5645_M_PDM1_R_SFT 12
+#define RT5645_PDM2_L_MASK (0x1 << 11)
+#define RT5645_PDM2_L_SFT 11
+#define RT5645_M_PDM2_L (0x1 << 10)
+#define RT5645_M_PDM2_L_SFT 10
+#define RT5645_PDM2_R_MASK (0x1 << 9)
+#define RT5645_PDM2_R_SFT 9
+#define RT5645_M_PDM2_R (0x1 << 8)
+#define RT5645_M_PDM2_R_SFT 8
+#define RT5645_PDM2_BUSY (0x1 << 7)
+#define RT5645_PDM1_BUSY (0x1 << 6)
+#define RT5645_PDM_PATTERN (0x1 << 5)
+#define RT5645_PDM_GAIN (0x1 << 4)
+#define RT5645_PDM_DIV_MASK (0x3)
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5645_G_HP_L_RM_L_MASK (0x7 << 13)
+#define RT5645_G_HP_L_RM_L_SFT 13
+#define RT5645_G_IN_L_RM_L_MASK (0x7 << 10)
+#define RT5645_G_IN_L_RM_L_SFT 10
+#define RT5645_G_BST4_RM_L_MASK (0x7 << 7)
+#define RT5645_G_BST4_RM_L_SFT 7
+#define RT5645_G_BST3_RM_L_MASK (0x7 << 4)
+#define RT5645_G_BST3_RM_L_SFT 4
+#define RT5645_G_BST2_RM_L_MASK (0x7 << 1)
+#define RT5645_G_BST2_RM_L_SFT 1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5645_G_BST1_RM_L_MASK (0x7 << 13)
+#define RT5645_G_BST1_RM_L_SFT 13
+#define RT5645_G_OM_L_RM_L_MASK (0x7 << 10)
+#define RT5645_G_OM_L_RM_L_SFT 10
+#define RT5645_M_MM_L_RM_L (0x1 << 6)
+#define RT5645_M_MM_L_RM_L_SFT 6
+#define RT5645_M_IN_L_RM_L (0x1 << 5)
+#define RT5645_M_IN_L_RM_L_SFT 5
+#define RT5645_M_HP_L_RM_L (0x1 << 4)
+#define RT5645_M_HP_L_RM_L_SFT 4
+#define RT5645_M_BST3_RM_L (0x1 << 3)
+#define RT5645_M_BST3_RM_L_SFT 3
+#define RT5645_M_BST2_RM_L (0x1 << 2)
+#define RT5645_M_BST2_RM_L_SFT 2
+#define RT5645_M_BST1_RM_L (0x1 << 1)
+#define RT5645_M_BST1_RM_L_SFT 1
+#define RT5645_M_OM_L_RM_L (0x1)
+#define RT5645_M_OM_L_RM_L_SFT 0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5645_G_HP_R_RM_R_MASK (0x7 << 13)
+#define RT5645_G_HP_R_RM_R_SFT 13
+#define RT5645_G_IN_R_RM_R_MASK (0x7 << 10)
+#define RT5645_G_IN_R_RM_R_SFT 10
+#define RT5645_G_BST4_RM_R_MASK (0x7 << 7)
+#define RT5645_G_BST4_RM_R_SFT 7
+#define RT5645_G_BST3_RM_R_MASK (0x7 << 4)
+#define RT5645_G_BST3_RM_R_SFT 4
+#define RT5645_G_BST2_RM_R_MASK (0x7 << 1)
+#define RT5645_G_BST2_RM_R_SFT 1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5645_G_BST1_RM_R_MASK (0x7 << 13)
+#define RT5645_G_BST1_RM_R_SFT 13
+#define RT5645_G_OM_R_RM_R_MASK (0x7 << 10)
+#define RT5645_G_OM_R_RM_R_SFT 10
+#define RT5645_M_MM_R_RM_R (0x1 << 6)
+#define RT5645_M_MM_R_RM_R_SFT 6
+#define RT5645_M_IN_R_RM_R (0x1 << 5)
+#define RT5645_M_IN_R_RM_R_SFT 5
+#define RT5645_M_HP_R_RM_R (0x1 << 4)
+#define RT5645_M_HP_R_RM_R_SFT 4
+#define RT5645_M_BST3_RM_R (0x1 << 3)
+#define RT5645_M_BST3_RM_R_SFT 3
+#define RT5645_M_BST2_RM_R (0x1 << 2)
+#define RT5645_M_BST2_RM_R_SFT 2
+#define RT5645_M_BST1_RM_R (0x1 << 1)
+#define RT5645_M_BST1_RM_R_SFT 1
+#define RT5645_M_OM_R_RM_R (0x1)
+#define RT5645_M_OM_R_RM_R_SFT 0
+
+/* HPOMIX Control (0x40) (0x42) */
+#define RT5645_M_BST1_HV (0x1 << 4)
+#define RT5645_M_BST1_HV_SFT 4
+#define RT5645_M_BST2_HV (0x1 << 4)
+#define RT5645_M_BST2_HV_SFT 4
+#define RT5645_M_BST3_HV (0x1 << 3)
+#define RT5645_M_BST3_HV_SFT 3
+#define RT5645_M_IN_HV (0x1 << 2)
+#define RT5645_M_IN_HV_SFT 2
+#define RT5645_M_DAC2_HV (0x1 << 1)
+#define RT5645_M_DAC2_HV_SFT 1
+#define RT5645_M_DAC1_HV (0x1 << 0)
+#define RT5645_M_DAC1_HV_SFT 0
+
+/* HPMIX Control (0x45) */
+#define RT5645_M_DAC1_HM (0x1 << 14)
+#define RT5645_M_DAC1_HM_SFT 14
+#define RT5645_M_HPVOL_HM (0x1 << 13)
+#define RT5645_M_HPVOL_HM_SFT 13
+
+/* SPK Left Mixer Control (0x46) */
+#define RT5645_G_RM_L_SM_L_MASK (0x3 << 14)
+#define RT5645_G_RM_L_SM_L_SFT 14
+#define RT5645_G_IN_L_SM_L_MASK (0x3 << 12)
+#define RT5645_G_IN_L_SM_L_SFT 12
+#define RT5645_G_DAC_L1_SM_L_MASK (0x3 << 10)
+#define RT5645_G_DAC_L1_SM_L_SFT 10
+#define RT5645_G_DAC_L2_SM_L_MASK (0x3 << 8)
+#define RT5645_G_DAC_L2_SM_L_SFT 8
+#define RT5645_G_OM_L_SM_L_MASK (0x3 << 6)
+#define RT5645_G_OM_L_SM_L_SFT 6
+#define RT5645_M_BST1_L_SM_L (0x1 << 5)
+#define RT5645_M_BST1_L_SM_L_SFT 5
+#define RT5645_M_IN_L_SM_L (0x1 << 3)
+#define RT5645_M_IN_L_SM_L_SFT 3
+#define RT5645_M_DAC_L1_SM_L (0x1 << 1)
+#define RT5645_M_DAC_L1_SM_L_SFT 1
+#define RT5645_M_DAC_L2_SM_L (0x1 << 2)
+#define RT5645_M_DAC_L2_SM_L_SFT 2
+#define RT5645_M_BST3_L_SM_L (0x1 << 4)
+#define RT5645_M_BST3_L_SM_L_SFT 4
+
+/* SPK Right Mixer Control (0x47) */
+#define RT5645_G_RM_R_SM_R_MASK (0x3 << 14)
+#define RT5645_G_RM_R_SM_R_SFT 14
+#define RT5645_G_IN_R_SM_R_MASK (0x3 << 12)
+#define RT5645_G_IN_R_SM_R_SFT 12
+#define RT5645_G_DAC_R1_SM_R_MASK (0x3 << 10)
+#define RT5645_G_DAC_R1_SM_R_SFT 10
+#define RT5645_G_DAC_R2_SM_R_MASK (0x3 << 8)
+#define RT5645_G_DAC_R2_SM_R_SFT 8
+#define RT5645_G_OM_R_SM_R_MASK (0x3 << 6)
+#define RT5645_G_OM_R_SM_R_SFT 6
+#define RT5645_M_BST2_R_SM_R (0x1 << 5)
+#define RT5645_M_BST2_R_SM_R_SFT 5
+#define RT5645_M_IN_R_SM_R (0x1 << 3)
+#define RT5645_M_IN_R_SM_R_SFT 3
+#define RT5645_M_DAC_R1_SM_R (0x1 << 1)
+#define RT5645_M_DAC_R1_SM_R_SFT 1
+#define RT5645_M_DAC_R2_SM_R (0x1 << 2)
+#define RT5645_M_DAC_R2_SM_R_SFT 2
+#define RT5645_M_BST3_R_SM_R (0x1 << 4)
+#define RT5645_M_BST3_R_SM_R_SFT 4
+
+/* SPOLMIX Control (0x48) */
+#define RT5645_M_DAC_L1_SPM_L (0x1 << 15)
+#define RT5645_M_DAC_L1_SPM_L_SFT 15
+#define RT5645_M_DAC_R1_SPM_L (0x1 << 14)
+#define RT5645_M_DAC_R1_SPM_L_SFT 14
+#define RT5645_M_SV_L_SPM_L (0x1 << 13)
+#define RT5645_M_SV_L_SPM_L_SFT 13
+#define RT5645_M_SV_R_SPM_L (0x1 << 12)
+#define RT5645_M_SV_R_SPM_L_SFT 12
+#define RT5645_M_BST3_SPM_L (0x1 << 11)
+#define RT5645_M_BST3_SPM_L_SFT 11
+#define RT5645_M_DAC_R1_SPM_R (0x1 << 2)
+#define RT5645_M_DAC_R1_SPM_R_SFT 2
+#define RT5645_M_BST3_SPM_R (0x1 << 1)
+#define RT5645_M_BST3_SPM_R_SFT 1
+#define RT5645_M_SV_R_SPM_R (0x1 << 0)
+#define RT5645_M_SV_R_SPM_R_SFT 0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5645_M_OV_L_MM (0x1 << 9)
+#define RT5645_M_OV_L_MM_SFT 9
+#define RT5645_M_DAC_L2_MA (0x1 << 8)
+#define RT5645_M_DAC_L2_MA_SFT 8
+#define RT5645_G_MONOMIX_MASK (0x1 << 10)
+#define RT5645_G_MONOMIX_SFT 10
+#define RT5645_M_BST2_MM (0x1 << 4)
+#define RT5645_M_BST2_MM_SFT 4
+#define RT5645_M_DAC_R1_MM (0x1 << 3)
+#define RT5645_M_DAC_R1_MM_SFT 3
+#define RT5645_M_DAC_R2_MM (0x1 << 2)
+#define RT5645_M_DAC_R2_MM_SFT 2
+#define RT5645_M_DAC_L2_MM (0x1 << 1)
+#define RT5645_M_DAC_L2_MM_SFT 1
+#define RT5645_M_BST3_MM (0x1 << 0)
+#define RT5645_M_BST3_MM_SFT 0
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5645_G_BST3_OM_L_MASK (0x7 << 13)
+#define RT5645_G_BST3_OM_L_SFT 13
+#define RT5645_G_BST2_OM_L_MASK (0x7 << 10)
+#define RT5645_G_BST2_OM_L_SFT 10
+#define RT5645_G_BST1_OM_L_MASK (0x7 << 7)
+#define RT5645_G_BST1_OM_L_SFT 7
+#define RT5645_G_IN_L_OM_L_MASK (0x7 << 4)
+#define RT5645_G_IN_L_OM_L_SFT 4
+#define RT5645_G_RM_L_OM_L_MASK (0x7 << 1)
+#define RT5645_G_RM_L_OM_L_SFT 1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5645_G_DAC_R2_OM_L_MASK (0x7 << 13)
+#define RT5645_G_DAC_R2_OM_L_SFT 13
+#define RT5645_G_DAC_L2_OM_L_MASK (0x7 << 10)
+#define RT5645_G_DAC_L2_OM_L_SFT 10
+#define RT5645_G_DAC_L1_OM_L_MASK (0x7 << 7)
+#define RT5645_G_DAC_L1_OM_L_SFT 7
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5645_M_BST3_OM_L (0x1 << 4)
+#define RT5645_M_BST3_OM_L_SFT 4
+#define RT5645_M_BST1_OM_L (0x1 << 3)
+#define RT5645_M_BST1_OM_L_SFT 3
+#define RT5645_M_IN_L_OM_L (0x1 << 2)
+#define RT5645_M_IN_L_OM_L_SFT 2
+#define RT5645_M_DAC_L2_OM_L (0x1 << 1)
+#define RT5645_M_DAC_L2_OM_L_SFT 1
+#define RT5645_M_DAC_L1_OM_L (0x1)
+#define RT5645_M_DAC_L1_OM_L_SFT 0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5645_G_BST4_OM_R_MASK (0x7 << 13)
+#define RT5645_G_BST4_OM_R_SFT 13
+#define RT5645_G_BST2_OM_R_MASK (0x7 << 10)
+#define RT5645_G_BST2_OM_R_SFT 10
+#define RT5645_G_BST1_OM_R_MASK (0x7 << 7)
+#define RT5645_G_BST1_OM_R_SFT 7
+#define RT5645_G_IN_R_OM_R_MASK (0x7 << 4)
+#define RT5645_G_IN_R_OM_R_SFT 4
+#define RT5645_G_RM_R_OM_R_MASK (0x7 << 1)
+#define RT5645_G_RM_R_OM_R_SFT 1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5645_G_DAC_L2_OM_R_MASK (0x7 << 13)
+#define RT5645_G_DAC_L2_OM_R_SFT 13
+#define RT5645_G_DAC_R2_OM_R_MASK (0x7 << 10)
+#define RT5645_G_DAC_R2_OM_R_SFT 10
+#define RT5645_G_DAC_R1_OM_R_MASK (0x7 << 7)
+#define RT5645_G_DAC_R1_OM_R_SFT 7
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5645_M_BST3_OM_R (0x1 << 4)
+#define RT5645_M_BST3_OM_R_SFT 4
+#define RT5645_M_BST2_OM_R (0x1 << 3)
+#define RT5645_M_BST2_OM_R_SFT 3
+#define RT5645_M_IN_R_OM_R (0x1 << 2)
+#define RT5645_M_IN_R_OM_R_SFT 2
+#define RT5645_M_DAC_R2_OM_R (0x1 << 1)
+#define RT5645_M_DAC_R2_OM_R_SFT 1
+#define RT5645_M_DAC_R1_OM_R (0x1)
+#define RT5645_M_DAC_R1_OM_R_SFT 0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5645_M_DAC_L1_LM (0x1 << 15)
+#define RT5645_M_DAC_L1_LM_SFT 15
+#define RT5645_M_DAC_R1_LM (0x1 << 14)
+#define RT5645_M_DAC_R1_LM_SFT 14
+#define RT5645_M_OV_L_LM (0x1 << 13)
+#define RT5645_M_OV_L_LM_SFT 13
+#define RT5645_M_OV_R_LM (0x1 << 12)
+#define RT5645_M_OV_R_LM_SFT 12
+#define RT5645_G_LOUTMIX_MASK (0x1 << 11)
+#define RT5645_G_LOUTMIX_SFT 11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5645_PWR_I2S1 (0x1 << 15)
+#define RT5645_PWR_I2S1_BIT 15
+#define RT5645_PWR_I2S2 (0x1 << 14)
+#define RT5645_PWR_I2S2_BIT 14
+#define RT5645_PWR_I2S3 (0x1 << 13)
+#define RT5645_PWR_I2S3_BIT 13
+#define RT5645_PWR_DAC_L1 (0x1 << 12)
+#define RT5645_PWR_DAC_L1_BIT 12
+#define RT5645_PWR_DAC_R1 (0x1 << 11)
+#define RT5645_PWR_DAC_R1_BIT 11
+#define RT5645_PWR_CLS_D_R (0x1 << 9)
+#define RT5645_PWR_CLS_D_R_BIT 9
+#define RT5645_PWR_CLS_D_L (0x1 << 8)
+#define RT5645_PWR_CLS_D_L_BIT 8
+#define RT5645_PWR_ADC_R (0x1 << 1)
+#define RT5645_PWR_ADC_R_BIT 1
+#define RT5645_PWR_DAC_L2 (0x1 << 7)
+#define RT5645_PWR_DAC_L2_BIT 7
+#define RT5645_PWR_DAC_R2 (0x1 << 6)
+#define RT5645_PWR_DAC_R2_BIT 6
+#define RT5645_PWR_ADC_L (0x1 << 2)
+#define RT5645_PWR_ADC_L_BIT 2
+#define RT5645_PWR_ADC_R (0x1 << 1)
+#define RT5645_PWR_ADC_R_BIT 1
+#define RT5645_PWR_CLS_D (0x1)
+#define RT5645_PWR_CLS_D_BIT 0
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5645_PWR_ADC_S1F (0x1 << 15)
+#define RT5645_PWR_ADC_S1F_BIT 15
+#define RT5645_PWR_ADC_MF_L (0x1 << 14)
+#define RT5645_PWR_ADC_MF_L_BIT 14
+#define RT5645_PWR_ADC_MF_R (0x1 << 13)
+#define RT5645_PWR_ADC_MF_R_BIT 13
+#define RT5645_PWR_I2S_DSP (0x1 << 12)
+#define RT5645_PWR_I2S_DSP_BIT 12
+#define RT5645_PWR_DAC_S1F (0x1 << 11)
+#define RT5645_PWR_DAC_S1F_BIT 11
+#define RT5645_PWR_DAC_MF_L (0x1 << 10)
+#define RT5645_PWR_DAC_MF_L_BIT 10
+#define RT5645_PWR_DAC_MF_R (0x1 << 9)
+#define RT5645_PWR_DAC_MF_R_BIT 9
+#define RT5645_PWR_ADC_S2F (0x1 << 8)
+#define RT5645_PWR_ADC_S2F_BIT 8
+#define RT5645_PWR_PDM1 (0x1 << 7)
+#define RT5645_PWR_PDM1_BIT 7
+#define RT5645_PWR_PDM2 (0x1 << 6)
+#define RT5645_PWR_PDM2_BIT 6
+#define RT5645_PWR_IPTV (0x1 << 1)
+#define RT5645_PWR_IPTV_BIT 1
+#define RT5645_PWR_PAD (0x1)
+#define RT5645_PWR_PAD_BIT 0
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5645_PWR_VREF1 (0x1 << 15)
+#define RT5645_PWR_VREF1_BIT 15
+#define RT5645_PWR_FV1 (0x1 << 14)
+#define RT5645_PWR_FV1_BIT 14
+#define RT5645_PWR_MB (0x1 << 13)
+#define RT5645_PWR_MB_BIT 13
+#define RT5645_PWR_LM (0x1 << 12)
+#define RT5645_PWR_LM_BIT 12
+#define RT5645_PWR_BG (0x1 << 11)
+#define RT5645_PWR_BG_BIT 11
+#define RT5645_PWR_MA (0x1 << 10)
+#define RT5645_PWR_MA_BIT 10
+#define RT5645_PWR_HP_L (0x1 << 7)
+#define RT5645_PWR_HP_L_BIT 7
+#define RT5645_PWR_HP_R (0x1 << 6)
+#define RT5645_PWR_HP_R_BIT 6
+#define RT5645_PWR_HA (0x1 << 5)
+#define RT5645_PWR_HA_BIT 5
+#define RT5645_PWR_VREF2 (0x1 << 4)
+#define RT5645_PWR_VREF2_BIT 4
+#define RT5645_PWR_FV2 (0x1 << 3)
+#define RT5645_PWR_FV2_BIT 3
+#define RT5645_LDO_SEL_MASK (0x3)
+#define RT5645_LDO_SEL_SFT 0
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5645_PWR_BST1 (0x1 << 15)
+#define RT5645_PWR_BST1_BIT 15
+#define RT5645_PWR_BST2 (0x1 << 14)
+#define RT5645_PWR_BST2_BIT 14
+#define RT5645_PWR_BST3 (0x1 << 13)
+#define RT5645_PWR_BST3_BIT 13
+#define RT5645_PWR_BST4 (0x1 << 12)
+#define RT5645_PWR_BST4_BIT 12
+#define RT5645_PWR_MB1 (0x1 << 11)
+#define RT5645_PWR_MB1_BIT 11
+#define RT5645_PWR_MB2 (0x1 << 10)
+#define RT5645_PWR_MB2_BIT 10
+#define RT5645_PWR_PLL (0x1 << 9)
+#define RT5645_PWR_PLL_BIT 9
+#define RT5645_PWR_BST2_P (0x1 << 5)
+#define RT5645_PWR_BST2_P_BIT 5
+#define RT5645_PWR_BST3_P (0x1 << 4)
+#define RT5645_PWR_BST3_P_BIT 4
+#define RT5645_PWR_BST4_P (0x1 << 3)
+#define RT5645_PWR_BST4_P_BIT 3
+#define RT5645_PWR_JD1 (0x1 << 2)
+#define RT5645_PWR_JD1_BIT 2
+#define RT5645_PWR_JD (0x1 << 1)
+#define RT5645_PWR_JD_BIT 1
+
+/* Power Management for Mixer (0x65) */
+#define RT5645_PWR_OM_L (0x1 << 15)
+#define RT5645_PWR_OM_L_BIT 15
+#define RT5645_PWR_OM_R (0x1 << 14)
+#define RT5645_PWR_OM_R_BIT 14
+#define RT5645_PWR_SM_L (0x1 << 13)
+#define RT5645_PWR_SM_L_BIT 13
+#define RT5645_PWR_SM_R (0x1 << 12)
+#define RT5645_PWR_SM_R_BIT 12
+#define RT5645_PWR_RM_L (0x1 << 11)
+#define RT5645_PWR_RM_L_BIT 11
+#define RT5645_PWR_RM_R (0x1 << 10)
+#define RT5645_PWR_RM_R_BIT 10
+#define RT5645_PWR_MM (0x1 << 8)
+#define RT5645_PWR_MM_BIT 8
+#define RT5645_PWR_HM_L (0x1 << 7)
+#define RT5645_PWR_HM_L_BIT 7
+#define RT5645_PWR_HM_R (0x1 << 6)
+#define RT5645_PWR_HM_R_BIT 6
+#define RT5645_PWR_LDO2 (0x1 << 1)
+#define RT5645_PWR_LDO2_BIT 1
+
+/* Power Management for Volume (0x66) */
+#define RT5645_PWR_SV_L (0x1 << 15)
+#define RT5645_PWR_SV_L_BIT 15
+#define RT5645_PWR_SV_R (0x1 << 14)
+#define RT5645_PWR_SV_R_BIT 14
+#define RT5645_PWR_HV_L (0x1 << 11)
+#define RT5645_PWR_HV_L_BIT 11
+#define RT5645_PWR_HV_R (0x1 << 10)
+#define RT5645_PWR_HV_R_BIT 10
+#define RT5645_PWR_IN_L (0x1 << 9)
+#define RT5645_PWR_IN_L_BIT 9
+#define RT5645_PWR_IN_R (0x1 << 8)
+#define RT5645_PWR_IN_R_BIT 8
+#define RT5645_PWR_MIC_DET (0x1 << 5)
+#define RT5645_PWR_MIC_DET_BIT 5
+
+/* I2S1/2 Audio Serial Data Port Control (0x70 0x71) */
+#define RT5645_I2S_MS_MASK (0x1 << 15)
+#define RT5645_I2S_MS_SFT 15
+#define RT5645_I2S_MS_M (0x0 << 15)
+#define RT5645_I2S_MS_S (0x1 << 15)
+#define RT5645_I2S_O_CP_MASK (0x3 << 10)
+#define RT5645_I2S_O_CP_SFT 10
+#define RT5645_I2S_O_CP_OFF (0x0 << 10)
+#define RT5645_I2S_O_CP_U_LAW (0x1 << 10)
+#define RT5645_I2S_O_CP_A_LAW (0x2 << 10)
+#define RT5645_I2S_I_CP_MASK (0x3 << 8)
+#define RT5645_I2S_I_CP_SFT 8
+#define RT5645_I2S_I_CP_OFF (0x0 << 8)
+#define RT5645_I2S_I_CP_U_LAW (0x1 << 8)
+#define RT5645_I2S_I_CP_A_LAW (0x2 << 8)
+#define RT5645_I2S_BP_MASK (0x1 << 7)
+#define RT5645_I2S_BP_SFT 7
+#define RT5645_I2S_BP_NOR (0x0 << 7)
+#define RT5645_I2S_BP_INV (0x1 << 7)
+#define RT5645_I2S_DL_MASK (0x3 << 2)
+#define RT5645_I2S_DL_SFT 2
+#define RT5645_I2S_DL_16 (0x0 << 2)
+#define RT5645_I2S_DL_20 (0x1 << 2)
+#define RT5645_I2S_DL_24 (0x2 << 2)
+#define RT5645_I2S_DL_8 (0x3 << 2)
+#define RT5645_I2S_DF_MASK (0x3)
+#define RT5645_I2S_DF_SFT 0
+#define RT5645_I2S_DF_I2S (0x0)
+#define RT5645_I2S_DF_LEFT (0x1)
+#define RT5645_I2S_DF_PCM_A (0x2)
+#define RT5645_I2S_DF_PCM_B (0x3)
+
+/* I2S2 Audio Serial Data Port Control (0x71) */
+#define RT5645_I2S2_SDI_MASK (0x1 << 6)
+#define RT5645_I2S2_SDI_SFT 6
+#define RT5645_I2S2_SDI_I2S1 (0x0 << 6)
+#define RT5645_I2S2_SDI_I2S2 (0x1 << 6)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5645_I2S_BCLK_MS1_MASK (0x1 << 15)
+#define RT5645_I2S_BCLK_MS1_SFT 15
+#define RT5645_I2S_BCLK_MS1_32 (0x0 << 15)
+#define RT5645_I2S_BCLK_MS1_64 (0x1 << 15)
+#define RT5645_I2S_PD1_MASK (0x7 << 12)
+#define RT5645_I2S_PD1_SFT 12
+#define RT5645_I2S_PD1_1 (0x0 << 12)
+#define RT5645_I2S_PD1_2 (0x1 << 12)
+#define RT5645_I2S_PD1_3 (0x2 << 12)
+#define RT5645_I2S_PD1_4 (0x3 << 12)
+#define RT5645_I2S_PD1_6 (0x4 << 12)
+#define RT5645_I2S_PD1_8 (0x5 << 12)
+#define RT5645_I2S_PD1_12 (0x6 << 12)
+#define RT5645_I2S_PD1_16 (0x7 << 12)
+#define RT5645_I2S_BCLK_MS2_MASK (0x1 << 11)
+#define RT5645_I2S_BCLK_MS2_SFT 11
+#define RT5645_I2S_BCLK_MS2_32 (0x0 << 11)
+#define RT5645_I2S_BCLK_MS2_64 (0x1 << 11)
+#define RT5645_I2S_PD2_MASK (0x7 << 8)
+#define RT5645_I2S_PD2_SFT 8
+#define RT5645_I2S_PD2_1 (0x0 << 8)
+#define RT5645_I2S_PD2_2 (0x1 << 8)
+#define RT5645_I2S_PD2_3 (0x2 << 8)
+#define RT5645_I2S_PD2_4 (0x3 << 8)
+#define RT5645_I2S_PD2_6 (0x4 << 8)
+#define RT5645_I2S_PD2_8 (0x5 << 8)
+#define RT5645_I2S_PD2_12 (0x6 << 8)
+#define RT5645_I2S_PD2_16 (0x7 << 8)
+#define RT5645_I2S_BCLK_MS3_MASK (0x1 << 7)
+#define RT5645_I2S_BCLK_MS3_SFT 7
+#define RT5645_I2S_BCLK_MS3_32 (0x0 << 7)
+#define RT5645_I2S_BCLK_MS3_64 (0x1 << 7)
+#define RT5645_I2S_PD3_MASK (0x7 << 4)
+#define RT5645_I2S_PD3_SFT 4
+#define RT5645_I2S_PD3_1 (0x0 << 4)
+#define RT5645_I2S_PD3_2 (0x1 << 4)
+#define RT5645_I2S_PD3_3 (0x2 << 4)
+#define RT5645_I2S_PD3_4 (0x3 << 4)
+#define RT5645_I2S_PD3_6 (0x4 << 4)
+#define RT5645_I2S_PD3_8 (0x5 << 4)
+#define RT5645_I2S_PD3_12 (0x6 << 4)
+#define RT5645_I2S_PD3_16 (0x7 << 4)
+#define RT5645_DAC_OSR_MASK (0x3 << 2)
+#define RT5645_DAC_OSR_SFT 2
+#define RT5645_DAC_OSR_128 (0x0 << 2)
+#define RT5645_DAC_OSR_64 (0x1 << 2)
+#define RT5645_DAC_OSR_32 (0x2 << 2)
+#define RT5645_DAC_OSR_16 (0x3 << 2)
+#define RT5645_ADC_OSR_MASK (0x3)
+#define RT5645_ADC_OSR_SFT 0
+#define RT5645_ADC_OSR_128 (0x0)
+#define RT5645_ADC_OSR_64 (0x1)
+#define RT5645_ADC_OSR_32 (0x2)
+#define RT5645_ADC_OSR_16 (0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5645_DAC_L_OSR_MASK (0x3 << 14)
+#define RT5645_DAC_L_OSR_SFT 14
+#define RT5645_DAC_L_OSR_128 (0x0 << 14)
+#define RT5645_DAC_L_OSR_64 (0x1 << 14)
+#define RT5645_DAC_L_OSR_32 (0x2 << 14)
+#define RT5645_DAC_L_OSR_16 (0x3 << 14)
+#define RT5645_ADC_R_OSR_MASK (0x3 << 12)
+#define RT5645_ADC_R_OSR_SFT 12
+#define RT5645_ADC_R_OSR_128 (0x0 << 12)
+#define RT5645_ADC_R_OSR_64 (0x1 << 12)
+#define RT5645_ADC_R_OSR_32 (0x2 << 12)
+#define RT5645_ADC_R_OSR_16 (0x3 << 12)
+#define RT5645_DAHPF_EN (0x1 << 11)
+#define RT5645_DAHPF_EN_SFT 11
+#define RT5645_ADHPF_EN (0x1 << 10)
+#define RT5645_ADHPF_EN_SFT 10
+
+/* Digital Microphone Control (0x75) */
+#define RT5645_DMIC_1_EN_MASK (0x1 << 15)
+#define RT5645_DMIC_1_EN_SFT 15
+#define RT5645_DMIC_1_DIS (0x0 << 15)
+#define RT5645_DMIC_1_EN (0x1 << 15)
+#define RT5645_DMIC_2_EN_MASK (0x1 << 14)
+#define RT5645_DMIC_2_EN_SFT 14
+#define RT5645_DMIC_2_DIS (0x0 << 14)
+#define RT5645_DMIC_2_EN (0x1 << 14)
+#define RT5645_DMIC_1L_LH_MASK (0x1 << 13)
+#define RT5645_DMIC_1L_LH_SFT 13
+#define RT5645_DMIC_1L_LH_FALLING (0x0 << 13)
+#define RT5645_DMIC_1L_LH_RISING (0x1 << 13)
+#define RT5645_DMIC_1R_LH_MASK (0x1 << 12)
+#define RT5645_DMIC_1R_LH_SFT 12
+#define RT5645_DMIC_1R_LH_FALLING (0x0 << 12)
+#define RT5645_DMIC_1R_LH_RISING (0x1 << 12)
+#define RT5645_DMIC_2_DP_MASK (0x3 << 10)
+#define RT5645_DMIC_2_DP_SFT 10
+#define RT5645_DMIC_2_DP_GPIO6 (0x0 << 10)
+#define RT5645_DMIC_2_DP_GPIO10 (0x1 << 10)
+#define RT5645_DMIC_2_DP_GPIO12 (0x2 << 10)
+#define RT5645_DMIC_2_DP_IN2P (0x3 << 10)
+#define RT5645_DMIC_2L_LH_MASK (0x1 << 9)
+#define RT5645_DMIC_2L_LH_SFT 9
+#define RT5645_DMIC_2L_LH_FALLING (0x0 << 9)
+#define RT5645_DMIC_2L_LH_RISING (0x1 << 9)
+#define RT5645_DMIC_2R_LH_MASK (0x1 << 8)
+#define RT5645_DMIC_2R_LH_SFT 8
+#define RT5645_DMIC_2R_LH_FALLING (0x0 << 8)
+#define RT5645_DMIC_2R_LH_RISING (0x1 << 8)
+#define RT5645_DMIC_CLK_MASK (0x7 << 5)
+#define RT5645_DMIC_CLK_SFT 5
+#define RT5645_DMIC_3_EN_MASK (0x1 << 4)
+#define RT5645_DMIC_3_EN_SFT 4
+#define RT5645_DMIC_3_DIS (0x0 << 4)
+#define RT5645_DMIC_3_EN (0x1 << 4)
+#define RT5645_DMIC_1_DP_MASK (0x3 << 0)
+#define RT5645_DMIC_1_DP_SFT 0
+#define RT5645_DMIC_1_DP_GPIO5 (0x0 << 0)
+#define RT5645_DMIC_1_DP_IN2N (0x1 << 0)
+#define RT5645_DMIC_1_DP_GPIO11 (0x2 << 0)
+
+/* TDM Control 1 (0x77) */
+#define RT5645_IF1_ADC_IN_MASK (0x3 << 8)
+#define RT5645_IF1_ADC_IN_SFT 8
+
+/* Global Clock Control (0x80) */
+#define RT5645_SCLK_SRC_MASK (0x3 << 14)
+#define RT5645_SCLK_SRC_SFT 14
+#define RT5645_SCLK_SRC_MCLK (0x0 << 14)
+#define RT5645_SCLK_SRC_PLL1 (0x1 << 14)
+#define RT5645_SCLK_SRC_RCCLK (0x2 << 14) /* 15MHz */
+#define RT5645_PLL1_SRC_MASK (0x3 << 12)
+#define RT5645_PLL1_SRC_SFT 12
+#define RT5645_PLL1_SRC_MCLK (0x0 << 12)
+#define RT5645_PLL1_SRC_BCLK1 (0x1 << 12)
+#define RT5645_PLL1_SRC_BCLK2 (0x2 << 12)
+#define RT5645_PLL1_SRC_BCLK3 (0x3 << 12)
+#define RT5645_PLL1_PD_MASK (0x1 << 3)
+#define RT5645_PLL1_PD_SFT 3
+#define RT5645_PLL1_PD_1 (0x0 << 3)
+#define RT5645_PLL1_PD_2 (0x1 << 3)
+
+#define RT5645_PLL_INP_MAX 40000000
+#define RT5645_PLL_INP_MIN 256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5645_PLL_N_MAX 0x1ff
+#define RT5645_PLL_N_MASK (RT5645_PLL_N_MAX << 7)
+#define RT5645_PLL_N_SFT 7
+#define RT5645_PLL_K_MAX 0x1f
+#define RT5645_PLL_K_MASK (RT5645_PLL_K_MAX)
+#define RT5645_PLL_K_SFT 0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5645_PLL_M_MAX 0xf
+#define RT5645_PLL_M_MASK (RT5645_PLL_M_MAX << 12)
+#define RT5645_PLL_M_SFT 12
+#define RT5645_PLL_M_BP (0x1 << 11)
+#define RT5645_PLL_M_BP_SFT 11
+
+/* ASRC Control 1 (0x83) */
+#define RT5645_STO_T_MASK (0x1 << 15)
+#define RT5645_STO_T_SFT 15
+#define RT5645_STO_T_SCLK (0x0 << 15)
+#define RT5645_STO_T_LRCK1 (0x1 << 15)
+#define RT5645_M1_T_MASK (0x1 << 14)
+#define RT5645_M1_T_SFT 14
+#define RT5645_M1_T_I2S2 (0x0 << 14)
+#define RT5645_M1_T_I2S2_D3 (0x1 << 14)
+#define RT5645_I2S2_F_MASK (0x1 << 12)
+#define RT5645_I2S2_F_SFT 12
+#define RT5645_I2S2_F_I2S2_D2 (0x0 << 12)
+#define RT5645_I2S2_F_I2S1_TCLK (0x1 << 12)
+#define RT5645_DMIC_1_M_MASK (0x1 << 9)
+#define RT5645_DMIC_1_M_SFT 9
+#define RT5645_DMIC_1_M_NOR (0x0 << 9)
+#define RT5645_DMIC_1_M_ASYN (0x1 << 9)
+#define RT5645_DMIC_2_M_MASK (0x1 << 8)
+#define RT5645_DMIC_2_M_SFT 8
+#define RT5645_DMIC_2_M_NOR (0x0 << 8)
+#define RT5645_DMIC_2_M_ASYN (0x1 << 8)
+
+/* ASRC Control 2 (0x84) */
+#define RT5645_MDA_L_M_MASK (0x1 << 15)
+#define RT5645_MDA_L_M_SFT 15
+#define RT5645_MDA_L_M_NOR (0x0 << 15)
+#define RT5645_MDA_L_M_ASYN (0x1 << 15)
+#define RT5645_MDA_R_M_MASK (0x1 << 14)
+#define RT5645_MDA_R_M_SFT 14
+#define RT5645_MDA_R_M_NOR (0x0 << 14)
+#define RT5645_MDA_R_M_ASYN (0x1 << 14)
+#define RT5645_MAD_L_M_MASK (0x1 << 13)
+#define RT5645_MAD_L_M_SFT 13
+#define RT5645_MAD_L_M_NOR (0x0 << 13)
+#define RT5645_MAD_L_M_ASYN (0x1 << 13)
+#define RT5645_MAD_R_M_MASK (0x1 << 12)
+#define RT5645_MAD_R_M_SFT 12
+#define RT5645_MAD_R_M_NOR (0x0 << 12)
+#define RT5645_MAD_R_M_ASYN (0x1 << 12)
+#define RT5645_ADC_M_MASK (0x1 << 11)
+#define RT5645_ADC_M_SFT 11
+#define RT5645_ADC_M_NOR (0x0 << 11)
+#define RT5645_ADC_M_ASYN (0x1 << 11)
+#define RT5645_STO_DAC_M_MASK (0x1 << 5)
+#define RT5645_STO_DAC_M_SFT 5
+#define RT5645_STO_DAC_M_NOR (0x0 << 5)
+#define RT5645_STO_DAC_M_ASYN (0x1 << 5)
+#define RT5645_I2S1_R_D_MASK (0x1 << 4)
+#define RT5645_I2S1_R_D_SFT 4
+#define RT5645_I2S1_R_D_DIS (0x0 << 4)
+#define RT5645_I2S1_R_D_EN (0x1 << 4)
+#define RT5645_I2S2_R_D_MASK (0x1 << 3)
+#define RT5645_I2S2_R_D_SFT 3
+#define RT5645_I2S2_R_D_DIS (0x0 << 3)
+#define RT5645_I2S2_R_D_EN (0x1 << 3)
+#define RT5645_PRE_SCLK_MASK (0x3)
+#define RT5645_PRE_SCLK_SFT 0
+#define RT5645_PRE_SCLK_512 (0x0)
+#define RT5645_PRE_SCLK_1024 (0x1)
+#define RT5645_PRE_SCLK_2048 (0x2)
+
+/* ASRC Control 3 (0x85) */
+#define RT5645_I2S1_RATE_MASK (0xf << 12)
+#define RT5645_I2S1_RATE_SFT 12
+#define RT5645_I2S2_RATE_MASK (0xf << 8)
+#define RT5645_I2S2_RATE_SFT 8
+
+/* ASRC Control 4 (0x89) */
+#define RT5645_I2S1_PD_MASK (0x7 << 12)
+#define RT5645_I2S1_PD_SFT 12
+#define RT5645_I2S2_PD_MASK (0x7 << 8)
+#define RT5645_I2S2_PD_SFT 8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5645_HP_OVCD_MASK (0x1 << 10)
+#define RT5645_HP_OVCD_SFT 10
+#define RT5645_HP_OVCD_DIS (0x0 << 10)
+#define RT5645_HP_OVCD_EN (0x1 << 10)
+#define RT5645_HP_OC_TH_MASK (0x3 << 8)
+#define RT5645_HP_OC_TH_SFT 8
+#define RT5645_HP_OC_TH_90 (0x0 << 8)
+#define RT5645_HP_OC_TH_105 (0x1 << 8)
+#define RT5645_HP_OC_TH_120 (0x2 << 8)
+#define RT5645_HP_OC_TH_135 (0x3 << 8)
+
+/* Class D Over Current Control (0x8c) */
+#define RT5645_CLSD_OC_MASK (0x1 << 9)
+#define RT5645_CLSD_OC_SFT 9
+#define RT5645_CLSD_OC_PU (0x0 << 9)
+#define RT5645_CLSD_OC_PD (0x1 << 9)
+#define RT5645_AUTO_PD_MASK (0x1 << 8)
+#define RT5645_AUTO_PD_SFT 8
+#define RT5645_AUTO_PD_DIS (0x0 << 8)
+#define RT5645_AUTO_PD_EN (0x1 << 8)
+#define RT5645_CLSD_OC_TH_MASK (0x3f)
+#define RT5645_CLSD_OC_TH_SFT 0
+
+/* Class D Output Control (0x8d) */
+#define RT5645_CLSD_RATIO_MASK (0xf << 12)
+#define RT5645_CLSD_RATIO_SFT 12
+#define RT5645_CLSD_OM_MASK (0x1 << 11)
+#define RT5645_CLSD_OM_SFT 11
+#define RT5645_CLSD_OM_MONO (0x0 << 11)
+#define RT5645_CLSD_OM_STO (0x1 << 11)
+#define RT5645_CLSD_SCH_MASK (0x1 << 10)
+#define RT5645_CLSD_SCH_SFT 10
+#define RT5645_CLSD_SCH_L (0x0 << 10)
+#define RT5645_CLSD_SCH_S (0x1 << 10)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5645_SMT_TRIG_MASK (0x1 << 15)
+#define RT5645_SMT_TRIG_SFT 15
+#define RT5645_SMT_TRIG_DIS (0x0 << 15)
+#define RT5645_SMT_TRIG_EN (0x1 << 15)
+#define RT5645_HP_L_SMT_MASK (0x1 << 9)
+#define RT5645_HP_L_SMT_SFT 9
+#define RT5645_HP_L_SMT_DIS (0x0 << 9)
+#define RT5645_HP_L_SMT_EN (0x1 << 9)
+#define RT5645_HP_R_SMT_MASK (0x1 << 8)
+#define RT5645_HP_R_SMT_SFT 8
+#define RT5645_HP_R_SMT_DIS (0x0 << 8)
+#define RT5645_HP_R_SMT_EN (0x1 << 8)
+#define RT5645_HP_CD_PD_MASK (0x1 << 7)
+#define RT5645_HP_CD_PD_SFT 7
+#define RT5645_HP_CD_PD_DIS (0x0 << 7)
+#define RT5645_HP_CD_PD_EN (0x1 << 7)
+#define RT5645_RSTN_MASK (0x1 << 6)
+#define RT5645_RSTN_SFT 6
+#define RT5645_RSTN_DIS (0x0 << 6)
+#define RT5645_RSTN_EN (0x1 << 6)
+#define RT5645_RSTP_MASK (0x1 << 5)
+#define RT5645_RSTP_SFT 5
+#define RT5645_RSTP_DIS (0x0 << 5)
+#define RT5645_RSTP_EN (0x1 << 5)
+#define RT5645_HP_CO_MASK (0x1 << 4)
+#define RT5645_HP_CO_SFT 4
+#define RT5645_HP_CO_DIS (0x0 << 4)
+#define RT5645_HP_CO_EN (0x1 << 4)
+#define RT5645_HP_CP_MASK (0x1 << 3)
+#define RT5645_HP_CP_SFT 3
+#define RT5645_HP_CP_PD (0x0 << 3)
+#define RT5645_HP_CP_PU (0x1 << 3)
+#define RT5645_HP_SG_MASK (0x1 << 2)
+#define RT5645_HP_SG_SFT 2
+#define RT5645_HP_SG_DIS (0x0 << 2)
+#define RT5645_HP_SG_EN (0x1 << 2)
+#define RT5645_HP_DP_MASK (0x1 << 1)
+#define RT5645_HP_DP_SFT 1
+#define RT5645_HP_DP_PD (0x0 << 1)
+#define RT5645_HP_DP_PU (0x1 << 1)
+#define RT5645_HP_CB_MASK (0x1)
+#define RT5645_HP_CB_SFT 0
+#define RT5645_HP_CB_PD (0x0)
+#define RT5645_HP_CB_PU (0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5645_DEPOP_MASK (0x1 << 13)
+#define RT5645_DEPOP_SFT 13
+#define RT5645_DEPOP_AUTO (0x0 << 13)
+#define RT5645_DEPOP_MAN (0x1 << 13)
+#define RT5645_RAMP_MASK (0x1 << 12)
+#define RT5645_RAMP_SFT 12
+#define RT5645_RAMP_DIS (0x0 << 12)
+#define RT5645_RAMP_EN (0x1 << 12)
+#define RT5645_BPS_MASK (0x1 << 11)
+#define RT5645_BPS_SFT 11
+#define RT5645_BPS_DIS (0x0 << 11)
+#define RT5645_BPS_EN (0x1 << 11)
+#define RT5645_FAST_UPDN_MASK (0x1 << 10)
+#define RT5645_FAST_UPDN_SFT 10
+#define RT5645_FAST_UPDN_DIS (0x0 << 10)
+#define RT5645_FAST_UPDN_EN (0x1 << 10)
+#define RT5645_MRES_MASK (0x3 << 8)
+#define RT5645_MRES_SFT 8
+#define RT5645_MRES_15MO (0x0 << 8)
+#define RT5645_MRES_25MO (0x1 << 8)
+#define RT5645_MRES_35MO (0x2 << 8)
+#define RT5645_MRES_45MO (0x3 << 8)
+#define RT5645_VLO_MASK (0x1 << 7)
+#define RT5645_VLO_SFT 7
+#define RT5645_VLO_3V (0x0 << 7)
+#define RT5645_VLO_32V (0x1 << 7)
+#define RT5645_DIG_DP_MASK (0x1 << 6)
+#define RT5645_DIG_DP_SFT 6
+#define RT5645_DIG_DP_DIS (0x0 << 6)
+#define RT5645_DIG_DP_EN (0x1 << 6)
+#define RT5645_DP_TH_MASK (0x3 << 4)
+#define RT5645_DP_TH_SFT 4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5645_CP_SYS_MASK (0x7 << 12)
+#define RT5645_CP_SYS_SFT 12
+#define RT5645_CP_FQ1_MASK (0x7 << 8)
+#define RT5645_CP_FQ1_SFT 8
+#define RT5645_CP_FQ2_MASK (0x7 << 4)
+#define RT5645_CP_FQ2_SFT 4
+#define RT5645_CP_FQ3_MASK (0x7)
+#define RT5645_CP_FQ3_SFT 0
+#define RT5645_CP_FQ_1_5_KHZ 0
+#define RT5645_CP_FQ_3_KHZ 1
+#define RT5645_CP_FQ_6_KHZ 2
+#define RT5645_CP_FQ_12_KHZ 3
+#define RT5645_CP_FQ_24_KHZ 4
+#define RT5645_CP_FQ_48_KHZ 5
+#define RT5645_CP_FQ_96_KHZ 6
+#define RT5645_CP_FQ_192_KHZ 7
+
+/* PV detection and SPK gain control (0x92) */
+#define RT5645_PVDD_DET_MASK (0x1 << 15)
+#define RT5645_PVDD_DET_SFT 15
+#define RT5645_PVDD_DET_DIS (0x0 << 15)
+#define RT5645_PVDD_DET_EN (0x1 << 15)
+#define RT5645_SPK_AG_MASK (0x1 << 14)
+#define RT5645_SPK_AG_SFT 14
+#define RT5645_SPK_AG_DIS (0x0 << 14)
+#define RT5645_SPK_AG_EN (0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5645_MIC1_BS_MASK (0x1 << 15)
+#define RT5645_MIC1_BS_SFT 15
+#define RT5645_MIC1_BS_9AV (0x0 << 15)
+#define RT5645_MIC1_BS_75AV (0x1 << 15)
+#define RT5645_MIC2_BS_MASK (0x1 << 14)
+#define RT5645_MIC2_BS_SFT 14
+#define RT5645_MIC2_BS_9AV (0x0 << 14)
+#define RT5645_MIC2_BS_75AV (0x1 << 14)
+#define RT5645_MIC1_CLK_MASK (0x1 << 13)
+#define RT5645_MIC1_CLK_SFT 13
+#define RT5645_MIC1_CLK_DIS (0x0 << 13)
+#define RT5645_MIC1_CLK_EN (0x1 << 13)
+#define RT5645_MIC2_CLK_MASK (0x1 << 12)
+#define RT5645_MIC2_CLK_SFT 12
+#define RT5645_MIC2_CLK_DIS (0x0 << 12)
+#define RT5645_MIC2_CLK_EN (0x1 << 12)
+#define RT5645_MIC1_OVCD_MASK (0x1 << 11)
+#define RT5645_MIC1_OVCD_SFT 11
+#define RT5645_MIC1_OVCD_DIS (0x0 << 11)
+#define RT5645_MIC1_OVCD_EN (0x1 << 11)
+#define RT5645_MIC1_OVTH_MASK (0x3 << 9)
+#define RT5645_MIC1_OVTH_SFT 9
+#define RT5645_MIC1_OVTH_600UA (0x0 << 9)
+#define RT5645_MIC1_OVTH_1500UA (0x1 << 9)
+#define RT5645_MIC1_OVTH_2000UA (0x2 << 9)
+#define RT5645_MIC2_OVCD_MASK (0x1 << 8)
+#define RT5645_MIC2_OVCD_SFT 8
+#define RT5645_MIC2_OVCD_DIS (0x0 << 8)
+#define RT5645_MIC2_OVCD_EN (0x1 << 8)
+#define RT5645_MIC2_OVTH_MASK (0x3 << 6)
+#define RT5645_MIC2_OVTH_SFT 6
+#define RT5645_MIC2_OVTH_600UA (0x0 << 6)
+#define RT5645_MIC2_OVTH_1500UA (0x1 << 6)
+#define RT5645_MIC2_OVTH_2000UA (0x2 << 6)
+#define RT5645_PWR_MB_MASK (0x1 << 5)
+#define RT5645_PWR_MB_SFT 5
+#define RT5645_PWR_MB_PD (0x0 << 5)
+#define RT5645_PWR_MB_PU (0x1 << 5)
+#define RT5645_PWR_CLK25M_MASK (0x1 << 4)
+#define RT5645_PWR_CLK25M_SFT 4
+#define RT5645_PWR_CLK25M_PD (0x0 << 4)
+#define RT5645_PWR_CLK25M_PU (0x1 << 4)
+
+/* VAD Control 4 (0x9d) */
+#define RT5645_VAD_SEL_MASK (0x3 << 8)
+#define RT5645_VAD_SEL_SFT 8
+
+/* EQ Control 1 (0xb0) */
+#define RT5645_EQ_SRC_MASK (0x1 << 15)
+#define RT5645_EQ_SRC_SFT 15
+#define RT5645_EQ_SRC_DAC (0x0 << 15)
+#define RT5645_EQ_SRC_ADC (0x1 << 15)
+#define RT5645_EQ_UPD (0x1 << 14)
+#define RT5645_EQ_UPD_BIT 14
+#define RT5645_EQ_CD_MASK (0x1 << 13)
+#define RT5645_EQ_CD_SFT 13
+#define RT5645_EQ_CD_DIS (0x0 << 13)
+#define RT5645_EQ_CD_EN (0x1 << 13)
+#define RT5645_EQ_DITH_MASK (0x3 << 8)
+#define RT5645_EQ_DITH_SFT 8
+#define RT5645_EQ_DITH_NOR (0x0 << 8)
+#define RT5645_EQ_DITH_LSB (0x1 << 8)
+#define RT5645_EQ_DITH_LSB_1 (0x2 << 8)
+#define RT5645_EQ_DITH_LSB_2 (0x3 << 8)
+
+/* EQ Control 2 (0xb1) */
+#define RT5645_EQ_HPF1_M_MASK (0x1 << 8)
+#define RT5645_EQ_HPF1_M_SFT 8
+#define RT5645_EQ_HPF1_M_HI (0x0 << 8)
+#define RT5645_EQ_HPF1_M_1ST (0x1 << 8)
+#define RT5645_EQ_LPF1_M_MASK (0x1 << 7)
+#define RT5645_EQ_LPF1_M_SFT 7
+#define RT5645_EQ_LPF1_M_LO (0x0 << 7)
+#define RT5645_EQ_LPF1_M_1ST (0x1 << 7)
+#define RT5645_EQ_HPF2_MASK (0x1 << 6)
+#define RT5645_EQ_HPF2_SFT 6
+#define RT5645_EQ_HPF2_DIS (0x0 << 6)
+#define RT5645_EQ_HPF2_EN (0x1 << 6)
+#define RT5645_EQ_HPF1_MASK (0x1 << 5)
+#define RT5645_EQ_HPF1_SFT 5
+#define RT5645_EQ_HPF1_DIS (0x0 << 5)
+#define RT5645_EQ_HPF1_EN (0x1 << 5)
+#define RT5645_EQ_BPF4_MASK (0x1 << 4)
+#define RT5645_EQ_BPF4_SFT 4
+#define RT5645_EQ_BPF4_DIS (0x0 << 4)
+#define RT5645_EQ_BPF4_EN (0x1 << 4)
+#define RT5645_EQ_BPF3_MASK (0x1 << 3)
+#define RT5645_EQ_BPF3_SFT 3
+#define RT5645_EQ_BPF3_DIS (0x0 << 3)
+#define RT5645_EQ_BPF3_EN (0x1 << 3)
+#define RT5645_EQ_BPF2_MASK (0x1 << 2)
+#define RT5645_EQ_BPF2_SFT 2
+#define RT5645_EQ_BPF2_DIS (0x0 << 2)
+#define RT5645_EQ_BPF2_EN (0x1 << 2)
+#define RT5645_EQ_BPF1_MASK (0x1 << 1)
+#define RT5645_EQ_BPF1_SFT 1
+#define RT5645_EQ_BPF1_DIS (0x0 << 1)
+#define RT5645_EQ_BPF1_EN (0x1 << 1)
+#define RT5645_EQ_LPF_MASK (0x1)
+#define RT5645_EQ_LPF_SFT 0
+#define RT5645_EQ_LPF_DIS (0x0)
+#define RT5645_EQ_LPF_EN (0x1)
+#define RT5645_EQ_CTRL_MASK (0x7f)
+
+/* Memory Test (0xb2) */
+#define RT5645_MT_MASK (0x1 << 15)
+#define RT5645_MT_SFT 15
+#define RT5645_MT_DIS (0x0 << 15)
+#define RT5645_MT_EN (0x1 << 15)
+
+/* DRC/AGC Control 1 (0xb4) */
+#define RT5645_DRC_AGC_P_MASK (0x1 << 15)
+#define RT5645_DRC_AGC_P_SFT 15
+#define RT5645_DRC_AGC_P_DAC (0x0 << 15)
+#define RT5645_DRC_AGC_P_ADC (0x1 << 15)
+#define RT5645_DRC_AGC_MASK (0x1 << 14)
+#define RT5645_DRC_AGC_SFT 14
+#define RT5645_DRC_AGC_DIS (0x0 << 14)
+#define RT5645_DRC_AGC_EN (0x1 << 14)
+#define RT5645_DRC_AGC_UPD (0x1 << 13)
+#define RT5645_DRC_AGC_UPD_BIT 13
+#define RT5645_DRC_AGC_AR_MASK (0x1f << 8)
+#define RT5645_DRC_AGC_AR_SFT 8
+#define RT5645_DRC_AGC_R_MASK (0x7 << 5)
+#define RT5645_DRC_AGC_R_SFT 5
+#define RT5645_DRC_AGC_R_48K (0x1 << 5)
+#define RT5645_DRC_AGC_R_96K (0x2 << 5)
+#define RT5645_DRC_AGC_R_192K (0x3 << 5)
+#define RT5645_DRC_AGC_R_441K (0x5 << 5)
+#define RT5645_DRC_AGC_R_882K (0x6 << 5)
+#define RT5645_DRC_AGC_R_1764K (0x7 << 5)
+#define RT5645_DRC_AGC_RC_MASK (0x1f)
+#define RT5645_DRC_AGC_RC_SFT 0
+
+/* DRC/AGC Control 2 (0xb5) */
+#define RT5645_DRC_AGC_POB_MASK (0x3f << 8)
+#define RT5645_DRC_AGC_POB_SFT 8
+#define RT5645_DRC_AGC_CP_MASK (0x1 << 7)
+#define RT5645_DRC_AGC_CP_SFT 7
+#define RT5645_DRC_AGC_CP_DIS (0x0 << 7)
+#define RT5645_DRC_AGC_CP_EN (0x1 << 7)
+#define RT5645_DRC_AGC_CPR_MASK (0x3 << 5)
+#define RT5645_DRC_AGC_CPR_SFT 5
+#define RT5645_DRC_AGC_CPR_1_1 (0x0 << 5)
+#define RT5645_DRC_AGC_CPR_1_2 (0x1 << 5)
+#define RT5645_DRC_AGC_CPR_1_3 (0x2 << 5)
+#define RT5645_DRC_AGC_CPR_1_4 (0x3 << 5)
+#define RT5645_DRC_AGC_PRB_MASK (0x1f)
+#define RT5645_DRC_AGC_PRB_SFT 0
+
+/* DRC/AGC Control 3 (0xb6) */
+#define RT5645_DRC_AGC_NGB_MASK (0xf << 12)
+#define RT5645_DRC_AGC_NGB_SFT 12
+#define RT5645_DRC_AGC_TAR_MASK (0x1f << 7)
+#define RT5645_DRC_AGC_TAR_SFT 7
+#define RT5645_DRC_AGC_NG_MASK (0x1 << 6)
+#define RT5645_DRC_AGC_NG_SFT 6
+#define RT5645_DRC_AGC_NG_DIS (0x0 << 6)
+#define RT5645_DRC_AGC_NG_EN (0x1 << 6)
+#define RT5645_DRC_AGC_NGH_MASK (0x1 << 5)
+#define RT5645_DRC_AGC_NGH_SFT 5
+#define RT5645_DRC_AGC_NGH_DIS (0x0 << 5)
+#define RT5645_DRC_AGC_NGH_EN (0x1 << 5)
+#define RT5645_DRC_AGC_NGT_MASK (0x1f)
+#define RT5645_DRC_AGC_NGT_SFT 0
+
+/* ANC Control 1 (0xb8) */
+#define RT5645_ANC_M_MASK (0x1 << 15)
+#define RT5645_ANC_M_SFT 15
+#define RT5645_ANC_M_NOR (0x0 << 15)
+#define RT5645_ANC_M_REV (0x1 << 15)
+#define RT5645_ANC_MASK (0x1 << 14)
+#define RT5645_ANC_SFT 14
+#define RT5645_ANC_DIS (0x0 << 14)
+#define RT5645_ANC_EN (0x1 << 14)
+#define RT5645_ANC_MD_MASK (0x3 << 12)
+#define RT5645_ANC_MD_SFT 12
+#define RT5645_ANC_MD_DIS (0x0 << 12)
+#define RT5645_ANC_MD_67MS (0x1 << 12)
+#define RT5645_ANC_MD_267MS (0x2 << 12)
+#define RT5645_ANC_MD_1067MS (0x3 << 12)
+#define RT5645_ANC_SN_MASK (0x1 << 11)
+#define RT5645_ANC_SN_SFT 11
+#define RT5645_ANC_SN_DIS (0x0 << 11)
+#define RT5645_ANC_SN_EN (0x1 << 11)
+#define RT5645_ANC_CLK_MASK (0x1 << 10)
+#define RT5645_ANC_CLK_SFT 10
+#define RT5645_ANC_CLK_ANC (0x0 << 10)
+#define RT5645_ANC_CLK_REG (0x1 << 10)
+#define RT5645_ANC_ZCD_MASK (0x3 << 8)
+#define RT5645_ANC_ZCD_SFT 8
+#define RT5645_ANC_ZCD_DIS (0x0 << 8)
+#define RT5645_ANC_ZCD_T1 (0x1 << 8)
+#define RT5645_ANC_ZCD_T2 (0x2 << 8)
+#define RT5645_ANC_ZCD_WT (0x3 << 8)
+#define RT5645_ANC_CS_MASK (0x1 << 7)
+#define RT5645_ANC_CS_SFT 7
+#define RT5645_ANC_CS_DIS (0x0 << 7)
+#define RT5645_ANC_CS_EN (0x1 << 7)
+#define RT5645_ANC_SW_MASK (0x1 << 6)
+#define RT5645_ANC_SW_SFT 6
+#define RT5645_ANC_SW_NOR (0x0 << 6)
+#define RT5645_ANC_SW_AUTO (0x1 << 6)
+#define RT5645_ANC_CO_L_MASK (0x3f)
+#define RT5645_ANC_CO_L_SFT 0
+
+/* ANC Control 2 (0xb6) */
+#define RT5645_ANC_FG_R_MASK (0xf << 12)
+#define RT5645_ANC_FG_R_SFT 12
+#define RT5645_ANC_FG_L_MASK (0xf << 8)
+#define RT5645_ANC_FG_L_SFT 8
+#define RT5645_ANC_CG_R_MASK (0xf << 4)
+#define RT5645_ANC_CG_R_SFT 4
+#define RT5645_ANC_CG_L_MASK (0xf)
+#define RT5645_ANC_CG_L_SFT 0
+
+/* ANC Control 3 (0xb6) */
+#define RT5645_ANC_CD_MASK (0x1 << 6)
+#define RT5645_ANC_CD_SFT 6
+#define RT5645_ANC_CD_BOTH (0x0 << 6)
+#define RT5645_ANC_CD_IND (0x1 << 6)
+#define RT5645_ANC_CO_R_MASK (0x3f)
+#define RT5645_ANC_CO_R_SFT 0
+
+/* Jack Detect Control (0xbb) */
+#define RT5645_JD_MASK (0x7 << 13)
+#define RT5645_JD_SFT 13
+#define RT5645_JD_DIS (0x0 << 13)
+#define RT5645_JD_GPIO1 (0x1 << 13)
+#define RT5645_JD_JD1_IN4P (0x2 << 13)
+#define RT5645_JD_JD2_IN4N (0x3 << 13)
+#define RT5645_JD_GPIO2 (0x4 << 13)
+#define RT5645_JD_GPIO3 (0x5 << 13)
+#define RT5645_JD_GPIO4 (0x6 << 13)
+#define RT5645_JD_HP_MASK (0x1 << 11)
+#define RT5645_JD_HP_SFT 11
+#define RT5645_JD_HP_DIS (0x0 << 11)
+#define RT5645_JD_HP_EN (0x1 << 11)
+#define RT5645_JD_HP_TRG_MASK (0x1 << 10)
+#define RT5645_JD_HP_TRG_SFT 10
+#define RT5645_JD_HP_TRG_LO (0x0 << 10)
+#define RT5645_JD_HP_TRG_HI (0x1 << 10)
+#define RT5645_JD_SPL_MASK (0x1 << 9)
+#define RT5645_JD_SPL_SFT 9
+#define RT5645_JD_SPL_DIS (0x0 << 9)
+#define RT5645_JD_SPL_EN (0x1 << 9)
+#define RT5645_JD_SPL_TRG_MASK (0x1 << 8)
+#define RT5645_JD_SPL_TRG_SFT 8
+#define RT5645_JD_SPL_TRG_LO (0x0 << 8)
+#define RT5645_JD_SPL_TRG_HI (0x1 << 8)
+#define RT5645_JD_SPR_MASK (0x1 << 7)
+#define RT5645_JD_SPR_SFT 7
+#define RT5645_JD_SPR_DIS (0x0 << 7)
+#define RT5645_JD_SPR_EN (0x1 << 7)
+#define RT5645_JD_SPR_TRG_MASK (0x1 << 6)
+#define RT5645_JD_SPR_TRG_SFT 6
+#define RT5645_JD_SPR_TRG_LO (0x0 << 6)
+#define RT5645_JD_SPR_TRG_HI (0x1 << 6)
+#define RT5645_JD_MO_MASK (0x1 << 5)
+#define RT5645_JD_MO_SFT 5
+#define RT5645_JD_MO_DIS (0x0 << 5)
+#define RT5645_JD_MO_EN (0x1 << 5)
+#define RT5645_JD_MO_TRG_MASK (0x1 << 4)
+#define RT5645_JD_MO_TRG_SFT 4
+#define RT5645_JD_MO_TRG_LO (0x0 << 4)
+#define RT5645_JD_MO_TRG_HI (0x1 << 4)
+#define RT5645_JD_LO_MASK (0x1 << 3)
+#define RT5645_JD_LO_SFT 3
+#define RT5645_JD_LO_DIS (0x0 << 3)
+#define RT5645_JD_LO_EN (0x1 << 3)
+#define RT5645_JD_LO_TRG_MASK (0x1 << 2)
+#define RT5645_JD_LO_TRG_SFT 2
+#define RT5645_JD_LO_TRG_LO (0x0 << 2)
+#define RT5645_JD_LO_TRG_HI (0x1 << 2)
+#define RT5645_JD1_IN4P_MASK (0x1 << 1)
+#define RT5645_JD1_IN4P_SFT 1
+#define RT5645_JD1_IN4P_DIS (0x0 << 1)
+#define RT5645_JD1_IN4P_EN (0x1 << 1)
+#define RT5645_JD2_IN4N_MASK (0x1)
+#define RT5645_JD2_IN4N_SFT 0
+#define RT5645_JD2_IN4N_DIS (0x0)
+#define RT5645_JD2_IN4N_EN (0x1)
+
+/* Jack detect for ANC (0xbc) */
+#define RT5645_ANC_DET_MASK (0x3 << 4)
+#define RT5645_ANC_DET_SFT 4
+#define RT5645_ANC_DET_DIS (0x0 << 4)
+#define RT5645_ANC_DET_MB1 (0x1 << 4)
+#define RT5645_ANC_DET_MB2 (0x2 << 4)
+#define RT5645_ANC_DET_JD (0x3 << 4)
+#define RT5645_AD_TRG_MASK (0x1 << 3)
+#define RT5645_AD_TRG_SFT 3
+#define RT5645_AD_TRG_LO (0x0 << 3)
+#define RT5645_AD_TRG_HI (0x1 << 3)
+#define RT5645_ANCM_DET_MASK (0x3 << 4)
+#define RT5645_ANCM_DET_SFT 4
+#define RT5645_ANCM_DET_DIS (0x0 << 4)
+#define RT5645_ANCM_DET_MB1 (0x1 << 4)
+#define RT5645_ANCM_DET_MB2 (0x2 << 4)
+#define RT5645_ANCM_DET_JD (0x3 << 4)
+#define RT5645_AMD_TRG_MASK (0x1 << 3)
+#define RT5645_AMD_TRG_SFT 3
+#define RT5645_AMD_TRG_LO (0x0 << 3)
+#define RT5645_AMD_TRG_HI (0x1 << 3)
+
+/* IRQ Control 1 (0xbd) */
+#define RT5645_IRQ_JD_MASK (0x1 << 15)
+#define RT5645_IRQ_JD_SFT 15
+#define RT5645_IRQ_JD_BP (0x0 << 15)
+#define RT5645_IRQ_JD_NOR (0x1 << 15)
+#define RT5645_IRQ_OT_MASK (0x1 << 14)
+#define RT5645_IRQ_OT_SFT 14
+#define RT5645_IRQ_OT_BP (0x0 << 14)
+#define RT5645_IRQ_OT_NOR (0x1 << 14)
+#define RT5645_JD_STKY_MASK (0x1 << 13)
+#define RT5645_JD_STKY_SFT 13
+#define RT5645_JD_STKY_DIS (0x0 << 13)
+#define RT5645_JD_STKY_EN (0x1 << 13)
+#define RT5645_OT_STKY_MASK (0x1 << 12)
+#define RT5645_OT_STKY_SFT 12
+#define RT5645_OT_STKY_DIS (0x0 << 12)
+#define RT5645_OT_STKY_EN (0x1 << 12)
+#define RT5645_JD_P_MASK (0x1 << 11)
+#define RT5645_JD_P_SFT 11
+#define RT5645_JD_P_NOR (0x0 << 11)
+#define RT5645_JD_P_INV (0x1 << 11)
+#define RT5645_OT_P_MASK (0x1 << 10)
+#define RT5645_OT_P_SFT 10
+#define RT5645_OT_P_NOR (0x0 << 10)
+#define RT5645_OT_P_INV (0x1 << 10)
+
+/* IRQ Control 2 (0xbe) */
+#define RT5645_IRQ_MB1_OC_MASK (0x1 << 15)
+#define RT5645_IRQ_MB1_OC_SFT 15
+#define RT5645_IRQ_MB1_OC_BP (0x0 << 15)
+#define RT5645_IRQ_MB1_OC_NOR (0x1 << 15)
+#define RT5645_IRQ_MB2_OC_MASK (0x1 << 14)
+#define RT5645_IRQ_MB2_OC_SFT 14
+#define RT5645_IRQ_MB2_OC_BP (0x0 << 14)
+#define RT5645_IRQ_MB2_OC_NOR (0x1 << 14)
+#define RT5645_MB1_OC_STKY_MASK (0x1 << 13)
+#define RT5645_MB1_OC_STKY_SFT 13
+#define RT5645_MB1_OC_STKY_DIS (0x0 << 13)
+#define RT5645_MB1_OC_STKY_EN (0x1 << 13)
+#define RT5645_MB2_OC_STKY_MASK (0x1 << 12)
+#define RT5645_MB2_OC_STKY_SFT 12
+#define RT5645_MB2_OC_STKY_DIS (0x0 << 12)
+#define RT5645_MB2_OC_STKY_EN (0x1 << 12)
+#define RT5645_MB1_OC_P_MASK (0x1 << 7)
+#define RT5645_MB1_OC_P_SFT 7
+#define RT5645_MB1_OC_P_NOR (0x0 << 7)
+#define RT5645_MB1_OC_P_INV (0x1 << 7)
+#define RT5645_MB2_OC_P_MASK (0x1 << 6)
+#define RT5645_MB2_OC_P_SFT 6
+#define RT5645_MB2_OC_P_NOR (0x0 << 6)
+#define RT5645_MB2_OC_P_INV (0x1 << 6)
+#define RT5645_MB1_OC_CLR (0x1 << 3)
+#define RT5645_MB1_OC_CLR_SFT 3
+#define RT5645_MB2_OC_CLR (0x1 << 2)
+#define RT5645_MB2_OC_CLR_SFT 2
+
+/* GPIO Control 1 (0xc0) */
+#define RT5645_GP1_PIN_MASK (0x1 << 15)
+#define RT5645_GP1_PIN_SFT 15
+#define RT5645_GP1_PIN_GPIO1 (0x0 << 15)
+#define RT5645_GP1_PIN_IRQ (0x1 << 15)
+#define RT5645_GP2_PIN_MASK (0x1 << 14)
+#define RT5645_GP2_PIN_SFT 14
+#define RT5645_GP2_PIN_GPIO2 (0x0 << 14)
+#define RT5645_GP2_PIN_DMIC1_SCL (0x1 << 14)
+#define RT5645_GP3_PIN_MASK (0x3 << 12)
+#define RT5645_GP3_PIN_SFT 12
+#define RT5645_GP3_PIN_GPIO3 (0x0 << 12)
+#define RT5645_GP3_PIN_DMIC1_SDA (0x1 << 12)
+#define RT5645_GP3_PIN_IRQ (0x2 << 12)
+#define RT5645_GP4_PIN_MASK (0x1 << 11)
+#define RT5645_GP4_PIN_SFT 11
+#define RT5645_GP4_PIN_GPIO4 (0x0 << 11)
+#define RT5645_GP4_PIN_DMIC2_SDA (0x1 << 11)
+#define RT5645_DP_SIG_MASK (0x1 << 10)
+#define RT5645_DP_SIG_SFT 10
+#define RT5645_DP_SIG_TEST (0x0 << 10)
+#define RT5645_DP_SIG_AP (0x1 << 10)
+#define RT5645_GPIO_M_MASK (0x1 << 9)
+#define RT5645_GPIO_M_SFT 9
+#define RT5645_GPIO_M_FLT (0x0 << 9)
+#define RT5645_GPIO_M_PH (0x1 << 9)
+#define RT5645_I2S2_SEL (0x1 << 8)
+#define RT5645_I2S2_SEL_SFT 8
+#define RT5645_GP5_PIN_MASK (0x1 << 7)
+#define RT5645_GP5_PIN_SFT 7
+#define RT5645_GP5_PIN_GPIO5 (0x0 << 7)
+#define RT5645_GP5_PIN_DMIC1_SDA (0x1 << 7)
+#define RT5645_GP6_PIN_MASK (0x1 << 6)
+#define RT5645_GP6_PIN_SFT 6
+#define RT5645_GP6_PIN_GPIO6 (0x0 << 6)
+#define RT5645_GP6_PIN_DMIC2_SDA (0x1 << 6)
+#define RT5645_GP8_PIN_MASK (0x1 << 3)
+#define RT5645_GP8_PIN_SFT 3
+#define RT5645_GP8_PIN_GPIO8 (0x0 << 3)
+#define RT5645_GP8_PIN_DMIC2_SDA (0x1 << 3)
+#define RT5645_GP12_PIN_MASK (0x1 << 2)
+#define RT5645_GP12_PIN_SFT 2
+#define RT5645_GP12_PIN_GPIO12 (0x0 << 2)
+#define RT5645_GP12_PIN_DMIC2_SDA (0x1 << 2)
+#define RT5645_GP11_PIN_MASK (0x1 << 1)
+#define RT5645_GP11_PIN_SFT 1
+#define RT5645_GP11_PIN_GPIO11 (0x0 << 1)
+#define RT5645_GP11_PIN_DMIC1_SDA (0x1 << 1)
+#define RT5645_GP10_PIN_MASK (0x1)
+#define RT5645_GP10_PIN_SFT 0
+#define RT5645_GP10_PIN_GPIO10 (0x0)
+#define RT5645_GP10_PIN_DMIC2_SDA (0x1)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5645_GP4_PF_MASK (0x1 << 11)
+#define RT5645_GP4_PF_SFT 11
+#define RT5645_GP4_PF_IN (0x0 << 11)
+#define RT5645_GP4_PF_OUT (0x1 << 11)
+#define RT5645_GP4_OUT_MASK (0x1 << 10)
+#define RT5645_GP4_OUT_SFT 10
+#define RT5645_GP4_OUT_LO (0x0 << 10)
+#define RT5645_GP4_OUT_HI (0x1 << 10)
+#define RT5645_GP4_P_MASK (0x1 << 9)
+#define RT5645_GP4_P_SFT 9
+#define RT5645_GP4_P_NOR (0x0 << 9)
+#define RT5645_GP4_P_INV (0x1 << 9)
+#define RT5645_GP3_PF_MASK (0x1 << 8)
+#define RT5645_GP3_PF_SFT 8
+#define RT5645_GP3_PF_IN (0x0 << 8)
+#define RT5645_GP3_PF_OUT (0x1 << 8)
+#define RT5645_GP3_OUT_MASK (0x1 << 7)
+#define RT5645_GP3_OUT_SFT 7
+#define RT5645_GP3_OUT_LO (0x0 << 7)
+#define RT5645_GP3_OUT_HI (0x1 << 7)
+#define RT5645_GP3_P_MASK (0x1 << 6)
+#define RT5645_GP3_P_SFT 6
+#define RT5645_GP3_P_NOR (0x0 << 6)
+#define RT5645_GP3_P_INV (0x1 << 6)
+#define RT5645_GP2_PF_MASK (0x1 << 5)
+#define RT5645_GP2_PF_SFT 5
+#define RT5645_GP2_PF_IN (0x0 << 5)
+#define RT5645_GP2_PF_OUT (0x1 << 5)
+#define RT5645_GP2_OUT_MASK (0x1 << 4)
+#define RT5645_GP2_OUT_SFT 4
+#define RT5645_GP2_OUT_LO (0x0 << 4)
+#define RT5645_GP2_OUT_HI (0x1 << 4)
+#define RT5645_GP2_P_MASK (0x1 << 3)
+#define RT5645_GP2_P_SFT 3
+#define RT5645_GP2_P_NOR (0x0 << 3)
+#define RT5645_GP2_P_INV (0x1 << 3)
+#define RT5645_GP1_PF_MASK (0x1 << 2)
+#define RT5645_GP1_PF_SFT 2
+#define RT5645_GP1_PF_IN (0x0 << 2)
+#define RT5645_GP1_PF_OUT (0x1 << 2)
+#define RT5645_GP1_OUT_MASK (0x1 << 1)
+#define RT5645_GP1_OUT_SFT 1
+#define RT5645_GP1_OUT_LO (0x0 << 1)
+#define RT5645_GP1_OUT_HI (0x1 << 1)
+#define RT5645_GP1_P_MASK (0x1)
+#define RT5645_GP1_P_SFT 0
+#define RT5645_GP1_P_NOR (0x0)
+#define RT5645_GP1_P_INV (0x1)
+
+/* Programmable Register Array Control 1 (0xc8) */
+#define RT5645_REG_SEQ_MASK (0xf << 12)
+#define RT5645_REG_SEQ_SFT 12
+#define RT5645_SEQ1_ST_MASK (0x1 << 11) /*RO*/
+#define RT5645_SEQ1_ST_SFT 11
+#define RT5645_SEQ1_ST_RUN (0x0 << 11)
+#define RT5645_SEQ1_ST_FIN (0x1 << 11)
+#define RT5645_SEQ2_ST_MASK (0x1 << 10) /*RO*/
+#define RT5645_SEQ2_ST_SFT 10
+#define RT5645_SEQ2_ST_RUN (0x0 << 10)
+#define RT5645_SEQ2_ST_FIN (0x1 << 10)
+#define RT5645_REG_LV_MASK (0x1 << 9)
+#define RT5645_REG_LV_SFT 9
+#define RT5645_REG_LV_MX (0x0 << 9)
+#define RT5645_REG_LV_PR (0x1 << 9)
+#define RT5645_SEQ_2_PT_MASK (0x1 << 8)
+#define RT5645_SEQ_2_PT_BIT 8
+#define RT5645_REG_IDX_MASK (0xff)
+#define RT5645_REG_IDX_SFT 0
+
+/* Programmable Register Array Control 2 (0xc9) */
+#define RT5645_REG_DAT_MASK (0xffff)
+#define RT5645_REG_DAT_SFT 0
+
+/* Programmable Register Array Control 3 (0xca) */
+#define RT5645_SEQ_DLY_MASK (0xff << 8)
+#define RT5645_SEQ_DLY_SFT 8
+#define RT5645_PROG_MASK (0x1 << 7)
+#define RT5645_PROG_SFT 7
+#define RT5645_PROG_DIS (0x0 << 7)
+#define RT5645_PROG_EN (0x1 << 7)
+#define RT5645_SEQ1_PT_RUN (0x1 << 6)
+#define RT5645_SEQ1_PT_RUN_BIT 6
+#define RT5645_SEQ2_PT_RUN (0x1 << 5)
+#define RT5645_SEQ2_PT_RUN_BIT 5
+
+/* Programmable Register Array Control 4 (0xcb) */
+#define RT5645_SEQ1_START_MASK (0xf << 8)
+#define RT5645_SEQ1_START_SFT 8
+#define RT5645_SEQ1_END_MASK (0xf)
+#define RT5645_SEQ1_END_SFT 0
+
+/* Programmable Register Array Control 5 (0xcc) */
+#define RT5645_SEQ2_START_MASK (0xf << 8)
+#define RT5645_SEQ2_START_SFT 8
+#define RT5645_SEQ2_END_MASK (0xf)
+#define RT5645_SEQ2_END_SFT 0
+
+/* Scramble Function (0xcd) */
+#define RT5645_SCB_KEY_MASK (0xff)
+#define RT5645_SCB_KEY_SFT 0
+
+/* Scramble Control (0xce) */
+#define RT5645_SCB_SWAP_MASK (0x1 << 15)
+#define RT5645_SCB_SWAP_SFT 15
+#define RT5645_SCB_SWAP_DIS (0x0 << 15)
+#define RT5645_SCB_SWAP_EN (0x1 << 15)
+#define RT5645_SCB_MASK (0x1 << 14)
+#define RT5645_SCB_SFT 14
+#define RT5645_SCB_DIS (0x0 << 14)
+#define RT5645_SCB_EN (0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5645_BB_MASK (0x1 << 15)
+#define RT5645_BB_SFT 15
+#define RT5645_BB_DIS (0x0 << 15)
+#define RT5645_BB_EN (0x1 << 15)
+#define RT5645_BB_CT_MASK (0x7 << 12)
+#define RT5645_BB_CT_SFT 12
+#define RT5645_BB_CT_A (0x0 << 12)
+#define RT5645_BB_CT_B (0x1 << 12)
+#define RT5645_BB_CT_C (0x2 << 12)
+#define RT5645_BB_CT_D (0x3 << 12)
+#define RT5645_M_BB_L_MASK (0x1 << 9)
+#define RT5645_M_BB_L_SFT 9
+#define RT5645_M_BB_R_MASK (0x1 << 8)
+#define RT5645_M_BB_R_SFT 8
+#define RT5645_M_BB_HPF_L_MASK (0x1 << 7)
+#define RT5645_M_BB_HPF_L_SFT 7
+#define RT5645_M_BB_HPF_R_MASK (0x1 << 6)
+#define RT5645_M_BB_HPF_R_SFT 6
+#define RT5645_G_BB_BST_MASK (0x3f)
+#define RT5645_G_BB_BST_SFT 0
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5645_M_MP3_L_MASK (0x1 << 15)
+#define RT5645_M_MP3_L_SFT 15
+#define RT5645_M_MP3_R_MASK (0x1 << 14)
+#define RT5645_M_MP3_R_SFT 14
+#define RT5645_M_MP3_MASK (0x1 << 13)
+#define RT5645_M_MP3_SFT 13
+#define RT5645_M_MP3_DIS (0x0 << 13)
+#define RT5645_M_MP3_EN (0x1 << 13)
+#define RT5645_EG_MP3_MASK (0x1f << 8)
+#define RT5645_EG_MP3_SFT 8
+#define RT5645_MP3_HLP_MASK (0x1 << 7)
+#define RT5645_MP3_HLP_SFT 7
+#define RT5645_MP3_HLP_DIS (0x0 << 7)
+#define RT5645_MP3_HLP_EN (0x1 << 7)
+#define RT5645_M_MP3_ORG_L_MASK (0x1 << 6)
+#define RT5645_M_MP3_ORG_L_SFT 6
+#define RT5645_M_MP3_ORG_R_MASK (0x1 << 5)
+#define RT5645_M_MP3_ORG_R_SFT 5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5645_MP3_WT_MASK (0x1 << 13)
+#define RT5645_MP3_WT_SFT 13
+#define RT5645_MP3_WT_1_4 (0x0 << 13)
+#define RT5645_MP3_WT_1_2 (0x1 << 13)
+#define RT5645_OG_MP3_MASK (0x1f << 8)
+#define RT5645_OG_MP3_SFT 8
+#define RT5645_HG_MP3_MASK (0x3f)
+#define RT5645_HG_MP3_SFT 0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5645_3D_CF_MASK (0x1 << 15)
+#define RT5645_3D_CF_SFT 15
+#define RT5645_3D_CF_DIS (0x0 << 15)
+#define RT5645_3D_CF_EN (0x1 << 15)
+#define RT5645_3D_HP_MASK (0x1 << 14)
+#define RT5645_3D_HP_SFT 14
+#define RT5645_3D_HP_DIS (0x0 << 14)
+#define RT5645_3D_HP_EN (0x1 << 14)
+#define RT5645_3D_BT_MASK (0x1 << 13)
+#define RT5645_3D_BT_SFT 13
+#define RT5645_3D_BT_DIS (0x0 << 13)
+#define RT5645_3D_BT_EN (0x1 << 13)
+#define RT5645_3D_1F_MIX_MASK (0x3 << 11)
+#define RT5645_3D_1F_MIX_SFT 11
+#define RT5645_3D_HP_M_MASK (0x1 << 10)
+#define RT5645_3D_HP_M_SFT 10
+#define RT5645_3D_HP_M_SUR (0x0 << 10)
+#define RT5645_3D_HP_M_FRO (0x1 << 10)
+#define RT5645_M_3D_HRTF_MASK (0x1 << 9)
+#define RT5645_M_3D_HRTF_SFT 9
+#define RT5645_M_3D_D2H_MASK (0x1 << 8)
+#define RT5645_M_3D_D2H_SFT 8
+#define RT5645_M_3D_D2R_MASK (0x1 << 7)
+#define RT5645_M_3D_D2R_SFT 7
+#define RT5645_M_3D_REVB_MASK (0x1 << 6)
+#define RT5645_M_3D_REVB_SFT 6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5645_2ND_HPF_MASK (0x1 << 15)
+#define RT5645_2ND_HPF_SFT 15
+#define RT5645_2ND_HPF_DIS (0x0 << 15)
+#define RT5645_2ND_HPF_EN (0x1 << 15)
+#define RT5645_HPF_CF_L_MASK (0x7 << 12)
+#define RT5645_HPF_CF_L_SFT 12
+#define RT5645_1ST_HPF_MASK (0x1 << 11)
+#define RT5645_1ST_HPF_SFT 11
+#define RT5645_1ST_HPF_DIS (0x0 << 11)
+#define RT5645_1ST_HPF_EN (0x1 << 11)
+#define RT5645_HPF_CF_R_MASK (0x7 << 8)
+#define RT5645_HPF_CF_R_SFT 8
+#define RT5645_ZD_T_MASK (0x3 << 6)
+#define RT5645_ZD_T_SFT 6
+#define RT5645_ZD_F_MASK (0x3 << 4)
+#define RT5645_ZD_F_SFT 4
+#define RT5645_ZD_F_IM (0x0 << 4)
+#define RT5645_ZD_F_ZC_IM (0x1 << 4)
+#define RT5645_ZD_F_ZC_IOD (0x2 << 4)
+#define RT5645_ZD_F_UN (0x3 << 4)
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5645_SI_DAC_MASK (0x1 << 11)
+#define RT5645_SI_DAC_SFT 11
+#define RT5645_SI_DAC_AUTO (0x0 << 11)
+#define RT5645_SI_DAC_TEST (0x1 << 11)
+#define RT5645_DC_CAL_M_MASK (0x1 << 10)
+#define RT5645_DC_CAL_M_SFT 10
+#define RT5645_DC_CAL_M_CAL (0x0 << 10)
+#define RT5645_DC_CAL_M_NOR (0x1 << 10)
+#define RT5645_DC_CAL_MASK (0x1 << 9)
+#define RT5645_DC_CAL_SFT 9
+#define RT5645_DC_CAL_DIS (0x0 << 9)
+#define RT5645_DC_CAL_EN (0x1 << 9)
+#define RT5645_HPD_RCV_MASK (0x7 << 6)
+#define RT5645_HPD_RCV_SFT 6
+#define RT5645_HPD_PS_MASK (0x1 << 5)
+#define RT5645_HPD_PS_SFT 5
+#define RT5645_HPD_PS_DIS (0x0 << 5)
+#define RT5645_HPD_PS_EN (0x1 << 5)
+#define RT5645_CAL_M_MASK (0x1 << 4)
+#define RT5645_CAL_M_SFT 4
+#define RT5645_CAL_M_DEP (0x0 << 4)
+#define RT5645_CAL_M_CAL (0x1 << 4)
+#define RT5645_CAL_MASK (0x1 << 3)
+#define RT5645_CAL_SFT 3
+#define RT5645_CAL_DIS (0x0 << 3)
+#define RT5645_CAL_EN (0x1 << 3)
+#define RT5645_CAL_TEST_MASK (0x1 << 2)
+#define RT5645_CAL_TEST_SFT 2
+#define RT5645_CAL_TEST_DIS (0x0 << 2)
+#define RT5645_CAL_TEST_EN (0x1 << 2)
+#define RT5645_CAL_P_MASK (0x3)
+#define RT5645_CAL_P_SFT 0
+#define RT5645_CAL_P_NONE (0x0)
+#define RT5645_CAL_P_CAL (0x1)
+#define RT5645_CAL_P_DAC_CAL (0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5645_SV_MASK (0x1 << 15)
+#define RT5645_SV_SFT 15
+#define RT5645_SV_DIS (0x0 << 15)
+#define RT5645_SV_EN (0x1 << 15)
+#define RT5645_SPO_SV_MASK (0x1 << 14)
+#define RT5645_SPO_SV_SFT 14
+#define RT5645_SPO_SV_DIS (0x0 << 14)
+#define RT5645_SPO_SV_EN (0x1 << 14)
+#define RT5645_OUT_SV_MASK (0x1 << 13)
+#define RT5645_OUT_SV_SFT 13
+#define RT5645_OUT_SV_DIS (0x0 << 13)
+#define RT5645_OUT_SV_EN (0x1 << 13)
+#define RT5645_HP_SV_MASK (0x1 << 12)
+#define RT5645_HP_SV_SFT 12
+#define RT5645_HP_SV_DIS (0x0 << 12)
+#define RT5645_HP_SV_EN (0x1 << 12)
+#define RT5645_ZCD_DIG_MASK (0x1 << 11)
+#define RT5645_ZCD_DIG_SFT 11
+#define RT5645_ZCD_DIG_DIS (0x0 << 11)
+#define RT5645_ZCD_DIG_EN (0x1 << 11)
+#define RT5645_ZCD_MASK (0x1 << 10)
+#define RT5645_ZCD_SFT 10
+#define RT5645_ZCD_PD (0x0 << 10)
+#define RT5645_ZCD_PU (0x1 << 10)
+#define RT5645_M_ZCD_MASK (0x3f << 4)
+#define RT5645_M_ZCD_SFT 4
+#define RT5645_M_ZCD_RM_L (0x1 << 9)
+#define RT5645_M_ZCD_RM_R (0x1 << 8)
+#define RT5645_M_ZCD_SM_L (0x1 << 7)
+#define RT5645_M_ZCD_SM_R (0x1 << 6)
+#define RT5645_M_ZCD_OM_L (0x1 << 5)
+#define RT5645_M_ZCD_OM_R (0x1 << 4)
+#define RT5645_SV_DLY_MASK (0xf)
+#define RT5645_SV_DLY_SFT 0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5645_ZCD_HP_MASK (0x1 << 15)
+#define RT5645_ZCD_HP_SFT 15
+#define RT5645_ZCD_HP_DIS (0x0 << 15)
+#define RT5645_ZCD_HP_EN (0x1 << 15)
+
+
+/* Codec Private Register definition */
+/* 3D Speaker Control (0x63) */
+#define RT5645_3D_SPK_MASK (0x1 << 15)
+#define RT5645_3D_SPK_SFT 15
+#define RT5645_3D_SPK_DIS (0x0 << 15)
+#define RT5645_3D_SPK_EN (0x1 << 15)
+#define RT5645_3D_SPK_M_MASK (0x3 << 13)
+#define RT5645_3D_SPK_M_SFT 13
+#define RT5645_3D_SPK_CG_MASK (0x1f << 8)
+#define RT5645_3D_SPK_CG_SFT 8
+#define RT5645_3D_SPK_SG_MASK (0x1f)
+#define RT5645_3D_SPK_SG_SFT 0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5645_WND_MASK (0x1 << 15)
+#define RT5645_WND_SFT 15
+#define RT5645_WND_DIS (0x0 << 15)
+#define RT5645_WND_EN (0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5645_WND_FC_NW_MASK (0x3f << 10)
+#define RT5645_WND_FC_NW_SFT 10
+#define RT5645_WND_FC_WK_MASK (0x3f << 4)
+#define RT5645_WND_FC_WK_SFT 4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5645_HPF_FC_MASK (0x3f << 6)
+#define RT5645_HPF_FC_SFT 6
+#define RT5645_WND_FC_ST_MASK (0x3f)
+#define RT5645_WND_FC_ST_SFT 0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5645_WND_TH_LO_MASK (0x3ff)
+#define RT5645_WND_TH_LO_SFT 0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5645_WND_TH_HI_MASK (0x3ff)
+#define RT5645_WND_TH_HI_SFT 0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5645_WND_WIND_MASK (0x1 << 13) /* Read-Only */
+#define RT5645_WND_WIND_SFT 13
+#define RT5645_WND_STRONG_MASK (0x1 << 12) /* Read-Only */
+#define RT5645_WND_STRONG_SFT 12
+enum {
+ RT5645_NO_WIND,
+ RT5645_BREEZE,
+ RT5645_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5645_DP_ATT_MASK (0x3 << 14)
+#define RT5645_DP_ATT_SFT 14
+#define RT5645_DP_SPK_MASK (0x1 << 10)
+#define RT5645_DP_SPK_SFT 10
+#define RT5645_DP_SPK_DIS (0x0 << 10)
+#define RT5645_DP_SPK_EN (0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5645_EQ_PRE_VOL_MASK (0xffff)
+#define RT5645_EQ_PRE_VOL_SFT 0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5645_EQ_PST_VOL_MASK (0xffff)
+#define RT5645_EQ_PST_VOL_SFT 0
+
+/* Jack Detect Control 3 (0xf8) */
+#define RT5645_CMP_MIC_IN_DET_MASK (0x7 << 12)
+#define RT5645_JD_CBJ_EN (0x1 << 7)
+#define RT5645_JD_CBJ_POL (0x1 << 6)
+#define RT5645_JD_TRI_CBJ_SEL_MASK (0x7 << 3)
+#define RT5645_JD_TRI_CBJ_SEL_SFT (3)
+#define RT5645_JD_TRI_HPO_SEL_MASK (0x7)
+#define RT5645_JD_TRI_HPO_SEL_SFT (0)
+#define RT5645_JD_F_GPIO_JD1 (0x0)
+#define RT5645_JD_F_JD1_1 (0x1)
+#define RT5645_JD_F_JD1_2 (0x2)
+#define RT5645_JD_F_JD2 (0x3)
+#define RT5645_JD_F_JD3 (0x4)
+#define RT5645_JD_F_GPIO_JD2 (0x5)
+#define RT5645_JD_F_MX0B_12 (0x6)
+
+/* Digital Misc Control (0xfa) */
+#define RT5645_RST_DSP (0x1 << 13)
+#define RT5645_IF1_ADC1_IN1_SEL (0x1 << 12)
+#define RT5645_IF1_ADC1_IN1_SFT 12
+#define RT5645_IF1_ADC1_IN2_SEL (0x1 << 11)
+#define RT5645_IF1_ADC1_IN2_SFT 11
+#define RT5645_IF1_ADC2_IN1_SEL (0x1 << 10)
+#define RT5645_IF1_ADC2_IN1_SFT 10
+#define RT5645_DIG_GATE_CTRL 0x1
+
+/* General Control2 (0xfb) */
+#define RT5645_RXDC_SRC_MASK (0x1 << 7)
+#define RT5645_RXDC_SRC_STO (0x0 << 7)
+#define RT5645_RXDC_SRC_MONO (0x1 << 7)
+#define RT5645_RXDC_SRC_SFT (7)
+#define RT5645_RXDP2_SEL_MASK (0x1 << 3)
+#define RT5645_RXDP2_SEL_IF2 (0x0 << 3)
+#define RT5645_RXDP2_SEL_ADC (0x1 << 3)
+#define RT5645_RXDP2_SEL_SFT (3)
+
+
+/* Vendor ID (0xfd) */
+#define RT5645_VER_C 0x2
+#define RT5645_VER_D 0x3
+
+
+/* Volume Rescale */
+#define RT5645_VOL_RSCL_MAX 0x27
+#define RT5645_VOL_RSCL_RANGE 0x1F
+/* Debug String Length */
+#define RT5645_REG_DISP_LEN 23
+
+
+/* System Clock Source */
+enum {
+ RT5645_SCLK_S_MCLK,
+ RT5645_SCLK_S_PLL1,
+ RT5645_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+ RT5645_PLL1_S_MCLK,
+ RT5645_PLL1_S_BCLK1,
+ RT5645_PLL1_S_BCLK2,
+};
+
+enum {
+ RT5645_AIF1,
+ RT5645_AIF2,
+ RT5645_AIFS,
+};
+
+enum {
+ RT5645_DMIC_DATA_IN2P,
+ RT5645_DMIC_DATA_GPIO6,
+ RT5645_DMIC_DATA_GPIO10,
+ RT5645_DMIC_DATA_GPIO12,
+};
+
+enum {
+ RT5645_DMIC_DATA_IN2N,
+ RT5645_DMIC_DATA_GPIO5,
+ RT5645_DMIC_DATA_GPIO11,
+};
+
+struct rt5645_pll_code {
+ bool m_bp; /* Indicates bypass m code or not. */
+ int m_code;
+ int n_code;
+ int k_code;
+};
+
+struct rt5645_priv {
+ struct snd_soc_codec *codec;
+ struct rt5645_platform_data pdata;
+ struct regmap *regmap;
+
+ int sysclk;
+ int sysclk_src;
+ int lrck[RT5645_AIFS];
+ int bclk[RT5645_AIFS];
+ int master[RT5645_AIFS];
+
+ int pll_src;
+ int pll_in;
+ int pll_out;
+};
+
+#endif /* __RT5645_H__ */
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
new file mode 100644
index 000000000000..9c88d89f41f0
--- /dev/null
+++ b/sound/soc/codecs/rt5651.c
@@ -0,0 +1,1897 @@
+/*
+ * rt5651.c -- RT5651 ALSA SoC audio codec driver
+ *
+ * Copyright 2014 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.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/i2c.h>
+#include <linux/regmap.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 "rt5651.h"
+
+#define RT5651_DEVICE_ID_VALUE 0x6281
+
+#define RT5651_PR_RANGE_BASE (0xff + 1)
+#define RT5651_PR_SPACING 0x100
+
+#define RT5651_PR_BASE (RT5651_PR_RANGE_BASE + (0 * RT5651_PR_SPACING))
+
+static const struct regmap_range_cfg rt5651_ranges[] = {
+ { .name = "PR", .range_min = RT5651_PR_BASE,
+ .range_max = RT5651_PR_BASE + 0xb4,
+ .selector_reg = RT5651_PRIV_INDEX,
+ .selector_mask = 0xff,
+ .selector_shift = 0x0,
+ .window_start = RT5651_PRIV_DATA,
+ .window_len = 0x1, },
+};
+
+static struct reg_default init_list[] = {
+ {RT5651_PR_BASE + 0x3d, 0x3e00},
+};
+
+static const struct reg_default rt5651_reg[] = {
+ { 0x00, 0x0000 },
+ { 0x02, 0xc8c8 },
+ { 0x03, 0xc8c8 },
+ { 0x05, 0x0000 },
+ { 0x0d, 0x0000 },
+ { 0x0e, 0x0000 },
+ { 0x0f, 0x0808 },
+ { 0x10, 0x0808 },
+ { 0x19, 0xafaf },
+ { 0x1a, 0xafaf },
+ { 0x1b, 0x0c00 },
+ { 0x1c, 0x2f2f },
+ { 0x1d, 0x2f2f },
+ { 0x1e, 0x0000 },
+ { 0x27, 0x7860 },
+ { 0x28, 0x7070 },
+ { 0x29, 0x8080 },
+ { 0x2a, 0x5252 },
+ { 0x2b, 0x5454 },
+ { 0x2f, 0x0000 },
+ { 0x30, 0x5000 },
+ { 0x3b, 0x0000 },
+ { 0x3c, 0x006f },
+ { 0x3d, 0x0000 },
+ { 0x3e, 0x006f },
+ { 0x45, 0x6000 },
+ { 0x4d, 0x0000 },
+ { 0x4e, 0x0000 },
+ { 0x4f, 0x0279 },
+ { 0x50, 0x0000 },
+ { 0x51, 0x0000 },
+ { 0x52, 0x0279 },
+ { 0x53, 0xf000 },
+ { 0x61, 0x0000 },
+ { 0x62, 0x0000 },
+ { 0x63, 0x00c0 },
+ { 0x64, 0x0000 },
+ { 0x65, 0x0000 },
+ { 0x66, 0x0000 },
+ { 0x70, 0x8000 },
+ { 0x71, 0x8000 },
+ { 0x73, 0x1104 },
+ { 0x74, 0x0c00 },
+ { 0x75, 0x1400 },
+ { 0x77, 0x0c00 },
+ { 0x78, 0x4000 },
+ { 0x79, 0x0123 },
+ { 0x80, 0x0000 },
+ { 0x81, 0x0000 },
+ { 0x82, 0x0000 },
+ { 0x83, 0x0800 },
+ { 0x84, 0x0000 },
+ { 0x85, 0x0008 },
+ { 0x89, 0x0000 },
+ { 0x8e, 0x0004 },
+ { 0x8f, 0x1100 },
+ { 0x90, 0x0000 },
+ { 0x93, 0x2000 },
+ { 0x94, 0x0200 },
+ { 0xb0, 0x2080 },
+ { 0xb1, 0x0000 },
+ { 0xb4, 0x2206 },
+ { 0xb5, 0x1f00 },
+ { 0xb6, 0x0000 },
+ { 0xbb, 0x0000 },
+ { 0xbc, 0x0000 },
+ { 0xbd, 0x0000 },
+ { 0xbe, 0x0000 },
+ { 0xbf, 0x0000 },
+ { 0xc0, 0x0400 },
+ { 0xc1, 0x0000 },
+ { 0xc2, 0x0000 },
+ { 0xcf, 0x0013 },
+ { 0xd0, 0x0680 },
+ { 0xd1, 0x1c17 },
+ { 0xd3, 0xb320 },
+ { 0xd9, 0x0809 },
+ { 0xfa, 0x0010 },
+ { 0xfe, 0x10ec },
+ { 0xff, 0x6281 },
+};
+
+static bool rt5651_volatile_register(struct device *dev, unsigned int reg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rt5651_ranges); i++) {
+ if ((reg >= rt5651_ranges[i].window_start &&
+ reg <= rt5651_ranges[i].window_start +
+ rt5651_ranges[i].window_len) ||
+ (reg >= rt5651_ranges[i].range_min &&
+ reg <= rt5651_ranges[i].range_max)) {
+ return true;
+ }
+ }
+
+ switch (reg) {
+ case RT5651_RESET:
+ case RT5651_PRIV_DATA:
+ case RT5651_EQ_CTRL1:
+ case RT5651_ALC_1:
+ case RT5651_IRQ_CTRL2:
+ case RT5651_INT_IRQ_ST:
+ case RT5651_PGM_REG_ARR1:
+ case RT5651_PGM_REG_ARR3:
+ case RT5651_VENDOR_ID:
+ case RT5651_DEVICE_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt5651_readable_register(struct device *dev, unsigned int reg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rt5651_ranges); i++) {
+ if ((reg >= rt5651_ranges[i].window_start &&
+ reg <= rt5651_ranges[i].window_start +
+ rt5651_ranges[i].window_len) ||
+ (reg >= rt5651_ranges[i].range_min &&
+ reg <= rt5651_ranges[i].range_max)) {
+ return true;
+ }
+ }
+
+ switch (reg) {
+ case RT5651_RESET:
+ case RT5651_VERSION_ID:
+ case RT5651_VENDOR_ID:
+ case RT5651_DEVICE_ID:
+ case RT5651_HP_VOL:
+ case RT5651_LOUT_CTRL1:
+ case RT5651_LOUT_CTRL2:
+ case RT5651_IN1_IN2:
+ case RT5651_IN3:
+ case RT5651_INL1_INR1_VOL:
+ case RT5651_INL2_INR2_VOL:
+ case RT5651_DAC1_DIG_VOL:
+ case RT5651_DAC2_DIG_VOL:
+ case RT5651_DAC2_CTRL:
+ case RT5651_ADC_DIG_VOL:
+ case RT5651_ADC_DATA:
+ case RT5651_ADC_BST_VOL:
+ case RT5651_STO1_ADC_MIXER:
+ case RT5651_STO2_ADC_MIXER:
+ case RT5651_AD_DA_MIXER:
+ case RT5651_STO_DAC_MIXER:
+ case RT5651_DD_MIXER:
+ case RT5651_DIG_INF_DATA:
+ case RT5651_PDM_CTL:
+ case RT5651_REC_L1_MIXER:
+ case RT5651_REC_L2_MIXER:
+ case RT5651_REC_R1_MIXER:
+ case RT5651_REC_R2_MIXER:
+ case RT5651_HPO_MIXER:
+ case RT5651_OUT_L1_MIXER:
+ case RT5651_OUT_L2_MIXER:
+ case RT5651_OUT_L3_MIXER:
+ case RT5651_OUT_R1_MIXER:
+ case RT5651_OUT_R2_MIXER:
+ case RT5651_OUT_R3_MIXER:
+ case RT5651_LOUT_MIXER:
+ case RT5651_PWR_DIG1:
+ case RT5651_PWR_DIG2:
+ case RT5651_PWR_ANLG1:
+ case RT5651_PWR_ANLG2:
+ case RT5651_PWR_MIXER:
+ case RT5651_PWR_VOL:
+ case RT5651_PRIV_INDEX:
+ case RT5651_PRIV_DATA:
+ case RT5651_I2S1_SDP:
+ case RT5651_I2S2_SDP:
+ case RT5651_ADDA_CLK1:
+ case RT5651_ADDA_CLK2:
+ case RT5651_DMIC:
+ case RT5651_TDM_CTL_1:
+ case RT5651_TDM_CTL_2:
+ case RT5651_TDM_CTL_3:
+ case RT5651_GLB_CLK:
+ case RT5651_PLL_CTRL1:
+ case RT5651_PLL_CTRL2:
+ case RT5651_PLL_MODE_1:
+ case RT5651_PLL_MODE_2:
+ case RT5651_PLL_MODE_3:
+ case RT5651_PLL_MODE_4:
+ case RT5651_PLL_MODE_5:
+ case RT5651_PLL_MODE_6:
+ case RT5651_PLL_MODE_7:
+ case RT5651_DEPOP_M1:
+ case RT5651_DEPOP_M2:
+ case RT5651_DEPOP_M3:
+ case RT5651_CHARGE_PUMP:
+ case RT5651_MICBIAS:
+ case RT5651_A_JD_CTL1:
+ case RT5651_EQ_CTRL1:
+ case RT5651_EQ_CTRL2:
+ case RT5651_ALC_1:
+ case RT5651_ALC_2:
+ case RT5651_ALC_3:
+ case RT5651_JD_CTRL1:
+ case RT5651_JD_CTRL2:
+ case RT5651_IRQ_CTRL1:
+ case RT5651_IRQ_CTRL2:
+ case RT5651_INT_IRQ_ST:
+ case RT5651_GPIO_CTRL1:
+ case RT5651_GPIO_CTRL2:
+ case RT5651_GPIO_CTRL3:
+ case RT5651_PGM_REG_ARR1:
+ case RT5651_PGM_REG_ARR2:
+ case RT5651_PGM_REG_ARR3:
+ case RT5651_PGM_REG_ARR4:
+ case RT5651_PGM_REG_ARR5:
+ case RT5651_SCB_FUNC:
+ case RT5651_SCB_CTRL:
+ case RT5651_BASE_BACK:
+ case RT5651_MP3_PLUS1:
+ case RT5651_MP3_PLUS2:
+ case RT5651_ADJ_HPF_CTRL1:
+ case RT5651_ADJ_HPF_CTRL2:
+ case RT5651_HP_CALIB_AMP_DET:
+ case RT5651_HP_CALIB2:
+ case RT5651_SV_ZCD1:
+ case RT5651_SV_ZCD2:
+ case RT5651_D_MISC:
+ case RT5651_DUMMY2:
+ case RT5651_DUMMY3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static unsigned int bst_tlv[] = {
+ TLV_DB_RANGE_HEAD(7),
+ 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),
+};
+
+/* Interface data select */
+static const char * const rt5651_data_select[] = {
+ "Normal", "Swap", "left copy to right", "right copy to left"};
+
+static SOC_ENUM_SINGLE_DECL(rt5651_if2_dac_enum, RT5651_DIG_INF_DATA,
+ RT5651_IF2_DAC_SEL_SFT, rt5651_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5651_if2_adc_enum, RT5651_DIG_INF_DATA,
+ RT5651_IF2_ADC_SEL_SFT, rt5651_data_select);
+
+static const struct snd_kcontrol_new rt5651_snd_controls[] = {
+ /* Headphone Output Volume */
+ SOC_DOUBLE_TLV("HP Playback Volume", RT5651_HP_VOL,
+ RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv),
+ /* OUTPUT Control */
+ SOC_DOUBLE_TLV("OUT Playback Volume", RT5651_LOUT_CTRL1,
+ RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+ /* DAC Digital Volume */
+ SOC_DOUBLE("DAC2 Playback Switch", RT5651_DAC2_CTRL,
+ RT5651_M_DAC_L2_VOL_SFT, RT5651_M_DAC_R2_VOL_SFT, 1, 1),
+ SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5651_DAC1_DIG_VOL,
+ RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
+ 175, 0, dac_vol_tlv),
+ SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5651_DAC2_DIG_VOL,
+ RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
+ 175, 0, dac_vol_tlv),
+ /* IN1/IN2 Control */
+ SOC_SINGLE_TLV("IN1 Boost", RT5651_IN1_IN2,
+ RT5651_BST_SFT1, 8, 0, bst_tlv),
+ SOC_SINGLE_TLV("IN2 Boost", RT5651_IN1_IN2,
+ RT5651_BST_SFT2, 8, 0, bst_tlv),
+ /* INL/INR Volume Control */
+ SOC_DOUBLE_TLV("IN Capture Volume", RT5651_INL1_INR1_VOL,
+ RT5651_INL_VOL_SFT, RT5651_INR_VOL_SFT,
+ 31, 1, in_vol_tlv),
+ /* ADC Digital Volume Control */
+ SOC_DOUBLE("ADC Capture Switch", RT5651_ADC_DIG_VOL,
+ RT5651_L_MUTE_SFT, RT5651_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_TLV("ADC Capture Volume", RT5651_ADC_DIG_VOL,
+ RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
+ 127, 0, adc_vol_tlv),
+ SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5651_ADC_DATA,
+ RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
+ 127, 0, adc_vol_tlv),
+ /* ADC Boost Volume Control */
+ SOC_DOUBLE_TLV("ADC Boost Gain", RT5651_ADC_BST_VOL,
+ RT5651_ADC_L_BST_SFT, RT5651_ADC_R_BST_SFT,
+ 3, 0, adc_bst_tlv),
+
+ /* ASRC */
+ SOC_SINGLE("IF1 ASRC Switch", RT5651_PLL_MODE_1,
+ RT5651_STO1_T_SFT, 1, 0),
+ SOC_SINGLE("IF2 ASRC Switch", RT5651_PLL_MODE_1,
+ RT5651_STO2_T_SFT, 1, 0),
+ SOC_SINGLE("DMIC ASRC Switch", RT5651_PLL_MODE_1,
+ RT5651_DMIC_1_M_SFT, 1, 0),
+
+ SOC_ENUM("ADC IF2 Data Switch", rt5651_if2_adc_enum),
+ SOC_ENUM("DAC IF2 Data Switch", rt5651_if2_dac_enum),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ int div[] = {2, 3, 4, 6, 8, 12}, idx = -EINVAL;
+ int i, rate, red, bound, temp;
+
+ rate = rt5651->sysclk;
+ red = 3000000 * 12;
+ for (i = 0; i < ARRAY_SIZE(div); i++) {
+ bound = div[i] * 3000000;
+ if (rate > bound)
+ continue;
+ temp = bound - rate;
+ if (temp < red) {
+ red = temp;
+ idx = i;
+ }
+ }
+ if (idx < 0)
+ dev_err(codec->dev, "Failed to set DMIC clock\n");
+ else
+ snd_soc_update_bits(codec, RT5651_DMIC, RT5651_DMIC_CLK_MASK,
+ idx << RT5651_DMIC_CLK_SFT);
+
+ return idx;
+}
+
+static int is_sysclk_from_pll(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int val;
+
+ val = snd_soc_read(source->codec, RT5651_GLB_CLK);
+ val &= RT5651_SCLK_SRC_MASK;
+ if (val == RT5651_SCLK_SRC_PLL1)
+ return 1;
+ else
+ return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5651_sto1_adc_l_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER,
+ RT5651_M_STO1_ADC_L1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER,
+ RT5651_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_r_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER,
+ RT5651_M_STO1_ADC_R1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER,
+ RT5651_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_l_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO2_ADC_MIXER,
+ RT5651_M_STO2_ADC_L1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO2_ADC_MIXER,
+ RT5651_M_STO2_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_r_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO2_ADC_MIXER,
+ RT5651_M_STO2_ADC_R1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO2_ADC_MIXER,
+ RT5651_M_STO2_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("Stereo ADC Switch", RT5651_AD_DA_MIXER,
+ RT5651_M_ADCMIX_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INF1 Switch", RT5651_AD_DA_MIXER,
+ RT5651_M_IF1_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("Stereo ADC Switch", RT5651_AD_DA_MIXER,
+ RT5651_M_ADCMIX_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INF1 Switch", RT5651_AD_DA_MIXER,
+ RT5651_M_IF1_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_STO_DAC_MIXER,
+ RT5651_M_DAC_L1_MIXL_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_STO_DAC_MIXER,
+ RT5651_M_DAC_L2_MIXL_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_STO_DAC_MIXER,
+ RT5651_M_DAC_R1_MIXL_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_STO_DAC_MIXER,
+ RT5651_M_DAC_R1_MIXR_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_STO_DAC_MIXER,
+ RT5651_M_DAC_R2_MIXR_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_STO_DAC_MIXER,
+ RT5651_M_DAC_L1_MIXR_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_dd_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_DD_MIXER,
+ RT5651_M_STO_DD_L1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_DD_MIXER,
+ RT5651_M_STO_DD_L2_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_DD_MIXER,
+ RT5651_M_STO_DD_R2_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_dd_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_DD_MIXER,
+ RT5651_M_STO_DD_R1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_DD_MIXER,
+ RT5651_M_STO_DD_R2_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_DD_MIXER,
+ RT5651_M_STO_DD_L2_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5651_rec_l_mix[] = {
+ SOC_DAPM_SINGLE("INL1 Switch", RT5651_REC_L2_MIXER,
+ RT5651_M_IN1_L_RM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST3 Switch", RT5651_REC_L2_MIXER,
+ RT5651_M_BST3_RM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5651_REC_L2_MIXER,
+ RT5651_M_BST2_RM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5651_REC_L2_MIXER,
+ RT5651_M_BST1_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_rec_r_mix[] = {
+ SOC_DAPM_SINGLE("INR1 Switch", RT5651_REC_R2_MIXER,
+ RT5651_M_IN1_R_RM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST3 Switch", RT5651_REC_R2_MIXER,
+ RT5651_M_BST3_RM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5651_REC_R2_MIXER,
+ RT5651_M_BST2_RM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5651_REC_R2_MIXER,
+ RT5651_M_BST1_RM_R_SFT, 1, 1),
+};
+
+/* Analog Output Mixer */
+
+static const struct snd_kcontrol_new rt5651_out_l_mix[] = {
+ SOC_DAPM_SINGLE("BST1 Switch", RT5651_OUT_L3_MIXER,
+ RT5651_M_BST1_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST2 Switch", RT5651_OUT_L3_MIXER,
+ RT5651_M_BST2_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INL1 Switch", RT5651_OUT_L3_MIXER,
+ RT5651_M_IN1_L_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("REC MIXL Switch", RT5651_OUT_L3_MIXER,
+ RT5651_M_RM_L_OM_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_OUT_L3_MIXER,
+ RT5651_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_out_r_mix[] = {
+ SOC_DAPM_SINGLE("BST2 Switch", RT5651_OUT_R3_MIXER,
+ RT5651_M_BST2_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("BST1 Switch", RT5651_OUT_R3_MIXER,
+ RT5651_M_BST1_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("INR1 Switch", RT5651_OUT_R3_MIXER,
+ RT5651_M_IN1_R_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("REC MIXR Switch", RT5651_OUT_R3_MIXER,
+ RT5651_M_RM_R_OM_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_OUT_R3_MIXER,
+ RT5651_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_hpo_mix[] = {
+ SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5651_HPO_MIXER,
+ RT5651_M_DAC1_HM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5651_HPO_MIXER,
+ RT5651_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_lout_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_LOUT_MIXER,
+ RT5651_M_DAC_L1_LM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_LOUT_MIXER,
+ RT5651_M_DAC_R1_LM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("OUTVOL L Switch", RT5651_LOUT_MIXER,
+ RT5651_M_OV_L_LM_SFT, 1, 1),
+ SOC_DAPM_SINGLE("OUTVOL R Switch", RT5651_LOUT_MIXER,
+ RT5651_M_OV_R_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new outvol_l_control =
+ SOC_DAPM_SINGLE("Switch", RT5651_LOUT_CTRL1,
+ RT5651_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_r_control =
+ SOC_DAPM_SINGLE("Switch", RT5651_LOUT_CTRL1,
+ RT5651_VOL_R_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_l_mute_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_LOUT_CTRL1,
+ RT5651_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_mute_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_LOUT_CTRL1,
+ RT5651_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpovol_l_control =
+ SOC_DAPM_SINGLE("Switch", RT5651_HP_VOL,
+ RT5651_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpovol_r_control =
+ SOC_DAPM_SINGLE("Switch", RT5651_HP_VOL,
+ RT5651_VOL_R_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_l_mute_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL,
+ RT5651_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_r_mute_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL,
+ RT5651_R_MUTE_SFT, 1, 1);
+
+/* INL/R source */
+static const char * const rt5651_inl_src[] = {"IN2P", "HPOVOLLP"};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_inl_enum, RT5651_INL1_INR1_VOL,
+ RT5651_INL_SEL_SFT, rt5651_inl_src);
+
+static const struct snd_kcontrol_new rt5651_inl1_mux =
+ SOC_DAPM_ENUM("INL1 source", rt5651_inl_enum);
+
+static const char * const rt5651_inr1_src[] = {"IN2N", "HPOVOLRP"};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_inr1_enum, RT5651_INL1_INR1_VOL,
+ RT5651_INR_SEL_SFT, rt5651_inr1_src);
+
+static const struct snd_kcontrol_new rt5651_inr1_mux =
+ SOC_DAPM_ENUM("INR1 source", rt5651_inr1_enum);
+
+static const char * const rt5651_inl2_src[] = {"IN3P", "OUTVOLLP"};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_inl2_enum, RT5651_INL2_INR2_VOL,
+ RT5651_INL_SEL_SFT, rt5651_inl2_src);
+
+static const struct snd_kcontrol_new rt5651_inl2_mux =
+ SOC_DAPM_ENUM("INL2 source", rt5651_inl2_enum);
+
+static const char * const rt5651_inr2_src[] = {"IN3N", "OUTVOLRP"};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_inr2_enum, RT5651_INL2_INR2_VOL,
+ RT5651_INR_SEL_SFT, rt5651_inr2_src);
+
+static const struct snd_kcontrol_new rt5651_inr2_mux =
+ SOC_DAPM_ENUM("INR2 source", rt5651_inr2_enum);
+
+
+/* Stereo ADC source */
+static const char * const rt5651_stereo1_adc1_src[] = {"DD MIX", "ADC"};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_stereo1_adc1_enum, RT5651_STO1_ADC_MIXER,
+ RT5651_STO1_ADC_1_SRC_SFT, rt5651_stereo1_adc1_src);
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_l1_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC L1 source", rt5651_stereo1_adc1_enum);
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_r1_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC R1 source", rt5651_stereo1_adc1_enum);
+
+static const char * const rt5651_stereo1_adc2_src[] = {"DMIC", "DD MIX"};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_stereo1_adc2_enum, RT5651_STO1_ADC_MIXER,
+ RT5651_STO1_ADC_2_SRC_SFT, rt5651_stereo1_adc2_src);
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_l2_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC L2 source", rt5651_stereo1_adc2_enum);
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_r2_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC R2 source", rt5651_stereo1_adc2_enum);
+
+/* Mono ADC source */
+static const char * const rt5651_sto2_adc_l1_src[] = {"DD MIXL", "ADCL"};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_sto2_adc_l1_enum, RT5651_STO1_ADC_MIXER,
+ RT5651_STO2_ADC_L1_SRC_SFT, rt5651_sto2_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_l1_mux =
+ SOC_DAPM_ENUM("Stereo2 ADC1 left source", rt5651_sto2_adc_l1_enum);
+
+static const char * const rt5651_sto2_adc_l2_src[] = {"DMIC L", "DD MIXL"};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_sto2_adc_l2_enum, RT5651_STO1_ADC_MIXER,
+ RT5651_STO2_ADC_L2_SRC_SFT, rt5651_sto2_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_l2_mux =
+ SOC_DAPM_ENUM("Stereo2 ADC2 left source", rt5651_sto2_adc_l2_enum);
+
+static const char * const rt5651_sto2_adc_r1_src[] = {"DD MIXR", "ADCR"};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_sto2_adc_r1_enum, RT5651_STO1_ADC_MIXER,
+ RT5651_STO2_ADC_R1_SRC_SFT, rt5651_sto2_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_r1_mux =
+ SOC_DAPM_ENUM("Stereo2 ADC1 right source", rt5651_sto2_adc_r1_enum);
+
+static const char * const rt5651_sto2_adc_r2_src[] = {"DMIC R", "DD MIXR"};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_sto2_adc_r2_enum, RT5651_STO1_ADC_MIXER,
+ RT5651_STO2_ADC_R2_SRC_SFT, rt5651_sto2_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_r2_mux =
+ SOC_DAPM_ENUM("Stereo2 ADC2 right source", rt5651_sto2_adc_r2_enum);
+
+/* DAC2 channel source */
+
+static const char * const rt5651_dac_src[] = {"IF1", "IF2"};
+
+static SOC_ENUM_SINGLE_DECL(rt5651_dac_l2_enum, RT5651_DAC2_CTRL,
+ RT5651_SEL_DAC_L2_SFT, rt5651_dac_src);
+
+static const struct snd_kcontrol_new rt5651_dac_l2_mux =
+ SOC_DAPM_ENUM("DAC2 left channel source", rt5651_dac_l2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_dac_r2_enum, RT5651_DAC2_CTRL,
+ RT5651_SEL_DAC_R2_SFT, rt5651_dac_src);
+
+static const struct snd_kcontrol_new rt5651_dac_r2_mux =
+ SOC_DAPM_ENUM("DAC2 right channel source", rt5651_dac_r2_enum);
+
+/* IF2_ADC channel source */
+
+static const char * const rt5651_adc_src[] = {"IF1 ADC1", "IF1 ADC2"};
+
+static SOC_ENUM_SINGLE_DECL(rt5651_if2_adc_src_enum, RT5651_DIG_INF_DATA,
+ RT5651_IF2_ADC_SRC_SFT, rt5651_adc_src);
+
+static const struct snd_kcontrol_new rt5651_if2_adc_src_mux =
+ SOC_DAPM_ENUM("IF2 ADC channel source", rt5651_if2_adc_src_enum);
+
+/* PDM select */
+static const char * const rt5651_pdm_sel[] = {"DD MIX", "Stereo DAC MIX"};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_pdm_l_sel_enum, RT5651_PDM_CTL,
+ RT5651_PDM_L_SEL_SFT, rt5651_pdm_sel);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5651_pdm_r_sel_enum, RT5651_PDM_CTL,
+ RT5651_PDM_R_SEL_SFT, rt5651_pdm_sel);
+
+static const struct snd_kcontrol_new rt5651_pdm_l_mux =
+ SOC_DAPM_ENUM("PDM L select", rt5651_pdm_l_sel_enum);
+
+static const struct snd_kcontrol_new rt5651_pdm_r_mux =
+ SOC_DAPM_ENUM("PDM R select", rt5651_pdm_r_sel_enum);
+
+static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* depop parameters */
+ regmap_update_bits(rt5651->regmap, RT5651_PR_BASE +
+ RT5651_CHPUMP_INT_REG1, 0x0700, 0x0200);
+ regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M2,
+ RT5651_DEPOP_MASK, RT5651_DEPOP_MAN);
+ regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M1,
+ RT5651_HP_CP_MASK | RT5651_HP_SG_MASK |
+ RT5651_HP_CB_MASK, RT5651_HP_CP_PU |
+ RT5651_HP_SG_DIS | RT5651_HP_CB_PU);
+ regmap_write(rt5651->regmap, RT5651_PR_BASE +
+ RT5651_HP_DCC_INT1, 0x9f00);
+ /* headphone amp power on */
+ regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1,
+ RT5651_PWR_FV1 | RT5651_PWR_FV2, 0);
+ regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1,
+ RT5651_PWR_HA,
+ RT5651_PWR_HA);
+ usleep_range(10000, 15000);
+ regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1,
+ RT5651_PWR_FV1 | RT5651_PWR_FV2 ,
+ RT5651_PWR_FV1 | RT5651_PWR_FV2);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5651_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* headphone unmute sequence */
+ regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M2,
+ RT5651_DEPOP_MASK | RT5651_DIG_DP_MASK,
+ RT5651_DEPOP_AUTO | RT5651_DIG_DP_EN);
+ regmap_update_bits(rt5651->regmap, RT5651_CHARGE_PUMP,
+ RT5651_PM_HP_MASK, RT5651_PM_HP_HV);
+
+ regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M3,
+ RT5651_CP_FQ1_MASK | RT5651_CP_FQ2_MASK |
+ RT5651_CP_FQ3_MASK,
+ (RT5651_CP_FQ_192_KHZ << RT5651_CP_FQ1_SFT) |
+ (RT5651_CP_FQ_12_KHZ << RT5651_CP_FQ2_SFT) |
+ (RT5651_CP_FQ_192_KHZ << RT5651_CP_FQ3_SFT));
+
+ regmap_write(rt5651->regmap, RT5651_PR_BASE +
+ RT5651_MAMP_INT_REG2, 0x1c00);
+ regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M1,
+ RT5651_HP_CP_MASK | RT5651_HP_SG_MASK,
+ RT5651_HP_CP_PD | RT5651_HP_SG_EN);
+ regmap_update_bits(rt5651->regmap, RT5651_PR_BASE +
+ RT5651_CHPUMP_INT_REG1, 0x0700, 0x0400);
+ rt5651->hp_mute = 0;
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ rt5651->hp_mute = 1;
+ usleep_range(70000, 75000);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (!rt5651->hp_mute)
+ usleep_range(80000, 85000);
+
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5651_bst1_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_POST_PMU:
+ snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+ RT5651_PWR_BST1_OP2, RT5651_PWR_BST1_OP2);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+ RT5651_PWR_BST1_OP2, 0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5651_bst2_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_POST_PMU:
+ snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+ RT5651_PWR_BST2_OP2, RT5651_PWR_BST2_OP2);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+ RT5651_PWR_BST2_OP2, 0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5651_bst3_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_POST_PMU:
+ snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+ RT5651_PWR_BST3_OP2, RT5651_PWR_BST3_OP2);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5651_PWR_ANLG2,
+ RT5651_PWR_BST3_OP2, 0);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = {
+ /* ASRC */
+ SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5651_PLL_MODE_2,
+ 15, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5651_PLL_MODE_2,
+ 14, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("STO1 DAC ASRC", 1, RT5651_PLL_MODE_2,
+ 13, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("STO2 DAC ASRC", 1, RT5651_PLL_MODE_2,
+ 12, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC ASRC", 1, RT5651_PLL_MODE_2,
+ 11, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("PLL1", RT5651_PWR_ANLG2,
+ RT5651_PWR_PLL_BIT, 0, NULL, 0),
+ /* Input Side */
+ /* micbias */
+ SND_SOC_DAPM_SUPPLY("LDO", RT5651_PWR_ANLG1,
+ RT5651_PWR_LDO_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MICBIAS("micbias1", RT5651_PWR_ANLG2,
+ RT5651_PWR_MB1_BIT, 0),
+ /* Input Lines */
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("MIC3"),
+
+ SND_SOC_DAPM_INPUT("IN1P"),
+ SND_SOC_DAPM_INPUT("IN2P"),
+ SND_SOC_DAPM_INPUT("IN2N"),
+ SND_SOC_DAPM_INPUT("IN3P"),
+ SND_SOC_DAPM_INPUT("DMIC L1"),
+ SND_SOC_DAPM_INPUT("DMIC R1"),
+ SND_SOC_DAPM_SUPPLY("DMIC CLK", RT5651_DMIC, RT5651_DMIC_1_EN_SFT,
+ 0, set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+ /* Boost */
+ SND_SOC_DAPM_PGA_E("BST1", RT5651_PWR_ANLG2,
+ RT5651_PWR_BST1_BIT, 0, NULL, 0, rt5651_bst1_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("BST2", RT5651_PWR_ANLG2,
+ RT5651_PWR_BST2_BIT, 0, NULL, 0, rt5651_bst2_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("BST3", RT5651_PWR_ANLG2,
+ RT5651_PWR_BST3_BIT, 0, NULL, 0, rt5651_bst3_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ /* Input Volume */
+ SND_SOC_DAPM_PGA("INL1 VOL", RT5651_PWR_VOL,
+ RT5651_PWR_IN1_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INR1 VOL", RT5651_PWR_VOL,
+ RT5651_PWR_IN1_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INL2 VOL", RT5651_PWR_VOL,
+ RT5651_PWR_IN2_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INR2 VOL", RT5651_PWR_VOL,
+ RT5651_PWR_IN2_R_BIT, 0, NULL, 0),
+ /* IN Mux */
+ SND_SOC_DAPM_MUX("INL1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl1_mux),
+ SND_SOC_DAPM_MUX("INR1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inr1_mux),
+ SND_SOC_DAPM_MUX("INL2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl2_mux),
+ SND_SOC_DAPM_MUX("INR2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inr2_mux),
+ /* REC Mixer */
+ SND_SOC_DAPM_MIXER("RECMIXL", RT5651_PWR_MIXER, RT5651_PWR_RM_L_BIT, 0,
+ rt5651_rec_l_mix, ARRAY_SIZE(rt5651_rec_l_mix)),
+ SND_SOC_DAPM_MIXER("RECMIXR", RT5651_PWR_MIXER, RT5651_PWR_RM_R_BIT, 0,
+ rt5651_rec_r_mix, ARRAY_SIZE(rt5651_rec_r_mix)),
+ /* ADCs */
+ SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_SUPPLY("ADC L Power", RT5651_PWR_DIG1,
+ RT5651_PWR_ADC_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC R Power", RT5651_PWR_DIG1,
+ RT5651_PWR_ADC_R_BIT, 0, NULL, 0),
+ /* ADC Mux */
+ SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5651_sto1_adc_l2_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5651_sto1_adc_r2_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5651_sto1_adc_l1_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5651_sto1_adc_r1_mux),
+ SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5651_sto2_adc_l2_mux),
+ SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5651_sto2_adc_l1_mux),
+ SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5651_sto2_adc_r1_mux),
+ SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5651_sto2_adc_r2_mux),
+ /* ADC Mixer */
+ SND_SOC_DAPM_SUPPLY("Stereo1 Filter", RT5651_PWR_DIG2,
+ RT5651_PWR_ADC_STO1_F_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Stereo2 Filter", RT5651_PWR_DIG2,
+ RT5651_PWR_ADC_STO2_F_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5651_sto1_adc_l_mix,
+ ARRAY_SIZE(rt5651_sto1_adc_l_mix)),
+ SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5651_sto1_adc_r_mix,
+ ARRAY_SIZE(rt5651_sto1_adc_r_mix)),
+ SND_SOC_DAPM_MIXER("Stereo2 ADC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5651_sto2_adc_l_mix,
+ ARRAY_SIZE(rt5651_sto2_adc_l_mix)),
+ SND_SOC_DAPM_MIXER("Stereo2 ADC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5651_sto2_adc_r_mix,
+ ARRAY_SIZE(rt5651_sto2_adc_r_mix)),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_SUPPLY("I2S1", RT5651_PWR_DIG1,
+ RT5651_PWR_I2S1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("I2S2", RT5651_PWR_DIG1,
+ RT5651_PWR_I2S2_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MUX("IF2 ADC", SND_SOC_NOPM, 0, 0,
+ &rt5651_if2_adc_src_mux),
+
+ /* Digital Interface Select */
+
+ SND_SOC_DAPM_MUX("PDM L Mux", RT5651_PDM_CTL,
+ RT5651_M_PDM_L_SFT, 1, &rt5651_pdm_l_mux),
+ SND_SOC_DAPM_MUX("PDM R Mux", RT5651_PDM_CTL,
+ RT5651_M_PDM_R_SFT, 1, &rt5651_pdm_r_mux),
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Audio DSP */
+ SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Output Side */
+ /* DAC mixer before sound effect */
+ SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5651_dac_l_mix, ARRAY_SIZE(rt5651_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5651_dac_r_mix, ARRAY_SIZE(rt5651_dac_r_mix)),
+
+ /* DAC2 channel Mux */
+ SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_dac_l2_mux),
+ SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_dac_r2_mux),
+ SND_SOC_DAPM_PGA("DAC L2 Volume", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DAC R2 Volume", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("Stero1 DAC Power", RT5651_PWR_DIG2,
+ RT5651_PWR_DAC_STO1_F_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Stero2 DAC Power", RT5651_PWR_DIG2,
+ RT5651_PWR_DAC_STO2_F_BIT, 0, NULL, 0),
+ /* DAC Mixer */
+ SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5651_sto_dac_l_mix,
+ ARRAY_SIZE(rt5651_sto_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5651_sto_dac_r_mix,
+ ARRAY_SIZE(rt5651_sto_dac_r_mix)),
+ SND_SOC_DAPM_MIXER("DD MIXL", SND_SOC_NOPM, 0, 0,
+ rt5651_dd_dac_l_mix,
+ ARRAY_SIZE(rt5651_dd_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("DD MIXR", SND_SOC_NOPM, 0, 0,
+ rt5651_dd_dac_r_mix,
+ ARRAY_SIZE(rt5651_dd_dac_r_mix)),
+
+ /* DACs */
+ SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_SUPPLY("DAC L1 Power", RT5651_PWR_DIG1,
+ RT5651_PWR_DAC_L1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC R1 Power", RT5651_PWR_DIG1,
+ RT5651_PWR_DAC_R1_BIT, 0, NULL, 0),
+ /* OUT Mixer */
+ SND_SOC_DAPM_MIXER("OUT MIXL", RT5651_PWR_MIXER, RT5651_PWR_OM_L_BIT,
+ 0, rt5651_out_l_mix, ARRAY_SIZE(rt5651_out_l_mix)),
+ SND_SOC_DAPM_MIXER("OUT MIXR", RT5651_PWR_MIXER, RT5651_PWR_OM_R_BIT,
+ 0, rt5651_out_r_mix, ARRAY_SIZE(rt5651_out_r_mix)),
+ /* Ouput Volume */
+ SND_SOC_DAPM_SWITCH("OUTVOL L", RT5651_PWR_VOL,
+ RT5651_PWR_OV_L_BIT, 0, &outvol_l_control),
+ SND_SOC_DAPM_SWITCH("OUTVOL R", RT5651_PWR_VOL,
+ RT5651_PWR_OV_R_BIT, 0, &outvol_r_control),
+ SND_SOC_DAPM_SWITCH("HPOVOL L", RT5651_PWR_VOL,
+ RT5651_PWR_HV_L_BIT, 0, &hpovol_l_control),
+ SND_SOC_DAPM_SWITCH("HPOVOL R", RT5651_PWR_VOL,
+ RT5651_PWR_HV_R_BIT, 0, &hpovol_r_control),
+ SND_SOC_DAPM_PGA("INL1", RT5651_PWR_VOL,
+ RT5651_PWR_IN1_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INR1", RT5651_PWR_VOL,
+ RT5651_PWR_IN1_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INL2", RT5651_PWR_VOL,
+ RT5651_PWR_IN2_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("INR2", RT5651_PWR_VOL,
+ RT5651_PWR_IN2_R_BIT, 0, NULL, 0),
+ /* HPO/LOUT/Mono Mixer */
+ SND_SOC_DAPM_MIXER("HPOL MIX", SND_SOC_NOPM, 0, 0,
+ rt5651_hpo_mix, ARRAY_SIZE(rt5651_hpo_mix)),
+ SND_SOC_DAPM_MIXER("HPOR MIX", SND_SOC_NOPM, 0, 0,
+ rt5651_hpo_mix, ARRAY_SIZE(rt5651_hpo_mix)),
+ SND_SOC_DAPM_SUPPLY("HP L Amp", RT5651_PWR_ANLG1,
+ RT5651_PWR_HP_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("HP R Amp", RT5651_PWR_ANLG1,
+ RT5651_PWR_HP_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("LOUT MIX", RT5651_PWR_ANLG1, RT5651_PWR_LM_BIT, 0,
+ rt5651_lout_mix, ARRAY_SIZE(rt5651_lout_mix)),
+
+ SND_SOC_DAPM_SUPPLY("Amp Power", RT5651_PWR_ANLG1,
+ RT5651_PWR_HA_BIT, 0, rt5651_amp_power_event,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5651_hp_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SWITCH("HPO L Playback", SND_SOC_NOPM, 0, 0,
+ &hpo_l_mute_control),
+ SND_SOC_DAPM_SWITCH("HPO R Playback", SND_SOC_NOPM, 0, 0,
+ &hpo_r_mute_control),
+ SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0,
+ &lout_l_mute_control),
+ SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0,
+ &lout_r_mute_control),
+ SND_SOC_DAPM_POST("HP Post", rt5651_hp_post_event),
+
+ /* Output Lines */
+ SND_SOC_DAPM_OUTPUT("HPOL"),
+ SND_SOC_DAPM_OUTPUT("HPOR"),
+ SND_SOC_DAPM_OUTPUT("LOUTL"),
+ SND_SOC_DAPM_OUTPUT("LOUTR"),
+ SND_SOC_DAPM_OUTPUT("PDML"),
+ SND_SOC_DAPM_OUTPUT("PDMR"),
+};
+
+static const struct snd_soc_dapm_route rt5651_dapm_routes[] = {
+ {"Stero1 DAC Power", NULL, "STO1 DAC ASRC"},
+ {"Stero2 DAC Power", NULL, "STO2 DAC ASRC"},
+ {"I2S1", NULL, "I2S1 ASRC"},
+ {"I2S2", NULL, "I2S2 ASRC"},
+
+ {"IN1P", NULL, "LDO"},
+ {"IN2P", NULL, "LDO"},
+ {"IN3P", NULL, "LDO"},
+
+ {"IN1P", NULL, "MIC1"},
+ {"IN2P", NULL, "MIC2"},
+ {"IN2N", NULL, "MIC2"},
+ {"IN3P", NULL, "MIC3"},
+
+ {"BST1", NULL, "IN1P"},
+ {"BST2", NULL, "IN2P"},
+ {"BST2", NULL, "IN2N"},
+ {"BST3", NULL, "IN3P"},
+
+ {"INL1 VOL", NULL, "IN2P"},
+ {"INR1 VOL", NULL, "IN2N"},
+
+ {"RECMIXL", "INL1 Switch", "INL1 VOL"},
+ {"RECMIXL", "BST3 Switch", "BST3"},
+ {"RECMIXL", "BST2 Switch", "BST2"},
+ {"RECMIXL", "BST1 Switch", "BST1"},
+
+ {"RECMIXR", "INR1 Switch", "INR1 VOL"},
+ {"RECMIXR", "BST3 Switch", "BST3"},
+ {"RECMIXR", "BST2 Switch", "BST2"},
+ {"RECMIXR", "BST1 Switch", "BST1"},
+
+ {"ADC L", NULL, "RECMIXL"},
+ {"ADC L", NULL, "ADC L Power"},
+ {"ADC R", NULL, "RECMIXR"},
+ {"ADC R", NULL, "ADC R Power"},
+
+ {"DMIC L1", NULL, "DMIC CLK"},
+ {"DMIC R1", NULL, "DMIC CLK"},
+
+ {"Stereo1 ADC L2 Mux", "DMIC", "DMIC L1"},
+ {"Stereo1 ADC L2 Mux", "DD MIX", "DD MIXL"},
+ {"Stereo1 ADC L1 Mux", "ADC", "ADC L"},
+ {"Stereo1 ADC L1 Mux", "DD MIX", "DD MIXL"},
+
+ {"Stereo1 ADC R1 Mux", "ADC", "ADC R"},
+ {"Stereo1 ADC R1 Mux", "DD MIX", "DD MIXR"},
+ {"Stereo1 ADC R2 Mux", "DMIC", "DMIC R1"},
+ {"Stereo1 ADC R2 Mux", "DD MIX", "DD MIXR"},
+
+ {"Stereo2 ADC L2 Mux", "DMIC L", "DMIC L1"},
+ {"Stereo2 ADC L2 Mux", "DD MIXL", "DD MIXL"},
+ {"Stereo2 ADC L1 Mux", "DD MIXL", "DD MIXL"},
+ {"Stereo2 ADC L1 Mux", "ADCL", "ADC L"},
+
+ {"Stereo2 ADC R1 Mux", "DD MIXR", "DD MIXR"},
+ {"Stereo2 ADC R1 Mux", "ADCR", "ADC R"},
+ {"Stereo2 ADC R2 Mux", "DMIC R", "DMIC R1"},
+ {"Stereo2 ADC R2 Mux", "DD MIXR", "DD MIXR"},
+
+ {"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"},
+ {"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"},
+ {"Stereo1 ADC MIXL", NULL, "Stereo1 Filter"},
+ {"Stereo1 Filter", NULL, "PLL1", is_sysclk_from_pll},
+ {"Stereo1 Filter", NULL, "ADC ASRC"},
+
+ {"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"},
+ {"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"},
+ {"Stereo1 ADC MIXR", NULL, "Stereo1 Filter"},
+
+ {"Stereo2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux"},
+ {"Stereo2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux"},
+ {"Stereo2 ADC MIXL", NULL, "Stereo2 Filter"},
+ {"Stereo2 Filter", NULL, "PLL1", is_sysclk_from_pll},
+ {"Stereo2 Filter", NULL, "ADC ASRC"},
+
+ {"Stereo2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux"},
+ {"Stereo2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC R2 Mux"},
+ {"Stereo2 ADC MIXR", NULL, "Stereo2 Filter"},
+
+ {"IF1 ADC2", NULL, "Stereo2 ADC MIXL"},
+ {"IF1 ADC2", NULL, "Stereo2 ADC MIXR"},
+ {"IF1 ADC1", NULL, "Stereo1 ADC MIXL"},
+ {"IF1 ADC1", NULL, "Stereo1 ADC MIXR"},
+
+ {"IF1 ADC1", NULL, "I2S1"},
+
+ {"IF2 ADC", "IF1 ADC1", "IF1 ADC1"},
+ {"IF2 ADC", "IF1 ADC2", "IF1 ADC2"},
+ {"IF2 ADC", NULL, "I2S2"},
+
+ {"AIF1TX", NULL, "IF1 ADC1"},
+ {"AIF1TX", NULL, "IF1 ADC2"},
+ {"AIF2TX", NULL, "IF2 ADC"},
+
+ {"IF1 DAC", NULL, "AIF1RX"},
+ {"IF1 DAC", NULL, "I2S1"},
+ {"IF2 DAC", NULL, "AIF2RX"},
+ {"IF2 DAC", NULL, "I2S2"},
+
+ {"IF1 DAC1 L", NULL, "IF1 DAC"},
+ {"IF1 DAC1 R", NULL, "IF1 DAC"},
+ {"IF1 DAC2 L", NULL, "IF1 DAC"},
+ {"IF1 DAC2 R", NULL, "IF1 DAC"},
+ {"IF2 DAC L", NULL, "IF2 DAC"},
+ {"IF2 DAC R", NULL, "IF2 DAC"},
+
+ {"DAC MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+ {"DAC MIXL", "INF1 Switch", "IF1 DAC1 L"},
+ {"DAC MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+ {"DAC MIXR", "INF1 Switch", "IF1 DAC1 R"},
+
+ {"Audio DSP", NULL, "DAC MIXL"},
+ {"Audio DSP", NULL, "DAC MIXR"},
+
+ {"DAC L2 Mux", "IF1", "IF1 DAC2 L"},
+ {"DAC L2 Mux", "IF2", "IF2 DAC L"},
+ {"DAC L2 Volume", NULL, "DAC L2 Mux"},
+
+ {"DAC R2 Mux", "IF1", "IF1 DAC2 R"},
+ {"DAC R2 Mux", "IF2", "IF2 DAC R"},
+ {"DAC R2 Volume", NULL, "DAC R2 Mux"},
+
+ {"Stereo DAC MIXL", "DAC L1 Switch", "Audio DSP"},
+ {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Volume"},
+ {"Stereo DAC MIXL", "DAC R1 Switch", "DAC MIXR"},
+ {"Stereo DAC MIXL", NULL, "Stero1 DAC Power"},
+ {"Stereo DAC MIXL", NULL, "Stero2 DAC Power"},
+ {"Stereo DAC MIXR", "DAC R1 Switch", "Audio DSP"},
+ {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Volume"},
+ {"Stereo DAC MIXR", "DAC L1 Switch", "DAC MIXL"},
+ {"Stereo DAC MIXR", NULL, "Stero1 DAC Power"},
+ {"Stereo DAC MIXR", NULL, "Stero2 DAC Power"},
+
+ {"PDM L Mux", "Stereo DAC MIX", "Stereo DAC MIXL"},
+ {"PDM L Mux", "DD MIX", "DAC MIXL"},
+ {"PDM R Mux", "Stereo DAC MIX", "Stereo DAC MIXR"},
+ {"PDM R Mux", "DD MIX", "DAC MIXR"},
+
+ {"DAC L1", NULL, "Stereo DAC MIXL"},
+ {"DAC L1", NULL, "PLL1", is_sysclk_from_pll},
+ {"DAC L1", NULL, "DAC L1 Power"},
+ {"DAC R1", NULL, "Stereo DAC MIXR"},
+ {"DAC R1", NULL, "PLL1", is_sysclk_from_pll},
+ {"DAC R1", NULL, "DAC R1 Power"},
+
+ {"DD MIXL", "DAC L1 Switch", "DAC MIXL"},
+ {"DD MIXL", "DAC L2 Switch", "DAC L2 Volume"},
+ {"DD MIXL", "DAC R2 Switch", "DAC R2 Volume"},
+ {"DD MIXL", NULL, "Stero2 DAC Power"},
+
+ {"DD MIXR", "DAC R1 Switch", "DAC MIXR"},
+ {"DD MIXR", "DAC R2 Switch", "DAC R2 Volume"},
+ {"DD MIXR", "DAC L2 Switch", "DAC L2 Volume"},
+ {"DD MIXR", NULL, "Stero2 DAC Power"},
+
+ {"OUT MIXL", "BST1 Switch", "BST1"},
+ {"OUT MIXL", "BST2 Switch", "BST2"},
+ {"OUT MIXL", "INL1 Switch", "INL1 VOL"},
+ {"OUT MIXL", "REC MIXL Switch", "RECMIXL"},
+ {"OUT MIXL", "DAC L1 Switch", "DAC L1"},
+
+ {"OUT MIXR", "BST2 Switch", "BST2"},
+ {"OUT MIXR", "BST1 Switch", "BST1"},
+ {"OUT MIXR", "INR1 Switch", "INR1 VOL"},
+ {"OUT MIXR", "REC MIXR Switch", "RECMIXR"},
+ {"OUT MIXR", "DAC R1 Switch", "DAC R1"},
+
+ {"HPOVOL L", "Switch", "OUT MIXL"},
+ {"HPOVOL R", "Switch", "OUT MIXR"},
+ {"OUTVOL L", "Switch", "OUT MIXL"},
+ {"OUTVOL R", "Switch", "OUT MIXR"},
+
+ {"HPOL MIX", "HPO MIX DAC1 Switch", "DAC L1"},
+ {"HPOL MIX", "HPO MIX HPVOL Switch", "HPOVOL L"},
+ {"HPOL MIX", NULL, "HP L Amp"},
+ {"HPOR MIX", "HPO MIX DAC1 Switch", "DAC R1"},
+ {"HPOR MIX", "HPO MIX HPVOL Switch", "HPOVOL R"},
+ {"HPOR MIX", NULL, "HP R Amp"},
+
+ {"LOUT MIX", "DAC L1 Switch", "DAC L1"},
+ {"LOUT MIX", "DAC R1 Switch", "DAC R1"},
+ {"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},
+ {"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"},
+
+ {"HP Amp", NULL, "HPOL MIX"},
+ {"HP Amp", NULL, "HPOR MIX"},
+ {"HP Amp", NULL, "Amp Power"},
+ {"HPO L Playback", "Switch", "HP Amp"},
+ {"HPO R Playback", "Switch", "HP Amp"},
+ {"HPOL", NULL, "HPO L Playback"},
+ {"HPOR", NULL, "HPO R Playback"},
+
+ {"LOUT L Playback", "Switch", "LOUT MIX"},
+ {"LOUT R Playback", "Switch", "LOUT MIX"},
+ {"LOUTL", NULL, "LOUT L Playback"},
+ {"LOUTL", NULL, "Amp Power"},
+ {"LOUTR", NULL, "LOUT R Playback"},
+ {"LOUTR", NULL, "Amp Power"},
+
+ {"PDML", NULL, "PDM L Mux"},
+ {"PDMR", NULL, "PDM R Mux"},
+};
+
+static int get_clk_info(int sclk, int rate)
+{
+ int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
+
+ if (sclk <= 0 || rate <= 0)
+ return -EINVAL;
+
+ rate = rate << 8;
+ for (i = 0; i < ARRAY_SIZE(pd); i++)
+ if (sclk == rate * pd[i])
+ return i;
+
+ return -EINVAL;
+}
+
+static int rt5651_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 rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val_len = 0, val_clk, mask_clk;
+ int pre_div, bclk_ms, frame_size;
+
+ rt5651->lrck[dai->id] = params_rate(params);
+ pre_div = get_clk_info(rt5651->sysclk, rt5651->lrck[dai->id]);
+
+ if (pre_div < 0) {
+ dev_err(codec->dev, "Unsupported clock setting\n");
+ return -EINVAL;
+ }
+ frame_size = snd_soc_params_to_frame_size(params);
+ if (frame_size < 0) {
+ dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+ return -EINVAL;
+ }
+ bclk_ms = frame_size > 32 ? 1 : 0;
+ rt5651->bclk[dai->id] = rt5651->lrck[dai->id] * (32 << bclk_ms);
+
+ dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+ rt5651->bclk[dai->id], rt5651->lrck[dai->id]);
+ dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+ bclk_ms, pre_div, dai->id);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ val_len |= RT5651_I2S_DL_20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ val_len |= RT5651_I2S_DL_24;
+ break;
+ case SNDRV_PCM_FORMAT_S8:
+ val_len |= RT5651_I2S_DL_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (dai->id) {
+ case RT5651_AIF1:
+ mask_clk = RT5651_I2S_PD1_MASK;
+ val_clk = pre_div << RT5651_I2S_PD1_SFT;
+ snd_soc_update_bits(codec, RT5651_I2S1_SDP,
+ RT5651_I2S_DL_MASK, val_len);
+ snd_soc_update_bits(codec, RT5651_ADDA_CLK1, mask_clk, val_clk);
+ break;
+ case RT5651_AIF2:
+ mask_clk = RT5651_I2S_BCLK_MS2_MASK | RT5651_I2S_PD2_MASK;
+ val_clk = pre_div << RT5651_I2S_PD2_SFT;
+ snd_soc_update_bits(codec, RT5651_I2S2_SDP,
+ RT5651_I2S_DL_MASK, val_len);
+ snd_soc_update_bits(codec, RT5651_ADDA_CLK1, mask_clk, val_clk);
+ break;
+ default:
+ dev_err(codec->dev, "Wrong dai->id: %d\n", dai->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ unsigned int reg_val = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ rt5651->master[dai->id] = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ reg_val |= RT5651_I2S_MS_S;
+ rt5651->master[dai->id] = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg_val |= RT5651_I2S_BP_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg_val |= RT5651_I2S_DF_LEFT;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ reg_val |= RT5651_I2S_DF_PCM_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ reg_val |= RT5651_I2S_DF_PCM_B;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (dai->id) {
+ case RT5651_AIF1:
+ snd_soc_update_bits(codec, RT5651_I2S1_SDP,
+ RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK |
+ RT5651_I2S_DF_MASK, reg_val);
+ break;
+ case RT5651_AIF2:
+ snd_soc_update_bits(codec, RT5651_I2S2_SDP,
+ RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK |
+ RT5651_I2S_DF_MASK, reg_val);
+ break;
+ default:
+ dev_err(codec->dev, "Wrong dai->id: %d\n", dai->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int rt5651_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ unsigned int reg_val = 0;
+
+ if (freq == rt5651->sysclk && clk_id == rt5651->sysclk_src)
+ return 0;
+
+ switch (clk_id) {
+ case RT5651_SCLK_S_MCLK:
+ reg_val |= RT5651_SCLK_SRC_MCLK;
+ break;
+ case RT5651_SCLK_S_PLL1:
+ reg_val |= RT5651_SCLK_SRC_PLL1;
+ break;
+ case RT5651_SCLK_S_RCCLK:
+ reg_val |= RT5651_SCLK_SRC_RCCLK;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, RT5651_GLB_CLK,
+ RT5651_SCLK_SRC_MASK, reg_val);
+ rt5651->sysclk = freq;
+ rt5651->sysclk_src = clk_id;
+
+ dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+ return 0;
+}
+
+/**
+ * rt5651_pll_calc - Calcualte PLL M/N/K code.
+ * @freq_in: external clock provided to codec.
+ * @freq_out: target clock which codec works on.
+ * @pll_code: Pointer to structure with M, N, K and bypass flag.
+ *
+ * Calcualte M/N/K code to configure PLL for codec. And K is assigned to 2
+ * which make calculation more efficiently.
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5651_pll_calc(const unsigned int freq_in,
+ const unsigned int freq_out, struct rt5651_pll_code *pll_code)
+{
+ int max_n = RT5651_PLL_N_MAX, max_m = RT5651_PLL_M_MAX;
+ int n = 0, m = 0, red, n_t, m_t, in_t, out_t;
+ int red_t = abs(freq_out - freq_in);
+ bool bypass = false;
+
+ if (RT5651_PLL_INP_MAX < freq_in || RT5651_PLL_INP_MIN > freq_in)
+ return -EINVAL;
+
+ for (n_t = 0; n_t <= max_n; n_t++) {
+ in_t = (freq_in >> 1) + (freq_in >> 2) * n_t;
+ if (in_t < 0)
+ continue;
+ if (in_t == freq_out) {
+ bypass = true;
+ n = n_t;
+ goto code_find;
+ }
+ for (m_t = 0; m_t <= max_m; m_t++) {
+ out_t = in_t / (m_t + 2);
+ red = abs(out_t - freq_out);
+ if (red < red_t) {
+ n = n_t;
+ m = m_t;
+ if (red == 0)
+ goto code_find;
+ red_t = red;
+ }
+ }
+ }
+ pr_debug("Only get approximation about PLL\n");
+
+code_find:
+ pll_code->m_bp = bypass;
+ pll_code->m_code = m;
+ pll_code->n_code = n;
+ pll_code->k_code = 2;
+ return 0;
+}
+
+static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ struct rt5651_pll_code *pll_code = &rt5651->pll_code;
+ int ret;
+
+ if (source == rt5651->pll_src && freq_in == rt5651->pll_in &&
+ freq_out == rt5651->pll_out)
+ return 0;
+
+ if (!freq_in || !freq_out) {
+ dev_dbg(codec->dev, "PLL disabled\n");
+
+ rt5651->pll_in = 0;
+ rt5651->pll_out = 0;
+ snd_soc_update_bits(codec, RT5651_GLB_CLK,
+ RT5651_SCLK_SRC_MASK, RT5651_SCLK_SRC_MCLK);
+ return 0;
+ }
+
+ switch (source) {
+ case RT5651_PLL1_S_MCLK:
+ snd_soc_update_bits(codec, RT5651_GLB_CLK,
+ RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_MCLK);
+ break;
+ case RT5651_PLL1_S_BCLK1:
+ snd_soc_update_bits(codec, RT5651_GLB_CLK,
+ RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK1);
+ break;
+ case RT5651_PLL1_S_BCLK2:
+ snd_soc_update_bits(codec, RT5651_GLB_CLK,
+ RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK2);
+ break;
+ default:
+ dev_err(codec->dev, "Unknown PLL source %d\n", source);
+ return -EINVAL;
+ }
+
+ ret = rt5651_pll_calc(freq_in, freq_out, pll_code);
+ if (ret < 0) {
+ dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+ return ret;
+ }
+
+ dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=2\n", pll_code->m_bp,
+ (pll_code->m_bp ? 0 : pll_code->m_code), pll_code->n_code);
+
+ snd_soc_write(codec, RT5651_PLL_CTRL1,
+ pll_code->n_code << RT5651_PLL_N_SFT | pll_code->k_code);
+ snd_soc_write(codec, RT5651_PLL_CTRL2,
+ (pll_code->m_bp ? 0 : pll_code->m_code) << RT5651_PLL_M_SFT |
+ pll_code->m_bp << RT5651_PLL_M_BP_SFT);
+
+ rt5651->pll_in = freq_in;
+ rt5651->pll_out = freq_out;
+ rt5651->pll_src = source;
+
+ return 0;
+}
+
+static int rt5651_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_PREPARE:
+ if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
+ snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+ RT5651_PWR_VREF1 | RT5651_PWR_MB |
+ RT5651_PWR_BG | RT5651_PWR_VREF2,
+ RT5651_PWR_VREF1 | RT5651_PWR_MB |
+ RT5651_PWR_BG | RT5651_PWR_VREF2);
+ usleep_range(10000, 15000);
+ snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+ RT5651_PWR_FV1 | RT5651_PWR_FV2,
+ RT5651_PWR_FV1 | RT5651_PWR_FV2);
+ snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+ RT5651_PWR_LDO_DVO_MASK,
+ RT5651_PWR_LDO_DVO_1_2V);
+ snd_soc_update_bits(codec, RT5651_D_MISC, 0x1, 0x1);
+ if (snd_soc_read(codec, RT5651_PLL_MODE_1) & 0x9200)
+ snd_soc_update_bits(codec, RT5651_D_MISC,
+ 0xc00, 0xc00);
+ }
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ snd_soc_write(codec, RT5651_D_MISC, 0x0010);
+ snd_soc_write(codec, RT5651_PWR_DIG1, 0x0000);
+ snd_soc_write(codec, RT5651_PWR_DIG2, 0x0000);
+ snd_soc_write(codec, RT5651_PWR_VOL, 0x0000);
+ snd_soc_write(codec, RT5651_PWR_MIXER, 0x0000);
+ snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0000);
+ snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0000);
+ break;
+
+ default:
+ break;
+ }
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+static int rt5651_probe(struct snd_soc_codec *codec)
+{
+ struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+ rt5651->codec = codec;
+
+ snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+ RT5651_PWR_VREF1 | RT5651_PWR_MB |
+ RT5651_PWR_BG | RT5651_PWR_VREF2,
+ RT5651_PWR_VREF1 | RT5651_PWR_MB |
+ RT5651_PWR_BG | RT5651_PWR_VREF2);
+ usleep_range(10000, 15000);
+ snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
+ RT5651_PWR_FV1 | RT5651_PWR_FV2,
+ RT5651_PWR_FV1 | RT5651_PWR_FV2);
+
+ rt5651_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5651_suspend(struct snd_soc_codec *codec)
+{
+ struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(rt5651->regmap, true);
+ regcache_mark_dirty(rt5651->regmap);
+ return 0;
+}
+
+static int rt5651_resume(struct snd_soc_codec *codec)
+{
+ struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(rt5651->regmap, false);
+ snd_soc_cache_sync(codec);
+
+ return 0;
+}
+#else
+#define rt5651_suspend NULL
+#define rt5651_resume NULL
+#endif
+
+#define RT5651_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5651_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5651_aif_dai_ops = {
+ .hw_params = rt5651_hw_params,
+ .set_fmt = rt5651_set_dai_fmt,
+ .set_sysclk = rt5651_set_dai_sysclk,
+ .set_pll = rt5651_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5651_dai[] = {
+ {
+ .name = "rt5651-aif1",
+ .id = RT5651_AIF1,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5651_STEREO_RATES,
+ .formats = RT5651_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5651_STEREO_RATES,
+ .formats = RT5651_FORMATS,
+ },
+ .ops = &rt5651_aif_dai_ops,
+ },
+ {
+ .name = "rt5651-aif2",
+ .id = RT5651_AIF2,
+ .playback = {
+ .stream_name = "AIF2 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5651_STEREO_RATES,
+ .formats = RT5651_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5651_STEREO_RATES,
+ .formats = RT5651_FORMATS,
+ },
+ .ops = &rt5651_aif_dai_ops,
+ },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5651 = {
+ .probe = rt5651_probe,
+ .suspend = rt5651_suspend,
+ .resume = rt5651_resume,
+ .set_bias_level = rt5651_set_bias_level,
+ .idle_bias_off = true,
+ .controls = rt5651_snd_controls,
+ .num_controls = ARRAY_SIZE(rt5651_snd_controls),
+ .dapm_widgets = rt5651_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt5651_dapm_widgets),
+ .dapm_routes = rt5651_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt5651_dapm_routes),
+};
+
+static const struct regmap_config rt5651_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+
+ .max_register = RT5651_DEVICE_ID + 1 + (ARRAY_SIZE(rt5651_ranges) *
+ RT5651_PR_SPACING),
+ .volatile_reg = rt5651_volatile_register,
+ .readable_reg = rt5651_readable_register,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rt5651_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt5651_reg),
+ .ranges = rt5651_ranges,
+ .num_ranges = ARRAY_SIZE(rt5651_ranges),
+};
+
+static const struct i2c_device_id rt5651_i2c_id[] = {
+ { "rt5651", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id);
+
+static int rt5651_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt5651_platform_data *pdata = dev_get_platdata(&i2c->dev);
+ struct rt5651_priv *rt5651;
+ int ret;
+
+ rt5651 = devm_kzalloc(&i2c->dev, sizeof(*rt5651),
+ GFP_KERNEL);
+ if (NULL == rt5651)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt5651);
+
+ if (pdata)
+ rt5651->pdata = *pdata;
+
+ rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap);
+ if (IS_ERR(rt5651->regmap)) {
+ ret = PTR_ERR(rt5651->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret);
+ if (ret != RT5651_DEVICE_ID_VALUE) {
+ dev_err(&i2c->dev,
+ "Device with ID register %x is not rt5651\n", ret);
+ return -ENODEV;
+ }
+
+ regmap_write(rt5651->regmap, RT5651_RESET, 0);
+
+ ret = regmap_register_patch(rt5651->regmap, init_list,
+ ARRAY_SIZE(init_list));
+ if (ret != 0)
+ dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+ if (rt5651->pdata.in2_diff)
+ regmap_update_bits(rt5651->regmap, RT5651_IN1_IN2,
+ RT5651_IN_DF2, RT5651_IN_DF2);
+
+ if (rt5651->pdata.dmic_en)
+ regmap_update_bits(rt5651->regmap, RT5651_GPIO_CTRL1,
+ RT5651_GP2_PIN_MASK, RT5651_GP2_PIN_DMIC1_SCL);
+
+ rt5651->hp_mute = 1;
+
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651,
+ rt5651_dai, ARRAY_SIZE(rt5651_dai));
+
+ return ret;
+}
+
+static int rt5651_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_codec(&i2c->dev);
+
+ return 0;
+}
+
+static struct i2c_driver rt5651_i2c_driver = {
+ .driver = {
+ .name = "rt5651",
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5651_i2c_probe,
+ .remove = rt5651_i2c_remove,
+ .id_table = rt5651_i2c_id,
+};
+module_i2c_driver(rt5651_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5651 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h
new file mode 100644
index 000000000000..a28bd0c3d613
--- /dev/null
+++ b/sound/soc/codecs/rt5651.h
@@ -0,0 +1,2081 @@
+/*
+ * rt5651.h -- RT5651 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.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 __RT5651_H__
+#define __RT5651_H__
+
+#include <sound/rt5651.h>
+
+/* Info */
+#define RT5651_RESET 0x00
+#define RT5651_VERSION_ID 0xfd
+#define RT5651_VENDOR_ID 0xfe
+#define RT5651_DEVICE_ID 0xff
+/* I/O - Output */
+#define RT5651_HP_VOL 0x02
+#define RT5651_LOUT_CTRL1 0x03
+#define RT5651_LOUT_CTRL2 0x05
+/* I/O - Input */
+#define RT5651_IN1_IN2 0x0d
+#define RT5651_IN3 0x0e
+#define RT5651_INL1_INR1_VOL 0x0f
+#define RT5651_INL2_INR2_VOL 0x10
+/* I/O - ADC/DAC/DMIC */
+#define RT5651_DAC1_DIG_VOL 0x19
+#define RT5651_DAC2_DIG_VOL 0x1a
+#define RT5651_DAC2_CTRL 0x1b
+#define RT5651_ADC_DIG_VOL 0x1c
+#define RT5651_ADC_DATA 0x1d
+#define RT5651_ADC_BST_VOL 0x1e
+/* Mixer - D-D */
+#define RT5651_STO1_ADC_MIXER 0x27
+#define RT5651_STO2_ADC_MIXER 0x28
+#define RT5651_AD_DA_MIXER 0x29
+#define RT5651_STO_DAC_MIXER 0x2a
+#define RT5651_DD_MIXER 0x2b
+#define RT5651_DIG_INF_DATA 0x2f
+/* PDM */
+#define RT5651_PDM_CTL 0x30
+#define RT5651_PDM_I2C_CTL1 0x31
+#define RT5651_PDM_I2C_CTL2 0x32
+#define RT5651_PDM_I2C_DATA_W 0x33
+#define RT5651_PDM_I2C_DATA_R 0x34
+/* Mixer - ADC */
+#define RT5651_REC_L1_MIXER 0x3b
+#define RT5651_REC_L2_MIXER 0x3c
+#define RT5651_REC_R1_MIXER 0x3d
+#define RT5651_REC_R2_MIXER 0x3e
+/* Mixer - DAC */
+#define RT5651_HPO_MIXER 0x45
+#define RT5651_OUT_L1_MIXER 0x4d
+#define RT5651_OUT_L2_MIXER 0x4e
+#define RT5651_OUT_L3_MIXER 0x4f
+#define RT5651_OUT_R1_MIXER 0x50
+#define RT5651_OUT_R2_MIXER 0x51
+#define RT5651_OUT_R3_MIXER 0x52
+#define RT5651_LOUT_MIXER 0x53
+/* Power */
+#define RT5651_PWR_DIG1 0x61
+#define RT5651_PWR_DIG2 0x62
+#define RT5651_PWR_ANLG1 0x63
+#define RT5651_PWR_ANLG2 0x64
+#define RT5651_PWR_MIXER 0x65
+#define RT5651_PWR_VOL 0x66
+/* Private Register Control */
+#define RT5651_PRIV_INDEX 0x6a
+#define RT5651_PRIV_DATA 0x6c
+/* Format - ADC/DAC */
+#define RT5651_I2S1_SDP 0x70
+#define RT5651_I2S2_SDP 0x71
+#define RT5651_ADDA_CLK1 0x73
+#define RT5651_ADDA_CLK2 0x74
+#define RT5651_DMIC 0x75
+/* TDM Control */
+#define RT5651_TDM_CTL_1 0x77
+#define RT5651_TDM_CTL_2 0x78
+#define RT5651_TDM_CTL_3 0x79
+/* Function - Analog */
+#define RT5651_GLB_CLK 0x80
+#define RT5651_PLL_CTRL1 0x81
+#define RT5651_PLL_CTRL2 0x82
+#define RT5651_PLL_MODE_1 0x83
+#define RT5651_PLL_MODE_2 0x84
+#define RT5651_PLL_MODE_3 0x85
+#define RT5651_PLL_MODE_4 0x86
+#define RT5651_PLL_MODE_5 0x87
+#define RT5651_PLL_MODE_6 0x89
+#define RT5651_PLL_MODE_7 0x8a
+#define RT5651_DEPOP_M1 0x8e
+#define RT5651_DEPOP_M2 0x8f
+#define RT5651_DEPOP_M3 0x90
+#define RT5651_CHARGE_PUMP 0x91
+#define RT5651_MICBIAS 0x93
+#define RT5651_A_JD_CTL1 0x94
+/* Function - Digital */
+#define RT5651_EQ_CTRL1 0xb0
+#define RT5651_EQ_CTRL2 0xb1
+#define RT5651_ALC_1 0xb4
+#define RT5651_ALC_2 0xb5
+#define RT5651_ALC_3 0xb6
+#define RT5651_JD_CTRL1 0xbb
+#define RT5651_JD_CTRL2 0xbc
+#define RT5651_IRQ_CTRL1 0xbd
+#define RT5651_IRQ_CTRL2 0xbe
+#define RT5651_INT_IRQ_ST 0xbf
+#define RT5651_GPIO_CTRL1 0xc0
+#define RT5651_GPIO_CTRL2 0xc1
+#define RT5651_GPIO_CTRL3 0xc2
+#define RT5651_PGM_REG_ARR1 0xc8
+#define RT5651_PGM_REG_ARR2 0xc9
+#define RT5651_PGM_REG_ARR3 0xca
+#define RT5651_PGM_REG_ARR4 0xcb
+#define RT5651_PGM_REG_ARR5 0xcc
+#define RT5651_SCB_FUNC 0xcd
+#define RT5651_SCB_CTRL 0xce
+#define RT5651_BASE_BACK 0xcf
+#define RT5651_MP3_PLUS1 0xd0
+#define RT5651_MP3_PLUS2 0xd1
+#define RT5651_ADJ_HPF_CTRL1 0xd3
+#define RT5651_ADJ_HPF_CTRL2 0xd4
+#define RT5651_HP_CALIB_AMP_DET 0xd6
+#define RT5651_HP_CALIB2 0xd7
+#define RT5651_SV_ZCD1 0xd9
+#define RT5651_SV_ZCD2 0xda
+#define RT5651_D_MISC 0xfa
+/* Dummy Register */
+#define RT5651_DUMMY2 0xfb
+#define RT5651_DUMMY3 0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5651_BIAS_CUR1 0x12
+#define RT5651_BIAS_CUR3 0x14
+#define RT5651_CLSD_INT_REG1 0x1c
+#define RT5651_CHPUMP_INT_REG1 0x24
+#define RT5651_MAMP_INT_REG2 0x37
+#define RT5651_CHOP_DAC_ADC 0x3d
+#define RT5651_3D_SPK 0x63
+#define RT5651_WND_1 0x6c
+#define RT5651_WND_2 0x6d
+#define RT5651_WND_3 0x6e
+#define RT5651_WND_4 0x6f
+#define RT5651_WND_5 0x70
+#define RT5651_WND_8 0x73
+#define RT5651_DIP_SPK_INF 0x75
+#define RT5651_HP_DCC_INT1 0x77
+#define RT5651_EQ_BW_LOP 0xa0
+#define RT5651_EQ_GN_LOP 0xa1
+#define RT5651_EQ_FC_BP1 0xa2
+#define RT5651_EQ_BW_BP1 0xa3
+#define RT5651_EQ_GN_BP1 0xa4
+#define RT5651_EQ_FC_BP2 0xa5
+#define RT5651_EQ_BW_BP2 0xa6
+#define RT5651_EQ_GN_BP2 0xa7
+#define RT5651_EQ_FC_BP3 0xa8
+#define RT5651_EQ_BW_BP3 0xa9
+#define RT5651_EQ_GN_BP3 0xaa
+#define RT5651_EQ_FC_BP4 0xab
+#define RT5651_EQ_BW_BP4 0xac
+#define RT5651_EQ_GN_BP4 0xad
+#define RT5651_EQ_FC_HIP1 0xae
+#define RT5651_EQ_GN_HIP1 0xaf
+#define RT5651_EQ_FC_HIP2 0xb0
+#define RT5651_EQ_BW_HIP2 0xb1
+#define RT5651_EQ_GN_HIP2 0xb2
+#define RT5651_EQ_PRE_VOL 0xb3
+#define RT5651_EQ_PST_VOL 0xb4
+
+
+/* global definition */
+#define RT5651_L_MUTE (0x1 << 15)
+#define RT5651_L_MUTE_SFT 15
+#define RT5651_VOL_L_MUTE (0x1 << 14)
+#define RT5651_VOL_L_SFT 14
+#define RT5651_R_MUTE (0x1 << 7)
+#define RT5651_R_MUTE_SFT 7
+#define RT5651_VOL_R_MUTE (0x1 << 6)
+#define RT5651_VOL_R_SFT 6
+#define RT5651_L_VOL_MASK (0x3f << 8)
+#define RT5651_L_VOL_SFT 8
+#define RT5651_R_VOL_MASK (0x3f)
+#define RT5651_R_VOL_SFT 0
+
+/* LOUT Control 2(0x05) */
+#define RT5651_EN_DFO (0x1 << 15)
+
+/* IN1 and IN2 Control (0x0d) */
+/* IN3 and IN4 Control (0x0e) */
+#define RT5651_BST_MASK1 (0xf<<12)
+#define RT5651_BST_SFT1 12
+#define RT5651_BST_MASK2 (0xf<<8)
+#define RT5651_BST_SFT2 8
+#define RT5651_IN_DF1 (0x1 << 7)
+#define RT5651_IN_SFT1 7
+#define RT5651_IN_DF2 (0x1 << 6)
+#define RT5651_IN_SFT2 6
+
+/* INL1 and INR1 Volume Control (0x0f) */
+/* INL2 and INR2 Volume Control (0x10) */
+#define RT5651_INL_SEL_MASK (0x1 << 15)
+#define RT5651_INL_SEL_SFT 15
+#define RT5651_INL_SEL_IN4P (0x0 << 15)
+#define RT5651_INL_SEL_MONOP (0x1 << 15)
+#define RT5651_INL_VOL_MASK (0x1f << 8)
+#define RT5651_INL_VOL_SFT 8
+#define RT5651_INR_SEL_MASK (0x1 << 7)
+#define RT5651_INR_SEL_SFT 7
+#define RT5651_INR_SEL_IN4N (0x0 << 7)
+#define RT5651_INR_SEL_MONON (0x1 << 7)
+#define RT5651_INR_VOL_MASK (0x1f)
+#define RT5651_INR_VOL_SFT 0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5651_DAC_L1_VOL_MASK (0xff << 8)
+#define RT5651_DAC_L1_VOL_SFT 8
+#define RT5651_DAC_R1_VOL_MASK (0xff)
+#define RT5651_DAC_R1_VOL_SFT 0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5651_DAC_L2_VOL_MASK (0xff << 8)
+#define RT5651_DAC_L2_VOL_SFT 8
+#define RT5651_DAC_R2_VOL_MASK (0xff)
+#define RT5651_DAC_R2_VOL_SFT 0
+
+/* DAC2 Control (0x1b) */
+#define RT5651_M_DAC_L2_VOL (0x1 << 13)
+#define RT5651_M_DAC_L2_VOL_SFT 13
+#define RT5651_M_DAC_R2_VOL (0x1 << 12)
+#define RT5651_M_DAC_R2_VOL_SFT 12
+#define RT5651_SEL_DAC_L2 (0x1 << 11)
+#define RT5651_IF2_DAC_L2 (0x1 << 11)
+#define RT5651_IF1_DAC_L2 (0x0 << 11)
+#define RT5651_SEL_DAC_L2_SFT 11
+#define RT5651_SEL_DAC_R2 (0x1 << 10)
+#define RT5651_IF2_DAC_R2 (0x1 << 11)
+#define RT5651_IF1_DAC_R2 (0x0 << 11)
+#define RT5651_SEL_DAC_R2_SFT 10
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5651_ADC_L_VOL_MASK (0x7f << 8)
+#define RT5651_ADC_L_VOL_SFT 8
+#define RT5651_ADC_R_VOL_MASK (0x7f)
+#define RT5651_ADC_R_VOL_SFT 0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5651_M_MONO_ADC_L (0x1 << 15)
+#define RT5651_M_MONO_ADC_L_SFT 15
+#define RT5651_MONO_ADC_L_VOL_MASK (0x7f << 8)
+#define RT5651_MONO_ADC_L_VOL_SFT 8
+#define RT5651_M_MONO_ADC_R (0x1 << 7)
+#define RT5651_M_MONO_ADC_R_SFT 7
+#define RT5651_MONO_ADC_R_VOL_MASK (0x7f)
+#define RT5651_MONO_ADC_R_VOL_SFT 0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5651_ADC_L_BST_MASK (0x3 << 14)
+#define RT5651_ADC_L_BST_SFT 14
+#define RT5651_ADC_R_BST_MASK (0x3 << 12)
+#define RT5651_ADC_R_BST_SFT 12
+#define RT5651_ADC_COMP_MASK (0x3 << 10)
+#define RT5651_ADC_COMP_SFT 10
+
+/* Stereo ADC1 Mixer Control (0x27) */
+#define RT5651_M_STO1_ADC_L1 (0x1 << 14)
+#define RT5651_M_STO1_ADC_L1_SFT 14
+#define RT5651_M_STO1_ADC_L2 (0x1 << 13)
+#define RT5651_M_STO1_ADC_L2_SFT 13
+#define RT5651_STO1_ADC_1_SRC_MASK (0x1 << 12)
+#define RT5651_STO1_ADC_1_SRC_SFT 12
+#define RT5651_STO1_ADC_1_SRC_ADC (0x1 << 12)
+#define RT5651_STO1_ADC_1_SRC_DACMIX (0x0 << 12)
+#define RT5651_STO1_ADC_2_SRC_MASK (0x1 << 11)
+#define RT5651_STO1_ADC_2_SRC_SFT 11
+#define RT5651_STO1_ADC_2_SRC_DMIC (0x0 << 11)
+#define RT5651_STO1_ADC_2_SRC_DACMIXR (0x1 << 11)
+#define RT5651_M_STO1_ADC_R1 (0x1 << 6)
+#define RT5651_M_STO1_ADC_R1_SFT 6
+#define RT5651_M_STO1_ADC_R2 (0x1 << 5)
+#define RT5651_M_STO1_ADC_R2_SFT 5
+
+/* Stereo ADC2 Mixer Control (0x28) */
+#define RT5651_M_STO2_ADC_L1 (0x1 << 14)
+#define RT5651_M_STO2_ADC_L1_SFT 14
+#define RT5651_M_STO2_ADC_L2 (0x1 << 13)
+#define RT5651_M_STO2_ADC_L2_SFT 13
+#define RT5651_STO2_ADC_L1_SRC_MASK (0x1 << 12)
+#define RT5651_STO2_ADC_L1_SRC_SFT 12
+#define RT5651_STO2_ADC_L1_SRC_DACMIXL (0x0 << 12)
+#define RT5651_STO2_ADC_L1_SRC_ADCL (0x1 << 12)
+#define RT5651_STO2_ADC_L2_SRC_MASK (0x1 << 11)
+#define RT5651_STO2_ADC_L2_SRC_SFT 11
+#define RT5651_STO2_ADC_L2_SRC_DMIC (0x0 << 11)
+#define RT5651_STO2_ADC_L2_SRC_DACMIXR (0x1 << 11)
+#define RT5651_M_STO2_ADC_R1 (0x1 << 6)
+#define RT5651_M_STO2_ADC_R1_SFT 6
+#define RT5651_M_STO2_ADC_R2 (0x1 << 5)
+#define RT5651_M_STO2_ADC_R2_SFT 5
+#define RT5651_STO2_ADC_R1_SRC_MASK (0x1 << 4)
+#define RT5651_STO2_ADC_R1_SRC_SFT 4
+#define RT5651_STO2_ADC_R1_SRC_ADCR (0x1 << 4)
+#define RT5651_STO2_ADC_R1_SRC_DACMIXR (0x0 << 4)
+#define RT5651_STO2_ADC_R2_SRC_MASK (0x1 << 3)
+#define RT5651_STO2_ADC_R2_SRC_SFT 3
+#define RT5651_STO2_ADC_R2_SRC_DMIC (0x0 << 3)
+#define RT5651_STO2_ADC_R2_SRC_DACMIXR (0x1 << 3)
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5651_M_ADCMIX_L (0x1 << 15)
+#define RT5651_M_ADCMIX_L_SFT 15
+#define RT5651_M_IF1_DAC_L (0x1 << 14)
+#define RT5651_M_IF1_DAC_L_SFT 14
+#define RT5651_M_ADCMIX_R (0x1 << 7)
+#define RT5651_M_ADCMIX_R_SFT 7
+#define RT5651_M_IF1_DAC_R (0x1 << 6)
+#define RT5651_M_IF1_DAC_R_SFT 6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5651_M_DAC_L1_MIXL (0x1 << 14)
+#define RT5651_M_DAC_L1_MIXL_SFT 14
+#define RT5651_DAC_L1_STO_L_VOL_MASK (0x1 << 13)
+#define RT5651_DAC_L1_STO_L_VOL_SFT 13
+#define RT5651_M_DAC_L2_MIXL (0x1 << 12)
+#define RT5651_M_DAC_L2_MIXL_SFT 12
+#define RT5651_DAC_L2_STO_L_VOL_MASK (0x1 << 11)
+#define RT5651_DAC_L2_STO_L_VOL_SFT 11
+#define RT5651_M_DAC_R1_MIXL (0x1 << 9)
+#define RT5651_M_DAC_R1_MIXL_SFT 9
+#define RT5651_DAC_R1_STO_L_VOL_MASK (0x1 << 8)
+#define RT5651_DAC_R1_STO_L_VOL_SFT 8
+#define RT5651_M_DAC_R1_MIXR (0x1 << 6)
+#define RT5651_M_DAC_R1_MIXR_SFT 6
+#define RT5651_DAC_R1_STO_R_VOL_MASK (0x1 << 5)
+#define RT5651_DAC_R1_STO_R_VOL_SFT 5
+#define RT5651_M_DAC_R2_MIXR (0x1 << 4)
+#define RT5651_M_DAC_R2_MIXR_SFT 4
+#define RT5651_DAC_R2_STO_R_VOL_MASK (0x1 << 3)
+#define RT5651_DAC_R2_STO_R_VOL_SFT 3
+#define RT5651_M_DAC_L1_MIXR (0x1 << 1)
+#define RT5651_M_DAC_L1_MIXR_SFT 1
+#define RT5651_DAC_L1_STO_R_VOL_MASK (0x1)
+#define RT5651_DAC_L1_STO_R_VOL_SFT 0
+
+/* DD Mixer Control (0x2b) */
+#define RT5651_M_STO_DD_L1 (0x1 << 14)
+#define RT5651_M_STO_DD_L1_SFT 14
+#define RT5651_STO_DD_L1_VOL_MASK (0x1 << 13)
+#define RT5651_DAC_DD_L1_VOL_SFT 13
+#define RT5651_M_STO_DD_L2 (0x1 << 12)
+#define RT5651_M_STO_DD_L2_SFT 12
+#define RT5651_STO_DD_L2_VOL_MASK (0x1 << 11)
+#define RT5651_STO_DD_L2_VOL_SFT 11
+#define RT5651_M_STO_DD_R2_L (0x1 << 10)
+#define RT5651_M_STO_DD_R2_L_SFT 10
+#define RT5651_STO_DD_R2_L_VOL_MASK (0x1 << 9)
+#define RT5651_STO_DD_R2_L_VOL_SFT 9
+#define RT5651_M_STO_DD_R1 (0x1 << 6)
+#define RT5651_M_STO_DD_R1_SFT 6
+#define RT5651_STO_DD_R1_VOL_MASK (0x1 << 5)
+#define RT5651_STO_DD_R1_VOL_SFT 5
+#define RT5651_M_STO_DD_R2 (0x1 << 4)
+#define RT5651_M_STO_DD_R2_SFT 4
+#define RT5651_STO_DD_R2_VOL_MASK (0x1 << 3)
+#define RT5651_STO_DD_R2_VOL_SFT 3
+#define RT5651_M_STO_DD_L2_R (0x1 << 2)
+#define RT5651_M_STO_DD_L2_R_SFT 2
+#define RT5651_STO_DD_L2_R_VOL_MASK (0x1 << 1)
+#define RT5651_STO_DD_L2_R_VOL_SFT 1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5651_M_STO_L_DAC_L (0x1 << 15)
+#define RT5651_M_STO_L_DAC_L_SFT 15
+#define RT5651_STO_L_DAC_L_VOL_MASK (0x1 << 14)
+#define RT5651_STO_L_DAC_L_VOL_SFT 14
+#define RT5651_M_DAC_L2_DAC_L (0x1 << 13)
+#define RT5651_M_DAC_L2_DAC_L_SFT 13
+#define RT5651_DAC_L2_DAC_L_VOL_MASK (0x1 << 12)
+#define RT5651_DAC_L2_DAC_L_VOL_SFT 12
+#define RT5651_M_STO_R_DAC_R (0x1 << 11)
+#define RT5651_M_STO_R_DAC_R_SFT 11
+#define RT5651_STO_R_DAC_R_VOL_MASK (0x1 << 10)
+#define RT5651_STO_R_DAC_R_VOL_SFT 10
+#define RT5651_M_DAC_R2_DAC_R (0x1 << 9)
+#define RT5651_M_DAC_R2_DAC_R_SFT 9
+#define RT5651_DAC_R2_DAC_R_VOL_MASK (0x1 << 8)
+#define RT5651_DAC_R2_DAC_R_VOL_SFT 8
+
+/* DSP Path Control 1 (0x2d) */
+#define RT5651_RXDP_SRC_MASK (0x1 << 15)
+#define RT5651_RXDP_SRC_SFT 15
+#define RT5651_RXDP_SRC_NOR (0x0 << 15)
+#define RT5651_RXDP_SRC_DIV3 (0x1 << 15)
+#define RT5651_TXDP_SRC_MASK (0x1 << 14)
+#define RT5651_TXDP_SRC_SFT 14
+#define RT5651_TXDP_SRC_NOR (0x0 << 14)
+#define RT5651_TXDP_SRC_DIV3 (0x1 << 14)
+
+/* DSP Path Control 2 (0x2e) */
+#define RT5651_DAC_L2_SEL_MASK (0x3 << 14)
+#define RT5651_DAC_L2_SEL_SFT 14
+#define RT5651_DAC_L2_SEL_IF2 (0x0 << 14)
+#define RT5651_DAC_L2_SEL_IF3 (0x1 << 14)
+#define RT5651_DAC_L2_SEL_TXDC (0x2 << 14)
+#define RT5651_DAC_L2_SEL_BASS (0x3 << 14)
+#define RT5651_DAC_R2_SEL_MASK (0x3 << 12)
+#define RT5651_DAC_R2_SEL_SFT 12
+#define RT5651_DAC_R2_SEL_IF2 (0x0 << 12)
+#define RT5651_DAC_R2_SEL_IF3 (0x1 << 12)
+#define RT5651_DAC_R2_SEL_TXDC (0x2 << 12)
+#define RT5651_IF2_ADC_L_SEL_MASK (0x1 << 11)
+#define RT5651_IF2_ADC_L_SEL_SFT 11
+#define RT5651_IF2_ADC_L_SEL_TXDP (0x0 << 11)
+#define RT5651_IF2_ADC_L_SEL_PASS (0x1 << 11)
+#define RT5651_IF2_ADC_R_SEL_MASK (0x1 << 10)
+#define RT5651_IF2_ADC_R_SEL_SFT 10
+#define RT5651_IF2_ADC_R_SEL_TXDP (0x0 << 10)
+#define RT5651_IF2_ADC_R_SEL_PASS (0x1 << 10)
+#define RT5651_RXDC_SEL_MASK (0x3 << 8)
+#define RT5651_RXDC_SEL_SFT 8
+#define RT5651_RXDC_SEL_NOR (0x0 << 8)
+#define RT5651_RXDC_SEL_L2R (0x1 << 8)
+#define RT5651_RXDC_SEL_R2L (0x2 << 8)
+#define RT5651_RXDC_SEL_SWAP (0x3 << 8)
+#define RT5651_RXDP_SEL_MASK (0x3 << 6)
+#define RT5651_RXDP_SEL_SFT 6
+#define RT5651_RXDP_SEL_NOR (0x0 << 6)
+#define RT5651_RXDP_SEL_L2R (0x1 << 6)
+#define RT5651_RXDP_SEL_R2L (0x2 << 6)
+#define RT5651_RXDP_SEL_SWAP (0x3 << 6)
+#define RT5651_TXDC_SEL_MASK (0x3 << 4)
+#define RT5651_TXDC_SEL_SFT 4
+#define RT5651_TXDC_SEL_NOR (0x0 << 4)
+#define RT5651_TXDC_SEL_L2R (0x1 << 4)
+#define RT5651_TXDC_SEL_R2L (0x2 << 4)
+#define RT5651_TXDC_SEL_SWAP (0x3 << 4)
+#define RT5651_TXDP_SEL_MASK (0x3 << 2)
+#define RT5651_TXDP_SEL_SFT 2
+#define RT5651_TXDP_SEL_NOR (0x0 << 2)
+#define RT5651_TXDP_SEL_L2R (0x1 << 2)
+#define RT5651_TXDP_SEL_R2L (0x2 << 2)
+#define RT5651_TRXDP_SEL_SWAP (0x3 << 2)
+
+/* Digital Interface Data Control (0x2f) */
+#define RT5651_IF2_DAC_SEL_MASK (0x3 << 10)
+#define RT5651_IF2_DAC_SEL_SFT 10
+#define RT5651_IF2_DAC_SEL_NOR (0x0 << 10)
+#define RT5651_IF2_DAC_SEL_SWAP (0x1 << 10)
+#define RT5651_IF2_DAC_SEL_L2R (0x2 << 10)
+#define RT5651_IF2_DAC_SEL_R2L (0x3 << 10)
+#define RT5651_IF2_ADC_SEL_MASK (0x3 << 8)
+#define RT5651_IF2_ADC_SEL_SFT 8
+#define RT5651_IF2_ADC_SEL_NOR (0x0 << 8)
+#define RT5651_IF2_ADC_SEL_SWAP (0x1 << 8)
+#define RT5651_IF2_ADC_SEL_L2R (0x2 << 8)
+#define RT5651_IF2_ADC_SEL_R2L (0x3 << 8)
+#define RT5651_IF2_ADC_SRC_MASK (0x1 << 7)
+#define RT5651_IF2_ADC_SRC_SFT 7
+#define RT5651_IF1_ADC1 (0x0 << 7)
+#define RT5651_IF1_ADC2 (0x1 << 7)
+
+/* PDM Output Control (0x30) */
+#define RT5651_PDM_L_SEL_MASK (0x1 << 15)
+#define RT5651_PDM_L_SEL_SFT 15
+#define RT5651_PDM_L_SEL_DD_L (0x0 << 15)
+#define RT5651_PDM_L_SEL_STO_L (0x1 << 15)
+#define RT5651_M_PDM_L (0x1 << 14)
+#define RT5651_M_PDM_L_SFT 14
+#define RT5651_PDM_R_SEL_MASK (0x1 << 13)
+#define RT5651_PDM_R_SEL_SFT 13
+#define RT5651_PDM_R_SEL_DD_L (0x0 << 13)
+#define RT5651_PDM_R_SEL_STO_L (0x1 << 13)
+#define RT5651_M_PDM_R (0x1 << 12)
+#define RT5651_M_PDM_R_SFT 12
+#define RT5651_PDM_BUSY (0x1 << 6)
+#define RT5651_PDM_BUSY_SFT 6
+#define RT5651_PDM_PATTERN_SEL_MASK (0x1 << 5)
+#define RT5651_PDM_PATTERN_SEL_64 (0x0 << 5)
+#define RT5651_PDM_PATTERN_SEL_128 (0x1 << 5)
+#define RT5651_PDM_VOL_MASK (0x1 << 4)
+#define RT5651_PDM_VOL_SFT 4
+#define RT5651_PDM_DIV_MASK (0x3)
+#define RT5651_PDM_DIV_SFT 0
+#define RT5651_PDM_DIV_1 0
+#define RT5651_PDM_DIV_2 1
+#define RT5651_PDM_DIV_3 2
+#define RT5651_PDM_DIV_4 3
+
+/* PDM I2C/Data Control 1 (0x31) */
+#define RT5651_PDM_I2C_ID_MASK (0xf << 12)
+#define PT5631_PDM_CMD_EXE (0x1 << 11)
+#define RT5651_PDM_I2C_CMD_MASK (0x1 << 10)
+#define RT5651_PDM_I2C_CMD_R (0x0 << 10)
+#define RT5651_PDM_I2C_CMD_W (0x1 << 10)
+#define RT5651_PDM_I2C_CMD_EXE (0x1 << 9)
+#define RT5651_PDM_I2C_NORMAL (0x0 << 8)
+#define RT5651_PDM_I2C_BUSY (0x1 << 8)
+
+/* PDM I2C/Data Control 2 (0x32) */
+#define RT5651_PDM_I2C_ADDR (0xff << 8)
+#define RT5651_PDM_I2C_CMD_PATTERN (0xff)
+
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5651_G_LN_L2_RM_L_MASK (0x7 << 13)
+#define RT5651_G_IN_L2_RM_L_SFT 13
+#define RT5651_G_LN_L1_RM_L_MASK (0x7 << 10)
+#define RT5651_G_IN_L1_RM_L_SFT 10
+#define RT5651_G_BST3_RM_L_MASK (0x7 << 4)
+#define RT5651_G_BST3_RM_L_SFT 4
+#define RT5651_G_BST2_RM_L_MASK (0x7 << 1)
+#define RT5651_G_BST2_RM_L_SFT 1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5651_G_BST1_RM_L_MASK (0x7 << 13)
+#define RT5651_G_BST1_RM_L_SFT 13
+#define RT5651_G_OM_L_RM_L_MASK (0x7 << 10)
+#define RT5651_G_OM_L_RM_L_SFT 10
+#define RT5651_M_IN2_L_RM_L (0x1 << 6)
+#define RT5651_M_IN2_L_RM_L_SFT 6
+#define RT5651_M_IN1_L_RM_L (0x1 << 5)
+#define RT5651_M_IN1_L_RM_L_SFT 5
+#define RT5651_M_BST3_RM_L (0x1 << 3)
+#define RT5651_M_BST3_RM_L_SFT 3
+#define RT5651_M_BST2_RM_L (0x1 << 2)
+#define RT5651_M_BST2_RM_L_SFT 2
+#define RT5651_M_BST1_RM_L (0x1 << 1)
+#define RT5651_M_BST1_RM_L_SFT 1
+#define RT5651_M_OM_L_RM_L (0x1)
+#define RT5651_M_OM_L_RM_L_SFT 0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5651_G_IN2_R_RM_R_MASK (0x7 << 13)
+#define RT5651_G_IN2_R_RM_R_SFT 13
+#define RT5651_G_IN1_R_RM_R_MASK (0x7 << 10)
+#define RT5651_G_IN1_R_RM_R_SFT 10
+#define RT5651_G_BST3_RM_R_MASK (0x7 << 4)
+#define RT5651_G_BST3_RM_R_SFT 4
+#define RT5651_G_BST2_RM_R_MASK (0x7 << 1)
+#define RT5651_G_BST2_RM_R_SFT 1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5651_G_BST1_RM_R_MASK (0x7 << 13)
+#define RT5651_G_BST1_RM_R_SFT 13
+#define RT5651_G_OM_R_RM_R_MASK (0x7 << 10)
+#define RT5651_G_OM_R_RM_R_SFT 10
+#define RT5651_M_IN2_R_RM_R (0x1 << 6)
+#define RT5651_M_IN2_R_RM_R_SFT 6
+#define RT5651_M_IN1_R_RM_R (0x1 << 5)
+#define RT5651_M_IN1_R_RM_R_SFT 5
+#define RT5651_M_BST3_RM_R (0x1 << 3)
+#define RT5651_M_BST3_RM_R_SFT 3
+#define RT5651_M_BST2_RM_R (0x1 << 2)
+#define RT5651_M_BST2_RM_R_SFT 2
+#define RT5651_M_BST1_RM_R (0x1 << 1)
+#define RT5651_M_BST1_RM_R_SFT 1
+#define RT5651_M_OM_R_RM_R (0x1)
+#define RT5651_M_OM_R_RM_R_SFT 0
+
+/* HPMIX Control (0x45) */
+#define RT5651_M_DAC1_HM (0x1 << 14)
+#define RT5651_M_DAC1_HM_SFT 14
+#define RT5651_M_HPVOL_HM (0x1 << 13)
+#define RT5651_M_HPVOL_HM_SFT 13
+#define RT5651_G_HPOMIX_MASK (0x1 << 12)
+#define RT5651_G_HPOMIX_SFT 12
+
+/* SPK Left Mixer Control (0x46) */
+#define RT5651_G_RM_L_SM_L_MASK (0x3 << 14)
+#define RT5651_G_RM_L_SM_L_SFT 14
+#define RT5651_G_IN_L_SM_L_MASK (0x3 << 12)
+#define RT5651_G_IN_L_SM_L_SFT 12
+#define RT5651_G_DAC_L1_SM_L_MASK (0x3 << 10)
+#define RT5651_G_DAC_L1_SM_L_SFT 10
+#define RT5651_G_DAC_L2_SM_L_MASK (0x3 << 8)
+#define RT5651_G_DAC_L2_SM_L_SFT 8
+#define RT5651_G_OM_L_SM_L_MASK (0x3 << 6)
+#define RT5651_G_OM_L_SM_L_SFT 6
+#define RT5651_M_RM_L_SM_L (0x1 << 5)
+#define RT5651_M_RM_L_SM_L_SFT 5
+#define RT5651_M_IN_L_SM_L (0x1 << 4)
+#define RT5651_M_IN_L_SM_L_SFT 4
+#define RT5651_M_DAC_L1_SM_L (0x1 << 3)
+#define RT5651_M_DAC_L1_SM_L_SFT 3
+#define RT5651_M_DAC_L2_SM_L (0x1 << 2)
+#define RT5651_M_DAC_L2_SM_L_SFT 2
+#define RT5651_M_OM_L_SM_L (0x1 << 1)
+#define RT5651_M_OM_L_SM_L_SFT 1
+
+/* SPK Right Mixer Control (0x47) */
+#define RT5651_G_RM_R_SM_R_MASK (0x3 << 14)
+#define RT5651_G_RM_R_SM_R_SFT 14
+#define RT5651_G_IN_R_SM_R_MASK (0x3 << 12)
+#define RT5651_G_IN_R_SM_R_SFT 12
+#define RT5651_G_DAC_R1_SM_R_MASK (0x3 << 10)
+#define RT5651_G_DAC_R1_SM_R_SFT 10
+#define RT5651_G_DAC_R2_SM_R_MASK (0x3 << 8)
+#define RT5651_G_DAC_R2_SM_R_SFT 8
+#define RT5651_G_OM_R_SM_R_MASK (0x3 << 6)
+#define RT5651_G_OM_R_SM_R_SFT 6
+#define RT5651_M_RM_R_SM_R (0x1 << 5)
+#define RT5651_M_RM_R_SM_R_SFT 5
+#define RT5651_M_IN_R_SM_R (0x1 << 4)
+#define RT5651_M_IN_R_SM_R_SFT 4
+#define RT5651_M_DAC_R1_SM_R (0x1 << 3)
+#define RT5651_M_DAC_R1_SM_R_SFT 3
+#define RT5651_M_DAC_R2_SM_R (0x1 << 2)
+#define RT5651_M_DAC_R2_SM_R_SFT 2
+#define RT5651_M_OM_R_SM_R (0x1 << 1)
+#define RT5651_M_OM_R_SM_R_SFT 1
+
+/* SPOLMIX Control (0x48) */
+#define RT5651_M_DAC_R1_SPM_L (0x1 << 15)
+#define RT5651_M_DAC_R1_SPM_L_SFT 15
+#define RT5651_M_DAC_L1_SPM_L (0x1 << 14)
+#define RT5651_M_DAC_L1_SPM_L_SFT 14
+#define RT5651_M_SV_R_SPM_L (0x1 << 13)
+#define RT5651_M_SV_R_SPM_L_SFT 13
+#define RT5651_M_SV_L_SPM_L (0x1 << 12)
+#define RT5651_M_SV_L_SPM_L_SFT 12
+#define RT5651_M_BST1_SPM_L (0x1 << 11)
+#define RT5651_M_BST1_SPM_L_SFT 11
+
+/* SPORMIX Control (0x49) */
+#define RT5651_M_DAC_R1_SPM_R (0x1 << 13)
+#define RT5651_M_DAC_R1_SPM_R_SFT 13
+#define RT5651_M_SV_R_SPM_R (0x1 << 12)
+#define RT5651_M_SV_R_SPM_R_SFT 12
+#define RT5651_M_BST1_SPM_R (0x1 << 11)
+#define RT5651_M_BST1_SPM_R_SFT 11
+
+/* SPOLMIX / SPORMIX Ratio Control (0x4a) */
+#define RT5651_SPO_CLSD_RATIO_MASK (0x7)
+#define RT5651_SPO_CLSD_RATIO_SFT 0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5651_M_DAC_R2_MM (0x1 << 15)
+#define RT5651_M_DAC_R2_MM_SFT 15
+#define RT5651_M_DAC_L2_MM (0x1 << 14)
+#define RT5651_M_DAC_L2_MM_SFT 14
+#define RT5651_M_OV_R_MM (0x1 << 13)
+#define RT5651_M_OV_R_MM_SFT 13
+#define RT5651_M_OV_L_MM (0x1 << 12)
+#define RT5651_M_OV_L_MM_SFT 12
+#define RT5651_M_BST1_MM (0x1 << 11)
+#define RT5651_M_BST1_MM_SFT 11
+#define RT5651_G_MONOMIX_MASK (0x1 << 10)
+#define RT5651_G_MONOMIX_SFT 10
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5651_G_BST2_OM_L_MASK (0x7 << 10)
+#define RT5651_G_BST2_OM_L_SFT 10
+#define RT5651_G_BST1_OM_L_MASK (0x7 << 7)
+#define RT5651_G_BST1_OM_L_SFT 7
+#define RT5651_G_IN1_L_OM_L_MASK (0x7 << 4)
+#define RT5651_G_IN1_L_OM_L_SFT 4
+#define RT5651_G_RM_L_OM_L_MASK (0x7 << 1)
+#define RT5651_G_RM_L_OM_L_SFT 1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5651_G_DAC_L1_OM_L_MASK (0x7 << 7)
+#define RT5651_G_DAC_L1_OM_L_SFT 7
+#define RT5651_G_IN2_L_OM_L_MASK (0x7 << 4)
+#define RT5651_G_IN2_L_OM_L_SFT 4
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5651_M_IN2_L_OM_L (0x1 << 9)
+#define RT5651_M_IN2_L_OM_L_SFT 9
+#define RT5651_M_BST2_OM_L (0x1 << 6)
+#define RT5651_M_BST2_OM_L_SFT 6
+#define RT5651_M_BST1_OM_L (0x1 << 5)
+#define RT5651_M_BST1_OM_L_SFT 5
+#define RT5651_M_IN1_L_OM_L (0x1 << 4)
+#define RT5651_M_IN1_L_OM_L_SFT 4
+#define RT5651_M_RM_L_OM_L (0x1 << 3)
+#define RT5651_M_RM_L_OM_L_SFT 3
+#define RT5651_M_DAC_L1_OM_L (0x1)
+#define RT5651_M_DAC_L1_OM_L_SFT 0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5651_G_BST2_OM_R_MASK (0x7 << 10)
+#define RT5651_G_BST2_OM_R_SFT 10
+#define RT5651_G_BST1_OM_R_MASK (0x7 << 7)
+#define RT5651_G_BST1_OM_R_SFT 7
+#define RT5651_G_IN1_R_OM_R_MASK (0x7 << 4)
+#define RT5651_G_IN1_R_OM_R_SFT 4
+#define RT5651_G_RM_R_OM_R_MASK (0x7 << 1)
+#define RT5651_G_RM_R_OM_R_SFT 1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5651_G_DAC_R1_OM_R_MASK (0x7 << 7)
+#define RT5651_G_DAC_R1_OM_R_SFT 7
+#define RT5651_G_IN2_R_OM_R_MASK (0x7 << 4)
+#define RT5651_G_IN2_R_OM_R_SFT 4
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5651_M_IN2_R_OM_R (0x1 << 9)
+#define RT5651_M_IN2_R_OM_R_SFT 9
+#define RT5651_M_BST2_OM_R (0x1 << 6)
+#define RT5651_M_BST2_OM_R_SFT 6
+#define RT5651_M_BST1_OM_R (0x1 << 5)
+#define RT5651_M_BST1_OM_R_SFT 5
+#define RT5651_M_IN1_R_OM_R (0x1 << 4)
+#define RT5651_M_IN1_R_OM_R_SFT 4
+#define RT5651_M_RM_R_OM_R (0x1 << 3)
+#define RT5651_M_RM_R_OM_R_SFT 3
+#define RT5651_M_DAC_R1_OM_R (0x1)
+#define RT5651_M_DAC_R1_OM_R_SFT 0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5651_M_DAC_L1_LM (0x1 << 15)
+#define RT5651_M_DAC_L1_LM_SFT 15
+#define RT5651_M_DAC_R1_LM (0x1 << 14)
+#define RT5651_M_DAC_R1_LM_SFT 14
+#define RT5651_M_OV_L_LM (0x1 << 13)
+#define RT5651_M_OV_L_LM_SFT 13
+#define RT5651_M_OV_R_LM (0x1 << 12)
+#define RT5651_M_OV_R_LM_SFT 12
+#define RT5651_G_LOUTMIX_MASK (0x1 << 11)
+#define RT5651_G_LOUTMIX_SFT 11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5651_PWR_I2S1 (0x1 << 15)
+#define RT5651_PWR_I2S1_BIT 15
+#define RT5651_PWR_I2S2 (0x1 << 14)
+#define RT5651_PWR_I2S2_BIT 14
+#define RT5651_PWR_DAC_L1 (0x1 << 12)
+#define RT5651_PWR_DAC_L1_BIT 12
+#define RT5651_PWR_DAC_R1 (0x1 << 11)
+#define RT5651_PWR_DAC_R1_BIT 11
+#define RT5651_PWR_ADC_L (0x1 << 2)
+#define RT5651_PWR_ADC_L_BIT 2
+#define RT5651_PWR_ADC_R (0x1 << 1)
+#define RT5651_PWR_ADC_R_BIT 1
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5651_PWR_ADC_STO1_F (0x1 << 15)
+#define RT5651_PWR_ADC_STO1_F_BIT 15
+#define RT5651_PWR_ADC_STO2_F (0x1 << 14)
+#define RT5651_PWR_ADC_STO2_F_BIT 14
+#define RT5651_PWR_DAC_STO1_F (0x1 << 11)
+#define RT5651_PWR_DAC_STO1_F_BIT 11
+#define RT5651_PWR_DAC_STO2_F (0x1 << 10)
+#define RT5651_PWR_DAC_STO2_F_BIT 10
+#define RT5651_PWR_PDM (0x1 << 9)
+#define RT5651_PWR_PDM_BIT 9
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5651_PWR_VREF1 (0x1 << 15)
+#define RT5651_PWR_VREF1_BIT 15
+#define RT5651_PWR_FV1 (0x1 << 14)
+#define RT5651_PWR_FV1_BIT 14
+#define RT5651_PWR_MB (0x1 << 13)
+#define RT5651_PWR_MB_BIT 13
+#define RT5651_PWR_LM (0x1 << 12)
+#define RT5651_PWR_LM_BIT 12
+#define RT5651_PWR_BG (0x1 << 11)
+#define RT5651_PWR_BG_BIT 11
+#define RT5651_PWR_HP_L (0x1 << 7)
+#define RT5651_PWR_HP_L_BIT 7
+#define RT5651_PWR_HP_R (0x1 << 6)
+#define RT5651_PWR_HP_R_BIT 6
+#define RT5651_PWR_HA (0x1 << 5)
+#define RT5651_PWR_HA_BIT 5
+#define RT5651_PWR_VREF2 (0x1 << 4)
+#define RT5651_PWR_VREF2_BIT 4
+#define RT5651_PWR_FV2 (0x1 << 3)
+#define RT5651_PWR_FV2_BIT 3
+#define RT5651_PWR_LDO (0x1 << 2)
+#define RT5651_PWR_LDO_BIT 2
+#define RT5651_PWR_LDO_DVO_MASK (0x3)
+#define RT5651_PWR_LDO_DVO_1_0V 0
+#define RT5651_PWR_LDO_DVO_1_1V 1
+#define RT5651_PWR_LDO_DVO_1_2V 2
+#define RT5651_PWR_LDO_DVO_1_3V 3
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5651_PWR_BST1 (0x1 << 15)
+#define RT5651_PWR_BST1_BIT 15
+#define RT5651_PWR_BST2 (0x1 << 14)
+#define RT5651_PWR_BST2_BIT 14
+#define RT5651_PWR_BST3 (0x1 << 13)
+#define RT5651_PWR_BST3_BIT 13
+#define RT5651_PWR_MB1 (0x1 << 11)
+#define RT5651_PWR_MB1_BIT 11
+#define RT5651_PWR_PLL (0x1 << 9)
+#define RT5651_PWR_PLL_BIT 9
+#define RT5651_PWR_BST1_OP2 (0x1 << 5)
+#define RT5651_PWR_BST1_OP2_BIT 5
+#define RT5651_PWR_BST2_OP2 (0x1 << 4)
+#define RT5651_PWR_BST2_OP2_BIT 4
+#define RT5651_PWR_BST3_OP2 (0x1 << 3)
+#define RT5651_PWR_BST3_OP2_BIT 3
+#define RT5651_PWR_JD_M (0x1 << 2)
+#define RT5651_PWM_JD_M_BIT 2
+#define RT5651_PWR_JD2 (0x1 << 1)
+#define RT5651_PWM_JD2_BIT 1
+#define RT5651_PWR_JD3 (0x1)
+#define RT5651_PWM_JD3_BIT 0
+
+/* Power Management for Mixer (0x65) */
+#define RT5651_PWR_OM_L (0x1 << 15)
+#define RT5651_PWR_OM_L_BIT 15
+#define RT5651_PWR_OM_R (0x1 << 14)
+#define RT5651_PWR_OM_R_BIT 14
+#define RT5651_PWR_RM_L (0x1 << 11)
+#define RT5651_PWR_RM_L_BIT 11
+#define RT5651_PWR_RM_R (0x1 << 10)
+#define RT5651_PWR_RM_R_BIT 10
+
+/* Power Management for Volume (0x66) */
+#define RT5651_PWR_OV_L (0x1 << 13)
+#define RT5651_PWR_OV_L_BIT 13
+#define RT5651_PWR_OV_R (0x1 << 12)
+#define RT5651_PWR_OV_R_BIT 12
+#define RT5651_PWR_HV_L (0x1 << 11)
+#define RT5651_PWR_HV_L_BIT 11
+#define RT5651_PWR_HV_R (0x1 << 10)
+#define RT5651_PWR_HV_R_BIT 10
+#define RT5651_PWR_IN1_L (0x1 << 9)
+#define RT5651_PWR_IN1_L_BIT 9
+#define RT5651_PWR_IN1_R (0x1 << 8)
+#define RT5651_PWR_IN1_R_BIT 8
+#define RT5651_PWR_IN2_L (0x1 << 7)
+#define RT5651_PWR_IN2_L_BIT 7
+#define RT5651_PWR_IN2_R (0x1 << 6)
+#define RT5651_PWR_IN2_R_BIT 6
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71) */
+#define RT5651_I2S_MS_MASK (0x1 << 15)
+#define RT5651_I2S_MS_SFT 15
+#define RT5651_I2S_MS_M (0x0 << 15)
+#define RT5651_I2S_MS_S (0x1 << 15)
+#define RT5651_I2S_O_CP_MASK (0x3 << 10)
+#define RT5651_I2S_O_CP_SFT 10
+#define RT5651_I2S_O_CP_OFF (0x0 << 10)
+#define RT5651_I2S_O_CP_U_LAW (0x1 << 10)
+#define RT5651_I2S_O_CP_A_LAW (0x2 << 10)
+#define RT5651_I2S_I_CP_MASK (0x3 << 8)
+#define RT5651_I2S_I_CP_SFT 8
+#define RT5651_I2S_I_CP_OFF (0x0 << 8)
+#define RT5651_I2S_I_CP_U_LAW (0x1 << 8)
+#define RT5651_I2S_I_CP_A_LAW (0x2 << 8)
+#define RT5651_I2S_BP_MASK (0x1 << 7)
+#define RT5651_I2S_BP_SFT 7
+#define RT5651_I2S_BP_NOR (0x0 << 7)
+#define RT5651_I2S_BP_INV (0x1 << 7)
+#define RT5651_I2S_DL_MASK (0x3 << 2)
+#define RT5651_I2S_DL_SFT 2
+#define RT5651_I2S_DL_16 (0x0 << 2)
+#define RT5651_I2S_DL_20 (0x1 << 2)
+#define RT5651_I2S_DL_24 (0x2 << 2)
+#define RT5651_I2S_DL_8 (0x3 << 2)
+#define RT5651_I2S_DF_MASK (0x3)
+#define RT5651_I2S_DF_SFT 0
+#define RT5651_I2S_DF_I2S (0x0)
+#define RT5651_I2S_DF_LEFT (0x1)
+#define RT5651_I2S_DF_PCM_A (0x2)
+#define RT5651_I2S_DF_PCM_B (0x3)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5651_I2S_PD1_MASK (0x7 << 12)
+#define RT5651_I2S_PD1_SFT 12
+#define RT5651_I2S_PD1_1 (0x0 << 12)
+#define RT5651_I2S_PD1_2 (0x1 << 12)
+#define RT5651_I2S_PD1_3 (0x2 << 12)
+#define RT5651_I2S_PD1_4 (0x3 << 12)
+#define RT5651_I2S_PD1_6 (0x4 << 12)
+#define RT5651_I2S_PD1_8 (0x5 << 12)
+#define RT5651_I2S_PD1_12 (0x6 << 12)
+#define RT5651_I2S_PD1_16 (0x7 << 12)
+#define RT5651_I2S_BCLK_MS2_MASK (0x1 << 11)
+#define RT5651_I2S_BCLK_MS2_SFT 11
+#define RT5651_I2S_BCLK_MS2_32 (0x0 << 11)
+#define RT5651_I2S_BCLK_MS2_64 (0x1 << 11)
+#define RT5651_I2S_PD2_MASK (0x7 << 8)
+#define RT5651_I2S_PD2_SFT 8
+#define RT5651_I2S_PD2_1 (0x0 << 8)
+#define RT5651_I2S_PD2_2 (0x1 << 8)
+#define RT5651_I2S_PD2_3 (0x2 << 8)
+#define RT5651_I2S_PD2_4 (0x3 << 8)
+#define RT5651_I2S_PD2_6 (0x4 << 8)
+#define RT5651_I2S_PD2_8 (0x5 << 8)
+#define RT5651_I2S_PD2_12 (0x6 << 8)
+#define RT5651_I2S_PD2_16 (0x7 << 8)
+#define RT5651_DAC_OSR_MASK (0x3 << 2)
+#define RT5651_DAC_OSR_SFT 2
+#define RT5651_DAC_OSR_128 (0x0 << 2)
+#define RT5651_DAC_OSR_64 (0x1 << 2)
+#define RT5651_DAC_OSR_32 (0x2 << 2)
+#define RT5651_DAC_OSR_128_3 (0x3 << 2)
+#define RT5651_ADC_OSR_MASK (0x3)
+#define RT5651_ADC_OSR_SFT 0
+#define RT5651_ADC_OSR_128 (0x0)
+#define RT5651_ADC_OSR_64 (0x1)
+#define RT5651_ADC_OSR_32 (0x2)
+#define RT5651_ADC_OSR_128_3 (0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5651_DAHPF_EN (0x1 << 11)
+#define RT5651_DAHPF_EN_SFT 11
+#define RT5651_ADHPF_EN (0x1 << 10)
+#define RT5651_ADHPF_EN_SFT 10
+
+/* Digital Microphone Control (0x75) */
+#define RT5651_DMIC_1_EN_MASK (0x1 << 15)
+#define RT5651_DMIC_1_EN_SFT 15
+#define RT5651_DMIC_1_DIS (0x0 << 15)
+#define RT5651_DMIC_1_EN (0x1 << 15)
+#define RT5651_DMIC_1L_LH_MASK (0x1 << 13)
+#define RT5651_DMIC_1L_LH_SFT 13
+#define RT5651_DMIC_1L_LH_FALLING (0x0 << 13)
+#define RT5651_DMIC_1L_LH_RISING (0x1 << 13)
+#define RT5651_DMIC_1R_LH_MASK (0x1 << 12)
+#define RT5651_DMIC_1R_LH_SFT 12
+#define RT5651_DMIC_1R_LH_FALLING (0x0 << 12)
+#define RT5651_DMIC_1R_LH_RISING (0x1 << 12)
+#define RT5651_DMIC_1_DP_MASK (0x3 << 10)
+#define RT5651_DMIC_1_DP_SFT 10
+#define RT5651_DMIC_1_DP_GPIO6 (0x0 << 10)
+#define RT5651_DMIC_1_DP_IN1P (0x1 << 10)
+#define RT5651_DMIC_2_DP_GPIO8 (0x2 << 10)
+#define RT5651_DMIC_CLK_MASK (0x7 << 5)
+#define RT5651_DMIC_CLK_SFT 5
+
+/* TDM Control 1 (0x77) */
+#define RT5651_TDM_INTEL_SEL_MASK (0x1 << 15)
+#define RT5651_TDM_INTEL_SEL_SFT 15
+#define RT5651_TDM_INTEL_SEL_64 (0x0 << 15)
+#define RT5651_TDM_INTEL_SEL_50 (0x1 << 15)
+#define RT5651_TDM_MODE_SEL_MASK (0x1 << 14)
+#define RT5651_TDM_MODE_SEL_SFT 14
+#define RT5651_TDM_MODE_SEL_NOR (0x0 << 14)
+#define RT5651_TDM_MODE_SEL_TDM (0x1 << 14)
+#define RT5651_TDM_CH_NUM_SEL_MASK (0x3 << 12)
+#define RT5651_TDM_CH_NUM_SEL_SFT 12
+#define RT5651_TDM_CH_NUM_SEL_2 (0x0 << 12)
+#define RT5651_TDM_CH_NUM_SEL_4 (0x1 << 12)
+#define RT5651_TDM_CH_NUM_SEL_6 (0x2 << 12)
+#define RT5651_TDM_CH_NUM_SEL_8 (0x3 << 12)
+#define RT5651_TDM_CH_LEN_SEL_MASK (0x3 << 10)
+#define RT5651_TDM_CH_LEN_SEL_SFT 10
+#define RT5651_TDM_CH_LEN_SEL_16 (0x0 << 10)
+#define RT5651_TDM_CH_LEN_SEL_20 (0x1 << 10)
+#define RT5651_TDM_CH_LEN_SEL_24 (0x2 << 10)
+#define RT5651_TDM_CH_LEN_SEL_32 (0x3 << 10)
+#define RT5651_TDM_ADC_SEL_MASK (0x1 << 9)
+#define RT5651_TDM_ADC_SEL_SFT 9
+#define RT5651_TDM_ADC_SEL_NOR (0x0 << 9)
+#define RT5651_TDM_ADC_SEL_SWAP (0x1 << 9)
+#define RT5651_TDM_ADC_START_SEL_MASK (0x1 << 8)
+#define RT5651_TDM_ADC_START_SEL_SFT 8
+#define RT5651_TDM_ADC_START_SEL_SL0 (0x0 << 8)
+#define RT5651_TDM_ADC_START_SEL_SL4 (0x1 << 8)
+#define RT5651_TDM_I2S_CH2_SEL_MASK (0x3 << 6)
+#define RT5651_TDM_I2S_CH2_SEL_SFT 6
+#define RT5651_TDM_I2S_CH2_SEL_LR (0x0 << 6)
+#define RT5651_TDM_I2S_CH2_SEL_RL (0x1 << 6)
+#define RT5651_TDM_I2S_CH2_SEL_LL (0x2 << 6)
+#define RT5651_TDM_I2S_CH2_SEL_RR (0x3 << 6)
+#define RT5651_TDM_I2S_CH4_SEL_MASK (0x3 << 4)
+#define RT5651_TDM_I2S_CH4_SEL_SFT 4
+#define RT5651_TDM_I2S_CH4_SEL_LR (0x0 << 4)
+#define RT5651_TDM_I2S_CH4_SEL_RL (0x1 << 4)
+#define RT5651_TDM_I2S_CH4_SEL_LL (0x2 << 4)
+#define RT5651_TDM_I2S_CH4_SEL_RR (0x3 << 4)
+#define RT5651_TDM_I2S_CH6_SEL_MASK (0x3 << 2)
+#define RT5651_TDM_I2S_CH6_SEL_SFT 2
+#define RT5651_TDM_I2S_CH6_SEL_LR (0x0 << 2)
+#define RT5651_TDM_I2S_CH6_SEL_RL (0x1 << 2)
+#define RT5651_TDM_I2S_CH6_SEL_LL (0x2 << 2)
+#define RT5651_TDM_I2S_CH6_SEL_RR (0x3 << 2)
+#define RT5651_TDM_I2S_CH8_SEL_MASK (0x3)
+#define RT5651_TDM_I2S_CH8_SEL_SFT 0
+#define RT5651_TDM_I2S_CH8_SEL_LR (0x0)
+#define RT5651_TDM_I2S_CH8_SEL_RL (0x1)
+#define RT5651_TDM_I2S_CH8_SEL_LL (0x2)
+#define RT5651_TDM_I2S_CH8_SEL_RR (0x3)
+
+/* TDM Control 2 (0x78) */
+#define RT5651_TDM_LRCK_POL_SEL_MASK (0x1 << 15)
+#define RT5651_TDM_LRCK_POL_SEL_SFT 15
+#define RT5651_TDM_LRCK_POL_SEL_NOR (0x0 << 15)
+#define RT5651_TDM_LRCK_POL_SEL_INV (0x1 << 15)
+#define RT5651_TDM_CH_VAL_SEL_MASK (0x1 << 14)
+#define RT5651_TDM_CH_VAL_SEL_SFT 14
+#define RT5651_TDM_CH_VAL_SEL_CH01 (0x0 << 14)
+#define RT5651_TDM_CH_VAL_SEL_CH0123 (0x1 << 14)
+#define RT5651_TDM_CH_VAL_EN (0x1 << 13)
+#define RT5651_TDM_CH_VAL_SFT 13
+#define RT5651_TDM_LPBK_EN (0x1 << 12)
+#define RT5651_TDM_LPBK_SFT 12
+#define RT5651_TDM_LRCK_PULSE_SEL_MASK (0x1 << 11)
+#define RT5651_TDM_LRCK_PULSE_SEL_SFT 11
+#define RT5651_TDM_LRCK_PULSE_SEL_BCLK (0x0 << 11)
+#define RT5651_TDM_LRCK_PULSE_SEL_CH (0x1 << 11)
+#define RT5651_TDM_END_EDGE_SEL_MASK (0x1 << 10)
+#define RT5651_TDM_END_EDGE_SEL_SFT 10
+#define RT5651_TDM_END_EDGE_SEL_POS (0x0 << 10)
+#define RT5651_TDM_END_EDGE_SEL_NEG (0x1 << 10)
+#define RT5651_TDM_END_EDGE_EN (0x1 << 9)
+#define RT5651_TDM_END_EDGE_EN_SFT 9
+#define RT5651_TDM_TRAN_EDGE_SEL_MASK (0x1 << 8)
+#define RT5651_TDM_TRAN_EDGE_SEL_SFT 8
+#define RT5651_TDM_TRAN_EDGE_SEL_POS (0x0 << 8)
+#define RT5651_TDM_TRAN_EDGE_SEL_NEG (0x1 << 8)
+#define RT5651_M_TDM2_L (0x1 << 7)
+#define RT5651_M_TDM2_L_SFT 7
+#define RT5651_M_TDM2_R (0x1 << 6)
+#define RT5651_M_TDM2_R_SFT 6
+#define RT5651_M_TDM4_L (0x1 << 5)
+#define RT5651_M_TDM4_L_SFT 5
+#define RT5651_M_TDM4_R (0x1 << 4)
+#define RT5651_M_TDM4_R_SFT 4
+
+/* TDM Control 3 (0x79) */
+#define RT5651_CH2_L_SEL_MASK (0x7 << 12)
+#define RT5651_CH2_L_SEL_SFT 12
+#define RT5651_CH2_L_SEL_SL0 (0x0 << 12)
+#define RT5651_CH2_L_SEL_SL1 (0x1 << 12)
+#define RT5651_CH2_L_SEL_SL2 (0x2 << 12)
+#define RT5651_CH2_L_SEL_SL3 (0x3 << 12)
+#define RT5651_CH2_L_SEL_SL4 (0x4 << 12)
+#define RT5651_CH2_L_SEL_SL5 (0x5 << 12)
+#define RT5651_CH2_L_SEL_SL6 (0x6 << 12)
+#define RT5651_CH2_L_SEL_SL7 (0x7 << 12)
+#define RT5651_CH2_R_SEL_MASK (0x7 << 8)
+#define RT5651_CH2_R_SEL_SFT 8
+#define RT5651_CH2_R_SEL_SL0 (0x0 << 8)
+#define RT5651_CH2_R_SEL_SL1 (0x1 << 8)
+#define RT5651_CH2_R_SEL_SL2 (0x2 << 8)
+#define RT5651_CH2_R_SEL_SL3 (0x3 << 8)
+#define RT5651_CH2_R_SEL_SL4 (0x4 << 8)
+#define RT5651_CH2_R_SEL_SL5 (0x5 << 8)
+#define RT5651_CH2_R_SEL_SL6 (0x6 << 8)
+#define RT5651_CH2_R_SEL_SL7 (0x7 << 8)
+#define RT5651_CH4_L_SEL_MASK (0x7 << 4)
+#define RT5651_CH4_L_SEL_SFT 4
+#define RT5651_CH4_L_SEL_SL0 (0x0 << 4)
+#define RT5651_CH4_L_SEL_SL1 (0x1 << 4)
+#define RT5651_CH4_L_SEL_SL2 (0x2 << 4)
+#define RT5651_CH4_L_SEL_SL3 (0x3 << 4)
+#define RT5651_CH4_L_SEL_SL4 (0x4 << 4)
+#define RT5651_CH4_L_SEL_SL5 (0x5 << 4)
+#define RT5651_CH4_L_SEL_SL6 (0x6 << 4)
+#define RT5651_CH4_L_SEL_SL7 (0x7 << 4)
+#define RT5651_CH4_R_SEL_MASK (0x7)
+#define RT5651_CH4_R_SEL_SFT 0
+#define RT5651_CH4_R_SEL_SL0 (0x0)
+#define RT5651_CH4_R_SEL_SL1 (0x1)
+#define RT5651_CH4_R_SEL_SL2 (0x2)
+#define RT5651_CH4_R_SEL_SL3 (0x3)
+#define RT5651_CH4_R_SEL_SL4 (0x4)
+#define RT5651_CH4_R_SEL_SL5 (0x5)
+#define RT5651_CH4_R_SEL_SL6 (0x6)
+#define RT5651_CH4_R_SEL_SL7 (0x7)
+
+/* Global Clock Control (0x80) */
+#define RT5651_SCLK_SRC_MASK (0x3 << 14)
+#define RT5651_SCLK_SRC_SFT 14
+#define RT5651_SCLK_SRC_MCLK (0x0 << 14)
+#define RT5651_SCLK_SRC_PLL1 (0x1 << 14)
+#define RT5651_SCLK_SRC_RCCLK (0x2 << 14)
+#define RT5651_PLL1_SRC_MASK (0x3 << 12)
+#define RT5651_PLL1_SRC_SFT 12
+#define RT5651_PLL1_SRC_MCLK (0x0 << 12)
+#define RT5651_PLL1_SRC_BCLK1 (0x1 << 12)
+#define RT5651_PLL1_SRC_BCLK2 (0x2 << 12)
+#define RT5651_PLL1_PD_MASK (0x1 << 3)
+#define RT5651_PLL1_PD_SFT 3
+#define RT5651_PLL1_PD_1 (0x0 << 3)
+#define RT5651_PLL1_PD_2 (0x1 << 3)
+
+#define RT5651_PLL_INP_MAX 40000000
+#define RT5651_PLL_INP_MIN 256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5651_PLL_N_MAX 0x1ff
+#define RT5651_PLL_N_MASK (RT5651_PLL_N_MAX << 7)
+#define RT5651_PLL_N_SFT 7
+#define RT5651_PLL_K_MAX 0x1f
+#define RT5651_PLL_K_MASK (RT5651_PLL_K_MAX)
+#define RT5651_PLL_K_SFT 0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5651_PLL_M_MAX 0xf
+#define RT5651_PLL_M_MASK (RT5651_PLL_M_MAX << 12)
+#define RT5651_PLL_M_SFT 12
+#define RT5651_PLL_M_BP (0x1 << 11)
+#define RT5651_PLL_M_BP_SFT 11
+
+/* PLL tracking mode 1 (0x83) */
+#define RT5651_STO1_T_MASK (0x1 << 15)
+#define RT5651_STO1_T_SFT 15
+#define RT5651_STO1_T_SCLK (0x0 << 15)
+#define RT5651_STO1_T_LRCK1 (0x1 << 15)
+#define RT5651_STO2_T_MASK (0x1 << 12)
+#define RT5651_STO2_T_SFT 12
+#define RT5651_STO2_T_I2S2 (0x0 << 12)
+#define RT5651_STO2_T_LRCK2 (0x1 << 12)
+#define RT5651_ASRC2_REF_MASK (0x1 << 11)
+#define RT5651_ASRC2_REF_SFT 11
+#define RT5651_ASRC2_REF_LRCK2 (0x0 << 11)
+#define RT5651_ASRC2_REF_LRCK1 (0x1 << 11)
+#define RT5651_DMIC_1_M_MASK (0x1 << 9)
+#define RT5651_DMIC_1_M_SFT 9
+#define RT5651_DMIC_1_M_NOR (0x0 << 9)
+#define RT5651_DMIC_1_M_ASYN (0x1 << 9)
+
+/* PLL tracking mode 2 (0x84) */
+#define RT5651_STO1_ASRC_EN (0x1 << 15)
+#define RT5651_STO1_ASRC_EN_SFT 15
+#define RT5651_STO2_ASRC_EN (0x1 << 14)
+#define RT5651_STO2_ASRC_EN_SFT 14
+#define RT5651_STO1_DAC_M_MASK (0x1 << 13)
+#define RT5651_STO1_DAC_M_SFT 13
+#define RT5651_STO1_DAC_M_NOR (0x0 << 13)
+#define RT5651_STO1_DAC_M_ASRC (0x1 << 13)
+#define RT5651_STO2_DAC_M_MASK (0x1 << 12)
+#define RT5651_STO2_DAC_M_SFT 12
+#define RT5651_STO2_DAC_M_NOR (0x0 << 12)
+#define RT5651_STO2_DAC_M_ASRC (0x1 << 12)
+#define RT5651_ADC_M_MASK (0x1 << 11)
+#define RT5651_ADC_M_SFT 11
+#define RT5651_ADC_M_NOR (0x0 << 11)
+#define RT5651_ADC_M_ASRC (0x1 << 11)
+#define RT5651_I2S1_R_D_MASK (0x1 << 4)
+#define RT5651_I2S1_R_D_SFT 4
+#define RT5651_I2S1_R_D_DIS (0x0 << 4)
+#define RT5651_I2S1_R_D_EN (0x1 << 4)
+#define RT5651_I2S2_R_D_MASK (0x1 << 3)
+#define RT5651_I2S2_R_D_SFT 3
+#define RT5651_I2S2_R_D_DIS (0x0 << 3)
+#define RT5651_I2S2_R_D_EN (0x1 << 3)
+#define RT5651_PRE_SCLK_MASK (0x3)
+#define RT5651_PRE_SCLK_SFT 0
+#define RT5651_PRE_SCLK_512 (0x0)
+#define RT5651_PRE_SCLK_1024 (0x1)
+#define RT5651_PRE_SCLK_2048 (0x2)
+
+/* PLL tracking mode 3 (0x85) */
+#define RT5651_I2S1_RATE_MASK (0xf << 12)
+#define RT5651_I2S1_RATE_SFT 12
+#define RT5651_I2S2_RATE_MASK (0xf << 8)
+#define RT5651_I2S2_RATE_SFT 8
+#define RT5651_G_ASRC_LP_MASK (0x1 << 3)
+#define RT5651_G_ASRC_LP_SFT 3
+#define RT5651_ASRC_LP_F_M (0x1 << 2)
+#define RT5651_ASRC_LP_F_SFT 2
+#define RT5651_ASRC_LP_F_NOR (0x0 << 2)
+#define RT5651_ASRC_LP_F_SB (0x1 << 2)
+#define RT5651_FTK_PH_DET_MASK (0x3)
+#define RT5651_FTK_PH_DET_SFT 0
+#define RT5651_FTK_PH_DET_DIV1 (0x0)
+#define RT5651_FTK_PH_DET_DIV2 (0x1)
+#define RT5651_FTK_PH_DET_DIV4 (0x2)
+#define RT5651_FTK_PH_DET_DIV8 (0x3)
+
+/*PLL tracking mode 6 (0x89) */
+#define RT5651_I2S1_PD_MASK (0x7 << 12)
+#define RT5651_I2S1_PD_SFT 12
+#define RT5651_I2S2_PD_MASK (0x7 << 8)
+#define RT5651_I2S2_PD_SFT 8
+
+/*PLL tracking mode 7 (0x8a) */
+#define RT5651_FSI1_RATE_MASK (0xf << 12)
+#define RT5651_FSI1_RATE_SFT 12
+#define RT5651_FSI2_RATE_MASK (0xf << 8)
+#define RT5651_FSI2_RATE_SFT 8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5651_HP_OVCD_MASK (0x1 << 10)
+#define RT5651_HP_OVCD_SFT 10
+#define RT5651_HP_OVCD_DIS (0x0 << 10)
+#define RT5651_HP_OVCD_EN (0x1 << 10)
+#define RT5651_HP_OC_TH_MASK (0x3 << 8)
+#define RT5651_HP_OC_TH_SFT 8
+#define RT5651_HP_OC_TH_90 (0x0 << 8)
+#define RT5651_HP_OC_TH_105 (0x1 << 8)
+#define RT5651_HP_OC_TH_120 (0x2 << 8)
+#define RT5651_HP_OC_TH_135 (0x3 << 8)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5651_SMT_TRIG_MASK (0x1 << 15)
+#define RT5651_SMT_TRIG_SFT 15
+#define RT5651_SMT_TRIG_DIS (0x0 << 15)
+#define RT5651_SMT_TRIG_EN (0x1 << 15)
+#define RT5651_HP_L_SMT_MASK (0x1 << 9)
+#define RT5651_HP_L_SMT_SFT 9
+#define RT5651_HP_L_SMT_DIS (0x0 << 9)
+#define RT5651_HP_L_SMT_EN (0x1 << 9)
+#define RT5651_HP_R_SMT_MASK (0x1 << 8)
+#define RT5651_HP_R_SMT_SFT 8
+#define RT5651_HP_R_SMT_DIS (0x0 << 8)
+#define RT5651_HP_R_SMT_EN (0x1 << 8)
+#define RT5651_HP_CD_PD_MASK (0x1 << 7)
+#define RT5651_HP_CD_PD_SFT 7
+#define RT5651_HP_CD_PD_DIS (0x0 << 7)
+#define RT5651_HP_CD_PD_EN (0x1 << 7)
+#define RT5651_RSTN_MASK (0x1 << 6)
+#define RT5651_RSTN_SFT 6
+#define RT5651_RSTN_DIS (0x0 << 6)
+#define RT5651_RSTN_EN (0x1 << 6)
+#define RT5651_RSTP_MASK (0x1 << 5)
+#define RT5651_RSTP_SFT 5
+#define RT5651_RSTP_DIS (0x0 << 5)
+#define RT5651_RSTP_EN (0x1 << 5)
+#define RT5651_HP_CO_MASK (0x1 << 4)
+#define RT5651_HP_CO_SFT 4
+#define RT5651_HP_CO_DIS (0x0 << 4)
+#define RT5651_HP_CO_EN (0x1 << 4)
+#define RT5651_HP_CP_MASK (0x1 << 3)
+#define RT5651_HP_CP_SFT 3
+#define RT5651_HP_CP_PD (0x0 << 3)
+#define RT5651_HP_CP_PU (0x1 << 3)
+#define RT5651_HP_SG_MASK (0x1 << 2)
+#define RT5651_HP_SG_SFT 2
+#define RT5651_HP_SG_DIS (0x0 << 2)
+#define RT5651_HP_SG_EN (0x1 << 2)
+#define RT5651_HP_DP_MASK (0x1 << 1)
+#define RT5651_HP_DP_SFT 1
+#define RT5651_HP_DP_PD (0x0 << 1)
+#define RT5651_HP_DP_PU (0x1 << 1)
+#define RT5651_HP_CB_MASK (0x1)
+#define RT5651_HP_CB_SFT 0
+#define RT5651_HP_CB_PD (0x0)
+#define RT5651_HP_CB_PU (0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5651_DEPOP_MASK (0x1 << 13)
+#define RT5651_DEPOP_SFT 13
+#define RT5651_DEPOP_AUTO (0x0 << 13)
+#define RT5651_DEPOP_MAN (0x1 << 13)
+#define RT5651_RAMP_MASK (0x1 << 12)
+#define RT5651_RAMP_SFT 12
+#define RT5651_RAMP_DIS (0x0 << 12)
+#define RT5651_RAMP_EN (0x1 << 12)
+#define RT5651_BPS_MASK (0x1 << 11)
+#define RT5651_BPS_SFT 11
+#define RT5651_BPS_DIS (0x0 << 11)
+#define RT5651_BPS_EN (0x1 << 11)
+#define RT5651_FAST_UPDN_MASK (0x1 << 10)
+#define RT5651_FAST_UPDN_SFT 10
+#define RT5651_FAST_UPDN_DIS (0x0 << 10)
+#define RT5651_FAST_UPDN_EN (0x1 << 10)
+#define RT5651_MRES_MASK (0x3 << 8)
+#define RT5651_MRES_SFT 8
+#define RT5651_MRES_15MO (0x0 << 8)
+#define RT5651_MRES_25MO (0x1 << 8)
+#define RT5651_MRES_35MO (0x2 << 8)
+#define RT5651_MRES_45MO (0x3 << 8)
+#define RT5651_VLO_MASK (0x1 << 7)
+#define RT5651_VLO_SFT 7
+#define RT5651_VLO_3V (0x0 << 7)
+#define RT5651_VLO_32V (0x1 << 7)
+#define RT5651_DIG_DP_MASK (0x1 << 6)
+#define RT5651_DIG_DP_SFT 6
+#define RT5651_DIG_DP_DIS (0x0 << 6)
+#define RT5651_DIG_DP_EN (0x1 << 6)
+#define RT5651_DP_TH_MASK (0x3 << 4)
+#define RT5651_DP_TH_SFT 4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5651_CP_SYS_MASK (0x7 << 12)
+#define RT5651_CP_SYS_SFT 12
+#define RT5651_CP_FQ1_MASK (0x7 << 8)
+#define RT5651_CP_FQ1_SFT 8
+#define RT5651_CP_FQ2_MASK (0x7 << 4)
+#define RT5651_CP_FQ2_SFT 4
+#define RT5651_CP_FQ3_MASK (0x7)
+#define RT5651_CP_FQ3_SFT 0
+#define RT5651_CP_FQ_1_5_KHZ 0
+#define RT5651_CP_FQ_3_KHZ 1
+#define RT5651_CP_FQ_6_KHZ 2
+#define RT5651_CP_FQ_12_KHZ 3
+#define RT5651_CP_FQ_24_KHZ 4
+#define RT5651_CP_FQ_48_KHZ 5
+#define RT5651_CP_FQ_96_KHZ 6
+#define RT5651_CP_FQ_192_KHZ 7
+
+/* HPOUT charge pump (0x91) */
+#define RT5651_OSW_L_MASK (0x1 << 11)
+#define RT5651_OSW_L_SFT 11
+#define RT5651_OSW_L_DIS (0x0 << 11)
+#define RT5651_OSW_L_EN (0x1 << 11)
+#define RT5651_OSW_R_MASK (0x1 << 10)
+#define RT5651_OSW_R_SFT 10
+#define RT5651_OSW_R_DIS (0x0 << 10)
+#define RT5651_OSW_R_EN (0x1 << 10)
+#define RT5651_PM_HP_MASK (0x3 << 8)
+#define RT5651_PM_HP_SFT 8
+#define RT5651_PM_HP_LV (0x0 << 8)
+#define RT5651_PM_HP_MV (0x1 << 8)
+#define RT5651_PM_HP_HV (0x2 << 8)
+#define RT5651_IB_HP_MASK (0x3 << 6)
+#define RT5651_IB_HP_SFT 6
+#define RT5651_IB_HP_125IL (0x0 << 6)
+#define RT5651_IB_HP_25IL (0x1 << 6)
+#define RT5651_IB_HP_5IL (0x2 << 6)
+#define RT5651_IB_HP_1IL (0x3 << 6)
+
+/* Micbias Control (0x93) */
+#define RT5651_MIC1_BS_MASK (0x1 << 15)
+#define RT5651_MIC1_BS_SFT 15
+#define RT5651_MIC1_BS_9AV (0x0 << 15)
+#define RT5651_MIC1_BS_75AV (0x1 << 15)
+#define RT5651_MIC1_CLK_MASK (0x1 << 13)
+#define RT5651_MIC1_CLK_SFT 13
+#define RT5651_MIC1_CLK_DIS (0x0 << 13)
+#define RT5651_MIC1_CLK_EN (0x1 << 13)
+#define RT5651_MIC1_OVCD_MASK (0x1 << 11)
+#define RT5651_MIC1_OVCD_SFT 11
+#define RT5651_MIC1_OVCD_DIS (0x0 << 11)
+#define RT5651_MIC1_OVCD_EN (0x1 << 11)
+#define RT5651_MIC1_OVTH_MASK (0x3 << 9)
+#define RT5651_MIC1_OVTH_SFT 9
+#define RT5651_MIC1_OVTH_600UA (0x0 << 9)
+#define RT5651_MIC1_OVTH_1500UA (0x1 << 9)
+#define RT5651_MIC1_OVTH_2000UA (0x2 << 9)
+#define RT5651_PWR_MB_MASK (0x1 << 5)
+#define RT5651_PWR_MB_SFT 5
+#define RT5651_PWR_MB_PD (0x0 << 5)
+#define RT5651_PWR_MB_PU (0x1 << 5)
+#define RT5651_PWR_CLK12M_MASK (0x1 << 4)
+#define RT5651_PWR_CLK12M_SFT 4
+#define RT5651_PWR_CLK12M_PD (0x0 << 4)
+#define RT5651_PWR_CLK12M_PU (0x1 << 4)
+
+/* Analog JD Control 1 (0x94) */
+#define RT5651_JD2_CMP_MASK (0x7 << 12)
+#define RT5651_JD2_CMP_SFT 12
+#define RT5651_JD_PU (0x1 << 11)
+#define RT5651_JD_PU_SFT 11
+#define RT5651_JD_PD (0x1 << 10)
+#define RT5651_JD_PD_SFT 10
+#define RT5651_JD_MODE_SEL_MASK (0x3 << 8)
+#define RT5651_JD_MODE_SEL_SFT 8
+#define RT5651_JD_MODE_SEL_M0 (0x0 << 8)
+#define RT5651_JD_MODE_SEL_M1 (0x1 << 8)
+#define RT5651_JD_MODE_SEL_M2 (0x2 << 8)
+#define RT5651_JD_M_CMP (0x7 << 4)
+#define RT5651_JD_M_CMP_SFT 4
+#define RT5651_JD_M_PU (0x1 << 3)
+#define RT5651_JD_M_PU_SFT 3
+#define RT5651_JD_M_PD (0x1 << 2)
+#define RT5651_JD_M_PD_SFT 2
+#define RT5651_JD_M_MODE_SEL_MASK (0x3)
+#define RT5651_JD_M_MODE_SEL_SFT 0
+#define RT5651_JD_M_MODE_SEL_M0 (0x0)
+#define RT5651_JD_M_MODE_SEL_M1 (0x1)
+#define RT5651_JD_M_MODE_SEL_M2 (0x2)
+
+/* Analog JD Control 2 (0x95) */
+#define RT5651_JD3_CMP_MASK (0x7 << 12)
+#define RT5651_JD3_CMP_SFT 12
+
+/* EQ Control 1 (0xb0) */
+#define RT5651_EQ_SRC_MASK (0x1 << 15)
+#define RT5651_EQ_SRC_SFT 15
+#define RT5651_EQ_SRC_DAC (0x0 << 15)
+#define RT5651_EQ_SRC_ADC (0x1 << 15)
+#define RT5651_EQ_UPD (0x1 << 14)
+#define RT5651_EQ_UPD_BIT 14
+#define RT5651_EQ_CD_MASK (0x1 << 13)
+#define RT5651_EQ_CD_SFT 13
+#define RT5651_EQ_CD_DIS (0x0 << 13)
+#define RT5651_EQ_CD_EN (0x1 << 13)
+#define RT5651_EQ_DITH_MASK (0x3 << 8)
+#define RT5651_EQ_DITH_SFT 8
+#define RT5651_EQ_DITH_NOR (0x0 << 8)
+#define RT5651_EQ_DITH_LSB (0x1 << 8)
+#define RT5651_EQ_DITH_LSB_1 (0x2 << 8)
+#define RT5651_EQ_DITH_LSB_2 (0x3 << 8)
+#define RT5651_EQ_CD_F (0x1 << 7)
+#define RT5651_EQ_CD_F_BIT 7
+#define RT5651_EQ_STA_HP2 (0x1 << 6)
+#define RT5651_EQ_STA_HP2_BIT 6
+#define RT5651_EQ_STA_HP1 (0x1 << 5)
+#define RT5651_EQ_STA_HP1_BIT 5
+#define RT5651_EQ_STA_BP4 (0x1 << 4)
+#define RT5651_EQ_STA_BP4_BIT 4
+#define RT5651_EQ_STA_BP3 (0x1 << 3)
+#define RT5651_EQ_STA_BP3_BIT 3
+#define RT5651_EQ_STA_BP2 (0x1 << 2)
+#define RT5651_EQ_STA_BP2_BIT 2
+#define RT5651_EQ_STA_BP1 (0x1 << 1)
+#define RT5651_EQ_STA_BP1_BIT 1
+#define RT5651_EQ_STA_LP (0x1)
+#define RT5651_EQ_STA_LP_BIT 0
+
+/* EQ Control 2 (0xb1) */
+#define RT5651_EQ_HPF1_M_MASK (0x1 << 8)
+#define RT5651_EQ_HPF1_M_SFT 8
+#define RT5651_EQ_HPF1_M_HI (0x0 << 8)
+#define RT5651_EQ_HPF1_M_1ST (0x1 << 8)
+#define RT5651_EQ_LPF1_M_MASK (0x1 << 7)
+#define RT5651_EQ_LPF1_M_SFT 7
+#define RT5651_EQ_LPF1_M_LO (0x0 << 7)
+#define RT5651_EQ_LPF1_M_1ST (0x1 << 7)
+#define RT5651_EQ_HPF2_MASK (0x1 << 6)
+#define RT5651_EQ_HPF2_SFT 6
+#define RT5651_EQ_HPF2_DIS (0x0 << 6)
+#define RT5651_EQ_HPF2_EN (0x1 << 6)
+#define RT5651_EQ_HPF1_MASK (0x1 << 5)
+#define RT5651_EQ_HPF1_SFT 5
+#define RT5651_EQ_HPF1_DIS (0x0 << 5)
+#define RT5651_EQ_HPF1_EN (0x1 << 5)
+#define RT5651_EQ_BPF4_MASK (0x1 << 4)
+#define RT5651_EQ_BPF4_SFT 4
+#define RT5651_EQ_BPF4_DIS (0x0 << 4)
+#define RT5651_EQ_BPF4_EN (0x1 << 4)
+#define RT5651_EQ_BPF3_MASK (0x1 << 3)
+#define RT5651_EQ_BPF3_SFT 3
+#define RT5651_EQ_BPF3_DIS (0x0 << 3)
+#define RT5651_EQ_BPF3_EN (0x1 << 3)
+#define RT5651_EQ_BPF2_MASK (0x1 << 2)
+#define RT5651_EQ_BPF2_SFT 2
+#define RT5651_EQ_BPF2_DIS (0x0 << 2)
+#define RT5651_EQ_BPF2_EN (0x1 << 2)
+#define RT5651_EQ_BPF1_MASK (0x1 << 1)
+#define RT5651_EQ_BPF1_SFT 1
+#define RT5651_EQ_BPF1_DIS (0x0 << 1)
+#define RT5651_EQ_BPF1_EN (0x1 << 1)
+#define RT5651_EQ_LPF_MASK (0x1)
+#define RT5651_EQ_LPF_SFT 0
+#define RT5651_EQ_LPF_DIS (0x0)
+#define RT5651_EQ_LPF_EN (0x1)
+#define RT5651_EQ_CTRL_MASK (0x7f)
+
+/* Memory Test (0xb2) */
+#define RT5651_MT_MASK (0x1 << 15)
+#define RT5651_MT_SFT 15
+#define RT5651_MT_DIS (0x0 << 15)
+#define RT5651_MT_EN (0x1 << 15)
+
+/* ALC Control 1 (0xb4) */
+#define RT5651_ALC_P_MASK (0x1 << 15)
+#define RT5651_ALC_P_SFT 15
+#define RT5651_ALC_P_DAC (0x0 << 15)
+#define RT5651_ALC_P_ADC (0x1 << 15)
+#define RT5651_ALC_MASK (0x1 << 14)
+#define RT5651_ALC_SFT 14
+#define RT5651_ALC_DIS (0x0 << 14)
+#define RT5651_ALC_EN (0x1 << 14)
+#define RT5651_ALC_UPD (0x1 << 13)
+#define RT5651_ALC_UPD_BIT 13
+#define RT5651_ALC_AR_MASK (0x1f << 8)
+#define RT5651_ALC_AR_SFT 8
+#define RT5651_ALC_R_MASK (0x7 << 5)
+#define RT5651_ALC_R_SFT 5
+#define RT5651_ALC_R_48K (0x1 << 5)
+#define RT5651_ALC_R_96K (0x2 << 5)
+#define RT5651_ALC_R_192K (0x3 << 5)
+#define RT5651_ALC_R_441K (0x5 << 5)
+#define RT5651_ALC_R_882K (0x6 << 5)
+#define RT5651_ALC_R_1764K (0x7 << 5)
+#define RT5651_ALC_RC_MASK (0x1f)
+#define RT5651_ALC_RC_SFT 0
+
+/* ALC Control 2 (0xb5) */
+#define RT5651_ALC_POB_MASK (0x3f << 8)
+#define RT5651_ALC_POB_SFT 8
+#define RT5651_ALC_DRC_MASK (0x1 << 7)
+#define RT5651_ALC_DRC_SFT 7
+#define RT5651_ALC_DRC_DIS (0x0 << 7)
+#define RT5651_ALC_DRC_EN (0x1 << 7)
+#define RT5651_ALC_CPR_MASK (0x3 << 5)
+#define RT5651_ALC_CPR_SFT 5
+#define RT5651_ALC_CPR_1_1 (0x0 << 5)
+#define RT5651_ALC_CPR_1_2 (0x1 << 5)
+#define RT5651_ALC_CPR_1_4 (0x2 << 5)
+#define RT5651_ALC_CPR_1_8 (0x3 << 5)
+#define RT5651_ALC_PRB_MASK (0x1f)
+#define RT5651_ALC_PRB_SFT 0
+
+/* ALC Control 3 (0xb6) */
+#define RT5651_ALC_NGB_MASK (0xf << 12)
+#define RT5651_ALC_NGB_SFT 12
+#define RT5651_ALC_TAR_MASK (0x1f << 7)
+#define RT5651_ALC_TAR_SFT 7
+#define RT5651_ALC_NG_MASK (0x1 << 6)
+#define RT5651_ALC_NG_SFT 6
+#define RT5651_ALC_NG_DIS (0x0 << 6)
+#define RT5651_ALC_NG_EN (0x1 << 6)
+#define RT5651_ALC_NGH_MASK (0x1 << 5)
+#define RT5651_ALC_NGH_SFT 5
+#define RT5651_ALC_NGH_DIS (0x0 << 5)
+#define RT5651_ALC_NGH_EN (0x1 << 5)
+#define RT5651_ALC_NGT_MASK (0x1f)
+#define RT5651_ALC_NGT_SFT 0
+
+/* Jack Detect Control 1 (0xbb) */
+#define RT5651_JD_MASK (0x7 << 13)
+#define RT5651_JD_SFT 13
+#define RT5651_JD_DIS (0x0 << 13)
+#define RT5651_JD_GPIO1 (0x1 << 13)
+#define RT5651_JD_GPIO2 (0x2 << 13)
+#define RT5651_JD_GPIO3 (0x3 << 13)
+#define RT5651_JD_GPIO4 (0x4 << 13)
+#define RT5651_JD_GPIO5 (0x5 << 13)
+#define RT5651_JD_GPIO6 (0x6 << 13)
+#define RT5651_JD_HP_MASK (0x1 << 11)
+#define RT5651_JD_HP_SFT 11
+#define RT5651_JD_HP_DIS (0x0 << 11)
+#define RT5651_JD_HP_EN (0x1 << 11)
+#define RT5651_JD_HP_TRG_MASK (0x1 << 10)
+#define RT5651_JD_HP_TRG_SFT 10
+#define RT5651_JD_HP_TRG_LO (0x0 << 10)
+#define RT5651_JD_HP_TRG_HI (0x1 << 10)
+#define RT5651_JD_SPL_MASK (0x1 << 9)
+#define RT5651_JD_SPL_SFT 9
+#define RT5651_JD_SPL_DIS (0x0 << 9)
+#define RT5651_JD_SPL_EN (0x1 << 9)
+#define RT5651_JD_SPL_TRG_MASK (0x1 << 8)
+#define RT5651_JD_SPL_TRG_SFT 8
+#define RT5651_JD_SPL_TRG_LO (0x0 << 8)
+#define RT5651_JD_SPL_TRG_HI (0x1 << 8)
+#define RT5651_JD_SPR_MASK (0x1 << 7)
+#define RT5651_JD_SPR_SFT 7
+#define RT5651_JD_SPR_DIS (0x0 << 7)
+#define RT5651_JD_SPR_EN (0x1 << 7)
+#define RT5651_JD_SPR_TRG_MASK (0x1 << 6)
+#define RT5651_JD_SPR_TRG_SFT 6
+#define RT5651_JD_SPR_TRG_LO (0x0 << 6)
+#define RT5651_JD_SPR_TRG_HI (0x1 << 6)
+#define RT5651_JD_LO_MASK (0x1 << 3)
+#define RT5651_JD_LO_SFT 3
+#define RT5651_JD_LO_DIS (0x0 << 3)
+#define RT5651_JD_LO_EN (0x1 << 3)
+#define RT5651_JD_LO_TRG_MASK (0x1 << 2)
+#define RT5651_JD_LO_TRG_SFT 2
+#define RT5651_JD_LO_TRG_LO (0x0 << 2)
+#define RT5651_JD_LO_TRG_HI (0x1 << 2)
+
+/* Jack Detect Control 2 (0xbc) */
+#define RT5651_JD_TRG_SEL_MASK (0x7 << 9)
+#define RT5651_JD_TRG_SEL_SFT 9
+#define RT5651_JD_TRG_SEL_GPIO (0x0 << 9)
+#define RT5651_JD_TRG_SEL_JD1_1 (0x1 << 9)
+#define RT5651_JD_TRG_SEL_JD1_2 (0x2 << 9)
+#define RT5651_JD_TRG_SEL_JD2 (0x3 << 9)
+#define RT5651_JD_TRG_SEL_JD3 (0x4 << 9)
+#define RT5651_JD3_IRQ_EN (0x1 << 8)
+#define RT5651_JD3_IRQ_EN_SFT 8
+#define RT5651_JD3_EN_STKY (0x1 << 7)
+#define RT5651_JD3_EN_STKY_SFT 7
+#define RT5651_JD3_INV (0x1 << 6)
+#define RT5651_JD3_INV_SFT 6
+
+/* IRQ Control 1 (0xbd) */
+#define RT5651_IRQ_JD_MASK (0x1 << 15)
+#define RT5651_IRQ_JD_SFT 15
+#define RT5651_IRQ_JD_BP (0x0 << 15)
+#define RT5651_IRQ_JD_NOR (0x1 << 15)
+#define RT5651_JD_STKY_MASK (0x1 << 13)
+#define RT5651_JD_STKY_SFT 13
+#define RT5651_JD_STKY_DIS (0x0 << 13)
+#define RT5651_JD_STKY_EN (0x1 << 13)
+#define RT5651_JD_P_MASK (0x1 << 11)
+#define RT5651_JD_P_SFT 11
+#define RT5651_JD_P_NOR (0x0 << 11)
+#define RT5651_JD_P_INV (0x1 << 11)
+#define RT5651_JD1_1_IRQ_EN (0x1 << 9)
+#define RT5651_JD1_1_IRQ_EN_SFT 9
+#define RT5651_JD1_1_EN_STKY (0x1 << 8)
+#define RT5651_JD1_1_EN_STKY_SFT 8
+#define RT5651_JD1_1_INV (0x1 << 7)
+#define RT5651_JD1_1_INV_SFT 7
+#define RT5651_JD1_2_IRQ_EN (0x1 << 6)
+#define RT5651_JD1_2_IRQ_EN_SFT 6
+#define RT5651_JD1_2_EN_STKY (0x1 << 5)
+#define RT5651_JD1_2_EN_STKY_SFT 5
+#define RT5651_JD1_2_INV (0x1 << 4)
+#define RT5651_JD1_2_INV_SFT 4
+#define RT5651_JD2_IRQ_EN (0x1 << 3)
+#define RT5651_JD2_IRQ_EN_SFT 3
+#define RT5651_JD2_EN_STKY (0x1 << 2)
+#define RT5651_JD2_EN_STKY_SFT 2
+#define RT5651_JD2_INV (0x1 << 1)
+#define RT5651_JD2_INV_SFT 1
+
+/* IRQ Control 2 (0xbe) */
+#define RT5651_IRQ_MB1_OC_MASK (0x1 << 15)
+#define RT5651_IRQ_MB1_OC_SFT 15
+#define RT5651_IRQ_MB1_OC_BP (0x0 << 15)
+#define RT5651_IRQ_MB1_OC_NOR (0x1 << 15)
+#define RT5651_MB1_OC_STKY_MASK (0x1 << 11)
+#define RT5651_MB1_OC_STKY_SFT 11
+#define RT5651_MB1_OC_STKY_DIS (0x0 << 11)
+#define RT5651_MB1_OC_STKY_EN (0x1 << 11)
+#define RT5651_MB1_OC_P_MASK (0x1 << 7)
+#define RT5651_MB1_OC_P_SFT 7
+#define RT5651_MB1_OC_P_NOR (0x0 << 7)
+#define RT5651_MB1_OC_P_INV (0x1 << 7)
+#define RT5651_MB2_OC_P_MASK (0x1 << 6)
+#define RT5651_MB1_OC_CLR (0x1 << 3)
+#define RT5651_MB1_OC_CLR_SFT 3
+#define RT5651_STA_GPIO8 (0x1)
+#define RT5651_STA_GPIO8_BIT 0
+
+/* Internal Status and GPIO status (0xbf) */
+#define RT5651_STA_JD3 (0x1 << 15)
+#define RT5651_STA_JD3_BIT 15
+#define RT5651_STA_JD2 (0x1 << 14)
+#define RT5651_STA_JD2_BIT 14
+#define RT5651_STA_JD1_2 (0x1 << 13)
+#define RT5651_STA_JD1_2_BIT 13
+#define RT5651_STA_JD1_1 (0x1 << 12)
+#define RT5651_STA_JD1_1_BIT 12
+#define RT5651_STA_GP7 (0x1 << 11)
+#define RT5651_STA_GP7_BIT 11
+#define RT5651_STA_GP6 (0x1 << 10)
+#define RT5651_STA_GP6_BIT 10
+#define RT5651_STA_GP5 (0x1 << 9)
+#define RT5651_STA_GP5_BIT 9
+#define RT5651_STA_GP1 (0x1 << 8)
+#define RT5651_STA_GP1_BIT 8
+#define RT5651_STA_GP2 (0x1 << 7)
+#define RT5651_STA_GP2_BIT 7
+#define RT5651_STA_GP3 (0x1 << 6)
+#define RT5651_STA_GP3_BIT 6
+#define RT5651_STA_GP4 (0x1 << 5)
+#define RT5651_STA_GP4_BIT 5
+#define RT5651_STA_GP_JD (0x1 << 4)
+#define RT5651_STA_GP_JD_BIT 4
+
+/* GPIO Control 1 (0xc0) */
+#define RT5651_GP1_PIN_MASK (0x1 << 15)
+#define RT5651_GP1_PIN_SFT 15
+#define RT5651_GP1_PIN_GPIO1 (0x0 << 15)
+#define RT5651_GP1_PIN_IRQ (0x1 << 15)
+#define RT5651_GP2_PIN_MASK (0x1 << 14)
+#define RT5651_GP2_PIN_SFT 14
+#define RT5651_GP2_PIN_GPIO2 (0x0 << 14)
+#define RT5651_GP2_PIN_DMIC1_SCL (0x1 << 14)
+#define RT5651_GPIO_M_MASK (0x1 << 9)
+#define RT5651_GPIO_M_SFT 9
+#define RT5651_GPIO_M_FLT (0x0 << 9)
+#define RT5651_GPIO_M_PH (0x1 << 9)
+#define RT5651_I2S2_SEL_MASK (0x1 << 8)
+#define RT5651_I2S2_SEL_SFT 8
+#define RT5651_I2S2_SEL_I2S (0x0 << 8)
+#define RT5651_I2S2_SEL_GPIO (0x1 << 8)
+#define RT5651_GP5_PIN_MASK (0x1 << 7)
+#define RT5651_GP5_PIN_SFT 7
+#define RT5651_GP5_PIN_GPIO5 (0x0 << 7)
+#define RT5651_GP5_PIN_IRQ (0x1 << 7)
+#define RT5651_GP6_PIN_MASK (0x1 << 6)
+#define RT5651_GP6_PIN_SFT 6
+#define RT5651_GP6_PIN_GPIO6 (0x0 << 6)
+#define RT5651_GP6_PIN_DMIC_SDA (0x1 << 6)
+#define RT5651_GP7_PIN_MASK (0x1 << 5)
+#define RT5651_GP7_PIN_SFT 5
+#define RT5651_GP7_PIN_GPIO7 (0x0 << 5)
+#define RT5651_GP7_PIN_IRQ (0x1 << 5)
+#define RT5651_GP8_PIN_MASK (0x1 << 4)
+#define RT5651_GP8_PIN_SFT 4
+#define RT5651_GP8_PIN_GPIO8 (0x0 << 4)
+#define RT5651_GP8_PIN_DMIC_SDA (0x1 << 4)
+#define RT5651_GPIO_PDM_SEL_MASK (0x1 << 3)
+#define RT5651_GPIO_PDM_SEL_SFT 3
+#define RT5651_GPIO_PDM_SEL_GPIO (0x0 << 3)
+#define RT5651_GPIO_PDM_SEL_PDM (0x1 << 3)
+
+/* GPIO Control 2 (0xc1) */
+#define RT5651_GP5_DR_MASK (0x1 << 14)
+#define RT5651_GP5_DR_SFT 14
+#define RT5651_GP5_DR_IN (0x0 << 14)
+#define RT5651_GP5_DR_OUT (0x1 << 14)
+#define RT5651_GP5_OUT_MASK (0x1 << 13)
+#define RT5651_GP5_OUT_SFT 13
+#define RT5651_GP5_OUT_LO (0x0 << 13)
+#define RT5651_GP5_OUT_HI (0x1 << 13)
+#define RT5651_GP5_P_MASK (0x1 << 12)
+#define RT5651_GP5_P_SFT 12
+#define RT5651_GP5_P_NOR (0x0 << 12)
+#define RT5651_GP5_P_INV (0x1 << 12)
+#define RT5651_GP4_DR_MASK (0x1 << 11)
+#define RT5651_GP4_DR_SFT 11
+#define RT5651_GP4_DR_IN (0x0 << 11)
+#define RT5651_GP4_DR_OUT (0x1 << 11)
+#define RT5651_GP4_OUT_MASK (0x1 << 10)
+#define RT5651_GP4_OUT_SFT 10
+#define RT5651_GP4_OUT_LO (0x0 << 10)
+#define RT5651_GP4_OUT_HI (0x1 << 10)
+#define RT5651_GP4_P_MASK (0x1 << 9)
+#define RT5651_GP4_P_SFT 9
+#define RT5651_GP4_P_NOR (0x0 << 9)
+#define RT5651_GP4_P_INV (0x1 << 9)
+#define RT5651_GP3_DR_MASK (0x1 << 8)
+#define RT5651_GP3_DR_SFT 8
+#define RT5651_GP3_DR_IN (0x0 << 8)
+#define RT5651_GP3_DR_OUT (0x1 << 8)
+#define RT5651_GP3_OUT_MASK (0x1 << 7)
+#define RT5651_GP3_OUT_SFT 7
+#define RT5651_GP3_OUT_LO (0x0 << 7)
+#define RT5651_GP3_OUT_HI (0x1 << 7)
+#define RT5651_GP3_P_MASK (0x1 << 6)
+#define RT5651_GP3_P_SFT 6
+#define RT5651_GP3_P_NOR (0x0 << 6)
+#define RT5651_GP3_P_INV (0x1 << 6)
+#define RT5651_GP2_DR_MASK (0x1 << 5)
+#define RT5651_GP2_DR_SFT 5
+#define RT5651_GP2_DR_IN (0x0 << 5)
+#define RT5651_GP2_DR_OUT (0x1 << 5)
+#define RT5651_GP2_OUT_MASK (0x1 << 4)
+#define RT5651_GP2_OUT_SFT 4
+#define RT5651_GP2_OUT_LO (0x0 << 4)
+#define RT5651_GP2_OUT_HI (0x1 << 4)
+#define RT5651_GP2_P_MASK (0x1 << 3)
+#define RT5651_GP2_P_SFT 3
+#define RT5651_GP2_P_NOR (0x0 << 3)
+#define RT5651_GP2_P_INV (0x1 << 3)
+#define RT5651_GP1_DR_MASK (0x1 << 2)
+#define RT5651_GP1_DR_SFT 2
+#define RT5651_GP1_DR_IN (0x0 << 2)
+#define RT5651_GP1_DR_OUT (0x1 << 2)
+#define RT5651_GP1_OUT_MASK (0x1 << 1)
+#define RT5651_GP1_OUT_SFT 1
+#define RT5651_GP1_OUT_LO (0x0 << 1)
+#define RT5651_GP1_OUT_HI (0x1 << 1)
+#define RT5651_GP1_P_MASK (0x1)
+#define RT5651_GP1_P_SFT 0
+#define RT5651_GP1_P_NOR (0x0)
+#define RT5651_GP1_P_INV (0x1)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5651_GP8_DR_MASK (0x1 << 8)
+#define RT5651_GP8_DR_SFT 8
+#define RT5651_GP8_DR_IN (0x0 << 8)
+#define RT5651_GP8_DR_OUT (0x1 << 8)
+#define RT5651_GP8_OUT_MASK (0x1 << 7)
+#define RT5651_GP8_OUT_SFT 7
+#define RT5651_GP8_OUT_LO (0x0 << 7)
+#define RT5651_GP8_OUT_HI (0x1 << 7)
+#define RT5651_GP8_P_MASK (0x1 << 6)
+#define RT5651_GP8_P_SFT 6
+#define RT5651_GP8_P_NOR (0x0 << 6)
+#define RT5651_GP8_P_INV (0x1 << 6)
+#define RT5651_GP7_DR_MASK (0x1 << 5)
+#define RT5651_GP7_DR_SFT 5
+#define RT5651_GP7_DR_IN (0x0 << 5)
+#define RT5651_GP7_DR_OUT (0x1 << 5)
+#define RT5651_GP7_OUT_MASK (0x1 << 4)
+#define RT5651_GP7_OUT_SFT 4
+#define RT5651_GP7_OUT_LO (0x0 << 4)
+#define RT5651_GP7_OUT_HI (0x1 << 4)
+#define RT5651_GP7_P_MASK (0x1 << 3)
+#define RT5651_GP7_P_SFT 3
+#define RT5651_GP7_P_NOR (0x0 << 3)
+#define RT5651_GP7_P_INV (0x1 << 3)
+#define RT5651_GP6_DR_MASK (0x1 << 2)
+#define RT5651_GP6_DR_SFT 2
+#define RT5651_GP6_DR_IN (0x0 << 2)
+#define RT5651_GP6_DR_OUT (0x1 << 2)
+#define RT5651_GP6_OUT_MASK (0x1 << 1)
+#define RT5651_GP6_OUT_SFT 1
+#define RT5651_GP6_OUT_LO (0x0 << 1)
+#define RT5651_GP6_OUT_HI (0x1 << 1)
+#define RT5651_GP6_P_MASK (0x1)
+#define RT5651_GP6_P_SFT 0
+#define RT5651_GP6_P_NOR (0x0)
+#define RT5651_GP6_P_INV (0x1)
+
+/* Scramble Control (0xce) */
+#define RT5651_SCB_SWAP_MASK (0x1 << 15)
+#define RT5651_SCB_SWAP_SFT 15
+#define RT5651_SCB_SWAP_DIS (0x0 << 15)
+#define RT5651_SCB_SWAP_EN (0x1 << 15)
+#define RT5651_SCB_MASK (0x1 << 14)
+#define RT5651_SCB_SFT 14
+#define RT5651_SCB_DIS (0x0 << 14)
+#define RT5651_SCB_EN (0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5651_BB_MASK (0x1 << 15)
+#define RT5651_BB_SFT 15
+#define RT5651_BB_DIS (0x0 << 15)
+#define RT5651_BB_EN (0x1 << 15)
+#define RT5651_BB_CT_MASK (0x7 << 12)
+#define RT5651_BB_CT_SFT 12
+#define RT5651_BB_CT_A (0x0 << 12)
+#define RT5651_BB_CT_B (0x1 << 12)
+#define RT5651_BB_CT_C (0x2 << 12)
+#define RT5651_BB_CT_D (0x3 << 12)
+#define RT5651_M_BB_L_MASK (0x1 << 9)
+#define RT5651_M_BB_L_SFT 9
+#define RT5651_M_BB_R_MASK (0x1 << 8)
+#define RT5651_M_BB_R_SFT 8
+#define RT5651_M_BB_HPF_L_MASK (0x1 << 7)
+#define RT5651_M_BB_HPF_L_SFT 7
+#define RT5651_M_BB_HPF_R_MASK (0x1 << 6)
+#define RT5651_M_BB_HPF_R_SFT 6
+#define RT5651_G_BB_BST_MASK (0x3f)
+#define RT5651_G_BB_BST_SFT 0
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5651_M_MP3_L_MASK (0x1 << 15)
+#define RT5651_M_MP3_L_SFT 15
+#define RT5651_M_MP3_R_MASK (0x1 << 14)
+#define RT5651_M_MP3_R_SFT 14
+#define RT5651_M_MP3_MASK (0x1 << 13)
+#define RT5651_M_MP3_SFT 13
+#define RT5651_M_MP3_DIS (0x0 << 13)
+#define RT5651_M_MP3_EN (0x1 << 13)
+#define RT5651_EG_MP3_MASK (0x1f << 8)
+#define RT5651_EG_MP3_SFT 8
+#define RT5651_MP3_HLP_MASK (0x1 << 7)
+#define RT5651_MP3_HLP_SFT 7
+#define RT5651_MP3_HLP_DIS (0x0 << 7)
+#define RT5651_MP3_HLP_EN (0x1 << 7)
+#define RT5651_M_MP3_ORG_L_MASK (0x1 << 6)
+#define RT5651_M_MP3_ORG_L_SFT 6
+#define RT5651_M_MP3_ORG_R_MASK (0x1 << 5)
+#define RT5651_M_MP3_ORG_R_SFT 5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5651_MP3_WT_MASK (0x1 << 13)
+#define RT5651_MP3_WT_SFT 13
+#define RT5651_MP3_WT_1_4 (0x0 << 13)
+#define RT5651_MP3_WT_1_2 (0x1 << 13)
+#define RT5651_OG_MP3_MASK (0x1f << 8)
+#define RT5651_OG_MP3_SFT 8
+#define RT5651_HG_MP3_MASK (0x3f)
+#define RT5651_HG_MP3_SFT 0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5651_3D_CF_MASK (0x1 << 15)
+#define RT5651_3D_CF_SFT 15
+#define RT5651_3D_CF_DIS (0x0 << 15)
+#define RT5651_3D_CF_EN (0x1 << 15)
+#define RT5651_3D_HP_MASK (0x1 << 14)
+#define RT5651_3D_HP_SFT 14
+#define RT5651_3D_HP_DIS (0x0 << 14)
+#define RT5651_3D_HP_EN (0x1 << 14)
+#define RT5651_3D_BT_MASK (0x1 << 13)
+#define RT5651_3D_BT_SFT 13
+#define RT5651_3D_BT_DIS (0x0 << 13)
+#define RT5651_3D_BT_EN (0x1 << 13)
+#define RT5651_3D_1F_MIX_MASK (0x3 << 11)
+#define RT5651_3D_1F_MIX_SFT 11
+#define RT5651_3D_HP_M_MASK (0x1 << 10)
+#define RT5651_3D_HP_M_SFT 10
+#define RT5651_3D_HP_M_SUR (0x0 << 10)
+#define RT5651_3D_HP_M_FRO (0x1 << 10)
+#define RT5651_M_3D_HRTF_MASK (0x1 << 9)
+#define RT5651_M_3D_HRTF_SFT 9
+#define RT5651_M_3D_D2H_MASK (0x1 << 8)
+#define RT5651_M_3D_D2H_SFT 8
+#define RT5651_M_3D_D2R_MASK (0x1 << 7)
+#define RT5651_M_3D_D2R_SFT 7
+#define RT5651_M_3D_REVB_MASK (0x1 << 6)
+#define RT5651_M_3D_REVB_SFT 6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5651_2ND_HPF_MASK (0x1 << 15)
+#define RT5651_2ND_HPF_SFT 15
+#define RT5651_2ND_HPF_DIS (0x0 << 15)
+#define RT5651_2ND_HPF_EN (0x1 << 15)
+#define RT5651_HPF_CF_L_MASK (0x7 << 12)
+#define RT5651_HPF_CF_L_SFT 12
+#define RT5651_HPF_CF_R_MASK (0x7 << 8)
+#define RT5651_HPF_CF_R_SFT 8
+#define RT5651_ZD_T_MASK (0x3 << 6)
+#define RT5651_ZD_T_SFT 6
+#define RT5651_ZD_F_MASK (0x3 << 4)
+#define RT5651_ZD_F_SFT 4
+#define RT5651_ZD_F_IM (0x0 << 4)
+#define RT5651_ZD_F_ZC_IM (0x1 << 4)
+#define RT5651_ZD_F_ZC_IOD (0x2 << 4)
+#define RT5651_ZD_F_UN (0x3 << 4)
+
+/* Adjustable high pass filter control 2 (0xd4) */
+#define RT5651_HPF_CF_L_NUM_MASK (0x3f << 8)
+#define RT5651_HPF_CF_L_NUM_SFT 8
+#define RT5651_HPF_CF_R_NUM_MASK (0x3f)
+#define RT5651_HPF_CF_R_NUM_SFT 0
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5651_SI_DAC_MASK (0x1 << 11)
+#define RT5651_SI_DAC_SFT 11
+#define RT5651_SI_DAC_AUTO (0x0 << 11)
+#define RT5651_SI_DAC_TEST (0x1 << 11)
+#define RT5651_DC_CAL_M_MASK (0x1 << 10)
+#define RT5651_DC_CAL_M_SFT 10
+#define RT5651_DC_CAL_M_NOR (0x0 << 10)
+#define RT5651_DC_CAL_M_CAL (0x1 << 10)
+#define RT5651_DC_CAL_MASK (0x1 << 9)
+#define RT5651_DC_CAL_SFT 9
+#define RT5651_DC_CAL_DIS (0x0 << 9)
+#define RT5651_DC_CAL_EN (0x1 << 9)
+#define RT5651_HPD_RCV_MASK (0x7 << 6)
+#define RT5651_HPD_RCV_SFT 6
+#define RT5651_HPD_PS_MASK (0x1 << 5)
+#define RT5651_HPD_PS_SFT 5
+#define RT5651_HPD_PS_DIS (0x0 << 5)
+#define RT5651_HPD_PS_EN (0x1 << 5)
+#define RT5651_CAL_M_MASK (0x1 << 4)
+#define RT5651_CAL_M_SFT 4
+#define RT5651_CAL_M_DEP (0x0 << 4)
+#define RT5651_CAL_M_CAL (0x1 << 4)
+#define RT5651_CAL_MASK (0x1 << 3)
+#define RT5651_CAL_SFT 3
+#define RT5651_CAL_DIS (0x0 << 3)
+#define RT5651_CAL_EN (0x1 << 3)
+#define RT5651_CAL_TEST_MASK (0x1 << 2)
+#define RT5651_CAL_TEST_SFT 2
+#define RT5651_CAL_TEST_DIS (0x0 << 2)
+#define RT5651_CAL_TEST_EN (0x1 << 2)
+#define RT5651_CAL_P_MASK (0x3)
+#define RT5651_CAL_P_SFT 0
+#define RT5651_CAL_P_NONE (0x0)
+#define RT5651_CAL_P_CAL (0x1)
+#define RT5651_CAL_P_DAC_CAL (0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5651_SV_MASK (0x1 << 15)
+#define RT5651_SV_SFT 15
+#define RT5651_SV_DIS (0x0 << 15)
+#define RT5651_SV_EN (0x1 << 15)
+#define RT5651_OUT_SV_MASK (0x1 << 13)
+#define RT5651_OUT_SV_SFT 13
+#define RT5651_OUT_SV_DIS (0x0 << 13)
+#define RT5651_OUT_SV_EN (0x1 << 13)
+#define RT5651_HP_SV_MASK (0x1 << 12)
+#define RT5651_HP_SV_SFT 12
+#define RT5651_HP_SV_DIS (0x0 << 12)
+#define RT5651_HP_SV_EN (0x1 << 12)
+#define RT5651_ZCD_DIG_MASK (0x1 << 11)
+#define RT5651_ZCD_DIG_SFT 11
+#define RT5651_ZCD_DIG_DIS (0x0 << 11)
+#define RT5651_ZCD_DIG_EN (0x1 << 11)
+#define RT5651_ZCD_MASK (0x1 << 10)
+#define RT5651_ZCD_SFT 10
+#define RT5651_ZCD_PD (0x0 << 10)
+#define RT5651_ZCD_PU (0x1 << 10)
+#define RT5651_M_ZCD_MASK (0x3f << 4)
+#define RT5651_M_ZCD_SFT 4
+#define RT5651_M_ZCD_OM_L (0x1 << 7)
+#define RT5651_M_ZCD_OM_R (0x1 << 6)
+#define RT5651_M_ZCD_RM_L (0x1 << 5)
+#define RT5651_M_ZCD_RM_R (0x1 << 4)
+#define RT5651_SV_DLY_MASK (0xf)
+#define RT5651_SV_DLY_SFT 0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5651_ZCD_HP_MASK (0x1 << 15)
+#define RT5651_ZCD_HP_SFT 15
+#define RT5651_ZCD_HP_DIS (0x0 << 15)
+#define RT5651_ZCD_HP_EN (0x1 << 15)
+
+/* Digital Misc Control (0xfa) */
+#define RT5651_I2S2_MS_SP_MASK (0x1 << 8)
+#define RT5651_I2S2_MS_SP_SEL 8
+#define RT5651_I2S2_MS_SP_64 (0x0 << 8)
+#define RT5651_I2S2_MS_SP_50 (0x1 << 8)
+#define RT5651_CLK_DET_EN (0x1 << 3)
+#define RT5651_CLK_DET_EN_SFT 3
+#define RT5651_AMP_DET_EN (0x1 << 1)
+#define RT5651_AMP_DET_EN_SFT 1
+#define RT5651_D_GATE_EN (0x1)
+#define RT5651_D_GATE_EN_SFT 0
+
+/* Codec Private Register definition */
+/* 3D Speaker Control (0x63) */
+#define RT5651_3D_SPK_MASK (0x1 << 15)
+#define RT5651_3D_SPK_SFT 15
+#define RT5651_3D_SPK_DIS (0x0 << 15)
+#define RT5651_3D_SPK_EN (0x1 << 15)
+#define RT5651_3D_SPK_M_MASK (0x3 << 13)
+#define RT5651_3D_SPK_M_SFT 13
+#define RT5651_3D_SPK_CG_MASK (0x1f << 8)
+#define RT5651_3D_SPK_CG_SFT 8
+#define RT5651_3D_SPK_SG_MASK (0x1f)
+#define RT5651_3D_SPK_SG_SFT 0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5651_WND_MASK (0x1 << 15)
+#define RT5651_WND_SFT 15
+#define RT5651_WND_DIS (0x0 << 15)
+#define RT5651_WND_EN (0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5651_WND_FC_NW_MASK (0x3f << 10)
+#define RT5651_WND_FC_NW_SFT 10
+#define RT5651_WND_FC_WK_MASK (0x3f << 4)
+#define RT5651_WND_FC_WK_SFT 4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5651_HPF_FC_MASK (0x3f << 6)
+#define RT5651_HPF_FC_SFT 6
+#define RT5651_WND_FC_ST_MASK (0x3f)
+#define RT5651_WND_FC_ST_SFT 0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5651_WND_TH_LO_MASK (0x3ff)
+#define RT5651_WND_TH_LO_SFT 0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5651_WND_TH_HI_MASK (0x3ff)
+#define RT5651_WND_TH_HI_SFT 0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5651_WND_WIND_MASK (0x1 << 13) /* Read-Only */
+#define RT5651_WND_WIND_SFT 13
+#define RT5651_WND_STRONG_MASK (0x1 << 12) /* Read-Only */
+#define RT5651_WND_STRONG_SFT 12
+enum {
+ RT5651_NO_WIND,
+ RT5651_BREEZE,
+ RT5651_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5651_DP_ATT_MASK (0x3 << 14)
+#define RT5651_DP_ATT_SFT 14
+#define RT5651_DP_SPK_MASK (0x1 << 10)
+#define RT5651_DP_SPK_SFT 10
+#define RT5651_DP_SPK_DIS (0x0 << 10)
+#define RT5651_DP_SPK_EN (0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5651_EQ_PRE_VOL_MASK (0xffff)
+#define RT5651_EQ_PRE_VOL_SFT 0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5651_EQ_PST_VOL_MASK (0xffff)
+#define RT5651_EQ_PST_VOL_SFT 0
+
+/* System Clock Source */
+enum {
+ RT5651_SCLK_S_MCLK,
+ RT5651_SCLK_S_PLL1,
+ RT5651_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+ RT5651_PLL1_S_MCLK,
+ RT5651_PLL1_S_BCLK1,
+ RT5651_PLL1_S_BCLK2,
+};
+
+enum {
+ RT5651_AIF1,
+ RT5651_AIF2,
+ RT5651_AIFS,
+};
+
+struct rt5651_pll_code {
+ bool m_bp; /* Indicates bypass m code or not. */
+ int m_code;
+ int n_code;
+ int k_code;
+};
+
+struct rt5651_priv {
+ struct snd_soc_codec *codec;
+ struct rt5651_platform_data pdata;
+ struct regmap *regmap;
+
+ int sysclk;
+ int sysclk_src;
+ int lrck[RT5651_AIFS];
+ int bclk[RT5651_AIFS];
+ int master[RT5651_AIFS];
+
+ struct rt5651_pll_code pll_code;
+ int pll_src;
+ int pll_in;
+ int pll_out;
+
+ int dmic_en;
+ bool hp_mute;
+};
+
+#endif /* __RT5651_H__ */
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index d3ed1be5a186..9626ee0417cd 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -296,7 +296,7 @@ static int dac_info_volsw(struct snd_kcontrol *kcontrol,
static int dac_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
int reg;
int l;
int r;
@@ -349,7 +349,7 @@ static int dac_get_volsw(struct snd_kcontrol *kcontrol,
static int dac_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
int reg;
int l;
int r;
@@ -1322,7 +1322,7 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
return ret;
}
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
+ ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
if (ret)
goto err_ldo_remove;
@@ -1330,16 +1330,13 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
if (ret)
- goto err_regulator_free;
+ goto err_ldo_remove;
/* wait for all power rails bring up */
udelay(10);
return 0;
-err_regulator_free:
- regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
- sgtl5000->supplies);
err_ldo_remove:
if (!external_vddd)
ldo_regulator_remove(codec);
@@ -1409,8 +1406,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
err:
regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
- regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
- sgtl5000->supplies);
ldo_regulator_remove(codec);
return ret;
@@ -1424,8 +1419,6 @@ static int sgtl5000_remove(struct snd_soc_codec *codec)
regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
- regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
- sgtl5000->supplies);
ldo_regulator_remove(codec);
return 0;
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index 244c097cd905..f26befb0c297 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -208,13 +208,6 @@ out:
return err;
}
-static int si476x_codec_probe(struct snd_soc_codec *codec)
-{
- struct regmap *regmap = dev_get_regmap(codec->dev->parent, NULL);
-
- return snd_soc_codec_set_cache_io(codec, regmap);
-}
-
static struct snd_soc_dai_ops si476x_dai_ops = {
.hw_params = si476x_codec_hw_params,
.set_fmt = si476x_codec_set_dai_fmt,
@@ -238,8 +231,13 @@ static struct snd_soc_dai_driver si476x_dai = {
.ops = &si476x_dai_ops,
};
+static struct regmap *si476x_get_regmap(struct device *dev)
+{
+ return dev_get_regmap(dev->parent, NULL);
+}
+
static struct snd_soc_codec_driver soc_codec_dev_si476x = {
- .probe = si476x_codec_probe,
+ .get_regmap = si476x_get_regmap,
.dapm_widgets = si476x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets),
.dapm_routes = si476x_dapm_routes,
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
index 58e7c1f23771..c5177bc5df82 100644
--- a/sound/soc/codecs/sirf-audio-codec.c
+++ b/sound/soc/codecs/sirf-audio-codec.c
@@ -279,13 +279,63 @@ static const struct snd_soc_dapm_route sirf_audio_codec_map[] = {
{"Mic input mode mux", "Differential", "MICIN1"},
};
+static void sirf_audio_codec_tx_enable(struct sirf_audio_codec *sirf_audio_codec)
+{
+ regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+ AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
+ regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+ AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
+ regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0);
+ regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
+ regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+ AUDIO_FIFO_START, AUDIO_FIFO_START);
+ regmap_update_bits(sirf_audio_codec->regmap,
+ AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, IC_TX_ENABLE);
+}
+
+static void sirf_audio_codec_tx_disable(struct sirf_audio_codec *sirf_audio_codec)
+{
+ regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
+ regmap_update_bits(sirf_audio_codec->regmap,
+ AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, ~IC_TX_ENABLE);
+}
+
+static void sirf_audio_codec_rx_enable(struct sirf_audio_codec *sirf_audio_codec,
+ int channels)
+{
+ regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+ AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
+ regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+ AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
+ regmap_write(sirf_audio_codec->regmap,
+ AUDIO_PORT_IC_RXFIFO_INT_MSK, 0);
+ regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0);
+ regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+ AUDIO_FIFO_START, AUDIO_FIFO_START);
+ if (channels == 1)
+ regmap_update_bits(sirf_audio_codec->regmap,
+ AUDIO_PORT_IC_CODEC_RX_CTRL,
+ IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO);
+ else
+ regmap_update_bits(sirf_audio_codec->regmap,
+ AUDIO_PORT_IC_CODEC_RX_CTRL,
+ IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO);
+}
+
+static void sirf_audio_codec_rx_disable(struct sirf_audio_codec *sirf_audio_codec)
+{
+ regmap_update_bits(sirf_audio_codec->regmap,
+ AUDIO_PORT_IC_CODEC_RX_CTRL,
+ IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO);
+}
+
static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
int cmd,
struct snd_soc_dai *dai)
{
- int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
struct snd_soc_codec *codec = dai->codec;
- u32 val = 0;
+ struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
+ int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
/*
* This is a workaround, When stop playback,
@@ -295,20 +345,28 @@ static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (playback) {
+ snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
+ IC_HSLEN | IC_HSREN, 0);
+ sirf_audio_codec_tx_disable(sirf_audio_codec);
+ } else
+ sirf_audio_codec_rx_disable(sirf_audio_codec);
break;
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (playback)
- val = IC_HSLEN | IC_HSREN;
+ if (playback) {
+ sirf_audio_codec_tx_enable(sirf_audio_codec);
+ snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
+ IC_HSLEN | IC_HSREN, IC_HSLEN | IC_HSREN);
+ } else
+ sirf_audio_codec_rx_enable(sirf_audio_codec,
+ substream->runtime->channels);
break;
default:
return -EINVAL;
}
- if (playback)
- snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
- IC_HSLEN | IC_HSREN, val);
return 0;
}
@@ -392,7 +450,7 @@ static const struct regmap_config sirf_audio_codec_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
- .max_register = AUDIO_IC_CODEC_CTRL3,
+ .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK,
.cache_type = REGCACHE_NONE,
};
diff --git a/sound/soc/codecs/sirf-audio-codec.h b/sound/soc/codecs/sirf-audio-codec.h
index d4c187b8e54a..ba1adc03839f 100644
--- a/sound/soc/codecs/sirf-audio-codec.h
+++ b/sound/soc/codecs/sirf-audio-codec.h
@@ -72,4 +72,54 @@
#define IC_RXPGAR 0x7B
#define IC_RXPGAL 0x7B
+#define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK 0x3F
+#define AUDIO_PORT_TX_FIFO_SC_OFFSET 0
+#define AUDIO_PORT_TX_FIFO_LC_OFFSET 10
+#define AUDIO_PORT_TX_FIFO_HC_OFFSET 20
+
+#define TX_FIFO_SC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+ << AUDIO_PORT_TX_FIFO_SC_OFFSET)
+#define TX_FIFO_LC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+ << AUDIO_PORT_TX_FIFO_LC_OFFSET)
+#define TX_FIFO_HC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+ << AUDIO_PORT_TX_FIFO_HC_OFFSET)
+
+#define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK 0x0F
+#define AUDIO_PORT_RX_FIFO_SC_OFFSET 0
+#define AUDIO_PORT_RX_FIFO_LC_OFFSET 10
+#define AUDIO_PORT_RX_FIFO_HC_OFFSET 20
+
+#define RX_FIFO_SC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+ << AUDIO_PORT_RX_FIFO_SC_OFFSET)
+#define RX_FIFO_LC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+ << AUDIO_PORT_RX_FIFO_LC_OFFSET)
+#define RX_FIFO_HC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+ << AUDIO_PORT_RX_FIFO_HC_OFFSET)
+#define AUDIO_PORT_IC_CODEC_TX_CTRL (0x00F4)
+#define AUDIO_PORT_IC_CODEC_RX_CTRL (0x00F8)
+
+#define AUDIO_PORT_IC_TXFIFO_OP (0x00FC)
+#define AUDIO_PORT_IC_TXFIFO_LEV_CHK (0x0100)
+#define AUDIO_PORT_IC_TXFIFO_STS (0x0104)
+#define AUDIO_PORT_IC_TXFIFO_INT (0x0108)
+#define AUDIO_PORT_IC_TXFIFO_INT_MSK (0x010C)
+
+#define AUDIO_PORT_IC_RXFIFO_OP (0x0110)
+#define AUDIO_PORT_IC_RXFIFO_LEV_CHK (0x0114)
+#define AUDIO_PORT_IC_RXFIFO_STS (0x0118)
+#define AUDIO_PORT_IC_RXFIFO_INT (0x011C)
+#define AUDIO_PORT_IC_RXFIFO_INT_MSK (0x0120)
+
+#define AUDIO_FIFO_START (1 << 0)
+#define AUDIO_FIFO_RESET (1 << 1)
+
+#define AUDIO_FIFO_FULL (1 << 0)
+#define AUDIO_FIFO_EMPTY (1 << 1)
+#define AUDIO_FIFO_OFLOW (1 << 2)
+#define AUDIO_FIFO_UFLOW (1 << 3)
+
+#define IC_TX_ENABLE (0x03)
+#define IC_RX_ENABLE_MONO (0x01)
+#define IC_RX_ENABLE_STEREO (0x03)
+
#endif /*__SIRF_AUDIO_CODEC_H*/
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 12577749b17b..0579d187135b 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -243,7 +243,7 @@ static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol,
static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff;
unsigned int cfud;
@@ -272,7 +272,7 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff;
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
new file mode 100644
index 000000000000..cc97dd52aa9c
--- /dev/null
+++ b/sound/soc/codecs/sta350.c
@@ -0,0 +1,1311 @@
+/*
+ * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system
+ *
+ * Copyright: 2014 Raumfeld GmbH
+ * Author: Sven Brandau <info@brandau.biz>
+ *
+ * based on code from:
+ * Raumfeld GmbH
+ * Johannes Stezenbach <js@sig21.net>
+ * Wolfson Microelectronics PLC.
+ * Mark Brown <broonie@opensource.wolfsonmicro.com>
+ * Freescale Semiconductor, Inc.
+ * Timur Tabi <timur@freescale.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
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__
+
+#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/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/slab.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 <sound/sta350.h>
+#include "sta350.h"
+
+#define STA350_RATES (SNDRV_PCM_RATE_32000 | \
+ SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_88200 | \
+ SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_176400 | \
+ SNDRV_PCM_RATE_192000)
+
+#define STA350_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
+ SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
+
+/* Power-up register defaults */
+static const struct reg_default sta350_regs[] = {
+ { 0x0, 0x63 },
+ { 0x1, 0x80 },
+ { 0x2, 0xdf },
+ { 0x3, 0x40 },
+ { 0x4, 0xc2 },
+ { 0x5, 0x5c },
+ { 0x6, 0x00 },
+ { 0x7, 0xff },
+ { 0x8, 0x60 },
+ { 0x9, 0x60 },
+ { 0xa, 0x60 },
+ { 0xb, 0x00 },
+ { 0xc, 0x00 },
+ { 0xd, 0x00 },
+ { 0xe, 0x00 },
+ { 0xf, 0x40 },
+ { 0x10, 0x80 },
+ { 0x11, 0x77 },
+ { 0x12, 0x6a },
+ { 0x13, 0x69 },
+ { 0x14, 0x6a },
+ { 0x15, 0x69 },
+ { 0x16, 0x00 },
+ { 0x17, 0x00 },
+ { 0x18, 0x00 },
+ { 0x19, 0x00 },
+ { 0x1a, 0x00 },
+ { 0x1b, 0x00 },
+ { 0x1c, 0x00 },
+ { 0x1d, 0x00 },
+ { 0x1e, 0x00 },
+ { 0x1f, 0x00 },
+ { 0x20, 0x00 },
+ { 0x21, 0x00 },
+ { 0x22, 0x00 },
+ { 0x23, 0x00 },
+ { 0x24, 0x00 },
+ { 0x25, 0x00 },
+ { 0x26, 0x00 },
+ { 0x27, 0x2a },
+ { 0x28, 0xc0 },
+ { 0x29, 0xf3 },
+ { 0x2a, 0x33 },
+ { 0x2b, 0x00 },
+ { 0x2c, 0x0c },
+ { 0x31, 0x00 },
+ { 0x36, 0x00 },
+ { 0x37, 0x00 },
+ { 0x38, 0x00 },
+ { 0x39, 0x01 },
+ { 0x3a, 0xee },
+ { 0x3b, 0xff },
+ { 0x3c, 0x7e },
+ { 0x3d, 0xc0 },
+ { 0x3e, 0x26 },
+ { 0x3f, 0x00 },
+ { 0x48, 0x00 },
+ { 0x49, 0x00 },
+ { 0x4a, 0x00 },
+ { 0x4b, 0x04 },
+ { 0x4c, 0x00 },
+};
+
+static const struct regmap_range sta350_write_regs_range[] = {
+ regmap_reg_range(STA350_CONFA, STA350_AUTO2),
+ regmap_reg_range(STA350_C1CFG, STA350_FDRC2),
+ regmap_reg_range(STA350_EQCFG, STA350_EVOLRES),
+ regmap_reg_range(STA350_NSHAPE, STA350_MISC2),
+};
+
+static const struct regmap_range sta350_read_regs_range[] = {
+ regmap_reg_range(STA350_CONFA, STA350_AUTO2),
+ regmap_reg_range(STA350_C1CFG, STA350_STATUS),
+ regmap_reg_range(STA350_EQCFG, STA350_EVOLRES),
+ regmap_reg_range(STA350_NSHAPE, STA350_MISC2),
+};
+
+static const struct regmap_range sta350_volatile_regs_range[] = {
+ regmap_reg_range(STA350_CFADDR2, STA350_CFUD),
+ regmap_reg_range(STA350_STATUS, STA350_STATUS),
+};
+
+static const struct regmap_access_table sta350_write_regs = {
+ .yes_ranges = sta350_write_regs_range,
+ .n_yes_ranges = ARRAY_SIZE(sta350_write_regs_range),
+};
+
+static const struct regmap_access_table sta350_read_regs = {
+ .yes_ranges = sta350_read_regs_range,
+ .n_yes_ranges = ARRAY_SIZE(sta350_read_regs_range),
+};
+
+static const struct regmap_access_table sta350_volatile_regs = {
+ .yes_ranges = sta350_volatile_regs_range,
+ .n_yes_ranges = ARRAY_SIZE(sta350_volatile_regs_range),
+};
+
+/* regulator power supply names */
+static const char * const sta350_supply_names[] = {
+ "vdd-dig", /* digital supply, 3.3V */
+ "vdd-pll", /* pll supply, 3.3V */
+ "vcc" /* power amp supply, 5V - 26V */
+};
+
+/* codec private data */
+struct sta350_priv {
+ struct regmap *regmap;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(sta350_supply_names)];
+ struct sta350_platform_data *pdata;
+
+ unsigned int mclk;
+ unsigned int format;
+
+ u32 coef_shadow[STA350_COEF_COUNT];
+ int shutdown;
+
+ struct gpio_desc *gpiod_nreset;
+ struct gpio_desc *gpiod_power_down;
+
+ struct mutex coeff_lock;
+};
+
+static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1);
+static const DECLARE_TLV_DB_SCALE(tone_tlv, -1200, 200, 0);
+
+static const char * const sta350_drc_ac[] = {
+ "Anti-Clipping", "Dynamic Range Compression"
+};
+static const char * const sta350_auto_gc_mode[] = {
+ "User", "AC no clipping", "AC limited clipping (10%)",
+ "DRC nighttime listening mode"
+};
+static const char * const sta350_auto_xo_mode[] = {
+ "User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz",
+ "200Hz", "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz",
+ "340Hz", "360Hz"
+};
+static const char * const sta350_binary_output[] = {
+ "FFX 3-state output - normal operation", "Binary output"
+};
+static const char * const sta350_limiter_select[] = {
+ "Limiter Disabled", "Limiter #1", "Limiter #2"
+};
+static const char * const sta350_limiter_attack_rate[] = {
+ "3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024",
+ "0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752",
+ "0.0645", "0.0564", "0.0501", "0.0451"
+};
+static const char * const sta350_limiter_release_rate[] = {
+ "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
+ "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
+ "0.0134", "0.0117", "0.0110", "0.0104"
+};
+static const char * const sta350_noise_shaper_type[] = {
+ "Third order", "Fourth order"
+};
+
+static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_attack_tlv,
+ 0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+ 8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
+);
+
+static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_release_tlv,
+ 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+ 1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
+ 3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
+ 8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
+);
+
+static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_attack_tlv,
+ 0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
+ 8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
+ 14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
+);
+
+static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_release_tlv,
+ 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+ 1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
+ 3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
+ 5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
+ 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
+);
+
+static SOC_ENUM_SINGLE_DECL(sta350_drc_ac_enum,
+ STA350_CONFD, STA350_CONFD_DRC_SHIFT,
+ sta350_drc_ac);
+static SOC_ENUM_SINGLE_DECL(sta350_noise_shaper_enum,
+ STA350_CONFE, STA350_CONFE_NSBW_SHIFT,
+ sta350_noise_shaper_type);
+static SOC_ENUM_SINGLE_DECL(sta350_auto_gc_enum,
+ STA350_AUTO1, STA350_AUTO1_AMGC_SHIFT,
+ sta350_auto_gc_mode);
+static SOC_ENUM_SINGLE_DECL(sta350_auto_xo_enum,
+ STA350_AUTO2, STA350_AUTO2_XO_SHIFT,
+ sta350_auto_xo_mode);
+static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch1_enum,
+ STA350_C1CFG, STA350_CxCFG_BO_SHIFT,
+ sta350_binary_output);
+static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch2_enum,
+ STA350_C2CFG, STA350_CxCFG_BO_SHIFT,
+ sta350_binary_output);
+static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch3_enum,
+ STA350_C3CFG, STA350_CxCFG_BO_SHIFT,
+ sta350_binary_output);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch1_enum,
+ STA350_C1CFG, STA350_CxCFG_LS_SHIFT,
+ sta350_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch2_enum,
+ STA350_C2CFG, STA350_CxCFG_LS_SHIFT,
+ sta350_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch3_enum,
+ STA350_C3CFG, STA350_CxCFG_LS_SHIFT,
+ sta350_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter1_attack_rate_enum,
+ STA350_L1AR, STA350_LxA_SHIFT,
+ sta350_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter2_attack_rate_enum,
+ STA350_L2AR, STA350_LxA_SHIFT,
+ sta350_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter1_release_rate_enum,
+ STA350_L1AR, STA350_LxR_SHIFT,
+ sta350_limiter_release_rate);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter2_release_rate_enum,
+ STA350_L2AR, STA350_LxR_SHIFT,
+ sta350_limiter_release_rate);
+
+/*
+ * byte array controls for setting biquad, mixer, scaling coefficients;
+ * for biquads all five coefficients need to be set in one go,
+ * mixer and pre/postscale coefs can be set individually;
+ * each coef is 24bit, the bytes are ordered in the same way
+ * as given in the STA350 data sheet (big endian; b1, b2, a1, a2, b0)
+ */
+
+static int sta350_coefficient_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int numcoef = kcontrol->private_value >> 16;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = 3 * numcoef;
+ return 0;
+}
+
+static int sta350_coefficient_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+ int numcoef = kcontrol->private_value >> 16;
+ int index = kcontrol->private_value & 0xffff;
+ unsigned int cfud, val;
+ int i, ret = 0;
+
+ mutex_lock(&sta350->coeff_lock);
+
+ /* preserve reserved bits in STA350_CFUD */
+ regmap_read(sta350->regmap, STA350_CFUD, &cfud);
+ cfud &= 0xf0;
+ /*
+ * chip documentation does not say if the bits are self clearing,
+ * so do it explicitly
+ */
+ regmap_write(sta350->regmap, STA350_CFUD, cfud);
+
+ regmap_write(sta350->regmap, STA350_CFADDR2, index);
+ if (numcoef == 1) {
+ regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x04);
+ } else if (numcoef == 5) {
+ regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x08);
+ } else {
+ ret = -EINVAL;
+ goto exit_unlock;
+ }
+
+ for (i = 0; i < 3 * numcoef; i++) {
+ regmap_read(sta350->regmap, STA350_B1CF1 + i, &val);
+ ucontrol->value.bytes.data[i] = val;
+ }
+
+exit_unlock:
+ mutex_unlock(&sta350->coeff_lock);
+
+ return ret;
+}
+
+static int sta350_coefficient_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+ int numcoef = kcontrol->private_value >> 16;
+ int index = kcontrol->private_value & 0xffff;
+ unsigned int cfud;
+ int i;
+
+ /* preserve reserved bits in STA350_CFUD */
+ regmap_read(sta350->regmap, STA350_CFUD, &cfud);
+ cfud &= 0xf0;
+ /*
+ * chip documentation does not say if the bits are self clearing,
+ * so do it explicitly
+ */
+ regmap_write(sta350->regmap, STA350_CFUD, cfud);
+
+ regmap_write(sta350->regmap, STA350_CFADDR2, index);
+ for (i = 0; i < numcoef && (index + i < STA350_COEF_COUNT); i++)
+ sta350->coef_shadow[index + i] =
+ (ucontrol->value.bytes.data[3 * i] << 16)
+ | (ucontrol->value.bytes.data[3 * i + 1] << 8)
+ | (ucontrol->value.bytes.data[3 * i + 2]);
+ for (i = 0; i < 3 * numcoef; i++)
+ regmap_write(sta350->regmap, STA350_B1CF1 + i,
+ ucontrol->value.bytes.data[i]);
+ if (numcoef == 1)
+ regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x01);
+ else if (numcoef == 5)
+ regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x02);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sta350_sync_coef_shadow(struct snd_soc_codec *codec)
+{
+ struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+ unsigned int cfud;
+ int i;
+
+ /* preserve reserved bits in STA350_CFUD */
+ regmap_read(sta350->regmap, STA350_CFUD, &cfud);
+ cfud &= 0xf0;
+
+ for (i = 0; i < STA350_COEF_COUNT; i++) {
+ regmap_write(sta350->regmap, STA350_CFADDR2, i);
+ regmap_write(sta350->regmap, STA350_B1CF1,
+ (sta350->coef_shadow[i] >> 16) & 0xff);
+ regmap_write(sta350->regmap, STA350_B1CF2,
+ (sta350->coef_shadow[i] >> 8) & 0xff);
+ regmap_write(sta350->regmap, STA350_B1CF3,
+ (sta350->coef_shadow[i]) & 0xff);
+ /*
+ * chip documentation does not say if the bits are
+ * self-clearing, so do it explicitly
+ */
+ regmap_write(sta350->regmap, STA350_CFUD, cfud);
+ regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x01);
+ }
+ return 0;
+}
+
+static int sta350_cache_sync(struct snd_soc_codec *codec)
+{
+ struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+ unsigned int mute;
+ int rc;
+
+ /* mute during register sync */
+ regmap_read(sta350->regmap, STA350_CFUD, &mute);
+ regmap_write(sta350->regmap, STA350_MMUTE, mute | STA350_MMUTE_MMUTE);
+ sta350_sync_coef_shadow(codec);
+ rc = regcache_sync(sta350->regmap);
+ regmap_write(sta350->regmap, STA350_MMUTE, mute);
+ return rc;
+}
+
+#define SINGLE_COEF(xname, index) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = sta350_coefficient_info, \
+ .get = sta350_coefficient_get,\
+ .put = sta350_coefficient_put, \
+ .private_value = index | (1 << 16) }
+
+#define BIQUAD_COEFS(xname, index) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = sta350_coefficient_info, \
+ .get = sta350_coefficient_get,\
+ .put = sta350_coefficient_put, \
+ .private_value = index | (5 << 16) }
+
+static const struct snd_kcontrol_new sta350_snd_controls[] = {
+SOC_SINGLE_TLV("Master Volume", STA350_MVOL, 0, 0xff, 1, mvol_tlv),
+/* VOL */
+SOC_SINGLE_TLV("Ch1 Volume", STA350_C1VOL, 0, 0xff, 1, chvol_tlv),
+SOC_SINGLE_TLV("Ch2 Volume", STA350_C2VOL, 0, 0xff, 1, chvol_tlv),
+SOC_SINGLE_TLV("Ch3 Volume", STA350_C3VOL, 0, 0xff, 1, chvol_tlv),
+/* CONFD */
+SOC_SINGLE("High Pass Filter Bypass Switch",
+ STA350_CONFD, STA350_CONFD_HPB_SHIFT, 1, 1),
+SOC_SINGLE("De-emphasis Filter Switch",
+ STA350_CONFD, STA350_CONFD_DEMP_SHIFT, 1, 0),
+SOC_SINGLE("DSP Bypass Switch",
+ STA350_CONFD, STA350_CONFD_DSPB_SHIFT, 1, 0),
+SOC_SINGLE("Post-scale Link Switch",
+ STA350_CONFD, STA350_CONFD_PSL_SHIFT, 1, 0),
+SOC_SINGLE("Biquad Coefficient Link Switch",
+ STA350_CONFD, STA350_CONFD_BQL_SHIFT, 1, 0),
+SOC_ENUM("Compressor/Limiter Switch", sta350_drc_ac_enum),
+SOC_ENUM("Noise Shaper Bandwidth", sta350_noise_shaper_enum),
+SOC_SINGLE("Zero-detect Mute Enable Switch",
+ STA350_CONFD, STA350_CONFD_ZDE_SHIFT, 1, 0),
+SOC_SINGLE("Submix Mode Switch",
+ STA350_CONFD, STA350_CONFD_SME_SHIFT, 1, 0),
+/* CONFE */
+SOC_SINGLE("Zero Cross Switch", STA350_CONFE, STA350_CONFE_ZCE_SHIFT, 1, 0),
+SOC_SINGLE("Soft Ramp Switch", STA350_CONFE, STA350_CONFE_SVE_SHIFT, 1, 0),
+/* MUTE */
+SOC_SINGLE("Master Switch", STA350_MMUTE, STA350_MMUTE_MMUTE_SHIFT, 1, 1),
+SOC_SINGLE("Ch1 Switch", STA350_MMUTE, STA350_MMUTE_C1M_SHIFT, 1, 1),
+SOC_SINGLE("Ch2 Switch", STA350_MMUTE, STA350_MMUTE_C2M_SHIFT, 1, 1),
+SOC_SINGLE("Ch3 Switch", STA350_MMUTE, STA350_MMUTE_C3M_SHIFT, 1, 1),
+/* AUTOx */
+SOC_ENUM("Automode GC", sta350_auto_gc_enum),
+SOC_ENUM("Automode XO", sta350_auto_xo_enum),
+/* CxCFG */
+SOC_SINGLE("Ch1 Tone Control Bypass Switch",
+ STA350_C1CFG, STA350_CxCFG_TCB_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 Tone Control Bypass Switch",
+ STA350_C2CFG, STA350_CxCFG_TCB_SHIFT, 1, 0),
+SOC_SINGLE("Ch1 EQ Bypass Switch",
+ STA350_C1CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 EQ Bypass Switch",
+ STA350_C2CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch1 Master Volume Bypass Switch",
+ STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 Master Volume Bypass Switch",
+ STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch3 Master Volume Bypass Switch",
+ STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0),
+SOC_ENUM("Ch1 Binary Output Select", sta350_binary_output_ch1_enum),
+SOC_ENUM("Ch2 Binary Output Select", sta350_binary_output_ch2_enum),
+SOC_ENUM("Ch3 Binary Output Select", sta350_binary_output_ch3_enum),
+SOC_ENUM("Ch1 Limiter Select", sta350_limiter_ch1_enum),
+SOC_ENUM("Ch2 Limiter Select", sta350_limiter_ch2_enum),
+SOC_ENUM("Ch3 Limiter Select", sta350_limiter_ch3_enum),
+/* TONE */
+SOC_SINGLE_RANGE_TLV("Bass Tone Control Volume",
+ STA350_TONE, STA350_TONE_BTC_SHIFT, 1, 13, 0, tone_tlv),
+SOC_SINGLE_RANGE_TLV("Treble Tone Control Volume",
+ STA350_TONE, STA350_TONE_TTC_SHIFT, 1, 13, 0, tone_tlv),
+SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta350_limiter1_attack_rate_enum),
+SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta350_limiter2_attack_rate_enum),
+SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta350_limiter1_release_rate_enum),
+SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta350_limiter2_release_rate_enum),
+
+/*
+ * depending on mode, the attack/release thresholds have
+ * two different enum definitions; provide both
+ */
+SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)",
+ STA350_L1ATRT, STA350_LxA_SHIFT,
+ 16, 0, sta350_limiter_ac_attack_tlv),
+SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)",
+ STA350_L2ATRT, STA350_LxA_SHIFT,
+ 16, 0, sta350_limiter_ac_attack_tlv),
+SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)",
+ STA350_L1ATRT, STA350_LxR_SHIFT,
+ 16, 0, sta350_limiter_ac_release_tlv),
+SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)",
+ STA350_L2ATRT, STA350_LxR_SHIFT,
+ 16, 0, sta350_limiter_ac_release_tlv),
+SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)",
+ STA350_L1ATRT, STA350_LxA_SHIFT,
+ 16, 0, sta350_limiter_drc_attack_tlv),
+SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)",
+ STA350_L2ATRT, STA350_LxA_SHIFT,
+ 16, 0, sta350_limiter_drc_attack_tlv),
+SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)",
+ STA350_L1ATRT, STA350_LxR_SHIFT,
+ 16, 0, sta350_limiter_drc_release_tlv),
+SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)",
+ STA350_L2ATRT, STA350_LxR_SHIFT,
+ 16, 0, sta350_limiter_drc_release_tlv),
+
+BIQUAD_COEFS("Ch1 - Biquad 1", 0),
+BIQUAD_COEFS("Ch1 - Biquad 2", 5),
+BIQUAD_COEFS("Ch1 - Biquad 3", 10),
+BIQUAD_COEFS("Ch1 - Biquad 4", 15),
+BIQUAD_COEFS("Ch2 - Biquad 1", 20),
+BIQUAD_COEFS("Ch2 - Biquad 2", 25),
+BIQUAD_COEFS("Ch2 - Biquad 3", 30),
+BIQUAD_COEFS("Ch2 - Biquad 4", 35),
+BIQUAD_COEFS("High-pass", 40),
+BIQUAD_COEFS("Low-pass", 45),
+SINGLE_COEF("Ch1 - Prescale", 50),
+SINGLE_COEF("Ch2 - Prescale", 51),
+SINGLE_COEF("Ch1 - Postscale", 52),
+SINGLE_COEF("Ch2 - Postscale", 53),
+SINGLE_COEF("Ch3 - Postscale", 54),
+SINGLE_COEF("Thermal warning - Postscale", 55),
+SINGLE_COEF("Ch1 - Mix 1", 56),
+SINGLE_COEF("Ch1 - Mix 2", 57),
+SINGLE_COEF("Ch2 - Mix 1", 58),
+SINGLE_COEF("Ch2 - Mix 2", 59),
+SINGLE_COEF("Ch3 - Mix 1", 60),
+SINGLE_COEF("Ch3 - Mix 2", 61),
+};
+
+static const struct snd_soc_dapm_widget sta350_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_OUTPUT("LEFT"),
+SND_SOC_DAPM_OUTPUT("RIGHT"),
+SND_SOC_DAPM_OUTPUT("SUB"),
+};
+
+static const struct snd_soc_dapm_route sta350_dapm_routes[] = {
+ { "LEFT", NULL, "DAC" },
+ { "RIGHT", NULL, "DAC" },
+ { "SUB", NULL, "DAC" },
+ { "DAC", NULL, "Playback" },
+};
+
+/* MCLK interpolation ratio per fs */
+static struct {
+ int fs;
+ int ir;
+} interpolation_ratios[] = {
+ { 32000, 0 },
+ { 44100, 0 },
+ { 48000, 0 },
+ { 88200, 1 },
+ { 96000, 1 },
+ { 176400, 2 },
+ { 192000, 2 },
+};
+
+/* MCLK to fs clock ratios */
+static int mcs_ratio_table[3][6] = {
+ { 768, 512, 384, 256, 128, 576 },
+ { 384, 256, 192, 128, 64, 0 },
+ { 192, 128, 96, 64, 32, 0 },
+};
+
+/**
+ * sta350_set_dai_sysclk - configure MCLK
+ * @codec_dai: the codec DAI
+ * @clk_id: the clock ID (ignored)
+ * @freq: the MCLK input frequency
+ * @dir: the clock direction (ignored)
+ *
+ * The value of MCLK is used to determine which sample rates are supported
+ * by the STA350, based on the mcs_ratio_table.
+ *
+ * This function must be called by the machine driver's 'startup' function,
+ * otherwise the list of supported sample rates will not be available in
+ * time for ALSA.
+ */
+static int sta350_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 sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "mclk=%u\n", freq);
+ sta350->mclk = freq;
+
+ return 0;
+}
+
+/**
+ * sta350_set_dai_fmt - configure the codec for the selected audio format
+ * @codec_dai: the codec DAI
+ * @fmt: a SND_SOC_DAIFMT_x value indicating the data format
+ *
+ * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
+ * codec accordingly.
+ */
+static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+ unsigned int confb = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_LEFT_J:
+ sta350->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ confb |= STA350_CONFB_C2IM;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ confb |= STA350_CONFB_C1IM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(sta350->regmap, STA350_CONFB,
+ STA350_CONFB_C1IM | STA350_CONFB_C2IM, confb);
+}
+
+/**
+ * sta350_hw_params - program the STA350 with the given hardware parameters.
+ * @substream: the audio stream
+ * @params: the hardware parameters to set
+ * @dai: the SOC DAI (ignored)
+ *
+ * This function programs the hardware with the values provided.
+ * Specifically, the sample rate and the data format.
+ */
+static int sta350_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 sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+ int i, mcs = -EINVAL, ir = -EINVAL;
+ unsigned int confa, confb;
+ unsigned int rate, ratio;
+ int ret;
+
+ if (!sta350->mclk) {
+ dev_err(codec->dev,
+ "sta350->mclk is unset. Unable to determine ratio\n");
+ return -EIO;
+ }
+
+ rate = params_rate(params);
+ ratio = sta350->mclk / rate;
+ dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio);
+
+ for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
+ if (interpolation_ratios[i].fs == rate) {
+ ir = interpolation_ratios[i].ir;
+ break;
+ }
+ }
+
+ if (ir < 0) {
+ dev_err(codec->dev, "Unsupported samplerate: %u\n", rate);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 6; i++) {
+ if (mcs_ratio_table[ir][i] == ratio) {
+ mcs = i;
+ break;
+ }
+ }
+
+ if (mcs < 0) {
+ dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio);
+ return -EINVAL;
+ }
+
+ confa = (ir << STA350_CONFA_IR_SHIFT) |
+ (mcs << STA350_CONFA_MCS_SHIFT);
+ confb = 0;
+
+ switch (params_width(params)) {
+ case 24:
+ dev_dbg(codec->dev, "24bit\n");
+ /* fall through */
+ case 32:
+ dev_dbg(codec->dev, "24bit or 32bit\n");
+ switch (sta350->format) {
+ case SND_SOC_DAIFMT_I2S:
+ confb |= 0x0;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ confb |= 0x1;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ confb |= 0x2;
+ break;
+ }
+
+ break;
+ case 20:
+ dev_dbg(codec->dev, "20bit\n");
+ switch (sta350->format) {
+ case SND_SOC_DAIFMT_I2S:
+ confb |= 0x4;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ confb |= 0x5;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ confb |= 0x6;
+ break;
+ }
+
+ break;
+ case 18:
+ dev_dbg(codec->dev, "18bit\n");
+ switch (sta350->format) {
+ case SND_SOC_DAIFMT_I2S:
+ confb |= 0x8;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ confb |= 0x9;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ confb |= 0xa;
+ break;
+ }
+
+ break;
+ case 16:
+ dev_dbg(codec->dev, "16bit\n");
+ switch (sta350->format) {
+ case SND_SOC_DAIFMT_I2S:
+ confb |= 0x0;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ confb |= 0xd;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ confb |= 0xe;
+ break;
+ }
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(sta350->regmap, STA350_CONFA,
+ STA350_CONFA_MCS_MASK | STA350_CONFA_IR_MASK,
+ confa);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(sta350->regmap, STA350_CONFB,
+ STA350_CONFB_SAI_MASK | STA350_CONFB_SAIFB,
+ confb);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int sta350_startup_sequence(struct sta350_priv *sta350)
+{
+ if (sta350->gpiod_power_down)
+ gpiod_set_value(sta350->gpiod_power_down, 1);
+
+ if (sta350->gpiod_nreset) {
+ gpiod_set_value(sta350->gpiod_nreset, 0);
+ mdelay(1);
+ gpiod_set_value(sta350->gpiod_nreset, 1);
+ mdelay(1);
+ }
+
+ return 0;
+}
+
+/**
+ * sta350_set_bias_level - DAPM callback
+ * @codec: the codec device
+ * @level: DAPM power level
+ *
+ * This is called by ALSA to put the codec into low power mode
+ * or to wake it up. If the codec is powered off completely
+ * all registers must be restored after power on.
+ */
+static int sta350_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ dev_dbg(codec->dev, "level = %d\n", level);
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ /* Full power on */
+ regmap_update_bits(sta350->regmap, STA350_CONFF,
+ STA350_CONFF_PWDN | STA350_CONFF_EAPD,
+ STA350_CONFF_PWDN | STA350_CONFF_EAPD);
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ ret = regulator_bulk_enable(
+ ARRAY_SIZE(sta350->supplies),
+ sta350->supplies);
+ if (ret < 0) {
+ dev_err(codec->dev,
+ "Failed to enable supplies: %d\n",
+ ret);
+ return ret;
+ }
+ sta350_startup_sequence(sta350);
+ sta350_cache_sync(codec);
+ }
+
+ /* Power down */
+ regmap_update_bits(sta350->regmap, STA350_CONFF,
+ STA350_CONFF_PWDN | STA350_CONFF_EAPD,
+ 0);
+
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ /* The chip runs through the power down sequence for us */
+ regmap_update_bits(sta350->regmap, STA350_CONFF,
+ STA350_CONFF_PWDN | STA350_CONFF_EAPD, 0);
+
+ /* power down: low */
+ if (sta350->gpiod_power_down)
+ gpiod_set_value(sta350->gpiod_power_down, 0);
+
+ if (sta350->gpiod_nreset)
+ gpiod_set_value(sta350->gpiod_nreset, 0);
+
+ regulator_bulk_disable(ARRAY_SIZE(sta350->supplies),
+ sta350->supplies);
+ break;
+ }
+ codec->dapm.bias_level = level;
+ return 0;
+}
+
+static const struct snd_soc_dai_ops sta350_dai_ops = {
+ .hw_params = sta350_hw_params,
+ .set_sysclk = sta350_set_dai_sysclk,
+ .set_fmt = sta350_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver sta350_dai = {
+ .name = "sta350-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = STA350_RATES,
+ .formats = STA350_FORMATS,
+ },
+ .ops = &sta350_dai_ops,
+};
+
+#ifdef CONFIG_PM
+static int sta350_suspend(struct snd_soc_codec *codec)
+{
+ sta350_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int sta350_resume(struct snd_soc_codec *codec)
+{
+ sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+}
+#else
+#define sta350_suspend NULL
+#define sta350_resume NULL
+#endif
+
+static int sta350_probe(struct snd_soc_codec *codec)
+{
+ struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+ struct sta350_platform_data *pdata = sta350->pdata;
+ int i, ret = 0, thermal = 0;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(sta350->supplies),
+ sta350->supplies);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = sta350_startup_sequence(sta350);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to startup device\n");
+ return ret;
+ }
+
+ /* CONFA */
+ if (!pdata->thermal_warning_recovery)
+ thermal |= STA350_CONFA_TWAB;
+ if (!pdata->thermal_warning_adjustment)
+ thermal |= STA350_CONFA_TWRB;
+ if (!pdata->fault_detect_recovery)
+ thermal |= STA350_CONFA_FDRB;
+ regmap_update_bits(sta350->regmap, STA350_CONFA,
+ STA350_CONFA_TWAB | STA350_CONFA_TWRB |
+ STA350_CONFA_FDRB,
+ thermal);
+
+ /* CONFC */
+ regmap_update_bits(sta350->regmap, STA350_CONFC,
+ STA350_CONFC_OM_MASK,
+ pdata->ffx_power_output_mode
+ << STA350_CONFC_OM_SHIFT);
+ regmap_update_bits(sta350->regmap, STA350_CONFC,
+ STA350_CONFC_CSZ_MASK,
+ pdata->drop_compensation_ns
+ << STA350_CONFC_CSZ_SHIFT);
+ regmap_update_bits(sta350->regmap,
+ STA350_CONFC,
+ STA350_CONFC_OCRB,
+ pdata->oc_warning_adjustment ?
+ STA350_CONFC_OCRB : 0);
+
+ /* CONFE */
+ regmap_update_bits(sta350->regmap, STA350_CONFE,
+ STA350_CONFE_MPCV,
+ pdata->max_power_use_mpcc ?
+ STA350_CONFE_MPCV : 0);
+ regmap_update_bits(sta350->regmap, STA350_CONFE,
+ STA350_CONFE_MPC,
+ pdata->max_power_correction ?
+ STA350_CONFE_MPC : 0);
+ regmap_update_bits(sta350->regmap, STA350_CONFE,
+ STA350_CONFE_AME,
+ pdata->am_reduction_mode ?
+ STA350_CONFE_AME : 0);
+ regmap_update_bits(sta350->regmap, STA350_CONFE,
+ STA350_CONFE_PWMS,
+ pdata->odd_pwm_speed_mode ?
+ STA350_CONFE_PWMS : 0);
+ regmap_update_bits(sta350->regmap, STA350_CONFE,
+ STA350_CONFE_DCCV,
+ pdata->distortion_compensation ?
+ STA350_CONFE_DCCV : 0);
+ /* CONFF */
+ regmap_update_bits(sta350->regmap, STA350_CONFF,
+ STA350_CONFF_IDE,
+ pdata->invalid_input_detect_mute ?
+ STA350_CONFF_IDE : 0);
+ regmap_update_bits(sta350->regmap, STA350_CONFF,
+ STA350_CONFF_OCFG_MASK,
+ pdata->output_conf
+ << STA350_CONFF_OCFG_SHIFT);
+
+ /* channel to output mapping */
+ regmap_update_bits(sta350->regmap, STA350_C1CFG,
+ STA350_CxCFG_OM_MASK,
+ pdata->ch1_output_mapping
+ << STA350_CxCFG_OM_SHIFT);
+ regmap_update_bits(sta350->regmap, STA350_C2CFG,
+ STA350_CxCFG_OM_MASK,
+ pdata->ch2_output_mapping
+ << STA350_CxCFG_OM_SHIFT);
+ regmap_update_bits(sta350->regmap, STA350_C3CFG,
+ STA350_CxCFG_OM_MASK,
+ pdata->ch3_output_mapping
+ << STA350_CxCFG_OM_SHIFT);
+
+ /* miscellaneous registers */
+ regmap_update_bits(sta350->regmap, STA350_MISC1,
+ STA350_MISC1_CPWMEN,
+ pdata->activate_mute_output ?
+ STA350_MISC1_CPWMEN : 0);
+ regmap_update_bits(sta350->regmap, STA350_MISC1,
+ STA350_MISC1_BRIDGOFF,
+ pdata->bridge_immediate_off ?
+ STA350_MISC1_BRIDGOFF : 0);
+ regmap_update_bits(sta350->regmap, STA350_MISC1,
+ STA350_MISC1_NSHHPEN,
+ pdata->noise_shape_dc_cut ?
+ STA350_MISC1_NSHHPEN : 0);
+ regmap_update_bits(sta350->regmap, STA350_MISC1,
+ STA350_MISC1_RPDNEN,
+ pdata->powerdown_master_vol ?
+ STA350_MISC1_RPDNEN: 0);
+
+ regmap_update_bits(sta350->regmap, STA350_MISC2,
+ STA350_MISC2_PNDLSL_MASK,
+ pdata->powerdown_delay_divider
+ << STA350_MISC2_PNDLSL_SHIFT);
+
+ /* initialize coefficient shadow RAM with reset values */
+ for (i = 4; i <= 49; i += 5)
+ sta350->coef_shadow[i] = 0x400000;
+ for (i = 50; i <= 54; i++)
+ sta350->coef_shadow[i] = 0x7fffff;
+ sta350->coef_shadow[55] = 0x5a9df7;
+ sta350->coef_shadow[56] = 0x7fffff;
+ sta350->coef_shadow[59] = 0x7fffff;
+ sta350->coef_shadow[60] = 0x400000;
+ sta350->coef_shadow[61] = 0x400000;
+
+ sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ /* Bias level configuration will have done an extra enable */
+ regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
+
+ return 0;
+}
+
+static int sta350_remove(struct snd_soc_codec *codec)
+{
+ struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
+
+ sta350_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
+
+ return 0;
+}
+
+static const struct snd_soc_codec_driver sta350_codec = {
+ .probe = sta350_probe,
+ .remove = sta350_remove,
+ .suspend = sta350_suspend,
+ .resume = sta350_resume,
+ .set_bias_level = sta350_set_bias_level,
+ .controls = sta350_snd_controls,
+ .num_controls = ARRAY_SIZE(sta350_snd_controls),
+ .dapm_widgets = sta350_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sta350_dapm_widgets),
+ .dapm_routes = sta350_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(sta350_dapm_routes),
+};
+
+static const struct regmap_config sta350_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = STA350_MISC2,
+ .reg_defaults = sta350_regs,
+ .num_reg_defaults = ARRAY_SIZE(sta350_regs),
+ .cache_type = REGCACHE_RBTREE,
+ .wr_table = &sta350_write_regs,
+ .rd_table = &sta350_read_regs,
+ .volatile_table = &sta350_volatile_regs,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id st350_dt_ids[] = {
+ { .compatible = "st,sta350", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, st350_dt_ids);
+
+static const char * const sta350_ffx_modes[] = {
+ [STA350_FFX_PM_DROP_COMP] = "drop-compensation",
+ [STA350_FFX_PM_TAPERED_COMP] = "tapered-compensation",
+ [STA350_FFX_PM_FULL_POWER] = "full-power-mode",
+ [STA350_FFX_PM_VARIABLE_DROP_COMP] = "variable-drop-compensation",
+};
+
+static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350)
+{
+ struct device_node *np = dev->of_node;
+ struct sta350_platform_data *pdata;
+ const char *ffx_power_mode;
+ u16 tmp;
+ u8 tmp8;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ of_property_read_u8(np, "st,output-conf",
+ &pdata->output_conf);
+ of_property_read_u8(np, "st,ch1-output-mapping",
+ &pdata->ch1_output_mapping);
+ of_property_read_u8(np, "st,ch2-output-mapping",
+ &pdata->ch2_output_mapping);
+ of_property_read_u8(np, "st,ch3-output-mapping",
+ &pdata->ch3_output_mapping);
+
+ if (of_get_property(np, "st,thermal-warning-recovery", NULL))
+ pdata->thermal_warning_recovery = 1;
+ if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
+ pdata->thermal_warning_adjustment = 1;
+ if (of_get_property(np, "st,fault-detect-recovery", NULL))
+ pdata->fault_detect_recovery = 1;
+
+ pdata->ffx_power_output_mode = STA350_FFX_PM_VARIABLE_DROP_COMP;
+ if (!of_property_read_string(np, "st,ffx-power-output-mode",
+ &ffx_power_mode)) {
+ int i, mode = -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(sta350_ffx_modes); i++)
+ if (!strcasecmp(ffx_power_mode, sta350_ffx_modes[i]))
+ mode = i;
+
+ if (mode < 0)
+ dev_warn(dev, "Unsupported ffx output mode: %s\n",
+ ffx_power_mode);
+ else
+ pdata->ffx_power_output_mode = mode;
+ }
+
+ tmp = 140;
+ of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
+ pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
+
+ if (of_get_property(np, "st,overcurrent-warning-adjustment", NULL))
+ pdata->oc_warning_adjustment = 1;
+
+ /* CONFE */
+ if (of_get_property(np, "st,max-power-use-mpcc", NULL))
+ pdata->max_power_use_mpcc = 1;
+
+ if (of_get_property(np, "st,max-power-correction", NULL))
+ pdata->max_power_correction = 1;
+
+ if (of_get_property(np, "st,am-reduction-mode", NULL))
+ pdata->am_reduction_mode = 1;
+
+ if (of_get_property(np, "st,odd-pwm-speed-mode", NULL))
+ pdata->odd_pwm_speed_mode = 1;
+
+ if (of_get_property(np, "st,distortion-compensation", NULL))
+ pdata->distortion_compensation = 1;
+
+ /* CONFF */
+ if (of_get_property(np, "st,invalid-input-detect-mute", NULL))
+ pdata->invalid_input_detect_mute = 1;
+
+ /* MISC */
+ if (of_get_property(np, "st,activate-mute-output", NULL))
+ pdata->activate_mute_output = 1;
+
+ if (of_get_property(np, "st,bridge-immediate-off", NULL))
+ pdata->bridge_immediate_off = 1;
+
+ if (of_get_property(np, "st,noise-shape-dc-cut", NULL))
+ pdata->noise_shape_dc_cut = 1;
+
+ if (of_get_property(np, "st,powerdown-master-volume", NULL))
+ pdata->powerdown_master_vol = 1;
+
+ if (!of_property_read_u8(np, "st,powerdown-delay-divider", &tmp8)) {
+ if (is_power_of_2(tmp8) && tmp8 >= 1 && tmp8 <= 128)
+ pdata->powerdown_delay_divider = ilog2(tmp8);
+ else
+ dev_warn(dev, "Unsupported powerdown delay divider %d\n",
+ tmp8);
+ }
+
+ sta350->pdata = pdata;
+
+ return 0;
+}
+#endif
+
+static int sta350_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &i2c->dev;
+ struct sta350_priv *sta350;
+ int ret, i;
+
+ sta350 = devm_kzalloc(dev, sizeof(struct sta350_priv), GFP_KERNEL);
+ if (!sta350)
+ return -ENOMEM;
+
+ mutex_init(&sta350->coeff_lock);
+ sta350->pdata = dev_get_platdata(dev);
+
+#ifdef CONFIG_OF
+ if (dev->of_node) {
+ ret = sta350_probe_dt(dev, sta350);
+ if (ret < 0)
+ return ret;
+ }
+#endif
+
+ /* GPIOs */
+ sta350->gpiod_nreset = devm_gpiod_get(dev, "reset");
+ if (IS_ERR(sta350->gpiod_nreset)) {
+ ret = PTR_ERR(sta350->gpiod_nreset);
+ if (ret != -ENOENT && ret != -ENOSYS)
+ return ret;
+
+ sta350->gpiod_nreset = NULL;
+ } else {
+ gpiod_direction_output(sta350->gpiod_nreset, 0);
+ }
+
+ sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down");
+ if (IS_ERR(sta350->gpiod_power_down)) {
+ ret = PTR_ERR(sta350->gpiod_power_down);
+ if (ret != -ENOENT && ret != -ENOSYS)
+ return ret;
+
+ sta350->gpiod_power_down = NULL;
+ } else {
+ gpiod_direction_output(sta350->gpiod_power_down, 0);
+ }
+
+ /* regulators */
+ for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++)
+ sta350->supplies[i].supply = sta350_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sta350->supplies),
+ sta350->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ sta350->regmap = devm_regmap_init_i2c(i2c, &sta350_regmap);
+ if (IS_ERR(sta350->regmap)) {
+ ret = PTR_ERR(sta350->regmap);
+ dev_err(dev, "Failed to init regmap: %d\n", ret);
+ return ret;
+ }
+
+ i2c_set_clientdata(i2c, sta350);
+
+ ret = snd_soc_register_codec(dev, &sta350_codec, &sta350_dai, 1);
+ if (ret < 0)
+ dev_err(dev, "Failed to register codec (%d)\n", ret);
+
+ return ret;
+}
+
+static int sta350_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id sta350_i2c_id[] = {
+ { "sta350", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sta350_i2c_id);
+
+static struct i2c_driver sta350_i2c_driver = {
+ .driver = {
+ .name = "sta350",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(st350_dt_ids),
+ },
+ .probe = sta350_i2c_probe,
+ .remove = sta350_i2c_remove,
+ .id_table = sta350_i2c_id,
+};
+
+module_i2c_driver(sta350_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC STA350 driver");
+MODULE_AUTHOR("Sven Brandau <info@brandau.biz>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sta350.h b/sound/soc/codecs/sta350.h
new file mode 100644
index 000000000000..fb7285290779
--- /dev/null
+++ b/sound/soc/codecs/sta350.h
@@ -0,0 +1,238 @@
+/*
+ * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system
+ *
+ * Copyright: 2011 Raumfeld GmbH
+ * Author: Sven Brandau <info@brandau.biz>
+ *
+ * based on code from:
+ * Raumfeld GmbH
+ * Johannes Stezenbach <js@sig21.net>
+ * Wolfson Microelectronics PLC.
+ * 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 as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#ifndef _ASOC_STA_350_H
+#define _ASOC_STA_350_H
+
+/* STA50 register addresses */
+
+#define STA350_REGISTER_COUNT 0x4D
+#define STA350_COEF_COUNT 62
+
+#define STA350_CONFA 0x00
+#define STA350_CONFB 0x01
+#define STA350_CONFC 0x02
+#define STA350_CONFD 0x03
+#define STA350_CONFE 0x04
+#define STA350_CONFF 0x05
+#define STA350_MMUTE 0x06
+#define STA350_MVOL 0x07
+#define STA350_C1VOL 0x08
+#define STA350_C2VOL 0x09
+#define STA350_C3VOL 0x0a
+#define STA350_AUTO1 0x0b
+#define STA350_AUTO2 0x0c
+#define STA350_AUTO3 0x0d
+#define STA350_C1CFG 0x0e
+#define STA350_C2CFG 0x0f
+#define STA350_C3CFG 0x10
+#define STA350_TONE 0x11
+#define STA350_L1AR 0x12
+#define STA350_L1ATRT 0x13
+#define STA350_L2AR 0x14
+#define STA350_L2ATRT 0x15
+#define STA350_CFADDR2 0x16
+#define STA350_B1CF1 0x17
+#define STA350_B1CF2 0x18
+#define STA350_B1CF3 0x19
+#define STA350_B2CF1 0x1a
+#define STA350_B2CF2 0x1b
+#define STA350_B2CF3 0x1c
+#define STA350_A1CF1 0x1d
+#define STA350_A1CF2 0x1e
+#define STA350_A1CF3 0x1f
+#define STA350_A2CF1 0x20
+#define STA350_A2CF2 0x21
+#define STA350_A2CF3 0x22
+#define STA350_B0CF1 0x23
+#define STA350_B0CF2 0x24
+#define STA350_B0CF3 0x25
+#define STA350_CFUD 0x26
+#define STA350_MPCC1 0x27
+#define STA350_MPCC2 0x28
+#define STA350_DCC1 0x29
+#define STA350_DCC2 0x2a
+#define STA350_FDRC1 0x2b
+#define STA350_FDRC2 0x2c
+#define STA350_STATUS 0x2d
+/* reserved: 0x2d - 0x30 */
+#define STA350_EQCFG 0x31
+#define STA350_EATH1 0x32
+#define STA350_ERTH1 0x33
+#define STA350_EATH2 0x34
+#define STA350_ERTH2 0x35
+#define STA350_CONFX 0x36
+#define STA350_SVCA 0x37
+#define STA350_SVCB 0x38
+#define STA350_RMS0A 0x39
+#define STA350_RMS0B 0x3a
+#define STA350_RMS0C 0x3b
+#define STA350_RMS1A 0x3c
+#define STA350_RMS1B 0x3d
+#define STA350_RMS1C 0x3e
+#define STA350_EVOLRES 0x3f
+/* reserved: 0x40 - 0x47 */
+#define STA350_NSHAPE 0x48
+#define STA350_CTXB4B1 0x49
+#define STA350_CTXB7B5 0x4a
+#define STA350_MISC1 0x4b
+#define STA350_MISC2 0x4c
+
+/* 0x00 CONFA */
+#define STA350_CONFA_MCS_MASK 0x03
+#define STA350_CONFA_MCS_SHIFT 0
+#define STA350_CONFA_IR_MASK 0x18
+#define STA350_CONFA_IR_SHIFT 3
+#define STA350_CONFA_TWRB BIT(5)
+#define STA350_CONFA_TWAB BIT(6)
+#define STA350_CONFA_FDRB BIT(7)
+
+/* 0x01 CONFB */
+#define STA350_CONFB_SAI_MASK 0x0f
+#define STA350_CONFB_SAI_SHIFT 0
+#define STA350_CONFB_SAIFB BIT(4)
+#define STA350_CONFB_DSCKE BIT(5)
+#define STA350_CONFB_C1IM BIT(6)
+#define STA350_CONFB_C2IM BIT(7)
+
+/* 0x02 CONFC */
+#define STA350_CONFC_OM_MASK 0x03
+#define STA350_CONFC_OM_SHIFT 0
+#define STA350_CONFC_CSZ_MASK 0x3c
+#define STA350_CONFC_CSZ_SHIFT 2
+#define STA350_CONFC_OCRB BIT(7)
+
+/* 0x03 CONFD */
+#define STA350_CONFD_HPB_SHIFT 0
+#define STA350_CONFD_DEMP_SHIFT 1
+#define STA350_CONFD_DSPB_SHIFT 2
+#define STA350_CONFD_PSL_SHIFT 3
+#define STA350_CONFD_BQL_SHIFT 4
+#define STA350_CONFD_DRC_SHIFT 5
+#define STA350_CONFD_ZDE_SHIFT 6
+#define STA350_CONFD_SME_SHIFT 7
+
+/* 0x04 CONFE */
+#define STA350_CONFE_MPCV BIT(0)
+#define STA350_CONFE_MPCV_SHIFT 0
+#define STA350_CONFE_MPC BIT(1)
+#define STA350_CONFE_MPC_SHIFT 1
+#define STA350_CONFE_NSBW BIT(2)
+#define STA350_CONFE_NSBW_SHIFT 2
+#define STA350_CONFE_AME BIT(3)
+#define STA350_CONFE_AME_SHIFT 3
+#define STA350_CONFE_PWMS BIT(4)
+#define STA350_CONFE_PWMS_SHIFT 4
+#define STA350_CONFE_DCCV BIT(5)
+#define STA350_CONFE_DCCV_SHIFT 5
+#define STA350_CONFE_ZCE BIT(6)
+#define STA350_CONFE_ZCE_SHIFT 6
+#define STA350_CONFE_SVE BIT(7)
+#define STA350_CONFE_SVE_SHIFT 7
+
+/* 0x05 CONFF */
+#define STA350_CONFF_OCFG_MASK 0x03
+#define STA350_CONFF_OCFG_SHIFT 0
+#define STA350_CONFF_IDE BIT(2)
+#define STA350_CONFF_BCLE BIT(3)
+#define STA350_CONFF_LDTE BIT(4)
+#define STA350_CONFF_ECLE BIT(5)
+#define STA350_CONFF_PWDN BIT(6)
+#define STA350_CONFF_EAPD BIT(7)
+
+/* 0x06 MMUTE */
+#define STA350_MMUTE_MMUTE 0x01
+#define STA350_MMUTE_MMUTE_SHIFT 0
+#define STA350_MMUTE_C1M 0x02
+#define STA350_MMUTE_C1M_SHIFT 1
+#define STA350_MMUTE_C2M 0x04
+#define STA350_MMUTE_C2M_SHIFT 2
+#define STA350_MMUTE_C3M 0x08
+#define STA350_MMUTE_C3M_SHIFT 3
+#define STA350_MMUTE_LOC_MASK 0xC0
+#define STA350_MMUTE_LOC_SHIFT 6
+
+/* 0x0b AUTO1 */
+#define STA350_AUTO1_AMGC_MASK 0x30
+#define STA350_AUTO1_AMGC_SHIFT 4
+
+/* 0x0c AUTO2 */
+#define STA350_AUTO2_AMAME 0x01
+#define STA350_AUTO2_AMAM_MASK 0x0e
+#define STA350_AUTO2_AMAM_SHIFT 1
+#define STA350_AUTO2_XO_MASK 0xf0
+#define STA350_AUTO2_XO_SHIFT 4
+
+/* 0x0d AUTO3 */
+#define STA350_AUTO3_PEQ_MASK 0x1f
+#define STA350_AUTO3_PEQ_SHIFT 0
+
+/* 0x0e 0x0f 0x10 CxCFG */
+#define STA350_CxCFG_TCB_SHIFT 0
+#define STA350_CxCFG_EQBP_SHIFT 1
+#define STA350_CxCFG_VBP_SHIFT 2
+#define STA350_CxCFG_BO_SHIFT 3
+#define STA350_CxCFG_LS_SHIFT 4
+#define STA350_CxCFG_OM_MASK 0xc0
+#define STA350_CxCFG_OM_SHIFT 6
+
+/* 0x11 TONE */
+#define STA350_TONE_BTC_SHIFT 0
+#define STA350_TONE_TTC_SHIFT 4
+
+/* 0x12 0x13 0x14 0x15 limiter attack/release */
+#define STA350_LxA_SHIFT 0
+#define STA350_LxR_SHIFT 4
+
+/* 0x26 CFUD */
+#define STA350_CFUD_W1 0x01
+#define STA350_CFUD_WA 0x02
+#define STA350_CFUD_R1 0x04
+#define STA350_CFUD_RA 0x08
+
+
+/* biquad filter coefficient table offsets */
+#define STA350_C1_BQ_BASE 0
+#define STA350_C2_BQ_BASE 20
+#define STA350_CH_BQ_NUM 4
+#define STA350_BQ_NUM_COEF 5
+#define STA350_XO_HP_BQ_BASE 40
+#define STA350_XO_LP_BQ_BASE 45
+#define STA350_C1_PRESCALE 50
+#define STA350_C2_PRESCALE 51
+#define STA350_C1_POSTSCALE 52
+#define STA350_C2_POSTSCALE 53
+#define STA350_C3_POSTSCALE 54
+#define STA350_TW_POSTSCALE 55
+#define STA350_C1_MIX1 56
+#define STA350_C1_MIX2 57
+#define STA350_C2_MIX1 58
+#define STA350_C2_MIX2 59
+#define STA350_C3_MIX1 60
+#define STA350_C3_MIX2 61
+
+/* miscellaneous register 1 */
+#define STA350_MISC1_CPWMEN BIT(2)
+#define STA350_MISC1_BRIDGOFF BIT(5)
+#define STA350_MISC1_NSHHPEN BIT(6)
+#define STA350_MISC1_RPDNEN BIT(7)
+
+/* miscellaneous register 2 */
+#define STA350_MISC2_PNDLSL_MASK 0x1c
+#define STA350_MISC2_PNDLSL_SHIFT 2
+
+#endif /* _ASOC_STA_350_H */
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index a895a5e4bdf2..d48491a4a19d 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -272,7 +272,7 @@ static int tas5086_set_deemph(struct snd_soc_codec *codec)
static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = priv->deemph;
@@ -283,7 +283,7 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
priv->deemph = ucontrol->value.enumerated.item[0];
diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c
index b73c94ebcc2a..f13701995482 100644
--- a/sound/soc/codecs/tlv320aic23-i2c.c
+++ b/sound/soc/codecs/tlv320aic23-i2c.c
@@ -13,6 +13,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <sound/soc.h>
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 20864ee8793b..686b8b85b956 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -82,7 +82,7 @@ static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);
static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
u16 val, reg;
val = (ucontrol->value.integer.value[0] & 0x07);
@@ -105,7 +105,7 @@ static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
u16 val;
val = snd_soc_read(codec, TLV320AIC23_ANLG) & (0x1C0);
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index fa158cfe9b32..23419109ecac 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -28,6 +28,7 @@
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
+#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -376,7 +377,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
reg = AIC31XX_ADCFLAG;
break;
default:
- dev_err(w->codec->dev, "Unknown widget '%s' calling %s/n",
+ dev_err(w->codec->dev, "Unknown widget '%s' calling %s\n",
w->name, __func__);
return -EINVAL;
}
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index b1835103e9b4..e12fafbb1e09 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -169,7 +169,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
mask <<= shift;
val <<= shift;
- change = snd_soc_test_bits(codec, val, mask, reg);
+ change = snd_soc_test_bits(codec, reg, mask, val);
if (change) {
update.kcontrol = kcontrol;
update.reg = reg;
@@ -1399,7 +1399,6 @@ static int aic3x_probe(struct snd_soc_codec *codec)
}
aic3x_add_widgets(codec);
- list_add(&aic3x->list, &reset_list);
return 0;
@@ -1569,7 +1568,13 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_aic3x, &aic3x_dai, 1);
- return ret;
+
+ if (ret != 0)
+ goto err_gpio;
+
+ list_add(&aic3x->list, &reset_list);
+
+ return 0;
err_gpio:
if (gpio_is_valid(aic3x->gpio_reset) &&
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 6bfc8a17331b..df3a7506c023 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -442,7 +442,7 @@ static int dac33_playback_event(struct snd_soc_dapm_widget *w,
static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = dac33->fifo_mode;
@@ -453,7 +453,7 @@ static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
@@ -1540,7 +1540,7 @@ static int dac33_i2c_probe(struct i2c_client *client,
for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)
dac33->supplies[i].supply = dac33_supply_names[i];
- ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies),
+ ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies),
dac33->supplies);
if (ret != 0) {
@@ -1551,11 +1551,9 @@ static int dac33_i2c_probe(struct i2c_client *client,
ret = snd_soc_register_codec(&client->dev,
&soc_codec_dev_tlv320dac33, &dac33_dai, 1);
if (ret < 0)
- goto err_register;
+ goto err_get;
return ret;
-err_register:
- regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
err_get:
if (dac33->power_gpio >= 0)
gpio_free(dac33->power_gpio);
@@ -1573,8 +1571,6 @@ static int dac33_i2c_remove(struct i2c_client *client)
if (dac33->power_gpio >= 0)
gpio_free(dac33->power_gpio);
- regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
-
snd_soc_unregister_codec(&client->dev);
return 0;
}
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index b27c396037d4..8fc5a647453b 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -30,6 +30,7 @@
#include <sound/tpa6130a2-plat.h>
#include <sound/soc.h>
#include <sound/tlv.h>
+#include <linux/of.h>
#include <linux/of_gpio.h>
#include "tpa6130a2.h"
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 975e0f760ac1..69e12a311ba2 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -830,7 +830,7 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
unsigned int rshift = mc->rshift;
@@ -859,7 +859,7 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
unsigned int rshift = mc->rshift;
@@ -888,7 +888,7 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
@@ -915,7 +915,7 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
@@ -956,7 +956,7 @@ static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum,
static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
if (twl4030->configured) {
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index bd3a20647fdf..0f6067f04e29 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -484,7 +484,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum,
static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = priv->hs_power_mode;
@@ -495,7 +495,7 @@ static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
int high_perf = ucontrol->value.enumerated.item[0];
int ret = 0;
@@ -512,7 +512,7 @@ static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = priv->pll_power_mode;
@@ -523,7 +523,7 @@ static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
priv->pll_power_mode = ucontrol->value.enumerated.item[0];
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index 6be5f80b65f1..4ead0dc02b87 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -172,7 +172,7 @@ out:
static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = wl1273->mode;
@@ -190,7 +190,7 @@ static const char * const wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
if (wl1273->mode == ucontrol->value.integer.value[0])
@@ -214,7 +214,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route);
static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
dev_dbg(codec->dev, "%s: enter.\n", __func__);
@@ -227,7 +227,7 @@ static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
int val, r = 0;
@@ -251,7 +251,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings);
static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
dev_dbg(codec->dev, "%s: enter.\n", __func__);
@@ -264,7 +264,7 @@ static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
int r;
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 83a2c872925c..a4c352cc3464 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -607,7 +607,7 @@ static int wm2000_anc_set_mode(struct wm2000_priv *wm2000)
static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
ucontrol->value.enumerated.item[0] = wm2000->anc_active;
@@ -618,7 +618,7 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
int anc_active = ucontrol->value.enumerated.item[0];
int ret;
@@ -640,7 +640,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
ucontrol->value.enumerated.item[0] = wm2000->spk_ena;
@@ -651,7 +651,7 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
int val = ucontrol->value.enumerated.item[0];
int ret;
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 2e721e06671b..cdea9d9c1631 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1083,7 +1083,7 @@ static int wm2200_mixer_values[] = {
#define WM2200_MUX_CTL_DECL(name) \
const struct snd_kcontrol_new name##_mux = \
- SOC_DAPM_VALUE_ENUM("Route", name##_enum)
+ SOC_DAPM_ENUM("Route", name##_enum)
#define WM2200_MIXER_ENUMS(name, base_reg) \
static WM2200_MUX_ENUM_DECL(name##_in1_enum, base_reg); \
@@ -1207,7 +1207,7 @@ WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE);
WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);
#define WM2200_MUX(name, ctrl) \
- SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+ SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
#define WM2200_MIXER_WIDGETS(name, name_str) \
WM2200_MUX(name_str " Input 1", &name##_in1_mux), \
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index eca983fad891..91a9ea2a2056 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -390,7 +390,7 @@ static int wm5100_mixer_values[] = {
#define WM5100_MUX_CTL_DECL(name) \
const struct snd_kcontrol_new name##_mux = \
- SOC_DAPM_VALUE_ENUM("Route", name##_enum)
+ SOC_DAPM_ENUM("Route", name##_enum)
#define WM5100_MIXER_ENUMS(name, base_reg) \
static WM5100_MUX_ENUM_DECL(name##_in1_enum, base_reg); \
@@ -448,7 +448,7 @@ 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)
+ SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
#define WM5100_MIXER_WIDGETS(name, name_str) \
WM5100_MUX(name_str " Input 1", &name##_in1_mux), \
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index dcf1d12cfef8..289b64d89abd 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -764,8 +764,8 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
-SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
-SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
@@ -814,9 +814,9 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
0xbf, 0, digital_tlv),
-SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]),
-SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
-SOC_VALUE_ENUM("EPOUT OSR", wm5102_hpout_osr[2]),
+SOC_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]),
+SOC_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
+SOC_ENUM("EPOUT OSR", wm5102_hpout_osr[2]),
SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0),
@@ -970,7 +970,7 @@ static const struct soc_enum wm5102_aec_loopback =
wm5102_aec_loopback_values);
static const struct snd_kcontrol_new wm5102_aec_loopback_mux =
- SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5102_aec_loopback);
+ SOC_DAPM_ENUM("AEC Loopback", wm5102_aec_loopback);
static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
@@ -1204,7 +1204,7 @@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
-SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm5102_aec_loopback_mux),
@@ -1760,10 +1760,6 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret;
- ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
- if (ret != 0)
- return ret;
-
ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2);
if (ret != 0)
return ret;
@@ -1802,9 +1798,17 @@ static unsigned int wm5102_digital_vu[] = {
ARIZONA_DAC_DIGITAL_VOLUME_5R,
};
+static struct regmap *wm5102_get_regmap(struct device *dev)
+{
+ struct wm5102_priv *priv = dev_get_drvdata(dev);
+
+ return priv->core.arizona->regmap;
+}
+
static struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
.probe = wm5102_codec_probe,
.remove = wm5102_codec_remove,
+ .get_regmap = wm5102_get_regmap,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index df5a38dd8328..2e5fcb559e90 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -324,13 +324,13 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
-SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
-SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
-SOC_VALUE_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]),
-SOC_VALUE_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
-SOC_VALUE_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
-SOC_VALUE_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
-SOC_VALUE_ENUM("ASRC RATE 1", arizona_asrc_rate1),
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]),
+SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
+SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
+SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
+SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
@@ -367,6 +367,11 @@ SOC_SINGLE("HPOUT2 SC Protect Switch", ARIZONA_HP2_SHORT_CIRCUIT_CTRL,
SOC_SINGLE("HPOUT3 SC Protect Switch", ARIZONA_HP3_SHORT_CIRCUIT_CTRL,
ARIZONA_HP3_SC_ENA_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
+ ARIZONA_OUT5_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_6L,
+ ARIZONA_OUT6_OSR_SHIFT, 1, 0),
+
SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R("HPOUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,
@@ -592,7 +597,7 @@ static const struct soc_enum wm5110_aec_loopback =
wm5110_aec_loopback_values);
static const struct snd_kcontrol_new wm5110_aec_loopback_mux =
- SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5110_aec_loopback);
+ SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback);
static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
@@ -774,7 +779,7 @@ SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3,
SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3,
ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0),
-SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm5110_aec_loopback_mux),
@@ -1589,10 +1594,6 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
priv->core.arizona->dapm = &codec->dapm;
- ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
- if (ret != 0)
- return ret;
-
arizona_init_spk(codec);
arizona_init_gpio(codec);
@@ -1633,9 +1634,17 @@ static unsigned int wm5110_digital_vu[] = {
ARIZONA_DAC_DIGITAL_VOLUME_6R,
};
+static struct regmap *wm5110_get_regmap(struct device *dev)
+{
+ struct wm5110_priv *priv = dev_get_drvdata(dev);
+
+ return priv->core.arizona->regmap;
+}
+
static struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
.probe = wm5110_codec_probe,
.remove = wm5110_codec_remove,
+ .get_regmap = wm5110_get_regmap,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 757256bf7672..392285edb595 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -302,7 +302,7 @@ static int pga_event(struct snd_soc_dapm_widget *w,
static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec);
struct wm8350_output *out = NULL;
struct soc_mixer_control *mc =
@@ -345,7 +345,7 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec);
struct wm8350_output *out1 = &wm8350_priv->out1;
struct wm8350_output *out2 = &wm8350_priv->out2;
@@ -1505,8 +1505,6 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec)
if (ret != 0)
return ret;
- snd_soc_codec_set_cache_io(codec, wm8350->regmap);
-
/* Put the codec into reset if it wasn't already */
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
@@ -1608,11 +1606,19 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec)
return 0;
}
+static struct regmap *wm8350_get_regmap(struct device *dev)
+{
+ struct wm8350 *wm8350 = dev_get_platdata(dev);
+
+ return wm8350->regmap;
+}
+
static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
.probe = wm8350_codec_probe,
.remove = wm8350_codec_remove,
.suspend = wm8350_suspend,
.resume = wm8350_resume,
+ .get_regmap = wm8350_get_regmap,
.set_bias_level = wm8350_set_bias_level,
.controls = wm8350_snd_controls,
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 146564feaea0..06e913d3fea1 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -93,7 +93,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
int reg = mc->reg;
@@ -1318,8 +1318,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
priv->wm8400 = wm8400;
priv->codec = codec;
- snd_soc_codec_set_cache_io(codec, wm8400->regmap);
-
ret = devm_regulator_bulk_get(wm8400->dev,
ARRAY_SIZE(power), &power[0]);
if (ret != 0) {
@@ -1361,11 +1359,19 @@ static int wm8400_codec_remove(struct snd_soc_codec *codec)
return 0;
}
+static struct regmap *wm8400_get_regmap(struct device *dev)
+{
+ struct wm8400 *wm8400 = dev_get_platdata(dev);
+
+ return wm8400->regmap;
+}
+
static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
.probe = wm8400_codec_probe,
.remove = wm8400_codec_remove,
.suspend = wm8400_suspend,
.resume = wm8400_resume,
+ .get_regmap = wm8400_get_regmap,
.set_bias_level = wm8400_set_bias_level,
.controls = wm8400_snd_controls,
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index af7ed8b5d4e1..7665ff6aea6d 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -252,7 +252,7 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index d74f43975b90..5ada61611324 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -119,7 +119,7 @@ static int wm8731_set_deemph(struct snd_soc_codec *codec)
static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8731->deemph;
@@ -130,7 +130,7 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
int deemph = ucontrol->value.enumerated.item[0];
int ret = 0;
@@ -586,7 +586,7 @@ static int wm8731_probe(struct snd_soc_codec *codec)
for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
wm8731->supplies[i].supply = wm8731_supply_names[i];
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies),
+ ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies),
wm8731->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
@@ -597,7 +597,7 @@ static int wm8731_probe(struct snd_soc_codec *codec)
wm8731->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
- goto err_regulator_get;
+ return ret;
}
ret = wm8731_reset(codec);
@@ -624,8 +624,6 @@ static int wm8731_probe(struct snd_soc_codec *codec)
err_regulator_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-err_regulator_get:
- regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
return ret;
}
@@ -638,7 +636,6 @@ static int wm8731_remove(struct snd_soc_codec *codec)
wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
- regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
return 0;
}
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index cbb8d55052a4..53e57b4049a8 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -234,7 +234,7 @@ SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase),
static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = wm8753->dai_func;
@@ -244,7 +244,7 @@ static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
u16 ioctl;
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index ee76f0fb4299..bbcad9ff3c98 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -106,7 +106,7 @@ static int txsrc_get(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec;
unsigned int src;
- codec = snd_kcontrol_chip(kcontrol);
+ codec = snd_soc_kcontrol_codec(kcontrol);
src = snd_soc_read(codec, WM8804_SPDTX4);
if (src & 0x40)
ucontrol->value.integer.value[0] = 1;
@@ -122,7 +122,7 @@ static int txsrc_put(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec;
unsigned int src, txpwr;
- codec = snd_kcontrol_chip(kcontrol);
+ codec = snd_soc_kcontrol_codec(kcontrol);
if (ucontrol->value.integer.value[0] != 0
&& ucontrol->value.integer.value[0] != 1)
@@ -535,7 +535,6 @@ static int wm8804_remove(struct snd_soc_codec *codec)
for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
regulator_unregister_notifier(wm8804->supplies[i].consumer,
&wm8804->disable_nb[i]);
- regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
return 0;
}
@@ -549,7 +548,7 @@ static int wm8804_probe(struct snd_soc_codec *codec)
for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
wm8804->supplies[i].supply = wm8804_supply_names[i];
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies),
+ ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies),
wm8804->supplies);
if (ret) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
@@ -574,7 +573,7 @@ static int wm8804_probe(struct snd_soc_codec *codec)
wm8804->supplies);
if (ret) {
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
- goto err_reg_get;
+ return ret;
}
id1 = snd_soc_read(codec, WM8804_RST_DEVID1);
@@ -619,8 +618,6 @@ static int wm8804_probe(struct snd_soc_codec *codec)
err_reg_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
-err_reg_get:
- regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
return ret;
}
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index b0084a127d18..b84940c359a1 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -439,7 +439,7 @@ static int wm8903_set_deemph(struct snd_soc_codec *codec)
static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8903->deemph;
@@ -450,7 +450,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
int deemph = ucontrol->value.enumerated.item[0];
int ret = 0;
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 49c35c36935e..f7c549949c54 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -391,7 +391,7 @@ static void wm8904_set_drc(struct snd_soc_codec *codec)
static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
int value = ucontrol->value.integer.value[0];
@@ -409,7 +409,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8904->drc_cfg;
@@ -462,7 +462,7 @@ static void wm8904_set_retune_mobile(struct snd_soc_codec *codec)
static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
int value = ucontrol->value.integer.value[0];
@@ -480,7 +480,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg;
@@ -520,7 +520,7 @@ static int wm8904_set_deemph(struct snd_soc_codec *codec)
static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8904->deemph;
@@ -530,7 +530,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
int deemph = ucontrol->value.enumerated.item[0];
@@ -570,7 +570,7 @@ static SOC_ENUM_SINGLE_DECL(hpf_mode, WM8904_ADC_DIGITAL_0, 5,
static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int val;
int ret;
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index fecd4e4f4c57..2a35108f233d 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -390,7 +390,7 @@ static int wm8955_set_deemph(struct snd_soc_codec *codec)
static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8955->deemph;
@@ -400,7 +400,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
int deemph = ucontrol->value.enumerated.item[0];
@@ -898,7 +898,7 @@ static int wm8955_probe(struct snd_soc_codec *codec)
for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
wm8955->supplies[i].supply = wm8955_supply_names[i];
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies),
+ ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies),
wm8955->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
@@ -909,7 +909,7 @@ static int wm8955_probe(struct snd_soc_codec *codec)
wm8955->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
- goto err_get;
+ return ret;
}
ret = wm8955_reset(codec);
@@ -961,17 +961,12 @@ static int wm8955_probe(struct snd_soc_codec *codec)
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
-err_get:
- regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
return ret;
}
static int wm8955_remove(struct snd_soc_codec *codec)
{
- struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
-
wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
- regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
return 0;
}
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
index 7ac2e511403c..b2ebb104d879 100644
--- a/sound/soc/codecs/wm8958-dsp2.c
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -456,7 +456,7 @@ static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)
static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.integer.value[0];
@@ -478,7 +478,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
@@ -500,7 +500,7 @@ static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int mbc = kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
@@ -512,7 +512,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int mbc = kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0])
@@ -546,7 +546,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.integer.value[0];
@@ -568,7 +568,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8994->vss_cfg;
@@ -579,7 +579,7 @@ static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.integer.value[0];
@@ -601,7 +601,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg;
@@ -623,7 +623,7 @@ static int wm8958_vss_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int vss = kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = wm8994->vss_ena[vss];
@@ -635,7 +635,7 @@ static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int vss = kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0])
@@ -684,7 +684,7 @@ static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int hpf = kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
if (hpf < 3)
@@ -699,7 +699,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int hpf = kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
if (hpf < 3) {
@@ -746,7 +746,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.integer.value[0];
@@ -768,7 +768,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg;
@@ -790,7 +790,7 @@ static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int eq = kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq];
@@ -802,7 +802,7 @@ static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int eq = kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0])
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index d04e9cad445c..a145d0431b63 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -178,7 +178,7 @@ static int wm8960_set_deemph(struct snd_soc_codec *codec)
static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8960->deemph;
@@ -188,7 +188,7 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
int deemph = ucontrol->value.enumerated.item[0];
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 5522d2566c67..ca2fda9d72be 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -74,11 +74,9 @@ struct wm8962_priv {
struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];
struct notifier_block disable_nb[WM8962_NUM_SUPPLIES];
-#if IS_ENABLED(CONFIG_INPUT)
struct input_dev *beep;
struct work_struct beep_work;
int beep_rate;
-#endif
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio_chip;
@@ -154,6 +152,7 @@ static struct reg_default wm8962_reg[] = {
{ 40, 0x0000 }, /* R40 - SPKOUTL volume */
{ 41, 0x0000 }, /* R41 - SPKOUTR volume */
+ { 49, 0x0010 }, /* R49 - Class D Control 1 */
{ 51, 0x0003 }, /* R51 - Class D Control 2 */
{ 56, 0x0506 }, /* R56 - Clocking 4 */
@@ -795,7 +794,6 @@ static bool wm8962_volatile_register(struct device *dev, unsigned int reg)
case WM8962_ALC2:
case WM8962_THERMAL_SHUTDOWN_STATUS:
case WM8962_ADDITIONAL_CONTROL_4:
- case WM8962_CLASS_D_CONTROL_1:
case WM8962_DC_SERVO_6:
case WM8962_INTERRUPT_STATUS_1:
case WM8962_INTERRUPT_STATUS_2:
@@ -1552,7 +1550,7 @@ 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 snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = !!(wm8962->dsp2_ena & 1 << shift);
@@ -1564,7 +1562,7 @@ 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 snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
int old = wm8962->dsp2_ena;
int ret = 0;
@@ -1602,7 +1600,7 @@ out:
static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
int ret;
/* Apply the update (if any) */
@@ -1632,7 +1630,7 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
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);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
int ret;
/* Apply the update (if any) */
@@ -2929,13 +2927,22 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
static int wm8962_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- int val;
+ int val, ret;
if (mute)
- val = WM8962_DAC_MUTE;
+ val = WM8962_DAC_MUTE | WM8962_DAC_MUTE_ALT;
else
val = 0;
+ /**
+ * The DAC mute bit is mirrored in two registers, update both to keep
+ * the register cache consistent.
+ */
+ ret = snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_1,
+ WM8962_DAC_MUTE_ALT, val);
+ if (ret < 0)
+ return ret;
+
return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
WM8962_DAC_MUTE, val);
}
@@ -3145,7 +3152,6 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
}
EXPORT_SYMBOL_GPL(wm8962_mic_detect);
-#if IS_ENABLED(CONFIG_INPUT)
static int beep_rates[] = {
500, 1000, 2000, 4000,
};
@@ -3277,15 +3283,6 @@ static void wm8962_free_beep(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
}
-#else
-static void wm8962_init_beep(struct snd_soc_codec *codec)
-{
-}
-
-static void wm8962_free_beep(struct snd_soc_codec *codec)
-{
-}
-#endif
static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio)
{
diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h
index a1a5d5294c19..910aafd09d21 100644
--- a/sound/soc/codecs/wm8962.h
+++ b/sound/soc/codecs/wm8962.h
@@ -1954,6 +1954,10 @@
#define WM8962_SPKOUTL_ENA_MASK 0x0040 /* SPKOUTL_ENA */
#define WM8962_SPKOUTL_ENA_SHIFT 6 /* SPKOUTL_ENA */
#define WM8962_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */
+#define WM8962_DAC_MUTE_ALT 0x0010 /* DAC_MUTE */
+#define WM8962_DAC_MUTE_ALT_MASK 0x0010 /* DAC_MUTE */
+#define WM8962_DAC_MUTE_ALT_SHIFT 4 /* DAC_MUTE */
+#define WM8962_DAC_MUTE_ALT_WIDTH 1 /* DAC_MUTE */
#define WM8962_SPKOUTL_PGA_MUTE 0x0002 /* SPKOUTL_PGA_MUTE */
#define WM8962_SPKOUTL_PGA_MUTE_MASK 0x0002 /* SPKOUTL_PGA_MUTE */
#define WM8962_SPKOUTL_PGA_MUTE_SHIFT 1 /* SPKOUTL_PGA_MUTE */
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index 2b9bfa53efbf..19d5baa38f5c 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -552,7 +552,7 @@ static const struct snd_soc_dapm_route wm8983_audio_map[] = {
static int eqmode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int reg;
reg = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF);
@@ -567,7 +567,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol,
static int eqmode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int regpwr2, regpwr3;
unsigned int reg_eq;
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 5473dc969585..0f5780c09f3a 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -526,7 +526,7 @@ static const struct snd_soc_dapm_route wm8985_dapm_routes[] = {
static int eqmode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int reg;
reg = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
@@ -541,7 +541,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol,
static int eqmode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int regpwr2, regpwr3;
unsigned int reg_eq;
@@ -984,7 +984,6 @@ static int wm8985_remove(struct snd_soc_codec *codec)
wm8985 = snd_soc_codec_get_drvdata(codec);
wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
- regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
return 0;
}
@@ -999,7 +998,7 @@ static int wm8985_probe(struct snd_soc_codec *codec)
for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)
wm8985->supplies[i].supply = wm8985_supply_names[i];
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies),
+ ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies),
wm8985->supplies);
if (ret) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
@@ -1010,7 +1009,7 @@ static int wm8985_probe(struct snd_soc_codec *codec)
wm8985->supplies);
if (ret) {
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
- goto err_reg_get;
+ return ret;
}
ret = wm8985_reset(codec);
@@ -1032,8 +1031,6 @@ static int wm8985_probe(struct snd_soc_codec *codec)
err_reg_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
-err_reg_get:
- regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
return ret;
}
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 3a1ae4f5164d..d3fea46d58e8 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -268,7 +268,7 @@ static const struct soc_enum wm8988_lline_enum =
wm8988_line_texts,
wm8988_line_values);
static const struct snd_kcontrol_new wm8988_left_line_controls =
- SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum);
+ SOC_DAPM_ENUM("Route", wm8988_lline_enum);
static const struct soc_enum wm8988_rline_enum =
SOC_VALUE_ENUM_SINGLE(WM8988_ROUTM1, 0, 7,
@@ -276,7 +276,7 @@ static const struct soc_enum wm8988_rline_enum =
wm8988_line_texts,
wm8988_line_values);
static const struct snd_kcontrol_new wm8988_right_line_controls =
- SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum);
+ SOC_DAPM_ENUM("Route", wm8988_lline_enum);
/* Left Mixer */
static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = {
@@ -304,7 +304,7 @@ static const struct soc_enum wm8988_lpga_enum =
wm8988_pga_sel,
wm8988_pga_val);
static const struct snd_kcontrol_new wm8988_left_pga_controls =
- SOC_DAPM_VALUE_ENUM("Route", wm8988_lpga_enum);
+ SOC_DAPM_ENUM("Route", wm8988_lpga_enum);
/* Right PGA Mux */
static const struct soc_enum wm8988_rpga_enum =
@@ -313,7 +313,7 @@ static const struct soc_enum wm8988_rpga_enum =
wm8988_pga_sel,
wm8988_pga_val);
static const struct snd_kcontrol_new wm8988_right_pga_controls =
- SOC_DAPM_VALUE_ENUM("Route", wm8988_rpga_enum);
+ SOC_DAPM_ENUM("Route", wm8988_rpga_enum);
/* Differential Mux */
static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"};
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index c413c1991453..b5c1f0f07058 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -132,7 +132,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
int reg = mc->reg;
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 844cc4a60d66..b8fd284fc0c0 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -154,7 +154,7 @@ static const unsigned int out_sidetone_tlv[] = {
static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
int reg = kcontrol->private_value & 0xff;
int ret;
u16 val;
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 6303537f54c6..247b39013fba 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -298,7 +298,7 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
int mask, ret;
/* Can't enable both ADC and DAC paths simultaneously */
@@ -355,7 +355,7 @@ static int wm8994_get_drc(const char *name)
static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
@@ -378,7 +378,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int drc = wm8994_get_drc(kcontrol->id.name);
@@ -462,7 +462,7 @@ static int wm8994_get_retune_mobile_block(const char *name)
static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
@@ -485,7 +485,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
@@ -1347,10 +1347,10 @@ static const char *adc_mux_text[] = {
static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);
static const struct snd_kcontrol_new adcl_mux =
- SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum);
+ SOC_DAPM_ENUM("ADCL Mux", adc_enum);
static const struct snd_kcontrol_new adcr_mux =
- SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum);
+ SOC_DAPM_ENUM("ADCR Mux", adc_enum);
static const struct snd_kcontrol_new left_speaker_mixer[] = {
SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 9, 1, 0),
@@ -1651,15 +1651,15 @@ SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0),
};
static const struct snd_soc_dapm_widget wm8994_adc_revd_widgets[] = {
-SND_SOC_DAPM_VIRT_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux,
+SND_SOC_DAPM_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux,
adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
-SND_SOC_DAPM_VIRT_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux,
+SND_SOC_DAPM_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux,
adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
};
static const struct snd_soc_dapm_widget wm8994_adc_widgets[] = {
-SND_SOC_DAPM_VIRT_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux),
-SND_SOC_DAPM_VIRT_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux),
+SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux),
+SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux),
};
static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = {
@@ -3999,8 +3999,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8994->hubs.codec = codec;
- snd_soc_codec_set_cache_io(codec, control->regmap);
-
mutex_init(&wm8994->accdet_lock);
INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
wm1811_jackdet_bootstrap);
@@ -4434,11 +4432,19 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
return 0;
}
+static struct regmap *wm8994_get_regmap(struct device *dev)
+{
+ struct wm8994 *control = dev_get_drvdata(dev->parent);
+
+ return control->regmap;
+}
+
static struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
.probe = wm8994_codec_probe,
.remove = wm8994_codec_remove,
.suspend = wm8994_codec_suspend,
.resume = wm8994_codec_resume,
+ .get_regmap = wm8994_get_regmap,
.set_bias_level = wm8994_set_bias_level,
};
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index d3152cf5bd56..863a2c38bcb5 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -885,10 +885,10 @@ static const char *adc_mux_text[] = {
static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);
static const struct snd_kcontrol_new adcl_mux =
- SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum);
+ SOC_DAPM_ENUM("ADCL Mux", adc_enum);
static const struct snd_kcontrol_new adcr_mux =
- SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum);
+ SOC_DAPM_ENUM("ADCR Mux", adc_enum);
static const char *spk_src_text[] = {
"DAC1L", "DAC1R", "DAC2L", "DAC2R"
@@ -948,10 +948,8 @@ static const struct snd_soc_dapm_widget wm8995_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", "AIF1 Capture",
0, WM8995_POWER_MANAGEMENT_3, 10, 0),
- SND_SOC_DAPM_VIRT_MUX("ADCL Mux", SND_SOC_NOPM, 1, 0,
- &adcl_mux),
- SND_SOC_DAPM_VIRT_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0,
- &adcr_mux),
+ SND_SOC_DAPM_MUX("ADCL Mux", SND_SOC_NOPM, 1, 0, &adcl_mux),
+ SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8995_POWER_MANAGEMENT_3, 5, 0),
SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8995_POWER_MANAGEMENT_3, 4, 0),
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index c6cbb3b8ace9..69266332760e 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -412,7 +412,7 @@ static int wm8996_get_retune_mobile_block(const char *name)
static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
struct wm8996_pdata *pdata = &wm8996->pdata;
int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
@@ -434,7 +434,7 @@ static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index 004186b6bd48..bb9b47b956aa 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -245,8 +245,8 @@ SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1),
SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1),
SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1),
-SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
-SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
@@ -286,8 +286,8 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
0xbf, 0, digital_tlv),
-SOC_VALUE_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]),
-SOC_VALUE_ENUM("EPOUT OSR", wm8997_hpout_osr[1]),
+SOC_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]),
+SOC_ENUM("EPOUT OSR", wm8997_hpout_osr[1]),
SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
@@ -405,7 +405,7 @@ static const struct soc_enum wm8997_aec_loopback =
wm8997_aec_loopback_values);
static const struct snd_kcontrol_new wm8997_aec_loopback_mux =
- SOC_DAPM_VALUE_ENUM("AEC Loopback", wm8997_aec_loopback);
+ SOC_DAPM_ENUM("AEC Loopback", wm8997_aec_loopback);
static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
@@ -604,7 +604,7 @@ SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
ARIZONA_SLIMRX8_ENA_SHIFT, 0),
-SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm8997_aec_loopback_mux),
@@ -1051,11 +1051,6 @@ static struct snd_soc_dai_driver wm8997_dai[] = {
static int wm8997_codec_probe(struct snd_soc_codec *codec)
{
struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
- if (ret != 0)
- return ret;
arizona_init_spk(codec);
@@ -1086,9 +1081,17 @@ static unsigned int wm8997_digital_vu[] = {
ARIZONA_DAC_DIGITAL_VOLUME_5R,
};
+static struct regmap *wm8997_get_regmap(struct device *dev)
+{
+ struct wm8997_priv *priv = dev_get_drvdata(dev);
+
+ return priv->core.arizona->regmap;
+}
+
static struct snd_soc_codec_driver soc_codec_dev_wm8997 = {
.probe = wm8997_codec_probe,
.remove = wm8997_codec_remove,
+ .get_regmap = wm8997_get_regmap,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index d18eff31fbbc..185eb97769e7 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -340,7 +340,7 @@ static SOC_ENUM_SINGLE_DECL(speaker_mode, WM9081_ANALOGUE_SPEAKER_2, 6,
static int speaker_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int reg;
reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2);
@@ -361,7 +361,7 @@ static int speaker_mode_get(struct snd_kcontrol *kcontrol,
static int speaker_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned int reg_pwr = snd_soc_read(codec, WM9081_POWER_MANAGEMENT);
unsigned int reg2 = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2);
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index d0af15dc30ed..060027182dcb 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -242,7 +242,7 @@ struct wm_coeff_ctl {
static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
@@ -254,7 +254,7 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index b6209662ab13..916817fe6632 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -337,7 +337,7 @@ static void enable_dc_servo(struct snd_soc_codec *codec)
static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
int ret;
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index a8ec1fc3e4d0..50a098749b9e 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -18,7 +18,7 @@ config SND_DAVINCI_SOC_GENERIC_EVM
config SND_AM33XX_SOC_EVM
tristate "SoC Audio for the AM33XX chip based boards"
- depends on SND_DAVINCI_SOC && SOC_AM33XX
+ depends on SND_DAVINCI_SOC && SOC_AM33XX && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y or M if you want to add support for SoC audio on AM33XX
@@ -28,7 +28,7 @@ config SND_AM33XX_SOC_EVM
config SND_DAVINCI_SOC_EVM
tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
- depends on SND_DAVINCI_SOC
+ depends on SND_DAVINCI_SOC && I2C
depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
select SND_DAVINCI_SOC_GENERIC_EVM
help
@@ -56,7 +56,7 @@ endchoice
config SND_DM6467_SOC_EVM
tristate "SoC Audio support for DaVinci DM6467 EVM"
- depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM
+ depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
select SND_SOC_SPDIF
@@ -65,7 +65,7 @@ config SND_DM6467_SOC_EVM
config SND_DA830_SOC_EVM
tristate "SoC Audio support for DA830/OMAP-L137 EVM"
- depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM
+ depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
@@ -74,7 +74,7 @@ config SND_DA830_SOC_EVM
config SND_DA850_SOC_EVM
tristate "SoC Audio support for DA850/OMAP-L138 EVM"
- depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM
+ depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y if you want to add support for SoC audio on TI
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index ebe82947bab3..7682af31d6e6 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -757,7 +757,6 @@ static int davinci_i2s_remove(struct platform_device *pdev)
struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
- davinci_soc_platform_unregister(&pdev->dev);
clk_disable(dev->clk);
clk_put(dev->clk);
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 4f75cac462d1..14058dc6eaf8 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -36,6 +36,9 @@
#include "davinci-pcm.h"
#include "davinci-mcasp.h"
+#include "../omap/omap-pcm.h"
+
+#define MCASP_MAX_AFIFO_DEPTH 64
struct davinci_mcasp_context {
u32 txfmtctl;
@@ -269,25 +272,51 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
int ret = 0;
+ u32 data_delay;
+ bool fs_pol_rising;
+ bool inv_fs = false;
pm_runtime_get_sync(mcasp->dev);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+ /* 1st data bit occur one ACLK cycle after the frame sync */
+ data_delay = 1;
+ break;
case SND_SOC_DAIFMT_DSP_B:
case SND_SOC_DAIFMT_AC97:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+ /* No delay after FS */
+ data_delay = 0;
break;
- default:
+ case SND_SOC_DAIFMT_I2S:
/* configure a full-word SYNC pulse (LRCLK) */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
-
- /* make 1st data bit occur one ACLK cycle after the frame sync */
- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(1));
- mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(1));
+ /* 1st data bit occur one ACLK cycle after the frame sync */
+ data_delay = 1;
+ /* FS need to be inverted */
+ inv_fs = true;
break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ /* configure a full-word SYNC pulse (LRCLK) */
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+ /* No delay after FS */
+ data_delay = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
}
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay),
+ FSXDLY(3));
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay),
+ FSRDLY(3));
+
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
/* codec is clock and frame slave */
@@ -325,7 +354,6 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
mcasp->bclk_master = 0;
break;
-
default:
ret = -EINVAL;
goto out;
@@ -334,39 +362,38 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_NF:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ fs_pol_rising = true;
break;
-
case SND_SOC_DAIFMT_NB_IF:
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ fs_pol_rising = false;
break;
-
case SND_SOC_DAIFMT_IB_IF:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ fs_pol_rising = false;
break;
-
case SND_SOC_DAIFMT_NB_NF:
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ fs_pol_rising = true;
break;
-
default:
ret = -EINVAL;
- break;
+ goto out;
+ }
+
+ if (inv_fs)
+ fs_pol_rising = !fs_pol_rising;
+
+ if (fs_pol_rising) {
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ } else {
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
}
out:
pm_runtime_put_sync(mcasp->dev);
@@ -464,17 +491,19 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
}
static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
- int channels)
+ int period_words, int channels)
{
+ struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream];
+ struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream];
int i;
u8 tx_ser = 0;
u8 rx_ser = 0;
- u8 ser;
u8 slots = mcasp->tdm_slots;
u8 max_active_serializers = (channels + slots - 1) / slots;
+ int active_serializers, numevt, n;
u32 reg;
/* Default configuration */
- if (mcasp->version != MCASP_VERSION_4)
+ if (mcasp->version < MCASP_VERSION_3)
mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
/* All PINS as McASP */
@@ -505,37 +534,71 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
}
}
- if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- ser = tx_ser;
- else
- ser = rx_ser;
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ active_serializers = tx_ser;
+ numevt = mcasp->txnumevt;
+ reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+ } else {
+ active_serializers = rx_ser;
+ numevt = mcasp->rxnumevt;
+ reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+ }
- if (ser < max_active_serializers) {
+ if (active_serializers < max_active_serializers) {
dev_warn(mcasp->dev, "stream has more channels (%d) than are "
- "enabled in mcasp (%d)\n", channels, ser * slots);
+ "enabled in mcasp (%d)\n", channels,
+ active_serializers * slots);
return -EINVAL;
}
- if (mcasp->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (mcasp->txnumevt * tx_ser > 64)
- mcasp->txnumevt = 1;
-
- reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
- mcasp_mod_bits(mcasp, reg, tx_ser, NUMDMA_MASK);
- mcasp_mod_bits(mcasp, reg, ((mcasp->txnumevt * tx_ser) << 8),
- NUMEVT_MASK);
+ /* AFIFO is not in use */
+ if (!numevt) {
+ /* Configure the burst size for platform drivers */
+ if (active_serializers > 1) {
+ /*
+ * If more than one serializers are in use we have one
+ * DMA request to provide data for all serializers.
+ * For example if three serializers are enabled the DMA
+ * need to transfer three words per DMA request.
+ */
+ dma_params->fifo_level = active_serializers;
+ dma_data->maxburst = active_serializers;
+ } else {
+ dma_params->fifo_level = 0;
+ dma_data->maxburst = 0;
+ }
+ return 0;
}
- if (mcasp->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) {
- if (mcasp->rxnumevt * rx_ser > 64)
- mcasp->rxnumevt = 1;
-
- reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
- mcasp_mod_bits(mcasp, reg, rx_ser, NUMDMA_MASK);
- mcasp_mod_bits(mcasp, reg, ((mcasp->rxnumevt * rx_ser) << 8),
- NUMEVT_MASK);
+ if (period_words % active_serializers) {
+ dev_err(mcasp->dev, "Invalid combination of period words and "
+ "active serializers: %d, %d\n", period_words,
+ active_serializers);
+ return -EINVAL;
}
+ /*
+ * Calculate the optimal AFIFO depth for platform side:
+ * The number of words for numevt need to be in steps of active
+ * serializers.
+ */
+ n = numevt % active_serializers;
+ if (n)
+ numevt += (active_serializers - n);
+ while (period_words % numevt && numevt > 0)
+ numevt -= active_serializers;
+ if (numevt <= 0)
+ numevt = active_serializers;
+
+ mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK);
+ mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK);
+
+ /* Configure the burst size for platform drivers */
+ if (numevt == 1)
+ numevt = 0;
+ dma_params->fifo_level = numevt;
+ dma_data->maxburst = numevt;
+
return 0;
}
@@ -607,27 +670,24 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
struct davinci_pcm_dma_params *dma_params =
&mcasp->dma_params[substream->stream];
- struct snd_dmaengine_dai_dma_data *dma_data =
- &mcasp->dma_data[substream->stream];
int word_length;
- u8 fifo_level;
- u8 slots = mcasp->tdm_slots;
- u8 active_serializers;
int channels = params_channels(params);
+ int period_size = params_period_size(params);
int ret;
/* If mcasp is BCLK master we need to set BCLK divider */
if (mcasp->bclk_master) {
unsigned int bclk_freq = snd_soc_params_to_bclk(params);
if (mcasp->sysclk_freq % bclk_freq != 0) {
- dev_err(mcasp->dev, "Can't produce requred BCLK\n");
+ dev_err(mcasp->dev, "Can't produce required BCLK\n");
return -EINVAL;
}
davinci_mcasp_set_clkdiv(
cpu_dai, 1, mcasp->sysclk_freq / bclk_freq);
}
- ret = mcasp_common_hw_param(mcasp, substream->stream, channels);
+ ret = mcasp_common_hw_param(mcasp, substream->stream,
+ period_size * channels, channels);
if (ret)
return ret;
@@ -671,21 +731,11 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- /* Calculate FIFO level */
- active_serializers = (channels + slots - 1) / slots;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- fifo_level = mcasp->txnumevt * active_serializers;
- else
- fifo_level = mcasp->rxnumevt * active_serializers;
-
- if (mcasp->version == MCASP_VERSION_2 && !fifo_level)
+ if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level)
dma_params->acnt = 4;
else
dma_params->acnt = dma_params->data_type;
- dma_params->fifo_level = fifo_level;
- dma_data->maxburst = fifo_level;
-
davinci_config_channel_size(mcasp, word_length);
return 0;
@@ -716,22 +766,7 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
return ret;
}
-static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
-
- if (mcasp->version == MCASP_VERSION_4)
- snd_soc_dai_set_dma_data(dai, substream,
- &mcasp->dma_data[substream->stream]);
- else
- snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params);
-
- return 0;
-}
-
static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
- .startup = davinci_mcasp_startup,
.trigger = davinci_mcasp_trigger,
.hw_params = davinci_mcasp_hw_params,
.set_fmt = davinci_mcasp_set_dai_fmt,
@@ -739,6 +774,25 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
.set_sysclk = davinci_mcasp_set_sysclk,
};
+static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
+{
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+
+ if (mcasp->version == MCASP_VERSION_4) {
+ /* Using dmaengine PCM */
+ dai->playback_dma_data =
+ &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+ dai->capture_dma_data =
+ &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+ } else {
+ /* Using davinci-pcm */
+ dai->playback_dma_data = mcasp->dma_params;
+ dai->capture_dma_data = mcasp->dma_params;
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_PM_SLEEP
static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
{
@@ -792,6 +846,7 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai)
static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
{
.name = "davinci-mcasp.0",
+ .probe = davinci_mcasp_dai_probe,
.suspend = davinci_mcasp_suspend,
.resume = davinci_mcasp_resume,
.playback = {
@@ -811,6 +866,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
},
{
.name = "davinci-mcasp.1",
+ .probe = davinci_mcasp_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 384,
@@ -1078,7 +1134,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (!mcasp->base) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
- goto err_release_clk;
+ goto err;
}
mcasp->op_mode = pdata->op_mode;
@@ -1159,25 +1215,37 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp_reparent_fck(pdev);
- ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
- &davinci_mcasp_dai[pdata->op_mode], 1);
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &davinci_mcasp_component,
+ &davinci_mcasp_dai[pdata->op_mode], 1);
if (ret != 0)
- goto err_release_clk;
+ goto err;
- if (mcasp->version != MCASP_VERSION_4) {
+ switch (mcasp->version) {
+ case MCASP_VERSION_1:
+ case MCASP_VERSION_2:
+ case MCASP_VERSION_3:
ret = davinci_soc_platform_register(&pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
- goto err_unregister_component;
- }
+ break;
+ case MCASP_VERSION_4:
+ ret = omap_pcm_platform_register(&pdev->dev);
+ break;
+ default:
+ dev_err(&pdev->dev, "Invalid McASP version: %d\n",
+ mcasp->version);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret) {
+ dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+ goto err;
}
return 0;
-err_unregister_component:
- snd_soc_unregister_component(&pdev->dev);
-err_release_clk:
+err:
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return ret;
@@ -1185,12 +1253,6 @@ err_release_clk:
static int davinci_mcasp_remove(struct platform_device *pdev)
{
- struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev);
-
- snd_soc_unregister_component(&pdev->dev);
- if (mcasp->version != MCASP_VERSION_4)
- davinci_soc_platform_unregister(&pdev->dev);
-
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
index 8fed757d6087..98fbc451892a 100644
--- a/sound/soc/davinci/davinci-mcasp.h
+++ b/sound/soc/davinci/davinci-mcasp.h
@@ -283,6 +283,7 @@
*/
#define FIFO_ENABLE BIT(16)
#define NUMEVT_MASK (0xFF << 8)
+#define NUMEVT(x) (((x) & 0xFF) << 8)
#define NUMDMA_MASK (0xFF)
#endif /* DAVINCI_MCASP_H */
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 14145cdf8a11..7809e9d935fc 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -852,16 +852,10 @@ static struct snd_soc_platform_driver davinci_soc_platform = {
int davinci_soc_platform_register(struct device *dev)
{
- return snd_soc_register_platform(dev, &davinci_soc_platform);
+ return devm_snd_soc_register_platform(dev, &davinci_soc_platform);
}
EXPORT_SYMBOL_GPL(davinci_soc_platform_register);
-void davinci_soc_platform_unregister(struct device *dev)
-{
- snd_soc_unregister_platform(dev);
-}
-EXPORT_SYMBOL_GPL(davinci_soc_platform_unregister);
-
MODULE_AUTHOR("Vladimir Barinov");
MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index fbb710c76c08..0fe2346a9aa2 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -29,7 +29,13 @@ struct davinci_pcm_dma_params {
unsigned int fifo_level;
};
+#if IS_ENABLED(CONFIG_SND_DAVINCI_SOC)
int davinci_soc_platform_register(struct device *dev);
-void davinci_soc_platform_unregister(struct device *dev);
+#else
+static inline int davinci_soc_platform_register(struct device *dev)
+{
+ return 0;
+}
+#endif /* CONFIG_SND_DAVINCI_SOC */
#endif
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
index 30587c0cdbd2..77aef05588c3 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/davinci/davinci-vcif.c
@@ -258,7 +258,6 @@ static int davinci_vcif_probe(struct platform_device *pdev)
static int davinci_vcif_remove(struct platform_device *pdev)
{
snd_soc_unregister_component(&pdev->dev);
- davinci_soc_platform_unregister(&pdev->dev);
return 0;
}
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 338a91642471..d262ec0653d3 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,30 +1,77 @@
+menu "SoC Audio for Freescale CPUs"
+
+comment "Common SoC Audio options for Freescale CPUs:"
+
config SND_SOC_FSL_SAI
- tristate
+ tristate "Synchronous Audio Interface (SAI) module support"
select REGMAP_MMIO
select SND_SOC_GENERIC_DMAENGINE_PCM
+ help
+ Say Y if you want to add Synchronous Audio Interface (SAI)
+ support for the Freescale CPUs.
+ This option is only useful for out-of-tree drivers since
+ in-tree drivers select it automatically.
config SND_SOC_FSL_SSI
- tristate
+ tristate "Synchronous Serial Interface module support"
+ select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
+ select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && ARCH_MXC
+ help
+ Say Y if you want to add Synchronous Serial Interface (SSI)
+ support for the Freescale CPUs.
+ This option is only useful for out-of-tree drivers since
+ in-tree drivers select it automatically.
config SND_SOC_FSL_SPDIF
- tristate
+ tristate "Sony/Philips Digital Interface module support"
select REGMAP_MMIO
+ select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
+ select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && ARCH_MXC
+ help
+ Say Y if you want to add Sony/Philips Digital Interface (SPDIF)
+ support for the Freescale CPUs.
+ This option is only useful for out-of-tree drivers since
+ in-tree drivers select it automatically.
config SND_SOC_FSL_ESAI
- tristate
+ tristate "Enhanced Serial Audio Interface (ESAI) module support"
select REGMAP_MMIO
select SND_SOC_FSL_UTILS
+ help
+ Say Y if you want to add Enhanced Synchronous Audio Interface
+ (ESAI) support for the Freescale CPUs.
+ This option is only useful for out-of-tree drivers since
+ in-tree drivers select it automatically.
config SND_SOC_FSL_UTILS
tristate
-menuconfig SND_POWERPC_SOC
+config SND_SOC_IMX_PCM_DMA
+ tristate
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+
+config SND_SOC_IMX_AUDMUX
+ tristate "Digital Audio Mux module support"
+ help
+ Say Y if you want to add Digital Audio Mux (AUDMUX) support
+ for the ARM i.MX CPUs.
+ This option is only useful for out-of-tree drivers since
+ in-tree drivers select it automatically.
+
+config SND_POWERPC_SOC
tristate "SoC Audio for Freescale PowerPC CPUs"
depends on FSL_SOC || PPC_MPC52xx
help
Say Y or M if you want to add support for codecs attached to
the PowerPC CPUs.
+config SND_IMX_SOC
+ tristate "SoC Audio for Freescale i.MX CPUs"
+ depends on ARCH_MXC || COMPILE_TEST
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the i.MX CPUs.
+
if SND_POWERPC_SOC
config SND_MPC52xx_DMA
@@ -33,6 +80,8 @@ config SND_MPC52xx_DMA
config SND_SOC_POWERPC_DMA
tristate
+comment "SoC Audio support for Freescale PPC boards:"
+
config SND_SOC_MPC8610_HPCD
tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
# I2C is necessary for the CS4270 driver
@@ -110,13 +159,6 @@ config SND_MPC52xx_SOC_EFIKA
endif # SND_POWERPC_SOC
-menuconfig SND_IMX_SOC
- tristate "SoC Audio for Freescale i.MX CPUs"
- depends on ARCH_MXC || COMPILE_TEST
- help
- Say Y or M if you want to add support for codecs attached to
- the i.MX CPUs.
-
if SND_IMX_SOC
config SND_SOC_IMX_SSI
@@ -127,12 +169,7 @@ config SND_SOC_IMX_PCM_FIQ
tristate
select FIQ
-config SND_SOC_IMX_PCM_DMA
- tristate
- select SND_SOC_GENERIC_DMAENGINE_PCM
-
-config SND_SOC_IMX_AUDMUX
- tristate
+comment "SoC Audio support for Freescale i.MX boards:"
config SND_MXC_SOC_WM1133_EV1
tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted"
@@ -187,7 +224,7 @@ config SND_SOC_EUKREA_TLV320
config SND_SOC_IMX_WM8962
tristate "SoC Audio support for i.MX boards with wm8962"
- depends on OF && I2C
+ depends on OF && I2C && INPUT
select SND_SOC_WM8962
select SND_SOC_IMX_PCM_DMA
select SND_SOC_IMX_AUDMUX
@@ -225,3 +262,5 @@ config SND_SOC_IMX_MC13783
select SND_SOC_IMX_PCM_DMA
endif # SND_IMX_SOC
+
+endmenu
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index b12ad4b9b4da..db254e358c18 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -12,7 +12,8 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
# Freescale SSI/DMA/SAI/SPDIF Support
snd-soc-fsl-sai-objs := fsl_sai.o
-snd-soc-fsl-ssi-objs := fsl_ssi.o
+snd-soc-fsl-ssi-y := fsl_ssi.o
+snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o
snd-soc-fsl-spdif-objs := fsl_spdif.o
snd-soc-fsl-esai-objs := fsl_esai.o
snd-soc-fsl-utils-objs := fsl_utils.o
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index c8e5db1414d7..d719caf26dc2 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -39,6 +39,8 @@
* @fifo_depth: depth of tx/rx FIFO
* @slot_width: width of each DAI slot
* @hck_rate: clock rate of desired HCKx clock
+ * @sck_rate: clock rate of desired SCKx clock
+ * @hck_dir: the direction of HCKx pads
* @sck_div: if using PSR/PM dividers for SCKx clock
* @slave_mode: if fully using DAI slave mode
* @synchronous: if using tx/rx synchronous mode
@@ -55,6 +57,8 @@ struct fsl_esai {
u32 fifo_depth;
u32 slot_width;
u32 hck_rate[2];
+ u32 sck_rate[2];
+ bool hck_dir[2];
bool sck_div[2];
bool slave_mode;
bool synchronous;
@@ -209,8 +213,13 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
struct clk *clksrc = esai_priv->extalclk;
bool tx = clk_id <= ESAI_HCKT_EXTAL;
bool in = dir == SND_SOC_CLOCK_IN;
- u32 ret, ratio, ecr = 0;
+ u32 ratio, ecr = 0;
unsigned long clk_rate;
+ int ret;
+
+ /* Bypass divider settings if the requirement doesn't change */
+ if (freq == esai_priv->hck_rate[tx] && dir == esai_priv->hck_dir[tx])
+ return 0;
/* sck_div can be only bypassed if ETO/ERO=0 and SNC_SOC_CLOCK_OUT */
esai_priv->sck_div[tx] = true;
@@ -258,10 +267,16 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
return -EINVAL;
}
- if (ratio == 1) {
+ /* Only EXTAL source can be output directly without using PSR and PM */
+ if (ratio == 1 && clksrc == esai_priv->extalclk) {
/* Bypass all the dividers if not being needed */
ecr |= tx ? ESAI_ECR_ETO : ESAI_ECR_ERO;
goto out;
+ } else if (ratio < 2) {
+ /* The ratio should be no less than 2 if using other sources */
+ dev_err(dai->dev, "failed to derive required HCK%c rate\n",
+ tx ? 'T' : 'R');
+ return -EINVAL;
}
ret = fsl_esai_divisor_cal(dai, tx, ratio, false, 0);
@@ -271,6 +286,7 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
esai_priv->sck_div[tx] = false;
out:
+ esai_priv->hck_dir[tx] = dir;
esai_priv->hck_rate[tx] = freq;
regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,
@@ -288,9 +304,10 @@ static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
u32 hck_rate = esai_priv->hck_rate[tx];
u32 sub, ratio = hck_rate / freq;
+ int ret;
- /* Don't apply for fully slave mode*/
- if (esai_priv->slave_mode)
+ /* Don't apply for fully slave mode or unchanged bclk */
+ if (esai_priv->slave_mode || esai_priv->sck_rate[tx] == freq)
return 0;
if (ratio * freq > hck_rate)
@@ -307,13 +324,21 @@ static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
return -EINVAL;
}
- if (esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) {
+ /* The ratio should be contented by FP alone if bypassing PM and PSR */
+ if (!esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) {
dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n");
return -EINVAL;
}
- return fsl_esai_divisor_cal(dai, tx, ratio, true,
+ ret = fsl_esai_divisor_cal(dai, tx, ratio, true,
esai_priv->sck_div[tx] ? 0 : ratio);
+ if (ret)
+ return ret;
+
+ /* Save current bclk rate */
+ esai_priv->sck_rate[tx] = freq;
+
+ return 0;
}
static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
@@ -432,8 +457,8 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
static int fsl_esai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- int ret;
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+ int ret;
/*
* Some platforms might use the same bit to gate all three or two of
@@ -454,12 +479,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
}
if (!dai->active) {
- /* Reset Port C */
- regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
- ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));
- regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,
- ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));
-
/* Set synchronous mode */
regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR,
ESAI_SAICR_SYNC, esai_priv->synchronous ?
@@ -491,7 +510,8 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
u32 width = snd_pcm_format_width(params_format(params));
u32 channels = params_channels(params);
- u32 bclk, mask, val, ret;
+ u32 bclk, mask, val;
+ int ret;
bclk = params_rate(params) * esai_priv->slot_width * 2;
@@ -519,6 +539,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
+ /* Remove ESAI personal reset by configuring ESAI_PCRC and ESAI_PRRC */
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
+ ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,
+ ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));
return 0;
}
@@ -816,6 +841,7 @@ static int fsl_esai_probe(struct platform_device *pdev)
static const struct of_device_id fsl_esai_dt_ids[] = {
{ .compatible = "fsl,imx35-esai", },
+ { .compatible = "fsl,vf610-esai", },
{}
};
MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 56da8c8c5960..c5a0e8af8226 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -22,6 +22,7 @@
#include <sound/pcm_params.h>
#include "fsl_sai.h"
+#include "imx-pcm.h"
#define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
FSL_SAI_CSR_FEIE)
@@ -30,78 +31,96 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid)
{
struct fsl_sai *sai = (struct fsl_sai *)devid;
struct device *dev = &sai->pdev->dev;
- u32 xcsr, mask;
+ u32 flags, xcsr, mask;
+ bool irq_none = true;
- /* Only handle those what we enabled */
+ /*
+ * Both IRQ status bits and IRQ mask bits are in the xCSR but
+ * different shifts. And we here create a mask only for those
+ * IRQs that we activated.
+ */
mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
/* Tx IRQ */
regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr);
- xcsr &= mask;
+ flags = xcsr & mask;
+
+ if (flags)
+ irq_none = false;
+ else
+ goto irq_rx;
- if (xcsr & FSL_SAI_CSR_WSF)
+ if (flags & FSL_SAI_CSR_WSF)
dev_dbg(dev, "isr: Start of Tx word detected\n");
- if (xcsr & FSL_SAI_CSR_SEF)
+ if (flags & FSL_SAI_CSR_SEF)
dev_warn(dev, "isr: Tx Frame sync error detected\n");
- if (xcsr & FSL_SAI_CSR_FEF) {
+ if (flags & FSL_SAI_CSR_FEF) {
dev_warn(dev, "isr: Transmit underrun detected\n");
/* FIFO reset for safety */
xcsr |= FSL_SAI_CSR_FR;
}
- if (xcsr & FSL_SAI_CSR_FWF)
+ if (flags & FSL_SAI_CSR_FWF)
dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n");
- if (xcsr & FSL_SAI_CSR_FRF)
+ if (flags & FSL_SAI_CSR_FRF)
dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n");
- regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
- FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
+ flags &= FSL_SAI_CSR_xF_W_MASK;
+ xcsr &= ~FSL_SAI_CSR_xF_MASK;
+
+ if (flags)
+ regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr);
+irq_rx:
/* Rx IRQ */
regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr);
- xcsr &= mask;
+ flags = xcsr & mask;
- if (xcsr & FSL_SAI_CSR_WSF)
+ if (flags)
+ irq_none = false;
+ else
+ goto out;
+
+ if (flags & FSL_SAI_CSR_WSF)
dev_dbg(dev, "isr: Start of Rx word detected\n");
- if (xcsr & FSL_SAI_CSR_SEF)
+ if (flags & FSL_SAI_CSR_SEF)
dev_warn(dev, "isr: Rx Frame sync error detected\n");
- if (xcsr & FSL_SAI_CSR_FEF) {
+ if (flags & FSL_SAI_CSR_FEF) {
dev_warn(dev, "isr: Receive overflow detected\n");
/* FIFO reset for safety */
xcsr |= FSL_SAI_CSR_FR;
}
- if (xcsr & FSL_SAI_CSR_FWF)
+ if (flags & FSL_SAI_CSR_FWF)
dev_dbg(dev, "isr: Enabled receive FIFO is full\n");
- if (xcsr & FSL_SAI_CSR_FRF)
+ if (flags & FSL_SAI_CSR_FRF)
dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n");
- regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
- FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
+ flags &= FSL_SAI_CSR_xF_W_MASK;
+ xcsr &= ~FSL_SAI_CSR_xF_MASK;
+
+ if (flags)
+ regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr);
- return IRQ_HANDLED;
+out:
+ if (irq_none)
+ return IRQ_NONE;
+ else
+ return IRQ_HANDLED;
}
static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int fsl_dir)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- u32 val_cr2, reg_cr2;
-
- if (fsl_dir == FSL_FMT_TRANSMITTER)
- reg_cr2 = FSL_SAI_TCR2;
- else
- reg_cr2 = FSL_SAI_RCR2;
-
- regmap_read(sai->regmap, reg_cr2, &val_cr2);
-
- val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+ bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
+ u32 val_cr2 = 0;
switch (clk_id) {
case FSL_SAI_CLK_BUS:
@@ -120,7 +139,8 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
- regmap_write(sai->regmap, reg_cr2, val_cr2);
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx),
+ FSL_SAI_CR2_MSEL_MASK, val_cr2);
return 0;
}
@@ -152,22 +172,10 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
unsigned int fmt, int fsl_dir)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- u32 val_cr2, val_cr4, reg_cr2, reg_cr4;
-
- if (fsl_dir == FSL_FMT_TRANSMITTER) {
- reg_cr2 = FSL_SAI_TCR2;
- reg_cr4 = FSL_SAI_TCR4;
- } else {
- reg_cr2 = FSL_SAI_RCR2;
- reg_cr4 = FSL_SAI_RCR4;
- }
+ bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
+ u32 val_cr2 = 0, val_cr4 = 0;
- regmap_read(sai->regmap, reg_cr2, &val_cr2);
- regmap_read(sai->regmap, reg_cr4, &val_cr4);
-
- if (sai->big_endian_data)
- val_cr4 &= ~FSL_SAI_CR4_MF;
- else
+ if (!sai->big_endian_data)
val_cr4 |= FSL_SAI_CR4_MF;
/* DAI mode */
@@ -188,7 +196,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
* frame sync asserts with the first bit of the frame.
*/
val_cr2 |= FSL_SAI_CR2_BCP;
- val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
break;
case SND_SOC_DAIFMT_DSP_A:
/*
@@ -198,7 +205,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
* data word.
*/
val_cr2 |= FSL_SAI_CR2_BCP;
- val_cr4 &= ~FSL_SAI_CR4_FSP;
val_cr4 |= FSL_SAI_CR4_FSE;
sai->is_dsp_mode = true;
break;
@@ -208,7 +214,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
* frame sync asserts with the first bit of the frame.
*/
val_cr2 |= FSL_SAI_CR2_BCP;
- val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
sai->is_dsp_mode = true;
break;
case SND_SOC_DAIFMT_RIGHT_J:
@@ -246,23 +251,22 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
break;
case SND_SOC_DAIFMT_CBM_CFM:
- val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
- val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
break;
case SND_SOC_DAIFMT_CBS_CFM:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
- val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
break;
case SND_SOC_DAIFMT_CBM_CFS:
- val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
break;
default:
return -EINVAL;
}
- regmap_write(sai->regmap, reg_cr2, val_cr2);
- regmap_write(sai->regmap, reg_cr4, val_cr4);
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx),
+ FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val_cr2);
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
+ FSL_SAI_CR4_MF | FSL_SAI_CR4_FSE |
+ FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val_cr4);
return 0;
}
@@ -289,29 +293,10 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr;
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int channels = params_channels(params);
u32 word_width = snd_pcm_format_width(params_format(params));
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- reg_cr4 = FSL_SAI_TCR4;
- reg_cr5 = FSL_SAI_TCR5;
- reg_mr = FSL_SAI_TMR;
- } else {
- reg_cr4 = FSL_SAI_RCR4;
- reg_cr5 = FSL_SAI_RCR5;
- reg_mr = FSL_SAI_RMR;
- }
-
- regmap_read(sai->regmap, reg_cr4, &val_cr4);
- regmap_read(sai->regmap, reg_cr4, &val_cr5);
-
- val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
- val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
-
- val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
- val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
- val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
+ u32 val_cr4 = 0, val_cr5 = 0;
if (!sai->is_dsp_mode)
val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
@@ -319,18 +304,20 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
val_cr5 |= FSL_SAI_CR5_WNW(word_width);
val_cr5 |= FSL_SAI_CR5_W0W(word_width);
- val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
if (sai->big_endian_data)
val_cr5 |= FSL_SAI_CR5_FBT(0);
else
val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
- val_mr = ~0UL - ((1 << channels) - 1);
- regmap_write(sai->regmap, reg_cr4, val_cr4);
- regmap_write(sai->regmap, reg_cr5, val_cr5);
- regmap_write(sai->regmap, reg_mr, val_mr);
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
+ FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+ val_cr4);
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx),
+ FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+ FSL_SAI_CR5_FBT_MASK, val_cr5);
+ regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1));
return 0;
}
@@ -339,6 +326,7 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
u32 tcsr, rcsr;
/*
@@ -353,14 +341,6 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr);
regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- tcsr |= FSL_SAI_CSR_FRDE;
- rcsr &= ~FSL_SAI_CSR_FRDE;
- } else {
- rcsr |= FSL_SAI_CSR_FRDE;
- tcsr &= ~FSL_SAI_CSR_FRDE;
- }
-
/*
* It is recommended that the transmitter is the last enabled
* and the first disabled.
@@ -369,22 +349,33 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- tcsr |= FSL_SAI_CSR_TERE;
- rcsr |= FSL_SAI_CSR_TERE;
+ if (!(tcsr & FSL_SAI_CSR_FRDE || rcsr & FSL_SAI_CSR_FRDE)) {
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
+ FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
+ FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+ }
- regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
- regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+ FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+ FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (!(cpu_dai->playback_active || cpu_dai->capture_active)) {
- tcsr &= ~FSL_SAI_CSR_TERE;
- rcsr &= ~FSL_SAI_CSR_TERE;
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+ FSL_SAI_CSR_FRDE, 0);
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx),
+ FSL_SAI_CSR_xIE_MASK, 0);
+
+ /* Check if the opposite FRDE is also disabled */
+ if (!(tx ? rcsr & FSL_SAI_CSR_FRDE : tcsr & FSL_SAI_CSR_FRDE)) {
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
+ FSL_SAI_CSR_TERE, 0);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
+ FSL_SAI_CSR_TERE, 0);
}
-
- regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
- regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
break;
default:
return -EINVAL;
@@ -397,14 +388,17 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- u32 reg;
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ struct device *dev = &sai->pdev->dev;
+ int ret;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- reg = FSL_SAI_TCR3;
- else
- reg = FSL_SAI_RCR3;
+ ret = clk_prepare_enable(sai->bus_clk);
+ if (ret) {
+ dev_err(dev, "failed to enable bus clock: %d\n", ret);
+ return ret;
+ }
- regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE,
FSL_SAI_CR3_TRCE);
return 0;
@@ -414,15 +408,11 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- u32 reg;
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- reg = FSL_SAI_TCR3;
- else
- reg = FSL_SAI_RCR3;
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
- regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
- ~FSL_SAI_CR3_TRCE);
+ clk_disable_unprepare(sai->bus_clk);
}
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
@@ -438,8 +428,8 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
- regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, FSL_SAI_FLAGS);
- regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, FSL_SAI_FLAGS);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
FSL_SAI_MAXBURST_TX * 2);
regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
@@ -555,7 +545,8 @@ static int fsl_sai_probe(struct platform_device *pdev)
struct fsl_sai *sai;
struct resource *res;
void __iomem *base;
- int irq, ret;
+ char tmp[8];
+ int irq, ret, i;
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
if (!sai)
@@ -563,6 +554,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
sai->pdev = pdev;
+ if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai"))
+ sai->sai_on_imx = true;
+
sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
if (sai->big_endian_regs)
fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
@@ -575,12 +569,35 @@ static int fsl_sai_probe(struct platform_device *pdev)
return PTR_ERR(base);
sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
- "sai", base, &fsl_sai_regmap_config);
+ "bus", base, &fsl_sai_regmap_config);
+
+ /* Compatible with old DTB cases */
+ if (IS_ERR(sai->regmap))
+ sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+ "sai", base, &fsl_sai_regmap_config);
if (IS_ERR(sai->regmap)) {
dev_err(&pdev->dev, "regmap init failed\n");
return PTR_ERR(sai->regmap);
}
+ /* No error out for old DTB cases but only mark the clock NULL */
+ sai->bus_clk = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(sai->bus_clk)) {
+ dev_err(&pdev->dev, "failed to get bus clock: %ld\n",
+ PTR_ERR(sai->bus_clk));
+ sai->bus_clk = NULL;
+ }
+
+ for (i = 0; i < FSL_SAI_MCLK_MAX; i++) {
+ sprintf(tmp, "mclk%d", i + 1);
+ sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
+ if (IS_ERR(sai->mclk_clk[i])) {
+ dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n",
+ i + 1, PTR_ERR(sai->mclk_clk[i]));
+ sai->mclk_clk[i] = NULL;
+ }
+ }
+
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
@@ -605,12 +622,16 @@ static int fsl_sai_probe(struct platform_device *pdev)
if (ret)
return ret;
- return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
- SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
+ if (sai->sai_on_imx)
+ return imx_pcm_dma_init(pdev);
+ else
+ return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
+ SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
}
static const struct of_device_id fsl_sai_ids[] = {
{ .compatible = "fsl,vf610-sai", },
+ { .compatible = "fsl,imx6sx-sai", },
{ /* sentinel */ }
};
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index a264185c7138..0e6c9f595d75 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -35,6 +35,16 @@
#define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */
#define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */
+#define FSL_SAI_xCSR(tx) (tx ? FSL_SAI_TCSR : FSL_SAI_RCSR)
+#define FSL_SAI_xCR1(tx) (tx ? FSL_SAI_TCR1 : FSL_SAI_RCR1)
+#define FSL_SAI_xCR2(tx) (tx ? FSL_SAI_TCR2 : FSL_SAI_RCR2)
+#define FSL_SAI_xCR3(tx) (tx ? FSL_SAI_TCR3 : FSL_SAI_RCR3)
+#define FSL_SAI_xCR4(tx) (tx ? FSL_SAI_TCR4 : FSL_SAI_RCR4)
+#define FSL_SAI_xCR5(tx) (tx ? FSL_SAI_TCR5 : FSL_SAI_RCR5)
+#define FSL_SAI_xDR(tx) (tx ? FSL_SAI_TDR : FSL_SAI_RDR)
+#define FSL_SAI_xFR(tx) (tx ? FSL_SAI_TFR : FSL_SAI_RFR)
+#define FSL_SAI_xMR(tx) (tx ? FSL_SAI_TMR : FSL_SAI_RMR)
+
/* SAI Transmit/Recieve Control Register */
#define FSL_SAI_CSR_TERE BIT(31)
#define FSL_SAI_CSR_FR BIT(25)
@@ -48,6 +58,7 @@
#define FSL_SAI_CSR_FWF BIT(17)
#define FSL_SAI_CSR_FRF BIT(16)
#define FSL_SAI_CSR_xIE_SHIFT 8
+#define FSL_SAI_CSR_xIE_MASK (0x1f << FSL_SAI_CSR_xIE_SHIFT)
#define FSL_SAI_CSR_WSIE BIT(12)
#define FSL_SAI_CSR_SEIE BIT(11)
#define FSL_SAI_CSR_FEIE BIT(10)
@@ -108,6 +119,8 @@
#define FSL_SAI_CLK_MAST2 2
#define FSL_SAI_CLK_MAST3 3
+#define FSL_SAI_MCLK_MAX 3
+
/* SAI data transfer numbers per DMA request */
#define FSL_SAI_MAXBURST_TX 6
#define FSL_SAI_MAXBURST_RX 6
@@ -115,10 +128,13 @@
struct fsl_sai {
struct platform_device *pdev;
struct regmap *regmap;
+ struct clk *bus_clk;
+ struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
bool big_endian_regs;
bool big_endian_data;
bool is_dsp_mode;
+ bool sai_on_imx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 6452ca83d889..b912d45a2a4c 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -13,18 +13,18 @@
* kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/bitrev.h>
#include <linux/clk.h>
#include <linux/clk-private.h>
-#include <linux/bitrev.h>
-#include <linux/regmap.h>
+#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
+#include <linux/regmap.h>
#include <sound/asoundef.h>
-#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
#include "fsl_spdif.h"
#include "imx-pcm.h"
@@ -69,17 +69,42 @@ struct spdif_mixer_control {
u32 ready_buf;
};
+/**
+ * fsl_spdif_priv: Freescale SPDIF private data
+ *
+ * @fsl_spdif_control: SPDIF control data
+ * @cpu_dai_drv: cpu dai driver
+ * @pdev: platform device pointer
+ * @regmap: regmap handler
+ * @dpll_locked: dpll lock flag
+ * @txrate: the best rates for playback
+ * @txclk_df: STC_TXCLK_DF dividers value for playback
+ * @sysclk_df: STC_SYSCLK_DF dividers value for playback
+ * @txclk_src: STC_TXCLK_SRC values for playback
+ * @rxclk_src: SRPC_CLKSRC_SEL values for capture
+ * @txclk: tx clock sources for playback
+ * @rxclk: rx clock sources for capture
+ * @coreclk: core clock for register access via DMA
+ * @sysclk: system clock for rx clock rate measurement
+ * @dma_params_tx: DMA parameters for transmit channel
+ * @dma_params_rx: DMA parameters for receive channel
+ * @name: driver name
+ */
struct fsl_spdif_priv {
struct spdif_mixer_control fsl_spdif_control;
struct snd_soc_dai_driver cpu_dai_drv;
struct platform_device *pdev;
struct regmap *regmap;
bool dpll_locked;
- u8 txclk_div[SPDIF_TXRATE_MAX];
+ u16 txrate[SPDIF_TXRATE_MAX];
+ u8 txclk_df[SPDIF_TXRATE_MAX];
+ u8 sysclk_df[SPDIF_TXRATE_MAX];
u8 txclk_src[SPDIF_TXRATE_MAX];
u8 rxclk_src;
struct clk *txclk[SPDIF_TXRATE_MAX];
struct clk *rxclk;
+ struct clk *coreclk;
+ struct clk *sysclk;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -349,7 +374,7 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
struct platform_device *pdev = spdif_priv->pdev;
unsigned long csfs = 0;
u32 stc, mask, rate;
- u8 clk, div;
+ u8 clk, txclk_df, sysclk_df;
int ret;
switch (sample_rate) {
@@ -376,25 +401,31 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
return -EINVAL;
}
- div = spdif_priv->txclk_div[rate];
- if (div == 0) {
- dev_err(&pdev->dev, "the divisor can't be zero\n");
+ txclk_df = spdif_priv->txclk_df[rate];
+ if (txclk_df == 0) {
+ dev_err(&pdev->dev, "the txclk_df can't be zero\n");
return -EINVAL;
}
+ sysclk_df = spdif_priv->sysclk_df[rate];
+
+ /* Don't mess up the clocks from other modules */
+ if (clk != STC_TXCLK_SPDIF_ROOT)
+ goto clk_set_bypass;
+
/*
- * The S/PDIF block needs a clock of 64 * fs * div. The S/PDIF block
- * will divide by (div). So request 64 * fs * (div+1) which will
- * get rounded.
+ * The S/PDIF block needs a clock of 64 * fs * txclk_df.
+ * So request 64 * fs * (txclk_df + 1) to get rounded.
*/
- ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (div + 1));
+ ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (txclk_df + 1));
if (ret) {
dev_err(&pdev->dev, "failed to set tx clock rate\n");
return ret;
}
+clk_set_bypass:
dev_dbg(&pdev->dev, "expected clock rate = %d\n",
- (64 * sample_rate * div));
+ (64 * sample_rate * txclk_df * sysclk_df));
dev_dbg(&pdev->dev, "actual clock rate = %ld\n",
clk_get_rate(spdif_priv->txclk[rate]));
@@ -402,11 +433,15 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs);
/* select clock source and divisor */
- stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | STC_TXCLK_DIV(div);
- mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DIV_MASK;
+ stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | STC_TXCLK_DF(txclk_df);
+ mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DF_MASK;
regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc);
- dev_dbg(&pdev->dev, "set sample rate to %d\n", sample_rate);
+ regmap_update_bits(regmap, REG_SPDIF_STC,
+ STC_SYSCLK_DF_MASK, STC_SYSCLK_DF(sysclk_df));
+
+ dev_dbg(&pdev->dev, "set sample rate to %dHz for %dHz playback\n",
+ spdif_priv->txrate[rate], sample_rate);
return 0;
}
@@ -423,10 +458,16 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
/* Reset module and interrupts only for first initialization */
if (!cpu_dai->active) {
+ ret = clk_prepare_enable(spdif_priv->coreclk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable core clock\n");
+ return ret;
+ }
+
ret = spdif_softreset(spdif_priv);
if (ret) {
dev_err(&pdev->dev, "failed to soft reset\n");
- return ret;
+ goto err;
}
/* Disable all the interrupts */
@@ -454,6 +495,11 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0);
return 0;
+
+err:
+ clk_disable_unprepare(spdif_priv->coreclk);
+
+ return ret;
}
static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
@@ -484,6 +530,7 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
spdif_intr_status_clear(spdif_priv);
regmap_update_bits(regmap, REG_SPDIF_SCR,
SCR_LOW_POWER, SCR_LOW_POWER);
+ clk_disable_unprepare(spdif_priv->coreclk);
}
}
@@ -754,7 +801,7 @@ static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv,
clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf;
if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) {
/* Get bus clock from system */
- busclk_freq = clk_get_rate(spdif_priv->rxclk);
+ busclk_freq = clk_get_rate(spdif_priv->sysclk);
}
/* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */
@@ -997,43 +1044,61 @@ static struct regmap_config fsl_spdif_regmap_config = {
static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
struct clk *clk, u64 savesub,
- enum spdif_txrate index)
+ enum spdif_txrate index, bool round)
{
const u32 rate[] = { 32000, 44100, 48000 };
+ bool is_sysclk = clk == spdif_priv->sysclk;
u64 rate_ideal, rate_actual, sub;
- u32 div, arate;
-
- for (div = 1; div <= 128; div++) {
- rate_ideal = rate[index] * (div + 1) * 64;
- rate_actual = clk_round_rate(clk, rate_ideal);
-
- arate = rate_actual / 64;
- arate /= div;
-
- if (arate == rate[index]) {
- /* We are lucky */
- savesub = 0;
- spdif_priv->txclk_div[index] = div;
- break;
- } else if (arate / rate[index] == 1) {
- /* A little bigger than expect */
- sub = (arate - rate[index]) * 100000;
- do_div(sub, rate[index]);
- if (sub < savesub) {
+ u32 sysclk_dfmin, sysclk_dfmax;
+ u32 txclk_df, sysclk_df, arate;
+
+ /* The sysclk has an extra divisor [2, 512] */
+ sysclk_dfmin = is_sysclk ? 2 : 1;
+ sysclk_dfmax = is_sysclk ? 512 : 1;
+
+ for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) {
+ for (txclk_df = 1; txclk_df <= 128; txclk_df++) {
+ rate_ideal = rate[index] * (txclk_df + 1) * 64;
+ if (round)
+ rate_actual = clk_round_rate(clk, rate_ideal);
+ else
+ rate_actual = clk_get_rate(clk);
+
+ arate = rate_actual / 64;
+ arate /= txclk_df * sysclk_df;
+
+ if (arate == rate[index]) {
+ /* We are lucky */
+ savesub = 0;
+ spdif_priv->txclk_df[index] = txclk_df;
+ spdif_priv->sysclk_df[index] = sysclk_df;
+ spdif_priv->txrate[index] = arate;
+ goto out;
+ } else if (arate / rate[index] == 1) {
+ /* A little bigger than expect */
+ sub = (arate - rate[index]) * 100000;
+ do_div(sub, rate[index]);
+ if (sub >= savesub)
+ continue;
savesub = sub;
- spdif_priv->txclk_div[index] = div;
- }
- } else if (rate[index] / arate == 1) {
- /* A little smaller than expect */
- sub = (rate[index] - arate) * 100000;
- do_div(sub, rate[index]);
- if (sub < savesub) {
+ spdif_priv->txclk_df[index] = txclk_df;
+ spdif_priv->sysclk_df[index] = sysclk_df;
+ spdif_priv->txrate[index] = arate;
+ } else if (rate[index] / arate == 1) {
+ /* A little smaller than expect */
+ sub = (rate[index] - arate) * 100000;
+ do_div(sub, rate[index]);
+ if (sub >= savesub)
+ continue;
savesub = sub;
- spdif_priv->txclk_div[index] = div;
+ spdif_priv->txclk_df[index] = txclk_df;
+ spdif_priv->sysclk_df[index] = sysclk_df;
+ spdif_priv->txrate[index] = arate;
}
}
}
+out:
return savesub;
}
@@ -1058,7 +1123,8 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
if (!clk_get_rate(clk))
continue;
- ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index);
+ ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index,
+ i == STC_TXCLK_SPDIF_ROOT);
if (savesub == ret)
continue;
@@ -1073,8 +1139,13 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate\n",
spdif_priv->txclk_src[index], rate[index]);
- dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate\n",
- spdif_priv->txclk_div[index], rate[index]);
+ dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n",
+ spdif_priv->txclk_df[index], rate[index]);
+ if (spdif_priv->txclk[index] == spdif_priv->sysclk)
+ dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n",
+ spdif_priv->sysclk_df[index], rate[index]);
+ dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n",
+ rate[index], spdif_priv->txrate[index]);
return 0;
}
@@ -1134,6 +1205,20 @@ static int fsl_spdif_probe(struct platform_device *pdev)
return ret;
}
+ /* Get system clock for rx clock rate calculation */
+ spdif_priv->sysclk = devm_clk_get(&pdev->dev, "rxtx5");
+ if (IS_ERR(spdif_priv->sysclk)) {
+ dev_err(&pdev->dev, "no sys clock (rxtx5) in devicetree\n");
+ return PTR_ERR(spdif_priv->sysclk);
+ }
+
+ /* Get core clock for data register access via DMA */
+ spdif_priv->coreclk = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(spdif_priv->coreclk)) {
+ dev_err(&pdev->dev, "no core clock in devicetree\n");
+ return PTR_ERR(spdif_priv->coreclk);
+ }
+
/* Select clock source for rx/tx clock */
spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1");
if (IS_ERR(spdif_priv->rxclk)) {
@@ -1186,6 +1271,7 @@ static int fsl_spdif_probe(struct platform_device *pdev)
static const struct of_device_id fsl_spdif_dt_ids[] = {
{ .compatible = "fsl,imx35-spdif", },
+ { .compatible = "fsl,vf610-spdif", },
{}
};
MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h
index b1266790d117..16fde4b927d3 100644
--- a/sound/soc/fsl/fsl_spdif.h
+++ b/sound/soc/fsl/fsl_spdif.h
@@ -143,20 +143,22 @@ enum spdif_gainsel {
#define INT_RXFIFO_FUL (1 << 0)
/* SPDIF Clock register */
-#define STC_SYSCLK_DIV_OFFSET 11
-#define STC_SYSCLK_DIV_MASK (0x1ff << STC_TXCLK_SRC_OFFSET)
-#define STC_SYSCLK_DIV(x) ((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_SYSCLK_DIV_MASK)
+#define STC_SYSCLK_DF_OFFSET 11
+#define STC_SYSCLK_DF_MASK (0x1ff << STC_SYSCLK_DF_OFFSET)
+#define STC_SYSCLK_DF(x) ((((x) - 1) << STC_SYSCLK_DF_OFFSET) & STC_SYSCLK_DF_MASK)
#define STC_TXCLK_SRC_OFFSET 8
#define STC_TXCLK_SRC_MASK (0x7 << STC_TXCLK_SRC_OFFSET)
#define STC_TXCLK_SRC_SET(x) ((x << STC_TXCLK_SRC_OFFSET) & STC_TXCLK_SRC_MASK)
#define STC_TXCLK_ALL_EN_OFFSET 7
#define STC_TXCLK_ALL_EN_MASK (1 << STC_TXCLK_ALL_EN_OFFSET)
#define STC_TXCLK_ALL_EN (1 << STC_TXCLK_ALL_EN_OFFSET)
-#define STC_TXCLK_DIV_OFFSET 0
-#define STC_TXCLK_DIV_MASK (0x7ff << STC_TXCLK_DIV_OFFSET)
-#define STC_TXCLK_DIV(x) ((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_TXCLK_DIV_MASK)
+#define STC_TXCLK_DF_OFFSET 0
+#define STC_TXCLK_DF_MASK (0x7ff << STC_TXCLK_DF_OFFSET)
+#define STC_TXCLK_DF(x) ((((x) - 1) << STC_TXCLK_DF_OFFSET) & STC_TXCLK_DF_MASK)
#define STC_TXCLK_SRC_MAX 8
+#define STC_TXCLK_SPDIF_ROOT 1
+
/* SPDIF tx rate */
enum spdif_txrate {
SPDIF_TXRATE_32000 = 0,
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 5428a1fda260..f233d915b7e4 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -35,11 +35,11 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
-#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
@@ -113,8 +113,6 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
#define FSLSSI_SIER_DBG_TX_FLAGS (CCSR_SSI_SIER_TFE0_EN | \
CCSR_SSI_SIER_TLS_EN | CCSR_SSI_SIER_TFS_EN | \
CCSR_SSI_SIER_TUE0_EN | CCSR_SSI_SIER_TFRC_EN)
-#define FSLSSI_SISR_MASK (FSLSSI_SIER_DBG_RX_FLAGS | FSLSSI_SIER_DBG_TX_FLAGS)
-
enum fsl_ssi_type {
FSL_SSI_MCP8610,
@@ -146,7 +144,6 @@ struct fsl_ssi_rxtx_reg_val {
* @cpu_dai: the CPU DAI for this device
* @dev_attr: the sysfs device attribute structure
* @stats: SSI statistics
- * @name: name for this device
*/
struct fsl_ssi_private {
struct ccsr_ssi __iomem *ssi;
@@ -155,15 +152,11 @@ struct fsl_ssi_private {
unsigned int fifo_depth;
struct snd_soc_dai_driver cpu_dai_drv;
struct platform_device *pdev;
+ unsigned int dai_fmt;
enum fsl_ssi_type hw_type;
- bool new_binding;
- bool ssi_on_imx;
- bool imx_ac97;
bool use_dma;
bool baudclk_locked;
- bool irq_stats;
- bool offline_config;
bool use_dual_fifo;
u8 i2s_mode;
spinlock_t baudclk_lock;
@@ -171,39 +164,11 @@ struct fsl_ssi_private {
struct clk *clk;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
- struct imx_dma_data filter_data_tx;
- struct imx_dma_data filter_data_rx;
struct imx_pcm_fiq_params fiq_params;
/* Register values for rx/tx configuration */
struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
- struct {
- unsigned int rfrc;
- unsigned int tfrc;
- unsigned int cmdau;
- unsigned int cmddu;
- unsigned int rxt;
- unsigned int rdr1;
- unsigned int rdr0;
- unsigned int tde1;
- unsigned int tde0;
- unsigned int roe1;
- unsigned int roe0;
- unsigned int tue1;
- unsigned int tue0;
- unsigned int tfs;
- unsigned int rfs;
- unsigned int tls;
- unsigned int rls;
- unsigned int rff1;
- unsigned int rff0;
- unsigned int tfe1;
- unsigned int tfe0;
- } stats;
- struct dentry *dbg_dir;
- struct dentry *dbg_stats;
-
- char name[1];
+ struct fsl_ssi_dbg dbg_stats;
};
static const struct of_device_id fsl_ssi_ids[] = {
@@ -215,6 +180,54 @@ static const struct of_device_id fsl_ssi_ids[] = {
};
MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
+static bool fsl_ssi_is_ac97(struct fsl_ssi_private *ssi_private)
+{
+ return !!(ssi_private->dai_fmt & SND_SOC_DAIFMT_AC97);
+}
+
+static bool fsl_ssi_on_imx(struct fsl_ssi_private *ssi_private)
+{
+ switch (ssi_private->hw_type) {
+ case FSL_SSI_MX21:
+ case FSL_SSI_MX35:
+ case FSL_SSI_MX51:
+ return true;
+ case FSL_SSI_MCP8610:
+ return false;
+ }
+
+ return false;
+}
+
+/*
+ * imx51 and later SoCs have a slightly different IP that allows the
+ * SSI configuration while the SSI unit is running.
+ *
+ * More important, it is necessary on those SoCs to configure the
+ * sperate TX/RX DMA bits just before starting the stream
+ * (fsl_ssi_trigger). The SDMA unit has to be configured before fsl_ssi
+ * sends any DMA requests to the SDMA unit, otherwise it is not defined
+ * how the SDMA unit handles the DMA request.
+ *
+ * SDMA units are present on devices starting at imx35 but the imx35
+ * reference manual states that the DMA bits should not be changed
+ * while the SSI unit is running (SSIEN). So we support the necessary
+ * online configuration of fsl-ssi starting at imx51.
+ */
+static bool fsl_ssi_offline_config(struct fsl_ssi_private *ssi_private)
+{
+ switch (ssi_private->hw_type) {
+ case FSL_SSI_MCP8610:
+ case FSL_SSI_MX21:
+ case FSL_SSI_MX35:
+ return true;
+ case FSL_SSI_MX51:
+ return false;
+ }
+
+ return true;
+}
+
/**
* fsl_ssi_isr: SSI interrupt handler
*
@@ -231,7 +244,6 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
{
struct fsl_ssi_private *ssi_private = dev_id;
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
- irqreturn_t ret = IRQ_NONE;
__be32 sisr;
__be32 sisr2;
__be32 sisr_write_mask = 0;
@@ -258,217 +270,18 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
were interrupted for. We mask it with the Interrupt Enable register
so that we only check for events that we're interested in.
*/
- sisr = read_ssi(&ssi->sisr) & FSLSSI_SISR_MASK;
-
- if (sisr & CCSR_SSI_SISR_RFRC) {
- ssi_private->stats.rfrc++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_TFRC) {
- ssi_private->stats.tfrc++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_CMDAU) {
- ssi_private->stats.cmdau++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_CMDDU) {
- ssi_private->stats.cmddu++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_RXT) {
- ssi_private->stats.rxt++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_RDR1) {
- ssi_private->stats.rdr1++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_RDR0) {
- ssi_private->stats.rdr0++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_TDE1) {
- ssi_private->stats.tde1++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_TDE0) {
- ssi_private->stats.tde0++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_ROE1) {
- ssi_private->stats.roe1++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_ROE0) {
- ssi_private->stats.roe0++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_TUE1) {
- ssi_private->stats.tue1++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_TUE0) {
- ssi_private->stats.tue0++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_TFS) {
- ssi_private->stats.tfs++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_RFS) {
- ssi_private->stats.rfs++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_TLS) {
- ssi_private->stats.tls++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_RLS) {
- ssi_private->stats.rls++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_RFF1) {
- ssi_private->stats.rff1++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_RFF0) {
- ssi_private->stats.rff0++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_TFE1) {
- ssi_private->stats.tfe1++;
- ret = IRQ_HANDLED;
- }
-
- if (sisr & CCSR_SSI_SISR_TFE0) {
- ssi_private->stats.tfe0++;
- ret = IRQ_HANDLED;
- }
+ sisr = read_ssi(&ssi->sisr);
sisr2 = sisr & sisr_write_mask;
/* Clear the bits that we set */
if (sisr2)
write_ssi(sisr2, &ssi->sisr);
- return ret;
-}
-
-#if IS_ENABLED(CONFIG_DEBUG_FS)
-/* Show the statistics of a flag only if its interrupt is enabled. The
- * compiler will optimze this code to a no-op if the interrupt is not
- * enabled.
- */
-#define SIER_SHOW(flag, name) \
- do { \
- if (FSLSSI_SISR_MASK & CCSR_SSI_SIER_##flag) \
- seq_printf(s, #name "=%u\n", ssi_private->stats.name); \
- } while (0)
-
-
-/**
- * fsl_sysfs_ssi_show: display SSI statistics
- *
- * Display the statistics for the current SSI device. To avoid confusion,
- * we only show those counts that are enabled.
- */
-static int fsl_ssi_stats_show(struct seq_file *s, void *unused)
-{
- struct fsl_ssi_private *ssi_private = s->private;
-
- SIER_SHOW(RFRC_EN, rfrc);
- SIER_SHOW(TFRC_EN, tfrc);
- SIER_SHOW(CMDAU_EN, cmdau);
- SIER_SHOW(CMDDU_EN, cmddu);
- SIER_SHOW(RXT_EN, rxt);
- SIER_SHOW(RDR1_EN, rdr1);
- SIER_SHOW(RDR0_EN, rdr0);
- SIER_SHOW(TDE1_EN, tde1);
- SIER_SHOW(TDE0_EN, tde0);
- SIER_SHOW(ROE1_EN, roe1);
- SIER_SHOW(ROE0_EN, roe0);
- SIER_SHOW(TUE1_EN, tue1);
- SIER_SHOW(TUE0_EN, tue0);
- SIER_SHOW(TFS_EN, tfs);
- SIER_SHOW(RFS_EN, rfs);
- SIER_SHOW(TLS_EN, tls);
- SIER_SHOW(RLS_EN, rls);
- SIER_SHOW(RFF1_EN, rff1);
- SIER_SHOW(RFF0_EN, rff0);
- SIER_SHOW(TFE1_EN, tfe1);
- SIER_SHOW(TFE0_EN, tfe0);
+ fsl_ssi_dbg_isr(&ssi_private->dbg_stats, sisr);
- return 0;
+ return IRQ_HANDLED;
}
-static int fsl_ssi_stats_open(struct inode *inode, struct file *file)
-{
- return single_open(file, fsl_ssi_stats_show, inode->i_private);
-}
-
-static const struct file_operations fsl_ssi_stats_ops = {
- .open = fsl_ssi_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int fsl_ssi_debugfs_create(struct fsl_ssi_private *ssi_private,
- struct device *dev)
-{
- ssi_private->dbg_dir = debugfs_create_dir(dev_name(dev), NULL);
- if (!ssi_private->dbg_dir)
- return -ENOMEM;
-
- ssi_private->dbg_stats = debugfs_create_file("stats", S_IRUGO,
- ssi_private->dbg_dir, ssi_private, &fsl_ssi_stats_ops);
- if (!ssi_private->dbg_stats) {
- debugfs_remove(ssi_private->dbg_dir);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private)
-{
- debugfs_remove(ssi_private->dbg_stats);
- debugfs_remove(ssi_private->dbg_dir);
-}
-
-#else
-
-static int fsl_ssi_debugfs_create(struct fsl_ssi_private *ssi_private,
- struct device *dev)
-{
- return 0;
-}
-
-static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private)
-{
-}
-
-#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */
-
/*
* Enable/Disable all rx/tx config flags at once.
*/
@@ -490,6 +303,26 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private,
}
/*
+ * Calculate the bits that have to be disabled for the current stream that is
+ * getting disabled. This keeps the bits enabled that are necessary for the
+ * second stream to work if 'stream_active' is true.
+ *
+ * Detailed calculation:
+ * These are the values that need to be active after disabling. For non-active
+ * second stream, this is 0:
+ * vals_stream * !!stream_active
+ *
+ * The following computes the overall differences between the setup for the
+ * to-disable stream and the active stream, a simple XOR:
+ * vals_disable ^ (vals_stream * !!(stream_active))
+ *
+ * The full expression adds a mask on all values we care about
+ */
+#define fsl_ssi_disable_val(vals_disable, vals_stream, stream_active) \
+ ((vals_disable) & \
+ ((vals_disable) ^ ((vals_stream) * (u32)!!(stream_active))))
+
+/*
* Enable/Disable a ssi configuration. You have to pass either
* ssi_private->rxtx_reg_val.rx or tx as vals parameter.
*/
@@ -501,6 +334,12 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
u32 scr_val = read_ssi(&ssi->scr);
int nr_active_streams = !!(scr_val & CCSR_SSI_SCR_TE) +
!!(scr_val & CCSR_SSI_SCR_RE);
+ int keep_active;
+
+ if (nr_active_streams - 1 > 0)
+ keep_active = 1;
+ else
+ keep_active = 0;
/* Find the other direction values rx or tx which we do not want to
* modify */
@@ -511,7 +350,8 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
/* If vals should be disabled, start with disabling the unit */
if (!enable) {
- u32 scr = vals->scr & (vals->scr ^ avals->scr);
+ u32 scr = fsl_ssi_disable_val(vals->scr, avals->scr,
+ keep_active);
write_ssi_mask(&ssi->scr, scr, 0);
}
@@ -520,9 +360,9 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
* reconfiguration, so we have to enable all necessary flags at once
* even if we do not use them later (capture and playback configuration)
*/
- if (ssi_private->offline_config) {
+ if (fsl_ssi_offline_config(ssi_private)) {
if ((enable && !nr_active_streams) ||
- (!enable && nr_active_streams == 1))
+ (!enable && !keep_active))
fsl_ssi_rxtx_config(ssi_private, enable);
goto config_done;
@@ -551,9 +391,12 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
*/
/* These assignments are simply vals without bits set in avals*/
- sier = vals->sier & (vals->sier ^ avals->sier);
- srcr = vals->srcr & (vals->srcr ^ avals->srcr);
- stcr = vals->stcr & (vals->stcr ^ avals->stcr);
+ sier = fsl_ssi_disable_val(vals->sier, avals->sier,
+ keep_active);
+ srcr = fsl_ssi_disable_val(vals->srcr, avals->srcr,
+ keep_active);
+ stcr = fsl_ssi_disable_val(vals->stcr, avals->stcr,
+ keep_active);
write_ssi_mask(&ssi->srcr, srcr, 0);
write_ssi_mask(&ssi->stcr, stcr, 0);
@@ -593,7 +436,7 @@ static void fsl_ssi_setup_reg_vals(struct fsl_ssi_private *ssi_private)
reg->tx.stcr = CCSR_SSI_STCR_TFEN0;
reg->tx.scr = 0;
- if (!ssi_private->imx_ac97) {
+ if (!fsl_ssi_is_ac97(ssi_private)) {
reg->rx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE;
reg->rx.sier |= CCSR_SSI_SIER_RFF0_EN;
reg->tx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE;
@@ -642,96 +485,6 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private)
write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor);
}
-static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
-{
- struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
- u8 wm;
- int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
-
- fsl_ssi_setup_reg_vals(ssi_private);
-
- if (ssi_private->imx_ac97)
- ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET;
- else
- ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
-
- /*
- * Section 16.5 of the MPC8610 reference manual says that the SSI needs
- * to be disabled before updating the registers we set here.
- */
- write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
-
- /*
- * Program the SSI into I2S Slave Non-Network Synchronous mode. Also
- * enable the transmit and receive FIFO.
- *
- * FIXME: Little-endian samples require a different shift dir
- */
- write_ssi_mask(&ssi->scr,
- CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
- CCSR_SSI_SCR_TFR_CLK_DIS |
- ssi_private->i2s_mode |
- (synchronous ? CCSR_SSI_SCR_SYN : 0));
-
- write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFSI |
- CCSR_SSI_STCR_TEFS | CCSR_SSI_STCR_TSCKP, &ssi->stcr);
-
- write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFSI |
- CCSR_SSI_SRCR_REFS | CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
-
- /*
- * The DC and PM bits are only used if the SSI is the clock master.
- */
-
- /*
- * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't
- * use FIFO 1. We program the transmit water to signal a DMA transfer
- * if there are only two (or fewer) elements left in the FIFO. Two
- * elements equals one frame (left channel, right channel). This value,
- * however, depends on the depth of the transmit buffer.
- *
- * We set the watermark on the same level as the DMA burstsize. For
- * fiq it is probably better to use the biggest possible watermark
- * size.
- */
- if (ssi_private->use_dma)
- wm = ssi_private->fifo_depth - 2;
- else
- wm = ssi_private->fifo_depth;
-
- write_ssi(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) |
- CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm),
- &ssi->sfcsr);
-
- /*
- * For ac97 interrupts are enabled with the startup of the substream
- * because it is also running without an active substream. Normally SSI
- * is only enabled when there is a substream.
- */
- if (ssi_private->imx_ac97)
- fsl_ssi_setup_ac97(ssi_private);
-
- /*
- * Set a default slot number so that there is no need for those common
- * cases like I2S mode to call the extra set_tdm_slot() any more.
- */
- if (!ssi_private->imx_ac97) {
- write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK,
- CCSR_SSI_SxCCR_DC(2));
- write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK,
- CCSR_SSI_SxCCR_DC(2));
- }
-
- if (ssi_private->use_dual_fifo) {
- write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1);
- write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1);
- write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN);
- }
-
- return 0;
-}
-
-
/**
* fsl_ssi_startup: create a new substream
*
@@ -748,12 +501,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
snd_soc_dai_get_drvdata(rtd->cpu_dai);
unsigned long flags;
- /* First, we only do fsl_ssi_setup() when SSI is going to be active.
- * Second, fsl_ssi_setup was already called by ac97_init earlier if
- * the driver is in ac97 mode.
- */
- if (!dai->active && !ssi_private->imx_ac97) {
- fsl_ssi_setup(ssi_private);
+ if (!dai->active && !fsl_ssi_is_ac97(ssi_private)) {
spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
ssi_private->baudclk_locked = false;
spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
@@ -772,6 +520,102 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
}
/**
+ * fsl_ssi_set_dai_sysclk - configure Digital Audio Interface bit clock
+ *
+ * Note: This function can be only called when using SSI as DAI master
+ *
+ * Quick instruction for parameters:
+ * freq: Output BCLK frequency = samplerate * 32 (fixed) * channels
+ * dir: SND_SOC_CLOCK_OUT -> TxBCLK, SND_SOC_CLOCK_IN -> RxBCLK.
+ */
+static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
+ struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ int synchronous = ssi_private->cpu_dai_drv.symmetric_rates, ret;
+ u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i;
+ unsigned long flags, clkrate, baudrate, tmprate;
+ u64 sub, savesub = 100000;
+
+ /* Don't apply it to any non-baudclk circumstance */
+ if (IS_ERR(ssi_private->baudclk))
+ return -EINVAL;
+
+ /* It should be already enough to divide clock by setting pm alone */
+ psr = 0;
+ div2 = 0;
+
+ factor = (div2 + 1) * (7 * psr + 1) * 2;
+
+ for (i = 0; i < 255; i++) {
+ /* The bclk rate must be smaller than 1/5 sysclk rate */
+ if (factor * (i + 1) < 5)
+ continue;
+
+ tmprate = freq * factor * (i + 2);
+ clkrate = clk_round_rate(ssi_private->baudclk, tmprate);
+
+ do_div(clkrate, factor);
+ afreq = (u32)clkrate / (i + 1);
+
+ if (freq == afreq)
+ sub = 0;
+ else if (freq / afreq == 1)
+ sub = freq - afreq;
+ else if (afreq / freq == 1)
+ sub = afreq - freq;
+ else
+ continue;
+
+ /* Calculate the fraction */
+ sub *= 100000;
+ do_div(sub, freq);
+
+ if (sub < savesub) {
+ baudrate = tmprate;
+ savesub = sub;
+ pm = i;
+ }
+
+ /* We are lucky */
+ if (savesub == 0)
+ break;
+ }
+
+ /* No proper pm found if it is still remaining the initial value */
+ if (pm == 999) {
+ dev_err(cpu_dai->dev, "failed to handle the required sysclk\n");
+ return -EINVAL;
+ }
+
+ stccr = CCSR_SSI_SxCCR_PM(pm + 1) | (div2 ? CCSR_SSI_SxCCR_DIV2 : 0) |
+ (psr ? CCSR_SSI_SxCCR_PSR : 0);
+ mask = CCSR_SSI_SxCCR_PM_MASK | CCSR_SSI_SxCCR_DIV2 |
+ CCSR_SSI_SxCCR_PSR;
+
+ if (dir == SND_SOC_CLOCK_OUT || synchronous)
+ write_ssi_mask(&ssi->stccr, mask, stccr);
+ else
+ write_ssi_mask(&ssi->srccr, mask, stccr);
+
+ spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
+ if (!ssi_private->baudclk_locked) {
+ ret = clk_set_rate(ssi_private->baudclk, baudrate);
+ if (ret) {
+ spin_unlock_irqrestore(&ssi_private->baudclk_lock,
+ flags);
+ dev_err(cpu_dai->dev, "failed to set baudclk rate\n");
+ return -EINVAL;
+ }
+ ssi_private->baudclk_locked = true;
+ }
+ spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
+
+ return 0;
+}
+
+/**
* fsl_ssi_hw_params - program the sample size
*
* Most of the SSI registers have been programmed in the startup function,
@@ -819,7 +663,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
else
write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
- if (!ssi_private->imx_ac97)
+ if (!fsl_ssi_is_ac97(ssi_private))
write_ssi_mask(&ssi->scr,
CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
channels == 1 ? 0 : ssi_private->i2s_mode);
@@ -835,9 +679,14 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
u32 strcr = 0, stcr, srcr, scr, mask;
+ u8 wm;
+
+ ssi_private->dai_fmt = fmt;
+
+ fsl_ssi_setup_reg_vals(ssi_private);
scr = read_ssi(&ssi->scr) & ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK);
- scr |= CCSR_SSI_SCR_NET;
+ scr |= CCSR_SSI_SCR_SYNC_TX_FS;
mask = CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR |
CCSR_SSI_STCR_TSCKP | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TFSL |
@@ -845,19 +694,19 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
stcr = read_ssi(&ssi->stcr) & ~mask;
srcr = read_ssi(&ssi->srcr) & ~mask;
+ ssi_private->i2s_mode = CCSR_SSI_SCR_NET;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
- ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_MASTER;
+ ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER;
break;
case SND_SOC_DAIFMT_CBM_CFM:
- ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
+ ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_SLAVE;
break;
default:
return -EINVAL;
}
- scr |= ssi_private->i2s_mode;
/* Data on rising edge of bclk, frame low, 1clk before data */
strcr |= CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TSCKP |
@@ -877,9 +726,13 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP |
CCSR_SSI_STCR_TXBIT0;
break;
+ case SND_SOC_DAIFMT_AC97:
+ ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_NORMAL;
+ break;
default:
return -EINVAL;
}
+ scr |= ssi_private->i2s_mode;
/* DAI clock inversion */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -929,99 +782,37 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
write_ssi(srcr, &ssi->srcr);
write_ssi(scr, &ssi->scr);
- return 0;
-}
-
-/**
- * fsl_ssi_set_dai_sysclk - configure Digital Audio Interface bit clock
- *
- * Note: This function can be only called when using SSI as DAI master
- *
- * Quick instruction for parameters:
- * freq: Output BCLK frequency = samplerate * 32 (fixed) * channels
- * dir: SND_SOC_CLOCK_OUT -> TxBCLK, SND_SOC_CLOCK_IN -> RxBCLK.
- */
-static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
- int clk_id, unsigned int freq, int dir)
-{
- struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
- struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
- int synchronous = ssi_private->cpu_dai_drv.symmetric_rates, ret;
- u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i;
- unsigned long flags, clkrate, baudrate, tmprate;
- u64 sub, savesub = 100000;
-
- /* Don't apply it to any non-baudclk circumstance */
- if (IS_ERR(ssi_private->baudclk))
- return -EINVAL;
-
- /* It should be already enough to divide clock by setting pm alone */
- psr = 0;
- div2 = 0;
-
- factor = (div2 + 1) * (7 * psr + 1) * 2;
-
- for (i = 0; i < 255; i++) {
- /* The bclk rate must be smaller than 1/5 sysclk rate */
- if (factor * (i + 1) < 5)
- continue;
-
- tmprate = freq * factor * (i + 2);
- clkrate = clk_round_rate(ssi_private->baudclk, tmprate);
-
- do_div(clkrate, factor);
- afreq = (u32)clkrate / (i + 1);
-
- if (freq == afreq)
- sub = 0;
- else if (freq / afreq == 1)
- sub = freq - afreq;
- else if (afreq / freq == 1)
- sub = afreq - freq;
- else
- continue;
-
- /* Calculate the fraction */
- sub *= 100000;
- do_div(sub, freq);
-
- if (sub < savesub) {
- baudrate = tmprate;
- savesub = sub;
- pm = i;
- }
+ /*
+ * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't
+ * use FIFO 1. We program the transmit water to signal a DMA transfer
+ * if there are only two (or fewer) elements left in the FIFO. Two
+ * elements equals one frame (left channel, right channel). This value,
+ * however, depends on the depth of the transmit buffer.
+ *
+ * We set the watermark on the same level as the DMA burstsize. For
+ * fiq it is probably better to use the biggest possible watermark
+ * size.
+ */
+ if (ssi_private->use_dma)
+ wm = ssi_private->fifo_depth - 2;
+ else
+ wm = ssi_private->fifo_depth;
- /* We are lucky */
- if (savesub == 0)
- break;
- }
+ write_ssi(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) |
+ CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm),
+ &ssi->sfcsr);
- /* No proper pm found if it is still remaining the initial value */
- if (pm == 999) {
- dev_err(cpu_dai->dev, "failed to handle the required sysclk\n");
- return -EINVAL;
+ if (ssi_private->use_dual_fifo) {
+ write_ssi_mask(&ssi->srcr, CCSR_SSI_SRCR_RFEN1,
+ CCSR_SSI_SRCR_RFEN1);
+ write_ssi_mask(&ssi->stcr, CCSR_SSI_STCR_TFEN1,
+ CCSR_SSI_STCR_TFEN1);
+ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TCH_EN,
+ CCSR_SSI_SCR_TCH_EN);
}
- stccr = CCSR_SSI_SxCCR_PM(pm + 1) | (div2 ? CCSR_SSI_SxCCR_DIV2 : 0) |
- (psr ? CCSR_SSI_SxCCR_PSR : 0);
- mask = CCSR_SSI_SxCCR_PM_MASK | CCSR_SSI_SxCCR_DIV2 | CCSR_SSI_SxCCR_PSR;
-
- if (dir == SND_SOC_CLOCK_OUT || synchronous)
- write_ssi_mask(&ssi->stccr, mask, stccr);
- else
- write_ssi_mask(&ssi->srccr, mask, stccr);
-
- spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
- if (!ssi_private->baudclk_locked) {
- ret = clk_set_rate(ssi_private->baudclk, baudrate);
- if (ret) {
- spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
- dev_err(cpu_dai->dev, "failed to set baudclk rate\n");
- return -EINVAL;
- }
- ssi_private->baudclk_locked = true;
- }
- spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
+ if (fmt & SND_SOC_DAIFMT_AC97)
+ fsl_ssi_setup_ac97(ssi_private);
return 0;
}
@@ -1097,7 +888,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
else
fsl_ssi_rx_config(ssi_private, false);
- if (!ssi_private->imx_ac97 && (read_ssi(&ssi->scr) &
+ if (!fsl_ssi_is_ac97(ssi_private) && (read_ssi(&ssi->scr) &
(CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) {
spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
ssi_private->baudclk_locked = false;
@@ -1109,7 +900,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
return -EINVAL;
}
- if (ssi_private->imx_ac97) {
+ if (fsl_ssi_is_ac97(ssi_private)) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
write_ssi(CCSR_SSI_SOR_TX_CLR, &ssi->sor);
else
@@ -1123,7 +914,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
{
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai);
- if (ssi_private->ssi_on_imx && ssi_private->use_dma) {
+ if (fsl_ssi_on_imx(ssi_private) && ssi_private->use_dma) {
dai->playback_dma_data = &ssi_private->dma_params_tx;
dai->capture_dma_data = &ssi_private->dma_params_rx;
}
@@ -1184,11 +975,6 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
static struct fsl_ssi_private *fsl_ac97_data;
-static void fsl_ssi_ac97_init(void)
-{
- fsl_ssi_setup(fsl_ac97_data);
-}
-
static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
@@ -1251,11 +1037,107 @@ static void make_lowercase(char *s)
}
}
+static int fsl_ssi_imx_probe(struct platform_device *pdev,
+ struct fsl_ssi_private *ssi_private, void __iomem *iomem)
+{
+ struct device_node *np = pdev->dev.of_node;
+ u32 dmas[4];
+ int ret;
+
+ ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(ssi_private->clk)) {
+ ret = PTR_ERR(ssi_private->clk);
+ dev_err(&pdev->dev, "could not get clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(ssi_private->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+ return ret;
+ }
+
+ /* For those SLAVE implementations, we ingore non-baudclk cases
+ * and, instead, abandon MASTER mode that needs baud clock.
+ */
+ ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud");
+ if (IS_ERR(ssi_private->baudclk))
+ dev_dbg(&pdev->dev, "could not get baud clock: %ld\n",
+ PTR_ERR(ssi_private->baudclk));
+ else
+ clk_prepare_enable(ssi_private->baudclk);
+
+ /*
+ * We have burstsize be "fifo_depth - 2" to match the SSI
+ * watermark setting in fsl_ssi_startup().
+ */
+ ssi_private->dma_params_tx.maxburst = ssi_private->fifo_depth - 2;
+ ssi_private->dma_params_rx.maxburst = ssi_private->fifo_depth - 2;
+ ssi_private->dma_params_tx.addr = ssi_private->ssi_phys +
+ offsetof(struct ccsr_ssi, stx0);
+ ssi_private->dma_params_rx.addr = ssi_private->ssi_phys +
+ offsetof(struct ccsr_ssi, srx0);
+
+ ret = !of_property_read_u32_array(np, "dmas", dmas, 4);
+ if (ssi_private->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) {
+ ssi_private->use_dual_fifo = true;
+ /* When using dual fifo mode, we need to keep watermark
+ * as even numbers due to dma script limitation.
+ */
+ ssi_private->dma_params_tx.maxburst &= ~0x1;
+ ssi_private->dma_params_rx.maxburst &= ~0x1;
+ }
+
+ if (!ssi_private->use_dma) {
+
+ /*
+ * Some boards use an incompatible codec. To get it
+ * working, we are using imx-fiq-pcm-audio, that
+ * can handle those codecs. DMA is not possible in this
+ * situation.
+ */
+
+ ssi_private->fiq_params.irq = ssi_private->irq;
+ ssi_private->fiq_params.base = iomem;
+ ssi_private->fiq_params.dma_params_rx =
+ &ssi_private->dma_params_rx;
+ ssi_private->fiq_params.dma_params_tx =
+ &ssi_private->dma_params_tx;
+
+ ret = imx_pcm_fiq_init(pdev, &ssi_private->fiq_params);
+ if (ret)
+ goto error_pcm;
+ } else {
+ ret = imx_pcm_dma_init(pdev);
+ if (ret)
+ goto error_pcm;
+ }
+
+ return 0;
+
+error_pcm:
+ if (!IS_ERR(ssi_private->baudclk))
+ clk_disable_unprepare(ssi_private->baudclk);
+
+ clk_disable_unprepare(ssi_private->clk);
+
+ return ret;
+}
+
+static void fsl_ssi_imx_clean(struct platform_device *pdev,
+ struct fsl_ssi_private *ssi_private)
+{
+ if (!ssi_private->use_dma)
+ imx_pcm_fiq_exit(pdev);
+ if (!IS_ERR(ssi_private->baudclk))
+ clk_disable_unprepare(ssi_private->baudclk);
+ clk_disable_unprepare(ssi_private->clk);
+}
+
static int fsl_ssi_probe(struct platform_device *pdev)
{
struct fsl_ssi_private *ssi_private;
int ret = 0;
- struct device_attribute *dev_attr = NULL;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id;
enum fsl_ssi_type hw_type;
@@ -1263,7 +1145,6 @@ static int fsl_ssi_probe(struct platform_device *pdev)
const uint32_t *iprop;
struct resource res;
char name[64];
- bool shared;
bool ac97 = false;
/* SSIs that are not connected on the board should have a
@@ -1286,17 +1167,13 @@ static int fsl_ssi_probe(struct platform_device *pdev)
if (!strcmp(sprop, "ac97-slave"))
ac97 = true;
- /* The DAI name is the last part of the full name of the node. */
- p = strrchr(np->full_name, '/') + 1;
- ssi_private = devm_kzalloc(&pdev->dev, sizeof(*ssi_private) + strlen(p),
- GFP_KERNEL);
+ ssi_private = devm_kzalloc(&pdev->dev, sizeof(*ssi_private),
+ GFP_KERNEL);
if (!ssi_private) {
dev_err(&pdev->dev, "could not allocate DAI object\n");
return -ENOMEM;
}
- strcpy(ssi_private->name, p);
-
ssi_private->use_dma = !of_property_read_bool(np,
"fsl,fiq-stream-filter");
ssi_private->hw_type = hw_type;
@@ -1306,7 +1183,6 @@ static int fsl_ssi_probe(struct platform_device *pdev)
sizeof(fsl_ssi_ac97_dai));
fsl_ac97_data = ssi_private;
- ssi_private->imx_ac97 = true;
snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
} else {
@@ -1314,7 +1190,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
sizeof(fsl_ssi_dai_template));
}
- ssi_private->cpu_dai_drv.name = ssi_private->name;
+ ssi_private->cpu_dai_drv.name = dev_name(&pdev->dev);
/* Get the addresses and IRQ */
ret = of_address_to_resource(np, 0, &res);
@@ -1353,177 +1229,43 @@ static int fsl_ssi_probe(struct platform_device *pdev)
ssi_private->baudclk_locked = false;
spin_lock_init(&ssi_private->baudclk_lock);
- /*
- * imx51 and later SoCs have a slightly different IP that allows the
- * SSI configuration while the SSI unit is running.
- *
- * More important, it is necessary on those SoCs to configure the
- * sperate TX/RX DMA bits just before starting the stream
- * (fsl_ssi_trigger). The SDMA unit has to be configured before fsl_ssi
- * sends any DMA requests to the SDMA unit, otherwise it is not defined
- * how the SDMA unit handles the DMA request.
- *
- * SDMA units are present on devices starting at imx35 but the imx35
- * reference manual states that the DMA bits should not be changed
- * while the SSI unit is running (SSIEN). So we support the necessary
- * online configuration of fsl-ssi starting at imx51.
- */
- switch (hw_type) {
- case FSL_SSI_MCP8610:
- case FSL_SSI_MX21:
- case FSL_SSI_MX35:
- ssi_private->offline_config = true;
- break;
- case FSL_SSI_MX51:
- ssi_private->offline_config = false;
- break;
- }
-
- if (hw_type == FSL_SSI_MX21 || hw_type == FSL_SSI_MX51 ||
- hw_type == FSL_SSI_MX35) {
- u32 dma_events[2], dmas[4];
- ssi_private->ssi_on_imx = true;
+ dev_set_drvdata(&pdev->dev, ssi_private);
- ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(ssi_private->clk)) {
- ret = PTR_ERR(ssi_private->clk);
- dev_err(&pdev->dev, "could not get clock: %d\n", ret);
- goto error_irqmap;
- }
- ret = clk_prepare_enable(ssi_private->clk);
- if (ret) {
- dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n",
- ret);
+ if (fsl_ssi_on_imx(ssi_private)) {
+ ret = fsl_ssi_imx_probe(pdev, ssi_private, ssi_private->ssi);
+ if (ret)
goto error_irqmap;
- }
-
- /* For those SLAVE implementations, we ingore non-baudclk cases
- * and, instead, abandon MASTER mode that needs baud clock.
- */
- ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud");
- if (IS_ERR(ssi_private->baudclk))
- dev_dbg(&pdev->dev, "could not get baud clock: %ld\n",
- PTR_ERR(ssi_private->baudclk));
- else
- clk_prepare_enable(ssi_private->baudclk);
-
- /*
- * We have burstsize be "fifo_depth - 2" to match the SSI
- * watermark setting in fsl_ssi_startup().
- */
- ssi_private->dma_params_tx.maxburst =
- ssi_private->fifo_depth - 2;
- ssi_private->dma_params_rx.maxburst =
- ssi_private->fifo_depth - 2;
- ssi_private->dma_params_tx.addr =
- ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0);
- ssi_private->dma_params_rx.addr =
- ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0);
- ssi_private->dma_params_tx.filter_data =
- &ssi_private->filter_data_tx;
- ssi_private->dma_params_rx.filter_data =
- &ssi_private->filter_data_rx;
- if (!of_property_read_bool(pdev->dev.of_node, "dmas") &&
- ssi_private->use_dma) {
- /*
- * FIXME: This is a temporary solution until all
- * necessary dma drivers support the generic dma
- * bindings.
- */
- ret = of_property_read_u32_array(pdev->dev.of_node,
- "fsl,ssi-dma-events", dma_events, 2);
- if (ret && ssi_private->use_dma) {
- dev_err(&pdev->dev, "could not get dma events but fsl-ssi is configured to use DMA\n");
- goto error_clk;
- }
- }
- /* Should this be merge with the above? */
- if (!of_property_read_u32_array(pdev->dev.of_node, "dmas", dmas, 4)
- && dmas[2] == IMX_DMATYPE_SSI_DUAL) {
- ssi_private->use_dual_fifo = true;
- /* When using dual fifo mode, we need to keep watermark
- * as even numbers due to dma script limitation.
- */
- ssi_private->dma_params_tx.maxburst &= ~0x1;
- ssi_private->dma_params_rx.maxburst &= ~0x1;
- }
-
- shared = of_device_is_compatible(of_get_parent(np),
- "fsl,spba-bus");
+ }
- imx_pcm_dma_params_init_data(&ssi_private->filter_data_tx,
- dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
- imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
- dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
+ ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component,
+ &ssi_private->cpu_dai_drv, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+ goto error_asoc_register;
}
- /*
- * Enable interrupts only for MCP8610 and MX51. The other MXs have
- * different writeable interrupt status registers.
- */
if (ssi_private->use_dma) {
- /* The 'name' should not have any slashes in it. */
ret = devm_request_irq(&pdev->dev, ssi_private->irq,
- fsl_ssi_isr, 0, ssi_private->name,
+ fsl_ssi_isr, 0, dev_name(&pdev->dev),
ssi_private);
- ssi_private->irq_stats = true;
if (ret < 0) {
dev_err(&pdev->dev, "could not claim irq %u\n",
ssi_private->irq);
- goto error_clk;
+ goto error_irq;
}
}
- /* Register with ASoC */
- dev_set_drvdata(&pdev->dev, ssi_private);
-
- ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component,
- &ssi_private->cpu_dai_drv, 1);
- if (ret) {
- dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
- goto error_dev;
- }
-
- ret = fsl_ssi_debugfs_create(ssi_private, &pdev->dev);
+ ret = fsl_ssi_debugfs_create(&ssi_private->dbg_stats, &pdev->dev);
if (ret)
- goto error_dbgfs;
-
- if (ssi_private->ssi_on_imx) {
- if (!ssi_private->use_dma) {
-
- /*
- * Some boards use an incompatible codec. To get it
- * working, we are using imx-fiq-pcm-audio, that
- * can handle those codecs. DMA is not possible in this
- * situation.
- */
-
- ssi_private->fiq_params.irq = ssi_private->irq;
- ssi_private->fiq_params.base = ssi_private->ssi;
- ssi_private->fiq_params.dma_params_rx =
- &ssi_private->dma_params_rx;
- ssi_private->fiq_params.dma_params_tx =
- &ssi_private->dma_params_tx;
-
- ret = imx_pcm_fiq_init(pdev, &ssi_private->fiq_params);
- if (ret)
- goto error_pcm;
- } else {
- ret = imx_pcm_dma_init(pdev);
- if (ret)
- goto error_pcm;
- }
- }
+ goto error_asoc_register;
/*
* If codec-handle property is missing from SSI node, we assume
* that the machine driver uses new binding which does not require
* SSI driver to trigger machine driver's probe.
*/
- if (!of_get_property(np, "codec-handle", NULL)) {
- ssi_private->new_binding = true;
+ if (!of_get_property(np, "codec-handle", NULL))
goto done;
- }
/* Trigger the machine driver's probe function. The platform driver
* name of the machine driver is taken from /compatible property of the
@@ -1543,37 +1285,24 @@ static int 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_dai;
+ goto error_sound_card;
}
done:
- if (ssi_private->imx_ac97)
- fsl_ssi_ac97_init();
-
return 0;
-error_dai:
- if (ssi_private->ssi_on_imx && !ssi_private->use_dma)
- imx_pcm_fiq_exit(pdev);
-
-error_pcm:
- fsl_ssi_debugfs_remove(ssi_private);
+error_sound_card:
+ fsl_ssi_debugfs_remove(&ssi_private->dbg_stats);
-error_dbgfs:
+error_irq:
snd_soc_unregister_component(&pdev->dev);
-error_dev:
- device_remove_file(&pdev->dev, dev_attr);
-
-error_clk:
- if (ssi_private->ssi_on_imx) {
- if (!IS_ERR(ssi_private->baudclk))
- clk_disable_unprepare(ssi_private->baudclk);
- clk_disable_unprepare(ssi_private->clk);
- }
+error_asoc_register:
+ if (fsl_ssi_on_imx(ssi_private))
+ fsl_ssi_imx_clean(pdev, ssi_private);
error_irqmap:
- if (ssi_private->irq_stats)
+ if (ssi_private->use_dma)
irq_dispose_mapping(ssi_private->irq);
return ret;
@@ -1583,17 +1312,16 @@ static int fsl_ssi_remove(struct platform_device *pdev)
{
struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
- fsl_ssi_debugfs_remove(ssi_private);
+ fsl_ssi_debugfs_remove(&ssi_private->dbg_stats);
- if (!ssi_private->new_binding)
+ if (ssi_private->pdev)
platform_device_unregister(ssi_private->pdev);
snd_soc_unregister_component(&pdev->dev);
- if (ssi_private->ssi_on_imx) {
- if (!IS_ERR(ssi_private->baudclk))
- clk_disable_unprepare(ssi_private->baudclk);
- clk_disable_unprepare(ssi_private->clk);
- }
- if (ssi_private->irq_stats)
+
+ if (fsl_ssi_on_imx(ssi_private))
+ fsl_ssi_imx_clean(pdev, ssi_private);
+
+ if (ssi_private->use_dma)
irq_dispose_mapping(ssi_private->irq);
return 0;
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index e6b63240a3d7..71c3e7e4340d 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -39,6 +39,7 @@ struct ccsr_ssi {
__be32 saccdis; /* 0x.0058 - SSI AC97 Channel Disable Register */
};
+#define CCSR_SSI_SCR_SYNC_TX_FS 0x00001000
#define CCSR_SSI_SCR_RFR_CLK_DIS 0x00000800
#define CCSR_SSI_SCR_TFR_CLK_DIS 0x00000400
#define CCSR_SSI_SCR_TCH_EN 0x00000100
@@ -206,5 +207,64 @@ struct ccsr_ssi {
#define CCSR_SSI_SACNT_FV 0x00000002
#define CCSR_SSI_SACNT_AC97EN 0x00000001
-#endif
+struct device;
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+
+struct fsl_ssi_dbg {
+ struct dentry *dbg_dir;
+ struct dentry *dbg_stats;
+
+ struct {
+ unsigned int rfrc;
+ unsigned int tfrc;
+ unsigned int cmdau;
+ unsigned int cmddu;
+ unsigned int rxt;
+ unsigned int rdr1;
+ unsigned int rdr0;
+ unsigned int tde1;
+ unsigned int tde0;
+ unsigned int roe1;
+ unsigned int roe0;
+ unsigned int tue1;
+ unsigned int tue0;
+ unsigned int tfs;
+ unsigned int rfs;
+ unsigned int tls;
+ unsigned int rls;
+ unsigned int rff1;
+ unsigned int rff0;
+ unsigned int tfe1;
+ unsigned int tfe0;
+ } stats;
+};
+
+void fsl_ssi_dbg_isr(struct fsl_ssi_dbg *ssi_dbg, u32 sisr);
+
+int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev);
+
+void fsl_ssi_debugfs_remove(struct fsl_ssi_dbg *ssi_dbg);
+
+#else
+
+struct fsl_ssi_dbg {
+};
+
+static inline void fsl_ssi_dbg_isr(struct fsl_ssi_dbg *stats, u32 sisr)
+{
+}
+
+static inline int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg,
+ struct device *dev)
+{
+ return 0;
+}
+
+static inline void fsl_ssi_debugfs_remove(struct fsl_ssi_dbg *ssi_dbg)
+{
+}
+#endif /* ! IS_ENABLED(CONFIG_DEBUG_FS) */
+
+#endif
diff --git a/sound/soc/fsl/fsl_ssi_dbg.c b/sound/soc/fsl/fsl_ssi_dbg.c
new file mode 100644
index 000000000000..5469ffbc0253
--- /dev/null
+++ b/sound/soc/fsl/fsl_ssi_dbg.c
@@ -0,0 +1,163 @@
+/*
+ * Freescale SSI ALSA SoC Digital Audio Interface (DAI) debugging functions
+ *
+ * Copyright 2014 Markus Pargmann <mpa@pengutronix.de>, Pengutronix
+ *
+ * Splitted from fsl_ssi.c
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+
+#include "fsl_ssi.h"
+
+void fsl_ssi_dbg_isr(struct fsl_ssi_dbg *dbg, u32 sisr)
+{
+ if (sisr & CCSR_SSI_SISR_RFRC)
+ dbg->stats.rfrc++;
+
+ if (sisr & CCSR_SSI_SISR_TFRC)
+ dbg->stats.tfrc++;
+
+ if (sisr & CCSR_SSI_SISR_CMDAU)
+ dbg->stats.cmdau++;
+
+ if (sisr & CCSR_SSI_SISR_CMDDU)
+ dbg->stats.cmddu++;
+
+ if (sisr & CCSR_SSI_SISR_RXT)
+ dbg->stats.rxt++;
+
+ if (sisr & CCSR_SSI_SISR_RDR1)
+ dbg->stats.rdr1++;
+
+ if (sisr & CCSR_SSI_SISR_RDR0)
+ dbg->stats.rdr0++;
+
+ if (sisr & CCSR_SSI_SISR_TDE1)
+ dbg->stats.tde1++;
+
+ if (sisr & CCSR_SSI_SISR_TDE0)
+ dbg->stats.tde0++;
+
+ if (sisr & CCSR_SSI_SISR_ROE1)
+ dbg->stats.roe1++;
+
+ if (sisr & CCSR_SSI_SISR_ROE0)
+ dbg->stats.roe0++;
+
+ if (sisr & CCSR_SSI_SISR_TUE1)
+ dbg->stats.tue1++;
+
+ if (sisr & CCSR_SSI_SISR_TUE0)
+ dbg->stats.tue0++;
+
+ if (sisr & CCSR_SSI_SISR_TFS)
+ dbg->stats.tfs++;
+
+ if (sisr & CCSR_SSI_SISR_RFS)
+ dbg->stats.rfs++;
+
+ if (sisr & CCSR_SSI_SISR_TLS)
+ dbg->stats.tls++;
+
+ if (sisr & CCSR_SSI_SISR_RLS)
+ dbg->stats.rls++;
+
+ if (sisr & CCSR_SSI_SISR_RFF1)
+ dbg->stats.rff1++;
+
+ if (sisr & CCSR_SSI_SISR_RFF0)
+ dbg->stats.rff0++;
+
+ if (sisr & CCSR_SSI_SISR_TFE1)
+ dbg->stats.tfe1++;
+
+ if (sisr & CCSR_SSI_SISR_TFE0)
+ dbg->stats.tfe0++;
+}
+
+/* Show the statistics of a flag only if its interrupt is enabled. The
+ * compiler will optimze this code to a no-op if the interrupt is not
+ * enabled.
+ */
+#define SIER_SHOW(flag, name) \
+ do { \
+ if (CCSR_SSI_SIER_##flag) \
+ seq_printf(s, #name "=%u\n", ssi_dbg->stats.name); \
+ } while (0)
+
+
+/**
+ * fsl_sysfs_ssi_show: display SSI statistics
+ *
+ * Display the statistics for the current SSI device. To avoid confusion,
+ * we only show those counts that are enabled.
+ */
+static int fsl_ssi_stats_show(struct seq_file *s, void *unused)
+{
+ struct fsl_ssi_dbg *ssi_dbg = s->private;
+
+ SIER_SHOW(RFRC_EN, rfrc);
+ SIER_SHOW(TFRC_EN, tfrc);
+ SIER_SHOW(CMDAU_EN, cmdau);
+ SIER_SHOW(CMDDU_EN, cmddu);
+ SIER_SHOW(RXT_EN, rxt);
+ SIER_SHOW(RDR1_EN, rdr1);
+ SIER_SHOW(RDR0_EN, rdr0);
+ SIER_SHOW(TDE1_EN, tde1);
+ SIER_SHOW(TDE0_EN, tde0);
+ SIER_SHOW(ROE1_EN, roe1);
+ SIER_SHOW(ROE0_EN, roe0);
+ SIER_SHOW(TUE1_EN, tue1);
+ SIER_SHOW(TUE0_EN, tue0);
+ SIER_SHOW(TFS_EN, tfs);
+ SIER_SHOW(RFS_EN, rfs);
+ SIER_SHOW(TLS_EN, tls);
+ SIER_SHOW(RLS_EN, rls);
+ SIER_SHOW(RFF1_EN, rff1);
+ SIER_SHOW(RFF0_EN, rff0);
+ SIER_SHOW(TFE1_EN, tfe1);
+ SIER_SHOW(TFE0_EN, tfe0);
+
+ return 0;
+}
+
+static int fsl_ssi_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, fsl_ssi_stats_show, inode->i_private);
+}
+
+static const struct file_operations fsl_ssi_stats_ops = {
+ .open = fsl_ssi_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
+{
+ ssi_dbg->dbg_dir = debugfs_create_dir(dev_name(dev), NULL);
+ if (!ssi_dbg->dbg_dir)
+ return -ENOMEM;
+
+ ssi_dbg->dbg_stats = debugfs_create_file("stats", S_IRUGO,
+ ssi_dbg->dbg_dir, ssi_dbg, &fsl_ssi_stats_ops);
+ if (!ssi_dbg->dbg_stats) {
+ debugfs_remove(ssi_dbg->dbg_dir);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void fsl_ssi_debugfs_remove(struct fsl_ssi_dbg *ssi_dbg)
+{
+ debugfs_remove(ssi_dbg->dbg_stats);
+ debugfs_remove(ssi_dbg->dbg_dir);
+}
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index ac869931d7f1..267717aa96c1 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -145,7 +145,7 @@ static const struct file_operations audmux_debugfs_fops = {
.llseek = default_llseek,
};
-static void __init audmux_debugfs_init(void)
+static void audmux_debugfs_init(void)
{
int i;
char buf[20];
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index 2585ae44e634..0849b7b83f0a 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -40,7 +40,6 @@ static const struct snd_pcm_hardware imx_pcm_hardware = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
.period_bytes_min = 128,
.period_bytes_max = 65535, /* Limited by SDMA engine */
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 21f1ccbdf582..98f97e543c29 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -66,8 +66,7 @@ err:
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
- struct simple_card_data *priv =
- snd_soc_card_get_drvdata(rtd->card);
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *codec = rtd->codec_dai;
struct snd_soc_dai *cpu = rtd->cpu_dai;
struct simple_dai_props *dai_props;
@@ -88,7 +87,6 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
static int
asoc_simple_card_sub_parse_of(struct device_node *np,
- unsigned int daifmt,
struct asoc_simple_dai *dai,
const struct device_node **p_node,
const char **name)
@@ -117,14 +115,6 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
return ret;
/*
- * bitclock-inversion, frame-inversion
- * bitclock-master, frame-master
- * and specific "format" if it has
- */
- dai->fmt = snd_soc_of_parse_daifmt(np, NULL);
- dai->fmt |= daifmt;
-
- /*
* dai->sysclk come from
* "clocks = <&xxx>" (if system has common clock)
* or "system-clock-frequency = <xxx>"
@@ -151,37 +141,132 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
return 0;
}
-static int simple_card_cpu_codec_of(struct device_node *node,
- int daifmt,
- struct snd_soc_dai_link *dai_link,
- struct simple_dai_props *dai_props)
+static int simple_card_dai_link_of(struct device_node *node,
+ struct device *dev,
+ struct snd_soc_dai_link *dai_link,
+ struct simple_dai_props *dai_props)
{
- struct device_node *np;
+ struct device_node *np = NULL;
+ struct device_node *bitclkmaster = NULL;
+ struct device_node *framemaster = NULL;
+ unsigned int daifmt;
+ char *name;
+ char prop[128];
+ char *prefix = "";
int ret;
- /* CPU sub-node */
- ret = -EINVAL;
- np = of_get_child_by_name(node, "simple-audio-card,cpu");
- if (np) {
- ret = asoc_simple_card_sub_parse_of(np, daifmt,
- &dai_props->cpu_dai,
- &dai_link->cpu_of_node,
- &dai_link->cpu_dai_name);
- of_node_put(np);
+ prefix = "simple-audio-card,";
+
+ daifmt = snd_soc_of_parse_daifmt(node, prefix,
+ &bitclkmaster, &framemaster);
+ daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+
+ snprintf(prop, sizeof(prop), "%scpu", prefix);
+ np = of_get_child_by_name(node, prop);
+ if (!np) {
+ ret = -EINVAL;
+ dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
+ goto dai_link_of_err;
}
+
+ ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai,
+ &dai_link->cpu_of_node,
+ &dai_link->cpu_dai_name);
if (ret < 0)
- return ret;
+ goto dai_link_of_err;
+
+ dai_props->cpu_dai.fmt = daifmt;
+ switch (((np == bitclkmaster) << 4) | (np == framemaster)) {
+ case 0x11:
+ dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS;
+ break;
+ case 0x10:
+ dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM;
+ break;
+ case 0x01:
+ dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS;
+ break;
+ default:
+ dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM;
+ break;
+ }
- /* CODEC sub-node */
- ret = -EINVAL;
- np = of_get_child_by_name(node, "simple-audio-card,codec");
- if (np) {
- ret = asoc_simple_card_sub_parse_of(np, daifmt,
- &dai_props->codec_dai,
- &dai_link->codec_of_node,
- &dai_link->codec_dai_name);
- of_node_put(np);
+ of_node_put(np);
+ snprintf(prop, sizeof(prop), "%scodec", prefix);
+ np = of_get_child_by_name(node, prop);
+ if (!np) {
+ ret = -EINVAL;
+ dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
+ goto dai_link_of_err;
}
+
+ ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai,
+ &dai_link->codec_of_node,
+ &dai_link->codec_dai_name);
+ if (ret < 0)
+ goto dai_link_of_err;
+
+ if (strlen(prefix) && !bitclkmaster && !framemaster) {
+ /* No dai-link level and master setting was not found from
+ sound node level, revert back to legacy DT parsing and
+ take the settings from codec node. */
+ dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n",
+ __func__);
+ dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt =
+ snd_soc_of_parse_daifmt(np, NULL, NULL, NULL) |
+ (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK);
+ } else {
+ dai_props->codec_dai.fmt = daifmt;
+ switch (((np == bitclkmaster) << 4) | (np == framemaster)) {
+ case 0x11:
+ dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM;
+ break;
+ case 0x10:
+ dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS;
+ break;
+ case 0x01:
+ dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM;
+ break;
+ default:
+ dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS;
+ break;
+ }
+ }
+
+ if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
+ ret = -EINVAL;
+ goto dai_link_of_err;
+ }
+
+ /* simple-card assumes platform == cpu */
+ dai_link->platform_of_node = dai_link->cpu_of_node;
+
+ /* Link name is created from CPU/CODEC dai name */
+ name = devm_kzalloc(dev,
+ strlen(dai_link->cpu_dai_name) +
+ strlen(dai_link->codec_dai_name) + 2,
+ GFP_KERNEL);
+ sprintf(name, "%s-%s", dai_link->cpu_dai_name,
+ dai_link->codec_dai_name);
+ dai_link->name = dai_link->stream_name = name;
+
+ dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
+ dev_dbg(dev, "\tcpu : %s / %04x / %d\n",
+ dai_link->cpu_dai_name,
+ dai_props->cpu_dai.fmt,
+ dai_props->cpu_dai.sysclk);
+ dev_dbg(dev, "\tcodec : %s / %04x / %d\n",
+ dai_link->codec_dai_name,
+ dai_props->codec_dai.fmt,
+ dai_props->codec_dai.sysclk);
+
+dai_link_of_err:
+ if (np)
+ of_node_put(np);
+ if (bitclkmaster)
+ of_node_put(bitclkmaster);
+ if (framemaster)
+ of_node_put(framemaster);
return ret;
}
@@ -192,18 +277,11 @@ static int asoc_simple_card_parse_of(struct device_node *node,
{
struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
struct simple_dai_props *dai_props = priv->dai_props;
- struct device_node *np;
- char *name;
- unsigned int daifmt;
int ret;
/* parsing the card name from DT */
snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
- /* get CPU/CODEC common format via simple-audio-card,format */
- daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
- (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
-
/* off-codec widgets */
if (of_property_read_bool(node, "simple-audio-card,widgets")) {
ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
@@ -220,71 +298,31 @@ static int asoc_simple_card_parse_of(struct device_node *node,
return ret;
}
- /* loop on the DAI links */
- np = NULL;
- for (;;) {
- if (multi) {
- np = of_get_next_child(node, np);
- if (!np)
- break;
+ dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ?
+ priv->snd_card.name : "");
+
+ if (multi) {
+ struct device_node *np = NULL;
+ int i;
+ for (i = 0; (np = of_get_next_child(node, np)); i++) {
+ dev_dbg(dev, "\tlink %d:\n", i);
+ ret = simple_card_dai_link_of(np, dev, dai_link + i,
+ dai_props + i);
+ if (ret < 0) {
+ of_node_put(np);
+ return ret;
+ }
}
-
- ret = simple_card_cpu_codec_of(multi ? np : node,
- daifmt, dai_link, dai_props);
+ } else {
+ ret = simple_card_dai_link_of(node, dev, dai_link, dai_props);
if (ret < 0)
- goto err;
-
- /*
- * overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC
- * while the other bits should be identical unless buggy SW/HW design.
- */
- dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt;
-
- if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
- ret = -EINVAL;
- goto err;
- }
-
- /* simple-card assumes platform == cpu */
- dai_link->platform_of_node = dai_link->cpu_of_node;
-
- name = devm_kzalloc(dev,
- strlen(dai_link->cpu_dai_name) +
- strlen(dai_link->codec_dai_name) + 2,
- GFP_KERNEL);
- sprintf(name, "%s-%s", dai_link->cpu_dai_name,
- dai_link->codec_dai_name);
- dai_link->name = dai_link->stream_name = name;
-
- if (!multi)
- break;
-
- dai_link++;
- dai_props++;
+ return ret;
}
- /* card name is created from CPU/CODEC dai name */
- dai_link = priv->snd_card.dai_link;
if (!priv->snd_card.name)
- priv->snd_card.name = dai_link->name;
-
- dev_dbg(dev, "card-name : %s\n", priv->snd_card.name);
- dev_dbg(dev, "platform : %04x\n", daifmt);
- dai_props = priv->dai_props;
- dev_dbg(dev, "cpu : %s / %04x / %d\n",
- dai_link->cpu_dai_name,
- dai_props->cpu_dai.fmt,
- dai_props->cpu_dai.sysclk);
- dev_dbg(dev, "codec : %s / %04x / %d\n",
- dai_link->codec_dai_name,
- dai_props->codec_dai.fmt,
- dai_props->codec_dai.sysclk);
+ priv->snd_card.name = priv->snd_card.dai_link->name;
return 0;
-
-err:
- of_node_put(np);
- return ret;
}
/* update the reference count of the devices nodes at end of probe */
@@ -378,10 +416,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
return -EINVAL;
}
- if (!cinfo->name ||
- !cinfo->codec_dai.name ||
- !cinfo->codec ||
- !cinfo->platform ||
+ if (!cinfo->name ||
+ !cinfo->codec_dai.name ||
+ !cinfo->codec ||
+ !cinfo->platform ||
!cinfo->cpu_dai.name) {
dev_err(dev, "insufficient asoc_simple_card_info settings\n");
return -EINVAL;
@@ -425,11 +463,11 @@ MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
static struct platform_driver asoc_simple_card = {
.driver = {
- .name = "asoc-simple-card",
+ .name = "asoc-simple-card",
.owner = THIS_MODULE,
.of_match_table = asoc_simple_of_match,
},
- .probe = asoc_simple_card_probe,
+ .probe = asoc_simple_card_probe,
};
module_platform_driver(asoc_simple_card);
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index edeb79ae3dff..0db4e2f336dc 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -2,7 +2,7 @@
snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o
snd-soc-sst-acpi-objs := sst-acpi.o
-snd-soc-sst-mfld-platform-objs := sst-mfld-platform.o
+snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o sst-mfld-platform-compress.o
snd-soc-mfld-machine-objs := mfld_machine.o
obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c
index eff97c8e5218..5535c3fb7922 100644
--- a/sound/soc/intel/byt-rt5640.c
+++ b/sound/soc/intel/byt-rt5640.c
@@ -100,12 +100,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
snd_soc_dapm_ignore_suspend(dapm, "SPORP");
snd_soc_dapm_ignore_suspend(dapm, "SPORN");
- snd_soc_dapm_enable_pin(dapm, "Headset Mic");
- snd_soc_dapm_enable_pin(dapm, "Headphone");
- snd_soc_dapm_enable_pin(dapm, "Speaker");
- snd_soc_dapm_enable_pin(dapm, "Internal Mic");
-
- snd_soc_dapm_sync(dapm);
return ret;
}
@@ -117,27 +111,13 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
{
.name = "Baytrail Audio",
.stream_name = "Audio",
- .cpu_dai_name = "Front-cpu-dai",
+ .cpu_dai_name = "baytrail-pcm-audio",
.codec_dai_name = "rt5640-aif1",
.codec_name = "i2c-10EC5640:00",
.platform_name = "baytrail-pcm-audio",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.init = byt_rt5640_init,
- .ignore_suspend = 1,
- .ops = &byt_rt5640_ops,
- },
- {
- .name = "Baytrail Voice",
- .stream_name = "Voice",
- .cpu_dai_name = "Mic1-cpu-dai",
- .codec_dai_name = "rt5640-aif1",
- .codec_name = "i2c-10EC5640:00",
- .platform_name = "baytrail-pcm-audio",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
- .init = NULL,
- .ignore_suspend = 1,
.ops = &byt_rt5640_ops,
},
};
@@ -152,6 +132,17 @@ static struct snd_soc_card byt_rt5640_card = {
.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
};
+#ifdef CONFIG_PM_SLEEP
+static const struct dev_pm_ops byt_rt5640_pm_ops = {
+ .suspend = snd_soc_suspend,
+ .resume = snd_soc_resume,
+};
+
+#define BYT_RT5640_PM_OPS (&byt_rt5640_pm_ops)
+#else
+#define BYT_RT5640_PM_OPS NULL
+#endif
+
static int byt_rt5640_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &byt_rt5640_card;
@@ -177,6 +168,7 @@ static struct platform_driver byt_rt5640_audio = {
.driver = {
.name = "byt-rt5640",
.owner = THIS_MODULE,
+ .pm = BYT_RT5640_PM_OPS,
},
};
module_platform_driver(byt_rt5640_audio)
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c
index 54345a2a7386..94c2c33ffe49 100644
--- a/sound/soc/intel/haswell.c
+++ b/sound/soc/intel/haswell.c
@@ -89,8 +89,6 @@ static struct snd_soc_ops haswell_rt5640_ops = {
static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
struct sst_hsw *haswell = pdata->dsp;
int ret;
@@ -104,10 +102,6 @@ static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- /* always connected */
- snd_soc_dapm_enable_pin(dapm, "Headphones");
- snd_soc_dapm_enable_pin(dapm, "Mic");
-
return 0;
}
diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c
index 5d06eecb6198..18aee77f8d4a 100644
--- a/sound/soc/intel/sst-acpi.c
+++ b/sound/soc/intel/sst-acpi.c
@@ -138,6 +138,7 @@ static int sst_acpi_probe(struct platform_device *pdev)
sst_pdata = &sst_acpi->sst_pdata;
sst_pdata->id = desc->sst_id;
+ sst_pdata->dma_dev = dev;
sst_acpi->desc = desc;
sst_acpi->mach = mach;
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c
index a50bf7fc0e3a..fc588764ffa3 100644
--- a/sound/soc/intel/sst-baytrail-dsp.c
+++ b/sound/soc/intel/sst-baytrail-dsp.c
@@ -214,6 +214,13 @@ static void sst_byt_boot(struct sst_dsp *sst)
{
int tries = 10;
+ /*
+ * save the physical address of extended firmware block in the first
+ * 4 bytes of the mailbox
+ */
+ memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
+ &sst->pdata->fw_base, sizeof(u32));
+
/* release stall and wait to unstall */
sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0);
while (tries--) {
@@ -317,14 +324,7 @@ static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
return ret;
}
- /*
- * save the physical address of extended firmware block in the first
- * 4 bytes of the mailbox
- */
- memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
- &pdata->fw_base, sizeof(u32));
-
- ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ ret = dma_coerce_mask_and_coherent(sst->dma_dev, DMA_BIT_MASK(32));
if (ret)
return ret;
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c
index d0eaeee21be4..7c1ec003d55d 100644
--- a/sound/soc/intel/sst-baytrail-ipc.c
+++ b/sound/soc/intel/sst-baytrail-ipc.c
@@ -173,6 +173,7 @@ struct sst_byt {
/* boot */
wait_queue_head_t boot_wait;
bool boot_complete;
+ struct sst_fw *fw;
/* IPC messaging */
struct list_head tx_list;
@@ -299,6 +300,24 @@ static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt,
wake_up(&msg->waitq);
}
+static void sst_byt_drop_all(struct sst_byt *byt)
+{
+ struct ipc_message *msg, *tmp;
+ unsigned long flags;
+
+ /* drop all TX and Rx messages before we stall + reset DSP */
+ spin_lock_irqsave(&byt->dsp->spinlock, flags);
+ list_for_each_entry_safe(msg, tmp, &byt->tx_list, list) {
+ list_move(&msg->list, &byt->empty_list);
+ }
+
+ list_for_each_entry_safe(msg, tmp, &byt->rx_list, list) {
+ list_move(&msg->list, &byt->empty_list);
+ }
+
+ spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+}
+
static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg,
void *rx_data)
{
@@ -542,16 +561,20 @@ struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
void *data)
{
struct sst_byt_stream *stream;
+ struct sst_dsp *sst = byt->dsp;
+ unsigned long flags;
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
if (stream == NULL)
return NULL;
+ spin_lock_irqsave(&sst->spinlock, flags);
list_add(&stream->node, &byt->stream_list);
stream->notify_position = notify_position;
stream->pdata = data;
stream->byt = byt;
stream->str_id = id;
+ spin_unlock_irqrestore(&sst->spinlock, flags);
return stream;
}
@@ -630,6 +653,8 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
{
u64 header;
int ret = 0;
+ struct sst_dsp *sst = byt->dsp;
+ unsigned long flags;
if (!stream->commited)
goto out;
@@ -644,8 +669,10 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
stream->commited = false;
out:
+ spin_lock_irqsave(&sst->spinlock, flags);
list_del(&stream->node);
kfree(stream);
+ spin_unlock_irqrestore(&sst->spinlock, flags);
return ret;
}
@@ -653,36 +680,33 @@ out:
static int sst_byt_stream_operations(struct sst_byt *byt, int type,
int stream_id, int wait)
{
- struct sst_byt_start_stream_params start_stream;
u64 header;
- void *tx_msg = NULL;
- size_t size = 0;
-
- if (type != IPC_IA_START_STREAM) {
- header = sst_byt_header(type, 0, false, stream_id);
- } else {
- start_stream.byte_offset = 0;
- header = sst_byt_header(IPC_IA_START_STREAM,
- sizeof(start_stream) + sizeof(u32),
- true, stream_id);
- tx_msg = &start_stream;
- size = sizeof(start_stream);
- }
+ header = sst_byt_header(type, 0, false, stream_id);
if (wait)
- return sst_byt_ipc_tx_msg_wait(byt, header,
- tx_msg, size, NULL, 0);
+ return sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0);
else
- return sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size);
+ return sst_byt_ipc_tx_msg_nowait(byt, header, NULL, 0);
}
/* stream ALSA trigger operations */
-int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream)
+int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
+ u32 start_offset)
{
+ struct sst_byt_start_stream_params start_stream;
+ void *tx_msg;
+ size_t size;
+ u64 header;
int ret;
- ret = sst_byt_stream_operations(byt, IPC_IA_START_STREAM,
- stream->str_id, 0);
+ start_stream.byte_offset = start_offset;
+ header = sst_byt_header(IPC_IA_START_STREAM,
+ sizeof(start_stream) + sizeof(u32),
+ true, stream->str_id);
+ tx_msg = &start_stream;
+ size = sizeof(start_stream);
+
+ ret = sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size);
if (ret < 0)
dev_err(byt->dev, "ipc: error failed to start stream %d\n",
stream->str_id);
@@ -774,6 +798,73 @@ static struct sst_dsp_device byt_dev = {
.ops = &sst_byt_ops,
};
+int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata)
+{
+ struct sst_byt *byt = pdata->dsp;
+
+ dev_dbg(byt->dev, "dsp reset\n");
+ sst_dsp_reset(byt->dsp);
+ sst_byt_drop_all(byt);
+ dev_dbg(byt->dev, "dsp in reset\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_noirq);
+
+int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
+{
+ struct sst_byt *byt = pdata->dsp;
+
+ dev_dbg(byt->dev, "free all blocks and unload fw\n");
+ sst_fw_unload(byt->fw);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_late);
+
+int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata)
+{
+ struct sst_byt *byt = pdata->dsp;
+ int ret;
+
+ dev_dbg(byt->dev, "reload dsp fw\n");
+
+ sst_dsp_reset(byt->dsp);
+
+ ret = sst_fw_reload(byt->fw);
+ if (ret < 0) {
+ dev_err(dev, "error: failed to reload firmware\n");
+ return ret;
+ }
+
+ /* wait for DSP boot completion */
+ byt->boot_complete = false;
+ sst_dsp_boot(byt->dsp);
+ dev_dbg(byt->dev, "dsp booting...\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_boot);
+
+int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata)
+{
+ struct sst_byt *byt = pdata->dsp;
+ int err;
+
+ dev_dbg(byt->dev, "wait for dsp reboot\n");
+
+ err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
+ msecs_to_jiffies(IPC_BOOT_MSECS));
+ if (err == 0) {
+ dev_err(byt->dev, "ipc: error DSP boot timeout\n");
+ return -EIO;
+ }
+
+ dev_dbg(byt->dev, "dsp rebooted\n");
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready);
+
int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
{
struct sst_byt *byt;
@@ -840,6 +931,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
}
pdata->dsp = byt;
+ byt->fw = byt_sst_fw;
return 0;
diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/sst-baytrail-ipc.h
index f172b6440fa9..06a4d202689b 100644
--- a/sound/soc/intel/sst-baytrail-ipc.h
+++ b/sound/soc/intel/sst-baytrail-ipc.h
@@ -53,7 +53,8 @@ int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream);
int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream);
/* stream ALSA trigger operations */
-int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
+ u32 start_offset);
int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream);
int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream);
int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream);
@@ -65,5 +66,9 @@ int sst_byt_get_dsp_position(struct sst_byt *byt,
int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
+int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata);
+int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata);
+int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata);
+int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata);
#endif
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c
index 6d101f3813b4..3af38576e91e 100644
--- a/sound/soc/intel/sst-baytrail-pcm.c
+++ b/sound/soc/intel/sst-baytrail-pcm.c
@@ -45,6 +45,11 @@ struct sst_byt_pcm_data {
struct sst_byt_stream *stream;
struct snd_pcm_substream *substream;
struct mutex mutex;
+
+ /* latest DSP DMA hw pointer */
+ u32 hw_ptr;
+
+ struct work_struct work;
};
/* private data for the driver */
@@ -63,7 +68,7 @@ static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct sst_byt_priv_data *pdata =
snd_soc_platform_get_drvdata(rtd->platform);
- struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
struct sst_byt *byt = pdata->byt;
u32 rate, bits;
u8 channels;
@@ -130,21 +135,56 @@ static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
return 0;
}
+static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sst_byt_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+ struct sst_byt *byt = pdata->byt;
+ int ret;
+
+ /* commit stream using existing stream params */
+ ret = sst_byt_stream_commit(byt, pcm_data->stream);
+ if (ret < 0) {
+ dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
+ return ret;
+ }
+
+ sst_byt_stream_start(byt, pcm_data->stream, pcm_data->hw_ptr);
+
+ dev_dbg(rtd->dev, "stream context restored at offset %d\n",
+ pcm_data->hw_ptr);
+
+ return 0;
+}
+
+static void sst_byt_pcm_work(struct work_struct *work)
+{
+ struct sst_byt_pcm_data *pcm_data =
+ container_of(work, struct sst_byt_pcm_data, work);
+
+ if (snd_pcm_running(pcm_data->substream))
+ sst_byt_pcm_restore_stream_context(pcm_data->substream);
+}
+
static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct sst_byt_priv_data *pdata =
snd_soc_platform_get_drvdata(rtd->platform);
- struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
struct sst_byt *byt = pdata->byt;
dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- sst_byt_stream_start(byt, pcm_data->stream);
+ sst_byt_stream_start(byt, pcm_data->stream, 0);
break;
case SNDRV_PCM_TRIGGER_RESUME:
+ schedule_work(&pcm_data->work);
+ break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
sst_byt_stream_resume(byt, pcm_data->stream);
break;
@@ -168,13 +208,19 @@ static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
struct snd_pcm_substream *substream = pcm_data->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- u32 pos;
+ struct sst_byt_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct sst_byt *byt = pdata->byt;
+ u32 pos, hw_pos;
+ hw_pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
+ snd_pcm_lib_buffer_bytes(substream));
+ pcm_data->hw_ptr = hw_pos;
pos = frames_to_bytes(runtime,
(runtime->control->appl_ptr %
runtime->buffer_size));
- dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
+ dev_dbg(rtd->dev, "PCM: App/DMA pointer %u/%u bytes\n", pos, hw_pos);
snd_pcm_period_elapsed(substream);
return pos;
@@ -186,18 +232,11 @@ static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream
struct snd_pcm_runtime *runtime = substream->runtime;
struct sst_byt_priv_data *pdata =
snd_soc_platform_get_drvdata(rtd->platform);
- struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
- struct sst_byt *byt = pdata->byt;
- snd_pcm_uframes_t offset;
- int pos;
+ struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
- pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
- snd_pcm_lib_buffer_bytes(substream));
- offset = bytes_to_frames(runtime, pos);
+ dev_dbg(rtd->dev, "PCM: DMA pointer %u bytes\n", pcm_data->hw_ptr);
- dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
- frames_to_bytes(runtime, (u32)offset));
- return offset;
+ return bytes_to_frames(runtime, pcm_data->hw_ptr);
}
static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
@@ -205,20 +244,18 @@ static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct sst_byt_priv_data *pdata =
snd_soc_platform_get_drvdata(rtd->platform);
- struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
struct sst_byt *byt = pdata->byt;
dev_dbg(rtd->dev, "PCM: open\n");
- pcm_data = &pdata->pcm[rtd->cpu_dai->id];
mutex_lock(&pcm_data->mutex);
- snd_soc_pcm_set_drvdata(rtd, pcm_data);
pcm_data->substream = substream;
snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
- pcm_data->stream = sst_byt_stream_new(byt, rtd->cpu_dai->id + 1,
+ pcm_data->stream = sst_byt_stream_new(byt, substream->stream + 1,
byt_notify_pointer, pcm_data);
if (pcm_data->stream == NULL) {
dev_err(rtd->dev, "failed to create stream\n");
@@ -235,12 +272,13 @@ static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct sst_byt_priv_data *pdata =
snd_soc_platform_get_drvdata(rtd->platform);
- struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
struct sst_byt *byt = pdata->byt;
int ret;
dev_dbg(rtd->dev, "PCM: close\n");
+ cancel_work_sync(&pcm_data->work);
mutex_lock(&pcm_data->mutex);
ret = sst_byt_stream_free(byt, pcm_data->stream);
if (ret < 0) {
@@ -283,18 +321,16 @@ static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_pcm *pcm = rtd->pcm;
size_t size;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct sst_pdata *pdata = dev_get_platdata(platform->dev);
int ret = 0;
- ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
-
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
size = sst_byt_pcm_hardware.buffer_bytes_max;
ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_DEV,
- rtd->card->dev,
+ pdata->dma_dev,
size, size);
if (ret) {
dev_err(rtd->dev, "dma buffer allocation failed %d\n",
@@ -308,7 +344,7 @@ static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
static struct snd_soc_dai_driver byt_dais[] = {
{
- .name = "Front-cpu-dai",
+ .name = "Baytrail PCM",
.playback = {
.stream_name = "System Playback",
.channels_min = 2,
@@ -317,9 +353,6 @@ static struct snd_soc_dai_driver byt_dais[] = {
.formats = SNDRV_PCM_FMTBIT_S24_3LE |
SNDRV_PCM_FMTBIT_S16_LE,
},
- },
- {
- .name = "Mic1-cpu-dai",
.capture = {
.stream_name = "Analog Capture",
.channels_min = 2,
@@ -344,8 +377,10 @@ static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
priv_data->byt = plat_data->dsp;
snd_soc_platform_set_drvdata(platform, priv_data);
- for (i = 0; i < ARRAY_SIZE(byt_dais); i++)
+ for (i = 0; i < BYT_PCM_COUNT; i++) {
mutex_init(&priv_data->pcm[i].mutex);
+ INIT_WORK(&priv_data->pcm[i].work, sst_byt_pcm_work);
+ }
return 0;
}
@@ -367,6 +402,72 @@ static const struct snd_soc_component_driver byt_dai_component = {
.name = "byt-dai",
};
+#ifdef CONFIG_PM
+static int sst_byt_pcm_dev_suspend_noirq(struct device *dev)
+{
+ struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+ int ret;
+
+ dev_dbg(dev, "suspending noirq\n");
+
+ /* at this point all streams will be stopped and context saved */
+ ret = sst_byt_dsp_suspend_noirq(dev, sst_pdata);
+ if (ret < 0) {
+ dev_err(dev, "failed to suspend %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int sst_byt_pcm_dev_suspend_late(struct device *dev)
+{
+ struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+ int ret;
+
+ dev_dbg(dev, "suspending late\n");
+
+ ret = sst_byt_dsp_suspend_late(dev, sst_pdata);
+ if (ret < 0) {
+ dev_err(dev, "failed to suspend %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int sst_byt_pcm_dev_resume_early(struct device *dev)
+{
+ struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+
+ dev_dbg(dev, "resume early\n");
+
+ /* load fw and boot DSP */
+ return sst_byt_dsp_boot(dev, sst_pdata);
+}
+
+static int sst_byt_pcm_dev_resume(struct device *dev)
+{
+ struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+
+ dev_dbg(dev, "resume\n");
+
+ /* wait for FW to finish booting */
+ return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
+}
+
+static const struct dev_pm_ops sst_byt_pm_ops = {
+ .suspend_noirq = sst_byt_pcm_dev_suspend_noirq,
+ .suspend_late = sst_byt_pcm_dev_suspend_late,
+ .resume_early = sst_byt_pcm_dev_resume_early,
+ .resume = sst_byt_pcm_dev_resume,
+};
+
+#define SST_BYT_PM_OPS (&sst_byt_pm_ops)
+#else
+#define SST_BYT_PM_OPS NULL
+#endif
+
static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
{
struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
@@ -409,6 +510,7 @@ static struct platform_driver sst_byt_pcm_driver = {
.driver = {
.name = "baytrail-pcm-audio",
.owner = THIS_MODULE,
+ .pm = SST_BYT_PM_OPS,
},
.probe = sst_byt_pcm_dev_probe,
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h
index fe8e81aad646..ffb308bd81ce 100644
--- a/sound/soc/intel/sst-dsp-priv.h
+++ b/sound/soc/intel/sst-dsp-priv.h
@@ -136,7 +136,7 @@ struct sst_module_data {
enum sst_data_type data_type; /* type of module data */
u32 size; /* size in bytes */
- u32 offset; /* offset in FW file */
+ int32_t offset; /* offset in FW file */
u32 data_offset; /* offset in ADSP memory space */
void *data; /* module data */
};
@@ -228,6 +228,7 @@ struct sst_dsp {
spinlock_t spinlock; /* IPC locking */
struct mutex mutex; /* DSP FW lock */
struct device *dev;
+ struct device *dma_dev;
void *thread_context;
int irq;
u32 id;
@@ -283,6 +284,8 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
const struct firmware *fw, void *private);
void sst_fw_free(struct sst_fw *sst_fw);
void sst_fw_free_all(struct sst_dsp *dsp);
+int sst_fw_reload(struct sst_fw *sst_fw);
+void sst_fw_unload(struct sst_fw *sst_fw);
/* Create/Free firmware modules */
struct sst_module *sst_module_new(struct sst_fw *sst_fw,
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c
index 0c129fd85ecf..0b715b20a2d7 100644
--- a/sound/soc/intel/sst-dsp.c
+++ b/sound/soc/intel/sst-dsp.c
@@ -337,6 +337,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev,
spin_lock_init(&sst->spinlock);
mutex_init(&sst->mutex);
sst->dev = dev;
+ sst->dma_dev = pdata->dma_dev;
sst->thread_context = sst_dev->thread_context;
sst->sst_dev = sst_dev;
sst->id = pdata->id;
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h
index 74052b59485c..e44423be66c4 100644
--- a/sound/soc/intel/sst-dsp.h
+++ b/sound/soc/intel/sst-dsp.h
@@ -169,6 +169,7 @@ struct sst_pdata {
u32 dma_base;
u32 dma_size;
int dma_engine;
+ struct device *dma_dev;
/* DSP */
u32 id;
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c
index f7687107cf7f..3bb43dac892d 100644
--- a/sound/soc/intel/sst-firmware.c
+++ b/sound/soc/intel/sst-firmware.c
@@ -30,6 +30,8 @@
#include "sst-dsp.h"
#include "sst-dsp-priv.h"
+static void block_module_remove(struct sst_module *module);
+
static void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes)
{
u32 i;
@@ -57,14 +59,8 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
sst_fw->private = private;
sst_fw->size = fw->size;
- err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32));
- if (err < 0) {
- kfree(sst_fw);
- return NULL;
- }
-
/* allocate DMA buffer to store FW data */
- sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size,
+ sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size,
&sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL);
if (!sst_fw->dma_buf) {
dev_err(dsp->dev, "error: DMA alloc failed\n");
@@ -97,6 +93,42 @@ parse_err:
}
EXPORT_SYMBOL_GPL(sst_fw_new);
+int sst_fw_reload(struct sst_fw *sst_fw)
+{
+ struct sst_dsp *dsp = sst_fw->dsp;
+ int ret;
+
+ dev_dbg(dsp->dev, "reloading firmware\n");
+
+ /* call core specific FW paser to load FW data into DSP */
+ ret = dsp->ops->parse_fw(sst_fw);
+ if (ret < 0)
+ dev_err(dsp->dev, "error: parse fw failed %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sst_fw_reload);
+
+void sst_fw_unload(struct sst_fw *sst_fw)
+{
+ struct sst_dsp *dsp = sst_fw->dsp;
+ struct sst_module *module, *tmp;
+
+ dev_dbg(dsp->dev, "unloading firmware\n");
+
+ mutex_lock(&dsp->mutex);
+ list_for_each_entry_safe(module, tmp, &dsp->module_list, list) {
+ if (module->sst_fw == sst_fw) {
+ block_module_remove(module);
+ list_del(&module->list);
+ kfree(module);
+ }
+ }
+
+ mutex_unlock(&dsp->mutex);
+}
+EXPORT_SYMBOL_GPL(sst_fw_unload);
+
/* free single firmware object */
void sst_fw_free(struct sst_fw *sst_fw)
{
@@ -106,7 +138,7 @@ void sst_fw_free(struct sst_fw *sst_fw)
list_del(&sst_fw->list);
mutex_unlock(&dsp->mutex);
- dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf,
+ dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf,
sst_fw->dmable_fw_paddr);
kfree(sst_fw);
}
@@ -202,6 +234,9 @@ static int block_alloc_contiguous(struct sst_module *module,
size -= block->size;
}
+ list_for_each_entry(block, &tmp, list)
+ list_add(&block->module_list, &module->block_list);
+
list_splice(&tmp, &dsp->used_block_list);
return 0;
}
@@ -247,8 +282,7 @@ static int block_alloc(struct sst_module *module,
/* do we span > 1 blocks */
if (data->size > block->size) {
ret = block_alloc_contiguous(module, data,
- block->offset + block->size,
- data->size - block->size);
+ block->offset, data->size);
if (ret == 0)
return ret;
}
@@ -344,7 +378,7 @@ static int block_alloc_fixed(struct sst_module *module,
err = block_alloc_contiguous(module, data,
block->offset + block->size,
- data->size - block->size + data->offset - block->offset);
+ data->size - block->size);
if (err < 0)
return -ENOMEM;
@@ -371,15 +405,10 @@ static int block_alloc_fixed(struct sst_module *module,
if (data->offset >= block->offset && data->offset < block_end) {
err = block_alloc_contiguous(module, data,
- block->offset + block->size,
- data->size - block->size);
+ block->offset, data->size);
if (err < 0)
return -ENOMEM;
- /* add block */
- block->data_type = data->data_type;
- list_move(&block->list, &dsp->used_block_list);
- list_add(&block->module_list, &module->block_list);
return 0;
}
@@ -505,9 +534,7 @@ struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp)
/* calculate required scratch size */
list_for_each_entry(sst_module, &dsp->module_list, list) {
- if (scratch->s.size > sst_module->s.size)
- scratch->s.size = scratch->s.size;
- else
+ if (scratch->s.size < sst_module->s.size)
scratch->s.size = sst_module->s.size;
}
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c
index f5ebf36af889..535f517629fd 100644
--- a/sound/soc/intel/sst-haswell-dsp.c
+++ b/sound/soc/intel/sst-haswell-dsp.c
@@ -433,7 +433,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
int ret = -ENODEV, i, j, region_count;
u32 offset, size;
- dev = sst->dev;
+ dev = sst->dma_dev;
switch (sst->id) {
case SST_DEV_ID_LYNX_POINT:
@@ -466,7 +466,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
return ret;
}
- ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31));
if (ret)
return ret;
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
index f46bb4ddde6f..e7996b39a484 100644
--- a/sound/soc/intel/sst-haswell-ipc.c
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -617,7 +617,7 @@ static void hsw_notification_work(struct work_struct *work)
case IPC_POSITION_CHANGED:
trace_ipc_notification("DSP stream position changed for",
stream->reply.stream_hw_id);
- sst_dsp_inbox_read(hsw->dsp, pos, sizeof(pos));
+ sst_dsp_inbox_read(hsw->dsp, pos, sizeof(*pos));
if (stream->notify_position)
stream->notify_position(stream, stream->pdata);
@@ -991,7 +991,8 @@ int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream
return -EINVAL;
sst_dsp_read(hsw->dsp, volume,
- stream->reply.volume_register_address[channel], sizeof(volume));
+ stream->reply.volume_register_address[channel],
+ sizeof(*volume));
return 0;
}
@@ -1158,11 +1159,14 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
void *data)
{
struct sst_hsw_stream *stream;
+ struct sst_dsp *sst = hsw->dsp;
+ unsigned long flags;
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
if (stream == NULL)
return NULL;
+ spin_lock_irqsave(&sst->spinlock, flags);
list_add(&stream->node, &hsw->stream_list);
stream->notify_position = notify_position;
stream->pdata = data;
@@ -1171,6 +1175,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
/* work to process notification messages */
INIT_WORK(&stream->notify_work, hsw_notification_work);
+ spin_unlock_irqrestore(&sst->spinlock, flags);
return stream;
}
@@ -1179,6 +1184,8 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
{
u32 header;
int ret = 0;
+ struct sst_dsp *sst = hsw->dsp;
+ unsigned long flags;
/* dont free DSP streams that are not commited */
if (!stream->commited)
@@ -1200,8 +1207,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
trace_hsw_stream_free_req(stream, &stream->free_req);
out:
+ cancel_work_sync(&stream->notify_work);
+ spin_lock_irqsave(&sst->spinlock, flags);
list_del(&stream->node);
kfree(stream);
+ spin_unlock_irqrestore(&sst->spinlock, flags);
return ret;
}
@@ -1537,10 +1547,28 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
}
/* Stream pointer positions */
-int sst_hsw_get_dsp_position(struct sst_hsw *hsw,
+u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
struct sst_hsw_stream *stream)
{
- return stream->rpos.position;
+ u32 rpos;
+
+ sst_dsp_read(hsw->dsp, &rpos,
+ stream->reply.read_position_register_address, sizeof(rpos));
+
+ return rpos;
+}
+
+/* Stream presentation (monotonic) positions */
+u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream)
+{
+ u64 ppos;
+
+ sst_dsp_read(hsw->dsp, &ppos,
+ stream->reply.presentation_position_register_address,
+ sizeof(ppos));
+
+ return ppos;
}
int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
@@ -1609,7 +1637,7 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw,
trace_ipc_request("PM enter Dx state", state);
ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_),
- dx, sizeof(dx));
+ dx, sizeof(*dx));
if (ret < 0) {
dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state);
return ret;
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
index d517929ccc38..2ac194a6d04b 100644
--- a/sound/soc/intel/sst-haswell-ipc.h
+++ b/sound/soc/intel/sst-haswell-ipc.h
@@ -464,7 +464,9 @@ int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw,
struct sst_hsw_stream *stream, u32 *position);
int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
struct sst_hsw_stream *stream, u32 stage_id, u32 position);
-int sst_hsw_get_dsp_position(struct sst_hsw *hsw,
+u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream);
+u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
struct sst_hsw_stream *stream);
/* HW port config */
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index 0a32dd13a23d..ce27b507d5ef 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -99,6 +99,7 @@ struct hsw_pcm_data {
struct snd_compr_stream *cstream;
unsigned int wpos;
struct mutex mutex;
+ bool allocated;
};
/* private data for the driver */
@@ -107,12 +108,14 @@ struct hsw_priv_data {
struct sst_hsw *hsw;
/* page tables */
- unsigned char *pcm_pg[HSW_PCM_COUNT][2];
+ struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];
/* DAI data */
struct hsw_pcm_data pcm[HSW_PCM_COUNT];
};
+static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data);
+
static inline u32 hsw_mixer_to_ipc(unsigned int value)
{
if (value >= ARRAY_SIZE(volume_map))
@@ -136,7 +139,7 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value)
static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct hsw_priv_data *pdata =
@@ -174,7 +177,7 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct hsw_priv_data *pdata =
@@ -206,7 +209,7 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
static int hsw_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
struct sst_hsw *hsw = pdata->hsw;
u32 volume;
@@ -231,7 +234,7 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol,
static int hsw_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
struct sst_hsw *hsw = pdata->hsw;
unsigned int volume = 0;
@@ -273,28 +276,26 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = {
};
/* Create DMA buffer page table for DSP */
-static int create_adsp_page_table(struct hsw_priv_data *pdata,
- struct snd_soc_pcm_runtime *rtd,
- unsigned char *dma_area, size_t size, int pcm, int stream)
+static int create_adsp_page_table(struct snd_pcm_substream *substream,
+ struct hsw_priv_data *pdata, struct snd_soc_pcm_runtime *rtd,
+ unsigned char *dma_area, size_t size, int pcm)
{
- int i, pages;
+ struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
+ int i, pages, stream = substream->stream;
- if (size % PAGE_SIZE)
- pages = (size / PAGE_SIZE) + 1;
- else
- pages = size / PAGE_SIZE;
+ pages = snd_sgbuf_aligned_pages(size);
dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",
dma_area, size, pages);
for (i = 0; i < pages; i++) {
u32 idx = (((i << 2) + i)) >> 1;
- u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT;
+ u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
u32 *pg_table;
dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
- pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx);
+ pg_table = (u32 *)(pdata->dmab[pcm][stream].area + idx);
if (i & 1)
*pg_table |= (pfn << 4);
@@ -317,12 +318,36 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
struct sst_hsw *hsw = pdata->hsw;
struct sst_module *module_data;
struct sst_dsp *dsp;
+ struct snd_dma_buffer *dmab;
enum sst_hsw_stream_type stream_type;
enum sst_hsw_stream_path_id path_id;
u32 rate, bits, map, pages, module_id;
u8 channels;
int ret;
+ /* check if we are being called a subsequent time */
+ if (pcm_data->allocated) {
+ ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
+ if (ret < 0)
+ dev_dbg(rtd->dev, "error: reset stream failed %d\n",
+ ret);
+
+ ret = sst_hsw_stream_free(hsw, pcm_data->stream);
+ if (ret < 0) {
+ dev_dbg(rtd->dev, "error: free stream failed %d\n",
+ ret);
+ return ret;
+ }
+ pcm_data->allocated = false;
+
+ pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
+ hsw_notify_pointer, pcm_data);
+ if (pcm_data->stream == NULL) {
+ dev_err(rtd->dev, "error: failed to create stream\n");
+ return -EINVAL;
+ }
+ }
+
/* stream direction */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
@@ -416,8 +441,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- ret = create_adsp_page_table(pdata, rtd, runtime->dma_area,
- runtime->dma_bytes, rtd->cpu_dai->id, substream->stream);
+ dmab = snd_pcm_get_dma_buf(substream);
+
+ ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area,
+ runtime->dma_bytes, rtd->cpu_dai->id);
if (ret < 0)
return ret;
@@ -430,9 +457,9 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
pages = runtime->dma_bytes / PAGE_SIZE;
ret = sst_hsw_stream_buffer(hsw, pcm_data->stream,
- virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]),
+ pdata->dmab[rtd->cpu_dai->id][substream->stream].addr,
pages, runtime->dma_bytes, 0,
- (u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT));
+ snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT);
if (ret < 0) {
dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);
return ret;
@@ -474,6 +501,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
return ret;
}
+ pcm_data->allocated = true;
ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
if (ret < 0)
@@ -541,12 +569,14 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
struct sst_hsw *hsw = pdata->hsw;
snd_pcm_uframes_t offset;
+ uint64_t ppos;
+ u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
- offset = bytes_to_frames(runtime,
- sst_hsw_get_dsp_position(hsw, pcm_data->stream));
+ offset = bytes_to_frames(runtime, position);
+ ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream);
- dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
- frames_to_bytes(runtime, (u32)offset));
+ dev_dbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n",
+ position, ppos);
return offset;
}
@@ -606,6 +636,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream)
dev_dbg(rtd->dev, "error: free stream failed %d\n", ret);
goto out;
}
+ pcm_data->allocated = 0;
pcm_data->stream = NULL;
out:
@@ -621,7 +652,7 @@ static struct snd_pcm_ops hsw_pcm_ops = {
.hw_free = hsw_pcm_hw_free,
.trigger = hsw_pcm_trigger,
.pointer = hsw_pcm_pointer,
- .mmap = snd_pcm_lib_default_mmap,
+ .page = snd_pcm_sgbuf_ops_page,
};
static void hsw_pcm_free(struct snd_pcm *pcm)
@@ -632,17 +663,16 @@ static void hsw_pcm_free(struct snd_pcm *pcm)
static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_pcm *pcm = rtd->pcm;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct sst_pdata *pdata = dev_get_platdata(platform->dev);
+ struct device *dev = pdata->dma_dev;
int ret = 0;
- ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
-
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
- SNDRV_DMA_TYPE_DEV,
- rtd->card->dev,
+ SNDRV_DMA_TYPE_DEV_SG,
+ dev,
hsw_pcm_hardware.buffer_bytes_max,
hsw_pcm_hardware.buffer_bytes_max);
if (ret) {
@@ -742,11 +772,14 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
{
struct sst_pdata *pdata = dev_get_platdata(platform->dev);
struct hsw_priv_data *priv_data;
- int i;
+ struct device *dma_dev;
+ int i, ret = 0;
if (!pdata)
return -ENODEV;
+ dma_dev = pdata->dma_dev;
+
priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);
priv_data->hsw = pdata->dsp;
snd_soc_platform_set_drvdata(platform, priv_data);
@@ -758,15 +791,17 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
/* playback */
if (hsw_dais[i].playback.channels_min) {
- priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA);
- if (priv_data->pcm_pg[i][0] == NULL)
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
+ PAGE_SIZE, &priv_data->dmab[i][0]);
+ if (ret < 0)
goto err;
}
/* capture */
if (hsw_dais[i].capture.channels_min) {
- priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA);
- if (priv_data->pcm_pg[i][1] == NULL)
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
+ PAGE_SIZE, &priv_data->dmab[i][1]);
+ if (ret < 0)
goto err;
}
}
@@ -776,11 +811,11 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
err:
for (;i >= 0; i--) {
if (hsw_dais[i].playback.channels_min)
- kfree(priv_data->pcm_pg[i][0]);
+ snd_dma_free_pages(&priv_data->dmab[i][0]);
if (hsw_dais[i].capture.channels_min)
- kfree(priv_data->pcm_pg[i][1]);
+ snd_dma_free_pages(&priv_data->dmab[i][1]);
}
- return -ENOMEM;
+ return ret;
}
static int hsw_pcm_remove(struct snd_soc_platform *platform)
@@ -791,9 +826,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
if (hsw_dais[i].playback.channels_min)
- kfree(priv_data->pcm_pg[i][0]);
+ snd_dma_free_pages(&priv_data->dmab[i][0]);
if (hsw_dais[i].capture.channels_min)
- kfree(priv_data->pcm_pg[i][1]);
+ snd_dma_free_pages(&priv_data->dmab[i][1]);
}
return 0;
diff --git a/sound/soc/intel/sst-mfld-dsp.h b/sound/soc/intel/sst-mfld-dsp.h
index 3b63edc04b7f..8d482d76475a 100644
--- a/sound/soc/intel/sst-mfld-dsp.h
+++ b/sound/soc/intel/sst-mfld-dsp.h
@@ -16,10 +16,6 @@
* 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.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
@@ -40,7 +36,6 @@ enum stream_type {
};
struct snd_pcm_params {
- u16 codec; /* codec type */
u8 num_chan; /* 1=Mono, 2=Stereo */
u8 pcm_wd_sz; /* 16/24 - bit*/
u32 reserved; /* Bitrate in bits per second */
@@ -53,7 +48,6 @@ struct snd_pcm_params {
/* MP3 Music Parameters Message */
struct snd_mp3_params {
- u16 codec;
u8 num_chan; /* 1=Mono, 2=Stereo */
u8 pcm_wd_sz; /* 16/24 - bit*/
u8 crc_check; /* crc_check - disable (0) or enable (1) */
@@ -67,7 +61,6 @@ struct snd_mp3_params {
/* AAC Music Parameters Message */
struct snd_aac_params {
- u16 codec;
u8 num_chan; /* 1=Mono, 2=Stereo*/
u8 pcm_wd_sz; /* 16/24 - bit*/
u8 bdownsample; /*SBR downsampling 0 - disable 1 -enabled AAC+ only */
@@ -81,7 +74,6 @@ struct snd_aac_params {
/* WMA Music Parameters Message */
struct snd_wma_params {
- u16 codec;
u8 num_chan; /* 1=Mono, 2=Stereo */
u8 pcm_wd_sz; /* 16/24 - bit*/
u32 brate; /* Use the hard coded value. */
diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c
new file mode 100644
index 000000000000..02abd19fce1d
--- /dev/null
+++ b/sound/soc/intel/sst-mfld-platform-compress.c
@@ -0,0 +1,237 @@
+/*
+ * sst_mfld_platform.c - Intel MID Platform driver
+ *
+ * Copyright (C) 2010-2014 Intel Corp
+ * Author: Vinod Koul <vinod.koul@intel.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 Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#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>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include "sst-mfld-platform.h"
+
+/* compress stream operations */
+static void sst_compr_fragment_elapsed(void *arg)
+{
+ struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
+
+ pr_debug("fragment elapsed by driver\n");
+ if (cstream)
+ snd_compr_fragment_elapsed(cstream);
+}
+
+static void sst_drain_notify(void *arg)
+{
+ struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
+
+ pr_debug("drain notify by driver\n");
+ if (cstream)
+ snd_compr_drain_notify(cstream);
+}
+
+static int sst_platform_compr_open(struct snd_compr_stream *cstream)
+{
+
+ int ret_val = 0;
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct sst_runtime_stream *stream;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return -ENOMEM;
+
+ spin_lock_init(&stream->status_lock);
+
+ /* get the sst ops */
+ if (!sst || !try_module_get(sst->dev->driver->owner)) {
+ pr_err("no device available to run\n");
+ ret_val = -ENODEV;
+ goto out_ops;
+ }
+ stream->compr_ops = sst->compr_ops;
+
+ stream->id = 0;
+ sst_set_stream_status(stream, SST_PLATFORM_INIT);
+ runtime->private_data = stream;
+ return 0;
+out_ops:
+ kfree(stream);
+ return ret_val;
+}
+
+static int sst_platform_compr_free(struct snd_compr_stream *cstream)
+{
+ struct sst_runtime_stream *stream;
+ int ret_val = 0, str_id;
+
+ stream = cstream->runtime->private_data;
+ /*need to check*/
+ str_id = stream->id;
+ if (str_id)
+ ret_val = stream->compr_ops->close(str_id);
+ module_put(sst->dev->driver->owner);
+ kfree(stream);
+ pr_debug("%s: %d\n", __func__, ret_val);
+ return 0;
+}
+
+static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
+ struct snd_compr_params *params)
+{
+ struct sst_runtime_stream *stream;
+ int retval;
+ struct snd_sst_params str_params;
+ struct sst_compress_cb cb;
+
+ stream = cstream->runtime->private_data;
+ /* construct fw structure for this*/
+ memset(&str_params, 0, sizeof(str_params));
+
+ str_params.ops = STREAM_OPS_PLAYBACK;
+ str_params.stream_type = SST_STREAM_TYPE_MUSIC;
+ str_params.device_type = SND_SST_DEVICE_COMPRESS;
+
+ switch (params->codec.id) {
+ case SND_AUDIOCODEC_MP3: {
+ str_params.codec = SST_CODEC_TYPE_MP3;
+ str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
+ str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
+ break;
+ }
+
+ case SND_AUDIOCODEC_AAC: {
+ str_params.codec = SST_CODEC_TYPE_AAC;
+ str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
+ str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
+ if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
+ str_params.sparams.uc.aac_params.bs_format =
+ AAC_BIT_STREAM_ADTS;
+ else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
+ str_params.sparams.uc.aac_params.bs_format =
+ AAC_BIT_STREAM_RAW;
+ else {
+ pr_err("Undefined format%d\n", params->codec.format);
+ return -EINVAL;
+ }
+ str_params.sparams.uc.aac_params.externalsr =
+ params->codec.sample_rate;
+ break;
+ }
+
+ default:
+ pr_err("codec not supported, id =%d\n", params->codec.id);
+ return -EINVAL;
+ }
+
+ str_params.aparams.ring_buf_info[0].addr =
+ virt_to_phys(cstream->runtime->buffer);
+ str_params.aparams.ring_buf_info[0].size =
+ cstream->runtime->buffer_size;
+ str_params.aparams.sg_count = 1;
+ str_params.aparams.frag_size = cstream->runtime->fragment_size;
+
+ cb.param = cstream;
+ cb.compr_cb = sst_compr_fragment_elapsed;
+ cb.drain_cb_param = cstream;
+ cb.drain_notify = sst_drain_notify;
+
+ retval = stream->compr_ops->open(&str_params, &cb);
+ if (retval < 0) {
+ pr_err("stream allocation failed %d\n", retval);
+ return retval;
+ }
+
+ stream->id = retval;
+ return 0;
+}
+
+static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
+{
+ struct sst_runtime_stream *stream =
+ cstream->runtime->private_data;
+
+ return stream->compr_ops->control(cmd, stream->id);
+}
+
+static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
+ struct snd_compr_tstamp *tstamp)
+{
+ struct sst_runtime_stream *stream;
+
+ stream = cstream->runtime->private_data;
+ stream->compr_ops->tstamp(stream->id, tstamp);
+ tstamp->byte_offset = tstamp->copied_total %
+ (u32)cstream->runtime->buffer_size;
+ pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
+ return 0;
+}
+
+static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
+ size_t bytes)
+{
+ struct sst_runtime_stream *stream;
+
+ stream = cstream->runtime->private_data;
+ stream->compr_ops->ack(stream->id, (unsigned long)bytes);
+ stream->bytes_written += bytes;
+
+ return 0;
+}
+
+static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
+ struct snd_compr_caps *caps)
+{
+ struct sst_runtime_stream *stream =
+ cstream->runtime->private_data;
+
+ return stream->compr_ops->get_caps(caps);
+}
+
+static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
+ struct snd_compr_codec_caps *codec)
+{
+ struct sst_runtime_stream *stream =
+ cstream->runtime->private_data;
+
+ return stream->compr_ops->get_codec_caps(codec);
+}
+
+static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
+ struct snd_compr_metadata *metadata)
+{
+ struct sst_runtime_stream *stream =
+ cstream->runtime->private_data;
+
+ return stream->compr_ops->set_metadata(stream->id, metadata);
+}
+
+struct snd_compr_ops sst_platform_compr_ops = {
+
+ .open = sst_platform_compr_open,
+ .free = sst_platform_compr_free,
+ .set_params = sst_platform_compr_set_params,
+ .set_metadata = sst_platform_compr_set_metadata,
+ .trigger = sst_platform_compr_trigger,
+ .pointer = sst_platform_compr_pointer,
+ .ack = sst_platform_compr_ack,
+ .get_caps = sst_platform_compr_get_caps,
+ .get_codec_caps = sst_platform_compr_get_codec_caps,
+};
diff --git a/sound/soc/intel/sst-mfld-platform.c b/sound/soc/intel/sst-mfld-platform-pcm.c
index 840306c2ef14..7c790f51d259 100644
--- a/sound/soc/intel/sst-mfld-platform.c
+++ b/sound/soc/intel/sst-mfld-platform-pcm.c
@@ -15,13 +15,7 @@
* 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.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -35,8 +29,9 @@
#include <sound/compress_driver.h>
#include "sst-mfld-platform.h"
-static struct sst_device *sst;
+struct sst_device *sst;
static DEFINE_MUTEX(sst_lock);
+extern struct snd_compr_ops sst_platform_compr_ops;
int sst_register_dsp(struct sst_device *dev)
{
@@ -116,36 +111,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
},
},
{
- .name = "Speaker-cpu-dai",
- .id = 1,
- .playback = {
- .channels_min = SST_MONO,
- .channels_max = SST_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S24_LE,
- },
-},
-{
- .name = "Vibra1-cpu-dai",
- .id = 2,
- .playback = {
- .channels_min = SST_MONO,
- .channels_max = SST_MONO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S24_LE,
- },
-},
-{
- .name = "Vibra2-cpu-dai",
- .id = 3,
- .playback = {
- .channels_min = SST_MONO,
- .channels_max = SST_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S24_LE,
- },
-},
-{
.name = "Compress-cpu-dai",
.compress_dai = 1,
.playback = {
@@ -157,12 +122,8 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
},
};
-static const struct snd_soc_component_driver sst_component = {
- .name = "sst",
-};
-
/* helper functions */
-static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
+void sst_set_stream_status(struct sst_runtime_stream *stream,
int state)
{
unsigned long flags;
@@ -186,7 +147,6 @@ static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
struct sst_pcm_params *param)
{
- param->codec = SST_CODEC_TYPE_PCM;
param->num_chan = (u8) substream->runtime->channels;
param->pcm_wd_sz = substream->runtime->sample_bits;
param->reserved = 0;
@@ -471,205 +431,6 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
return retval;
}
-/* compress stream operations */
-static void sst_compr_fragment_elapsed(void *arg)
-{
- struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
-
- pr_debug("fragment elapsed by driver\n");
- if (cstream)
- snd_compr_fragment_elapsed(cstream);
-}
-
-static int sst_platform_compr_open(struct snd_compr_stream *cstream)
-{
-
- int ret_val = 0;
- struct snd_compr_runtime *runtime = cstream->runtime;
- struct sst_runtime_stream *stream;
-
- stream = kzalloc(sizeof(*stream), GFP_KERNEL);
- if (!stream)
- return -ENOMEM;
-
- spin_lock_init(&stream->status_lock);
-
- /* get the sst ops */
- if (!sst || !try_module_get(sst->dev->driver->owner)) {
- pr_err("no device available to run\n");
- ret_val = -ENODEV;
- goto out_ops;
- }
- stream->compr_ops = sst->compr_ops;
-
- stream->id = 0;
- sst_set_stream_status(stream, SST_PLATFORM_INIT);
- runtime->private_data = stream;
- return 0;
-out_ops:
- kfree(stream);
- return ret_val;
-}
-
-static int sst_platform_compr_free(struct snd_compr_stream *cstream)
-{
- struct sst_runtime_stream *stream;
- int ret_val = 0, str_id;
-
- stream = cstream->runtime->private_data;
- /*need to check*/
- str_id = stream->id;
- if (str_id)
- ret_val = stream->compr_ops->close(str_id);
- module_put(sst->dev->driver->owner);
- kfree(stream);
- pr_debug("%s: %d\n", __func__, ret_val);
- return 0;
-}
-
-static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
- struct snd_compr_params *params)
-{
- struct sst_runtime_stream *stream;
- int retval;
- struct snd_sst_params str_params;
- struct sst_compress_cb cb;
-
- stream = cstream->runtime->private_data;
- /* construct fw structure for this*/
- memset(&str_params, 0, sizeof(str_params));
-
- str_params.ops = STREAM_OPS_PLAYBACK;
- str_params.stream_type = SST_STREAM_TYPE_MUSIC;
- str_params.device_type = SND_SST_DEVICE_COMPRESS;
-
- switch (params->codec.id) {
- case SND_AUDIOCODEC_MP3: {
- str_params.codec = SST_CODEC_TYPE_MP3;
- str_params.sparams.uc.mp3_params.codec = SST_CODEC_TYPE_MP3;
- str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
- str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
- break;
- }
-
- case SND_AUDIOCODEC_AAC: {
- str_params.codec = SST_CODEC_TYPE_AAC;
- str_params.sparams.uc.aac_params.codec = SST_CODEC_TYPE_AAC;
- str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
- str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
- if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
- str_params.sparams.uc.aac_params.bs_format =
- AAC_BIT_STREAM_ADTS;
- else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
- str_params.sparams.uc.aac_params.bs_format =
- AAC_BIT_STREAM_RAW;
- else {
- pr_err("Undefined format%d\n", params->codec.format);
- return -EINVAL;
- }
- str_params.sparams.uc.aac_params.externalsr =
- params->codec.sample_rate;
- break;
- }
-
- default:
- pr_err("codec not supported, id =%d\n", params->codec.id);
- return -EINVAL;
- }
-
- str_params.aparams.ring_buf_info[0].addr =
- virt_to_phys(cstream->runtime->buffer);
- str_params.aparams.ring_buf_info[0].size =
- cstream->runtime->buffer_size;
- str_params.aparams.sg_count = 1;
- str_params.aparams.frag_size = cstream->runtime->fragment_size;
-
- cb.param = cstream;
- cb.compr_cb = sst_compr_fragment_elapsed;
-
- retval = stream->compr_ops->open(&str_params, &cb);
- if (retval < 0) {
- pr_err("stream allocation failed %d\n", retval);
- return retval;
- }
-
- stream->id = retval;
- return 0;
-}
-
-static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
-{
- struct sst_runtime_stream *stream =
- cstream->runtime->private_data;
-
- return stream->compr_ops->control(cmd, stream->id);
-}
-
-static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *tstamp)
-{
- struct sst_runtime_stream *stream;
-
- stream = cstream->runtime->private_data;
- stream->compr_ops->tstamp(stream->id, tstamp);
- tstamp->byte_offset = tstamp->copied_total %
- (u32)cstream->runtime->buffer_size;
- pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
- return 0;
-}
-
-static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
- size_t bytes)
-{
- struct sst_runtime_stream *stream;
-
- stream = cstream->runtime->private_data;
- stream->compr_ops->ack(stream->id, (unsigned long)bytes);
- stream->bytes_written += bytes;
-
- return 0;
-}
-
-static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
- struct snd_compr_caps *caps)
-{
- struct sst_runtime_stream *stream =
- cstream->runtime->private_data;
-
- return stream->compr_ops->get_caps(caps);
-}
-
-static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
- struct snd_compr_codec_caps *codec)
-{
- struct sst_runtime_stream *stream =
- cstream->runtime->private_data;
-
- return stream->compr_ops->get_codec_caps(codec);
-}
-
-static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
- struct snd_compr_metadata *metadata)
-{
- struct sst_runtime_stream *stream =
- cstream->runtime->private_data;
-
- return stream->compr_ops->set_metadata(stream->id, metadata);
-}
-
-static struct snd_compr_ops sst_platform_compr_ops = {
-
- .open = sst_platform_compr_open,
- .free = sst_platform_compr_free,
- .set_params = sst_platform_compr_set_params,
- .set_metadata = sst_platform_compr_set_metadata,
- .trigger = sst_platform_compr_trigger,
- .pointer = sst_platform_compr_pointer,
- .ack = sst_platform_compr_ack,
- .get_caps = sst_platform_compr_get_caps,
- .get_codec_caps = sst_platform_compr_get_codec_caps,
-};
-
static struct snd_soc_platform_driver sst_soc_platform_drv = {
.ops = &sst_platform_ops,
.compr_ops = &sst_platform_compr_ops,
@@ -677,6 +438,11 @@ static struct snd_soc_platform_driver sst_soc_platform_drv = {
.pcm_free = sst_pcm_free,
};
+static const struct snd_soc_component_driver sst_component = {
+ .name = "sst",
+};
+
+
static int sst_platform_probe(struct platform_device *pdev)
{
int ret;
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h
index 0c4e2ddcecb1..6c5e7dc49e3c 100644
--- a/sound/soc/intel/sst-mfld-platform.h
+++ b/sound/soc/intel/sst-mfld-platform.h
@@ -15,13 +15,7 @@
* 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.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *
*/
#ifndef __SST_PLATFORMDRV_H__
@@ -29,6 +23,8 @@
#include "sst-mfld-dsp.h"
+extern struct sst_device *sst;
+
#define SST_MONO 1
#define SST_STEREO 2
#define SST_MAX_CAP 5
@@ -108,6 +104,8 @@ struct sst_stream_params {
struct sst_compress_cb {
void *param;
void (*compr_cb)(void *param);
+ void *drain_cb_param;
+ void (*drain_notify)(void *param);
};
struct compress_sst_ops {
@@ -148,6 +146,7 @@ struct sst_device {
struct compress_sst_ops *compr_ops;
};
+void sst_set_stream_status(struct sst_runtime_stream *stream, int state);
int sst_register_dsp(struct sst_device *sst);
int sst_unregister_dsp(struct sst_device *sst);
#endif
diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig
index 29f76af5d963..1a354a6b6e87 100644
--- a/sound/soc/jz4740/Kconfig
+++ b/sound/soc/jz4740/Kconfig
@@ -1,24 +1,29 @@
config SND_JZ4740_SOC
tristate "SoC Audio for Ingenic JZ4740 SoC"
- depends on MACH_JZ4740 && SND_SOC
+ depends on MACH_JZ4740 || COMPILE_TEST
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for codecs attached to
the JZ4740 I2S interface. You will also need to select the audio
interfaces to support below.
+if SND_JZ4740_SOC
+
config SND_JZ4740_SOC_I2S
- depends on SND_JZ4740_SOC
tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC"
+ depends on HAS_IOMEM
help
Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740
based boards.
config SND_JZ4740_SOC_QI_LB60
tristate "SoC Audio support for Qi LB60"
- depends on SND_JZ4740_SOC && JZ4740_QI_LB60
+ depends on HAS_IOMEM
+ depends on JZ4740_QI_LB60 || COMPILE_TEST
select SND_JZ4740_SOC_I2S
select SND_SOC_JZ4740_CODEC
help
Say Y if you want to add support for ASoC audio on the Qi LB60 board
a.k.a Qi Ben NanoNote.
+
+endif
diff --git a/sound/soc/jz4740/Makefile b/sound/soc/jz4740/Makefile
index be873c1b0c20..d32c540555c4 100644
--- a/sound/soc/jz4740/Makefile
+++ b/sound/soc/jz4740/Makefile
@@ -1,10 +1,8 @@
#
# Jz4740 Platform Support
#
-snd-soc-jz4740-objs := jz4740-pcm.o
snd-soc-jz4740-i2s-objs := jz4740-i2s.o
-obj-$(CONFIG_SND_JZ4740_SOC) += snd-soc-jz4740.o
obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o
# Jz4740 Machine Support
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index 8f220009e0f6..3f9c3a9ae36f 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -31,10 +31,11 @@
#include <sound/initval.h>
#include <sound/dmaengine_pcm.h>
-#include <asm/mach-jz4740/dma.h>
-
#include "jz4740-i2s.h"
+#define JZ4740_DMA_TYPE_AIC_TRANSMIT 24
+#define JZ4740_DMA_TYPE_AIC_RECEIVE 25
+
#define JZ_REG_AIC_CONF 0x00
#define JZ_REG_AIC_CTRL 0x04
#define JZ_REG_AIC_I2S_FMT 0x10
diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c
index 82b5f37cd2c7..5cb91f9e8626 100644
--- a/sound/soc/jz4740/qi_lb60.c
+++ b/sound/soc/jz4740/qi_lb60.c
@@ -19,18 +19,21 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
-#define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29)
-#define QI_LB60_AMP_GPIO JZ_GPIO_PORTD(4)
+struct qi_lb60 {
+ struct gpio_desc *snd_gpio;
+ struct gpio_desc *amp_gpio;
+};
static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *ctrl, int event)
{
+ struct qi_lb60 *qi_lb60 = snd_soc_card_get_drvdata(widget->dapm->card);
int on = !SND_SOC_DAPM_EVENT_OFF(event);
- gpio_set_value(QI_LB60_SND_GPIO, on);
- gpio_set_value(QI_LB60_AMP_GPIO, on);
+ gpiod_set_value_cansleep(qi_lb60->snd_gpio, on);
+ gpiod_set_value_cansleep(qi_lb60->amp_gpio, on);
return 0;
}
@@ -46,29 +49,6 @@ static const struct snd_soc_dapm_route qi_lb60_routes[] = {
{"Speaker", NULL, "ROUT"},
};
-#define QI_LB60_DAIFMT (SND_SOC_DAIFMT_I2S | \
- SND_SOC_DAIFMT_NB_NF | \
- SND_SOC_DAIFMT_CBM_CFM)
-
-static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
-
- snd_soc_dapm_nc_pin(dapm, "LIN");
- snd_soc_dapm_nc_pin(dapm, "RIN");
-
- ret = snd_soc_dai_set_fmt(cpu_dai, QI_LB60_DAIFMT);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cpu dai format: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
static struct snd_soc_dai_link qi_lb60_dai = {
.name = "jz4740",
.stream_name = "jz4740",
@@ -76,10 +56,11 @@ static struct snd_soc_dai_link qi_lb60_dai = {
.platform_name = "jz4740-i2s",
.codec_dai_name = "jz4740-hifi",
.codec_name = "jz4740-codec",
- .init = qi_lb60_codec_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
};
-static struct snd_soc_card qi_lb60 = {
+static struct snd_soc_card qi_lb60_card = {
.name = "QI LB60",
.owner = THIS_MODULE,
.dai_link = &qi_lb60_dai,
@@ -89,40 +70,38 @@ static struct snd_soc_card qi_lb60 = {
.num_dapm_widgets = ARRAY_SIZE(qi_lb60_widgets),
.dapm_routes = qi_lb60_routes,
.num_dapm_routes = ARRAY_SIZE(qi_lb60_routes),
-};
-
-static const struct gpio qi_lb60_gpios[] = {
- { QI_LB60_SND_GPIO, GPIOF_OUT_INIT_LOW, "SND" },
- { QI_LB60_AMP_GPIO, GPIOF_OUT_INIT_LOW, "AMP" },
+ .fully_routed = true,
};
static int qi_lb60_probe(struct platform_device *pdev)
{
- struct snd_soc_card *card = &qi_lb60;
+ struct qi_lb60 *qi_lb60;
+ struct snd_soc_card *card = &qi_lb60_card;
int ret;
- ret = gpio_request_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
+ qi_lb60 = devm_kzalloc(&pdev->dev, sizeof(*qi_lb60), GFP_KERNEL);
+ if (!qi_lb60)
+ return -ENOMEM;
+
+ qi_lb60->snd_gpio = devm_gpiod_get(&pdev->dev, "snd");
+ if (IS_ERR(qi_lb60->snd_gpio))
+ return PTR_ERR(qi_lb60->snd_gpio);
+ ret = gpiod_direction_output(qi_lb60->snd_gpio, 0);
if (ret)
return ret;
- card->dev = &pdev->dev;
+ qi_lb60->amp_gpio = devm_gpiod_get(&pdev->dev, "amp");
+ if (IS_ERR(qi_lb60->amp_gpio))
+ return PTR_ERR(qi_lb60->amp_gpio);
+ ret = gpiod_direction_output(qi_lb60->amp_gpio, 0);
+ if (ret)
+ return ret;
- ret = snd_soc_register_card(card);
- if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
- ret);
- gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
- }
- return ret;
-}
+ card->dev = &pdev->dev;
-static int qi_lb60_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
+ snd_soc_card_set_drvdata(card, qi_lb60);
- snd_soc_unregister_card(card);
- gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
- return 0;
+ return devm_snd_soc_register_card(&pdev->dev, card);
}
static struct platform_driver qi_lb60_driver = {
@@ -131,7 +110,6 @@ static struct platform_driver qi_lb60_driver = {
.owner = THIS_MODULE,
},
.probe = qi_lb60_probe,
- .remove = qi_lb60_remove,
};
module_platform_driver(qi_lb60_driver);
diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c
index d213832b0c72..844b8415a011 100644
--- a/sound/soc/kirkwood/kirkwood-t5325.c
+++ b/sound/soc/kirkwood/kirkwood-t5325.c
@@ -52,18 +52,6 @@ static const struct snd_soc_dapm_route t5325_route[] = {
{ "MIC2", NULL, "Mic Jack" },
};
-static int t5325_dai_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_enable_pin(dapm, "Mic Jack");
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_enable_pin(dapm, "Speaker");
-
- return 0;
-}
-
static struct snd_soc_dai_link t5325_dai[] = {
{
.name = "ALC5621",
@@ -74,7 +62,6 @@ static struct snd_soc_dai_link t5325_dai[] = {
.codec_name = "alc562x-codec.0-001a",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
.ops = &t5325_ops,
- .init = t5325_dai_init,
},
};
diff --git a/sound/soc/nuc900/Kconfig b/sound/soc/nuc900/Kconfig
index a0ed1c618f60..7f0c954dff6f 100644
--- a/sound/soc/nuc900/Kconfig
+++ b/sound/soc/nuc900/Kconfig
@@ -4,6 +4,7 @@
config SND_SOC_NUC900
tristate "SoC Audio for NUC900 series"
depends on ARCH_W90X900
+ select SND_SOC_NUC900_AC97
help
This option enables support for AC97 mode on the NUC900 SoC.
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
index 8987bf987e58..f2f67942b229 100644
--- a/sound/soc/nuc900/nuc900-ac97.c
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -28,6 +28,7 @@
static DEFINE_MUTEX(ac97_mutex);
struct nuc900_audio *nuc900_ac97_data;
+EXPORT_SYMBOL_GPL(nuc900_ac97_data);
static int nuc900_checkready(void)
{
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index e00659351a4e..d44463a7b0fa 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -26,7 +26,7 @@ config SND_OMAP_SOC_N810
config SND_OMAP_SOC_RX51
tristate "SoC Audio support for Nokia RX-51"
- depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST)
+ depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST) && I2C
select SND_OMAP_SOC_MCBSP
select SND_SOC_TLV320AIC3X
select SND_SOC_TPA6130A2
@@ -37,7 +37,7 @@ config SND_OMAP_SOC_RX51
config SND_OMAP_SOC_AMS_DELTA
tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
- depends on SND_OMAP_SOC && MACH_AMS_DELTA
+ depends on SND_OMAP_SOC && MACH_AMS_DELTA && TTY
select SND_OMAP_SOC_MCBSP
select SND_SOC_CX20442
help
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
index 994dcf345975..25a33e9d417a 100644
--- a/sound/soc/omap/am3517evm.c
+++ b/sound/soc/omap/am3517evm.c
@@ -77,7 +77,7 @@ static struct snd_soc_dai_link am3517evm_dai = {
.stream_name = "AIC23",
.cpu_dai_name = "omap-mcbsp.1",
.codec_dai_name = "tlv320aic23-hifi",
- .platform_name = "omap-pcm-audio",
+ .platform_name = "omap-mcbsp.1",
.codec_name = "tlv320aic23-codec.2-001a",
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 56a5219c0a00..bb243c663e6b 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -38,7 +38,6 @@
#include "omap-mcbsp.h"
#include "../codecs/cx20442.h"
-
/* Board specific DAPM widgets */
static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = {
/* Handset */
@@ -90,17 +89,23 @@ static const unsigned short ams_delta_audio_mode_pins[] = {
static unsigned short ams_delta_audio_agc;
+/*
+ * Used for passing a codec structure pointer
+ * from the board initialization code to the tty line discipline.
+ */
+static struct snd_soc_codec *cx20442_codec;
+
static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = &card->dapm;
struct soc_enum *control = (struct soc_enum *)kcontrol->private_value;
unsigned short pins;
int pin, changed = 0;
/* Refuse any mode changes if we are not able to control the codec. */
- if (!codec->hw_write)
+ if (!cx20442_codec->hw_write)
return -EUNATCH;
if (ucontrol->value.enumerated.item[0] >= control->items)
@@ -166,8 +171,8 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = &card->dapm;
unsigned short pins, mode;
pins = ((snd_soc_dapm_get_pin_status(dapm, "Mouthpiece") <<
@@ -270,12 +275,6 @@ static void cx81801_timeout(unsigned long data)
ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, 0);
}
-/*
- * Used for passing a codec structure pointer
- * from the board initialization code to the tty line discipline.
- */
-static struct snd_soc_codec *cx20442_codec;
-
/* Line discipline .open() */
static int cx81801_open(struct tty_struct *tty)
{
@@ -302,7 +301,7 @@ static int cx81801_open(struct tty_struct *tty)
static void cx81801_close(struct tty_struct *tty)
{
struct snd_soc_codec *codec = tty->disc_data;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dapm_context *dapm = &codec->card->dapm;
del_timer_sync(&cx81801_timer);
@@ -475,15 +474,14 @@ static void ams_delta_shutdown(struct snd_pcm_substream *substream)
static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = &card->dapm;
int ret;
/* Codec is ready, now add/activate board specific controls */
/* Store a pointer to the codec structure for tty ldisc use */
- cx20442_codec = codec;
+ cx20442_codec = rtd->codec;
/* Set up digital mute if not provided by the codec */
if (!codec_dai->driver->ops) {
@@ -520,41 +518,12 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
- /* Add board specific DAPM widgets and routes */
- ret = snd_soc_dapm_new_controls(dapm, ams_delta_dapm_widgets,
- ARRAY_SIZE(ams_delta_dapm_widgets));
- if (ret) {
- dev_warn(card->dev,
- "Failed to register DAPM controls, "
- "will continue without any.\n");
- return 0;
- }
-
- ret = snd_soc_dapm_add_routes(dapm, ams_delta_audio_map,
- ARRAY_SIZE(ams_delta_audio_map));
- if (ret) {
- dev_warn(card->dev,
- "Failed to set up DAPM routes, "
- "will continue with codec default map.\n");
- return 0;
- }
-
/* Set up initial pin constellation */
snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
- snd_soc_dapm_enable_pin(dapm, "Earpiece");
- snd_soc_dapm_enable_pin(dapm, "Microphone");
snd_soc_dapm_disable_pin(dapm, "Speaker");
snd_soc_dapm_disable_pin(dapm, "AGCIN");
snd_soc_dapm_disable_pin(dapm, "AGCOUT");
- /* Add virtual switch */
- ret = snd_soc_add_codec_controls(codec, ams_delta_audio_controls,
- ARRAY_SIZE(ams_delta_audio_controls));
- if (ret)
- dev_warn(card->dev,
- "Failed to register audio mode control, "
- "will continue without it.\n");
-
return 0;
}
@@ -565,7 +534,7 @@ static struct snd_soc_dai_link ams_delta_dai_link = {
.cpu_dai_name = "omap-mcbsp.1",
.codec_dai_name = "cx20442-voice",
.init = ams_delta_cx20442_init,
- .platform_name = "omap-pcm-audio",
+ .platform_name = "omap-mcbsp.1",
.codec_name = "cx20442-codec",
.ops = &ams_delta_ops,
};
@@ -576,6 +545,13 @@ static struct snd_soc_card ams_delta_audio_card = {
.owner = THIS_MODULE,
.dai_link = &ams_delta_dai_link,
.num_links = 1,
+
+ .controls = ams_delta_audio_controls,
+ .num_controls = ARRAY_SIZE(ams_delta_audio_controls),
+ .dapm_widgets = ams_delta_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ams_delta_dapm_widgets),
+ .dapm_routes = ams_delta_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(ams_delta_audio_map),
};
/* Module init/exit */
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index fd4d9c809e50..5d7f9cebe041 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -278,7 +278,7 @@ static struct snd_soc_dai_link n810_dai = {
.name = "TLV320AIC33",
.stream_name = "AIC33",
.cpu_dai_name = "omap-mcbsp.2",
- .platform_name = "omap-pcm-audio",
+ .platform_name = "omap-mcbsp.2",
.codec_name = "tlv320aic3x-codec.2-0018",
.codec_dai_name = "tlv320aic3x-hifi",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index 024dafc3e298..cec836ed0c01 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -47,8 +47,7 @@ static int omap_abe_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_codec *codec = rtd->codec;
- struct snd_soc_card *card = codec->card;
+ struct snd_soc_card *card = rtd->card;
struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
int clk_id, freq;
int ret;
@@ -168,7 +167,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_card *card = codec->card;
+ struct snd_soc_card *card = rtd->card;
struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
int hs_trim;
int ret = 0;
@@ -214,9 +213,7 @@ static struct snd_soc_dai_link abe_twl6040_dai_links[] = {
{
.name = "TWL6040",
.stream_name = "TWL6040",
- .cpu_dai_name = "omap-mcpdm",
.codec_dai_name = "twl6040-legacy",
- .platform_name = "omap-pcm-audio",
.codec_name = "twl6040-codec",
.init = omap_abe_twl6040_init,
.ops = &omap_abe_ops,
@@ -224,9 +221,7 @@ static struct snd_soc_dai_link abe_twl6040_dai_links[] = {
{
.name = "DMIC",
.stream_name = "DMIC Capture",
- .cpu_dai_name = "omap-dmic",
.codec_dai_name = "dmic-hifi",
- .platform_name = "omap-pcm-audio",
.codec_name = "dmic-codec",
.init = omap_abe_dmic_init,
.ops = &omap_abe_dmic_ops,
@@ -281,14 +276,14 @@ static int omap_abe_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "McPDM node is not provided\n");
return -EINVAL;
}
- abe_twl6040_dai_links[0].cpu_dai_name = NULL;
abe_twl6040_dai_links[0].cpu_of_node = dai_node;
+ abe_twl6040_dai_links[0].platform_of_node = dai_node;
dai_node = of_parse_phandle(node, "ti,dmic", 0);
if (dai_node) {
num_links = 2;
- abe_twl6040_dai_links[1].cpu_dai_name = NULL;
abe_twl6040_dai_links[1].cpu_of_node = dai_node;
+ abe_twl6040_dai_links[1].platform_of_node = dai_node;
priv->dmic_codec_dev = platform_device_register_simple(
"dmic-codec", -1, NULL, 0);
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index 1bd531d718f9..53da041896c4 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -42,6 +42,7 @@
#include <sound/dmaengine_pcm.h>
#include "omap-dmic.h"
+#include "omap-pcm.h"
struct omap_dmic {
struct device *dev;
@@ -113,7 +114,6 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
mutex_unlock(&dmic->mutex);
- snd_soc_dai_set_dma_data(dai, substream, &dmic->dma_data);
return ret;
}
@@ -417,6 +417,9 @@ static int omap_dmic_probe(struct snd_soc_dai *dai)
/* Configure DMIC threshold value */
dmic->threshold = OMAP_DMIC_THRES_MAX - 3;
+
+ snd_soc_dai_init_dma_data(dai, NULL, &dmic->dma_data);
+
return 0;
}
@@ -492,6 +495,10 @@ static int asoc_dmic_probe(struct platform_device *pdev)
if (ret)
goto err_put_clk;
+ ret = omap_pcm_platform_register(&pdev->dev);
+ if (ret)
+ goto err_put_clk;
+
return 0;
err_put_clk:
diff --git a/sound/soc/omap/omap-hdmi-card.c b/sound/soc/omap/omap-hdmi-card.c
index 7e66e9cba5a8..f649fe84b629 100644
--- a/sound/soc/omap/omap-hdmi-card.c
+++ b/sound/soc/omap/omap-hdmi-card.c
@@ -33,7 +33,7 @@ static struct snd_soc_dai_link omap_hdmi_dai = {
.name = "HDMI",
.stream_name = "HDMI",
.cpu_dai_name = "omap-hdmi-audio-dai",
- .platform_name = "omap-pcm-audio",
+ .platform_name = "omap-hdmi-audio-dai",
.codec_name = "hdmi-audio-codec",
.codec_dai_name = "hdmi-hifi",
};
diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c
index ced3b88b44d4..537a1ec8ad61 100644
--- a/sound/soc/omap/omap-hdmi.c
+++ b/sound/soc/omap/omap-hdmi.c
@@ -36,6 +36,7 @@
#include <video/omapdss.h>
#include "omap-hdmi.h"
+#include "omap-pcm.h"
#define DRV_NAME "omap-hdmi-audio-dai"
@@ -324,7 +325,10 @@ static int omap_hdmi_probe(struct platform_device *pdev)
ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component,
&omap_hdmi_dai, 1);
- return ret;
+ if (ret)
+ return ret;
+
+ return omap_pcm_platform_register(&pdev->dev);
}
static int omap_hdmi_remove(struct platform_device *pdev)
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 6c19bba23570..71d226626f7c 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -38,6 +38,7 @@
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "mcbsp.h"
#include "omap-mcbsp.h"
+#include "omap-pcm.h"
#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000)
@@ -149,9 +150,6 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
}
- snd_soc_dai_set_dma_data(cpu_dai, substream,
- &mcbsp->dma_data[substream->stream]);
-
return err;
}
@@ -559,6 +557,10 @@ static int omap_mcbsp_probe(struct snd_soc_dai *dai)
pm_runtime_enable(mcbsp->dev);
+ snd_soc_dai_init_dma_data(dai,
+ &mcbsp->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
+ &mcbsp->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
+
return 0;
}
@@ -691,7 +693,7 @@ OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
OMAP_MCBSP_ST_CONTROLS(2);
OMAP_MCBSP_ST_CONTROLS(3);
-int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
{
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
@@ -701,7 +703,7 @@ int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
return 0;
}
- switch (mcbsp->id) {
+ switch (port_id) {
case 2: /* McBSP 2 */
return snd_soc_add_dai_controls(cpu_dai,
omap_mcbsp2_st_controls,
@@ -711,6 +713,7 @@ int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
omap_mcbsp3_st_controls,
ARRAY_SIZE(omap_mcbsp3_st_controls));
default:
+ dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
break;
}
@@ -799,11 +802,15 @@ static int asoc_mcbsp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mcbsp);
ret = omap_mcbsp_init(pdev);
- if (!ret)
- return snd_soc_register_component(&pdev->dev, &omap_mcbsp_component,
- &omap_mcbsp_dai, 1);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_register_component(&pdev->dev, &omap_mcbsp_component,
+ &omap_mcbsp_dai, 1);
+ if (ret)
+ return ret;
- return ret;
+ return omap_pcm_platform_register(&pdev->dev);
}
static int asoc_mcbsp_remove(struct platform_device *pdev)
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index ba8386a0d8dc..2e3369c27be3 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -39,6 +39,6 @@ enum omap_mcbsp_div {
OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */
};
-int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd);
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id);
#endif
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 2f5b1536477e..d8ebb52645a9 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -42,6 +42,7 @@
#include <sound/dmaengine_pcm.h>
#include "omap-mcpdm.h"
+#include "omap-pcm.h"
struct mcpdm_link_config {
u32 link_mask; /* channel mask for the direction */
@@ -265,9 +266,6 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
}
mutex_unlock(&mcpdm->mutex);
- snd_soc_dai_set_dma_data(dai, substream,
- &mcpdm->dma_data[substream->stream]);
-
return 0;
}
@@ -406,6 +404,11 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2;
mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold =
MCPDM_UP_THRES_MAX - 3;
+
+ snd_soc_dai_init_dma_data(dai,
+ &mcpdm->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
+ &mcpdm->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
+
return ret;
}
@@ -460,6 +463,7 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
{
struct omap_mcpdm *mcpdm;
struct resource *res;
+ int ret;
mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL);
if (!mcpdm)
@@ -490,9 +494,13 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
mcpdm->dev = &pdev->dev;
- return devm_snd_soc_register_component(&pdev->dev,
+ ret = devm_snd_soc_register_component(&pdev->dev,
&omap_mcpdm_component,
&omap_mcpdm_dai, 1);
+ if (ret)
+ return ret;
+
+ return omap_pcm_platform_register(&pdev->dev);
}
static const struct of_device_id omap_mcpdm_of_match[] = {
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 07b8b7bc9d20..8d809f8509c8 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -232,31 +232,12 @@ static struct snd_soc_platform_driver omap_soc_platform = {
.pcm_free = omap_pcm_free_dma_buffers,
};
-static int omap_pcm_probe(struct platform_device *pdev)
+int omap_pcm_platform_register(struct device *dev)
{
- return snd_soc_register_platform(&pdev->dev,
- &omap_soc_platform);
+ return devm_snd_soc_register_platform(dev, &omap_soc_platform);
}
-
-static int omap_pcm_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver omap_pcm_driver = {
- .driver = {
- .name = "omap-pcm-audio",
- .owner = THIS_MODULE,
- },
-
- .probe = omap_pcm_probe,
- .remove = omap_pcm_remove,
-};
-
-module_platform_driver(omap_pcm_driver);
+EXPORT_SYMBOL_GPL(omap_pcm_platform_register);
MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
MODULE_DESCRIPTION("OMAP PCM DMA module");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:omap-pcm-audio");
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
new file mode 100644
index 000000000000..c1d2f31d71e9
--- /dev/null
+++ b/sound/soc/omap/omap-pcm.h
@@ -0,0 +1,30 @@
+/*
+ * omap-pcm.h - OMAP PCM driver
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * Author: 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
+ * 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.
+ */
+
+#ifndef __OMAP_PCM_H__
+#define __OMAP_PCM_H__
+
+#if IS_ENABLED(CONFIG_SND_OMAP_SOC)
+int omap_pcm_platform_register(struct device *dev);
+#else
+static inline int omap_pcm_platform_register(struct device *dev)
+{
+ return 0;
+}
+#endif /* CONFIG_SND_OMAP_SOC */
+
+#endif /* __OMAP_PCM_H__ */
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c
index 6a8d6b5f160d..64141db311b2 100644
--- a/sound/soc/omap/omap-twl4030.c
+++ b/sound/soc/omap/omap-twl4030.c
@@ -55,8 +55,7 @@ static int omap_twl4030_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;
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_card *card = codec->card;
+ struct snd_soc_card *card = rtd->card;
unsigned int fmt;
int ret;
@@ -179,7 +178,7 @@ static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm,
static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_card *card = codec->card;
+ struct snd_soc_card *card = rtd->card;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev);
struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
@@ -239,7 +238,7 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
.stream_name = "TWL4030 HiFi",
.cpu_dai_name = "omap-mcbsp.2",
.codec_dai_name = "twl4030-hifi",
- .platform_name = "omap-pcm-audio",
+ .platform_name = "omap-mcbsp.2",
.codec_name = "twl4030-codec",
.init = omap_twl4030_init,
.ops = &omap_twl4030_ops,
@@ -249,7 +248,7 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
.stream_name = "TWL4030 Voice",
.cpu_dai_name = "omap-mcbsp.3",
.codec_dai_name = "twl4030-voice",
- .platform_name = "omap-pcm-audio",
+ .platform_name = "omap-mcbsp.2",
.codec_name = "twl4030-codec",
.dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
SND_SOC_DAIFMT_CBM_CFM,
@@ -299,12 +298,18 @@ static int omap_twl4030_probe(struct platform_device *pdev)
omap_twl4030_dai_links[0].cpu_dai_name = NULL;
omap_twl4030_dai_links[0].cpu_of_node = dai_node;
+ omap_twl4030_dai_links[0].platform_name = NULL;
+ omap_twl4030_dai_links[0].platform_of_node = dai_node;
+
dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0);
if (!dai_node) {
card->num_links = 1;
} else {
omap_twl4030_dai_links[1].cpu_dai_name = NULL;
omap_twl4030_dai_links[1].cpu_of_node = dai_node;
+
+ omap_twl4030_dai_links[1].platform_name = NULL;
+ omap_twl4030_dai_links[1].platform_of_node = dai_node;
}
priv->jack_detect = of_get_named_gpio(node,
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index cf604a2faa18..076bec606d78 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -121,7 +121,7 @@ static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
* |A| <~~clk~~+
* |P| <--- TWL4030 <--------- Line In and MICs
*/
-static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget omap3pandora_dapm_widgets[] = {
SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM,
0, 0, omap3pandora_dac_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -130,22 +130,18 @@ static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_LINE("Line Out", NULL),
-};
-static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic (internal)", NULL),
SND_SOC_DAPM_MIC("Mic (external)", NULL),
SND_SOC_DAPM_LINE("Line In", NULL),
};
-static const struct snd_soc_dapm_route omap3pandora_out_map[] = {
+static const struct snd_soc_dapm_route omap3pandora_map[] = {
{"PCM DAC", NULL, "APLL Enable"},
{"Headphone Amplifier", NULL, "PCM DAC"},
{"Line Out", NULL, "PCM DAC"},
{"Headphone Jack", NULL, "Headphone Amplifier"},
-};
-static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
{"AUXL", NULL, "Line In"},
{"AUXR", NULL, "Line In"},
@@ -160,7 +156,6 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
/* All TWL4030 output pins are floating */
snd_soc_dapm_nc_pin(dapm, "EARPIECE");
@@ -174,20 +169,13 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "HFR");
snd_soc_dapm_nc_pin(dapm, "VIBRA");
- ret = snd_soc_dapm_new_controls(dapm, omap3pandora_out_dapm_widgets,
- ARRAY_SIZE(omap3pandora_out_dapm_widgets));
- if (ret < 0)
- return ret;
-
- return snd_soc_dapm_add_routes(dapm, omap3pandora_out_map,
- ARRAY_SIZE(omap3pandora_out_map));
+ return 0;
}
static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
/* Not comnnected */
snd_soc_dapm_nc_pin(dapm, "HSMIC");
@@ -195,13 +183,7 @@ static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
- ret = snd_soc_dapm_new_controls(dapm, omap3pandora_in_dapm_widgets,
- ARRAY_SIZE(omap3pandora_in_dapm_widgets));
- if (ret < 0)
- return ret;
-
- return snd_soc_dapm_add_routes(dapm, omap3pandora_in_map,
- ARRAY_SIZE(omap3pandora_in_map));
+ return 0;
}
static struct snd_soc_ops omap3pandora_ops = {
@@ -215,7 +197,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
.stream_name = "HiFi Out",
.cpu_dai_name = "omap-mcbsp.2",
.codec_dai_name = "twl4030-hifi",
- .platform_name = "omap-pcm-audio",
+ .platform_name = "omap-mcbsp.2",
.codec_name = "twl4030-codec",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
@@ -226,7 +208,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
.stream_name = "Line/Mic In",
.cpu_dai_name = "omap-mcbsp.4",
.codec_dai_name = "twl4030-hifi",
- .platform_name = "omap-pcm-audio",
+ .platform_name = "omap-mcbsp.4",
.codec_name = "twl4030-codec",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
@@ -241,6 +223,11 @@ static struct snd_soc_card snd_soc_card_omap3pandora = {
.owner = THIS_MODULE,
.dai_link = omap3pandora_dai,
.num_links = ARRAY_SIZE(omap3pandora_dai),
+
+ .dapm_widgets = omap3pandora_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(omap3pandora_dapm_widgets),
+ .dapm_routes = omap3pandora_map,
+ .num_dapm_routes = ARRAY_SIZE(omap3pandora_map),
};
static struct platform_device *omap3pandora_snd_device;
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index d03e57da7708..aa4053bf6710 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -96,7 +96,7 @@ static struct snd_soc_dai_link osk_dai = {
.stream_name = "AIC23",
.cpu_dai_name = "omap-mcbsp.1",
.codec_dai_name = "tlv320aic23-hifi",
- .platform_name = "omap-pcm-audio",
+ .platform_name = "omap-mcbsp.1",
.codec_name = "tlv320aic23-codec",
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 7fb3d4b10370..6951dc812055 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/gpio/consumer.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
@@ -38,15 +39,6 @@
#include "omap-mcbsp.h"
-#define RX51_TVOUT_SEL_GPIO 40
-#define RX51_JACK_DETECT_GPIO 177
-#define RX51_ECI_SW_GPIO 182
-/*
- * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This
- * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c
- */
-#define RX51_SPEAKER_AMP_TWL_GPIO (192 + 7)
-
enum {
RX51_JACK_DISABLED,
RX51_JACK_TVOUT, /* tv-out with stereo output */
@@ -54,12 +46,21 @@ enum {
RX51_JACK_HS, /* headset: stereo output with mic */
};
+struct rx51_audio_pdata {
+ struct gpio_desc *tvout_selection_gpio;
+ struct gpio_desc *jack_detection_gpio;
+ struct gpio_desc *eci_sw_gpio;
+ struct gpio_desc *speaker_amp_gpio;
+};
+
static int rx51_spk_func;
static int rx51_dmic_func;
static int rx51_jack_func;
static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
{
+ struct snd_soc_card *card = dapm->card;
+ struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
int hp = 0, hs = 0, tvout = 0;
switch (rx51_jack_func) {
@@ -93,7 +94,7 @@ static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
else
snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
- gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout);
+ gpiod_set_value(pdata->tvout_selection_gpio, tvout);
snd_soc_dapm_sync_unlocked(dapm);
@@ -154,10 +155,12 @@ static int rx51_set_spk(struct snd_kcontrol *kcontrol,
static int rx51_spk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- if (SND_SOC_DAPM_EVENT_ON(event))
- gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1);
- else
- gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0);
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
+
+ gpiod_set_raw_value_cansleep(pdata->speaker_amp_gpio,
+ !!SND_SOC_DAPM_EVENT_ON(event));
return 0;
}
@@ -223,7 +226,6 @@ static struct snd_soc_jack rx51_av_jack;
static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
{
- .gpio = RX51_JACK_DETECT_GPIO,
.name = "avdet-gpio",
.report = SND_JACK_HEADSET,
.invert = 1,
@@ -237,9 +239,6 @@ static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event),
SND_SOC_DAPM_MIC("HS Mic", NULL),
SND_SOC_DAPM_LINE("FM Transmitter", NULL),
-};
-
-static const struct snd_soc_dapm_widget aic34_dapm_widgetsb[] = {
SND_SOC_DAPM_SPK("Earphone", NULL),
};
@@ -253,9 +252,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"DMic Rate 64", NULL, "Mic Bias"},
{"Mic Bias", NULL, "DMic"},
-};
-static const struct snd_soc_dapm_route audio_mapb[] = {
{"b LINE2R", NULL, "MONO_LOUT"},
{"Earphone", NULL, "b HPLOUT"},
@@ -263,9 +260,11 @@ static const struct snd_soc_dapm_route audio_mapb[] = {
{"b Mic Bias", NULL, "HS Mic"}
};
-static const char *spk_function[] = {"Off", "On"};
-static const char *input_function[] = {"ADC", "Digital Mic"};
-static const char *jack_function[] = {"Off", "TV-OUT", "Headphone", "Headset"};
+static const char * const spk_function[] = {"Off", "On"};
+static const char * const input_function[] = {"ADC", "Digital Mic"};
+static const char * const jack_function[] = {
+ "Off", "TV-OUT", "Headphone", "Headset"
+};
static const struct soc_enum rx51_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
@@ -281,15 +280,15 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
SOC_ENUM_EXT("Jack Function", rx51_enum[2],
rx51_get_jack, rx51_set_jack),
SOC_DAPM_PIN_SWITCH("FM Transmitter"),
-};
-
-static const struct snd_kcontrol_new aic34_rx51_controlsb[] = {
SOC_DAPM_PIN_SWITCH("Earphone"),
};
static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_card *card = rtd->card;
+ struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
+
struct snd_soc_dapm_context *dapm = &codec->dapm;
int err;
@@ -298,57 +297,41 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "MIC3R");
snd_soc_dapm_nc_pin(dapm, "LINE1R");
- /* Add RX-51 specific controls */
- err = snd_soc_add_card_controls(rtd->card, aic34_rx51_controls,
- ARRAY_SIZE(aic34_rx51_controls));
- if (err < 0)
- return err;
-
- /* Add RX-51 specific widgets */
- snd_soc_dapm_new_controls(dapm, aic34_dapm_widgets,
- ARRAY_SIZE(aic34_dapm_widgets));
-
- /* Set up RX-51 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
err = tpa6130a2_add_controls(codec);
- if (err < 0)
+ if (err < 0) {
+ dev_err(card->dev, "Failed to add TPA6130A2 controls\n");
return err;
+ }
snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42);
- err = omap_mcbsp_st_add_controls(rtd);
- if (err < 0)
+ err = omap_mcbsp_st_add_controls(rtd, 2);
+ if (err < 0) {
+ dev_err(card->dev, "Failed to add MCBSP controls\n");
return err;
+ }
/* AV jack detection */
err = snd_soc_jack_new(codec, "AV Jack",
SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
&rx51_av_jack);
- if (err)
+ if (err) {
+ dev_err(card->dev, "Failed to add AV Jack\n");
return err;
+ }
+
+ /* prepare gpio for snd_soc_jack_add_gpios */
+ rx51_av_jack_gpios[0].gpio = desc_to_gpio(pdata->jack_detection_gpio);
+ devm_gpiod_put(card->dev, pdata->jack_detection_gpio);
+
err = snd_soc_jack_add_gpios(&rx51_av_jack,
ARRAY_SIZE(rx51_av_jack_gpios),
rx51_av_jack_gpios);
-
- return err;
-}
-
-static int rx51_aic34b_init(struct snd_soc_dapm_context *dapm)
-{
- int err;
-
- err = snd_soc_add_card_controls(dapm->card, aic34_rx51_controlsb,
- ARRAY_SIZE(aic34_rx51_controlsb));
- if (err < 0)
+ if (err) {
+ dev_err(card->dev, "Failed to add GPIOs\n");
return err;
+ }
- err = snd_soc_dapm_new_controls(dapm, aic34_dapm_widgetsb,
- ARRAY_SIZE(aic34_dapm_widgetsb));
- if (err < 0)
- return 0;
-
- return snd_soc_dapm_add_routes(dapm, audio_mapb,
- ARRAY_SIZE(audio_mapb));
+ return err;
}
/* Digital audio interface glue - connects codec <--> CPU */
@@ -358,7 +341,7 @@ static struct snd_soc_dai_link rx51_dai[] = {
.stream_name = "AIC34",
.cpu_dai_name = "omap-mcbsp.2",
.codec_dai_name = "tlv320aic3x-hifi",
- .platform_name = "omap-pcm-audio",
+ .platform_name = "omap-mcbsp.2",
.codec_name = "tlv320aic3x-codec.2-0018",
.dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
SND_SOC_DAIFMT_CBM_CFM,
@@ -371,7 +354,6 @@ static struct snd_soc_aux_dev rx51_aux_dev[] = {
{
.name = "TLV320AIC34b",
.codec_name = "tlv320aic3x-codec.2-0019",
- .init = rx51_aic34b_init,
},
};
@@ -392,63 +374,160 @@ static struct snd_soc_card rx51_sound_card = {
.num_aux_devs = ARRAY_SIZE(rx51_aux_dev),
.codec_conf = rx51_codec_conf,
.num_configs = ARRAY_SIZE(rx51_codec_conf),
-};
-static struct platform_device *rx51_snd_device;
+ .controls = aic34_rx51_controls,
+ .num_controls = ARRAY_SIZE(aic34_rx51_controls),
+ .dapm_widgets = aic34_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(aic34_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
-static int __init rx51_soc_init(void)
+static int rx51_soc_probe(struct platform_device *pdev)
{
+ struct rx51_audio_pdata *pdata;
+ struct device_node *np = pdev->dev.of_node;
+ struct snd_soc_card *card = &rx51_sound_card;
int err;
if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900"))
return -ENODEV;
- err = gpio_request_one(RX51_TVOUT_SEL_GPIO,
- GPIOF_DIR_OUT | GPIOF_INIT_LOW, "tvout_sel");
- if (err)
- goto err_gpio_tvout_sel;
- err = gpio_request_one(RX51_ECI_SW_GPIO,
- GPIOF_DIR_OUT | GPIOF_INIT_HIGH, "eci_sw");
- if (err)
- goto err_gpio_eci_sw;
-
- rx51_snd_device = platform_device_alloc("soc-audio", -1);
- if (!rx51_snd_device) {
- err = -ENOMEM;
- goto err1;
+ card->dev = &pdev->dev;
+
+ if (np) {
+ struct device_node *dai_node;
+
+ dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0);
+ if (!dai_node) {
+ dev_err(&pdev->dev, "McBSP node is not provided\n");
+ return -EINVAL;
+ }
+ rx51_dai[0].cpu_dai_name = NULL;
+ rx51_dai[0].platform_name = NULL;
+ rx51_dai[0].cpu_of_node = dai_node;
+ rx51_dai[0].platform_of_node = dai_node;
+
+ dai_node = of_parse_phandle(np, "nokia,audio-codec", 0);
+ if (!dai_node) {
+ dev_err(&pdev->dev, "Codec node is not provided\n");
+ return -EINVAL;
+ }
+ rx51_dai[0].codec_name = NULL;
+ rx51_dai[0].codec_of_node = dai_node;
+
+ dai_node = of_parse_phandle(np, "nokia,audio-codec", 1);
+ if (!dai_node) {
+ dev_err(&pdev->dev, "Auxiliary Codec node is not provided\n");
+ return -EINVAL;
+ }
+ rx51_aux_dev[0].codec_name = NULL;
+ rx51_aux_dev[0].codec_of_node = dai_node;
+ rx51_codec_conf[0].dev_name = NULL;
+ rx51_codec_conf[0].of_node = dai_node;
+
+ dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0);
+ if (!dai_node) {
+ dev_err(&pdev->dev, "Headphone amplifier node is not provided\n");
+ return -EINVAL;
+ }
+
+ /* TODO: tpa6130a2a driver supports only a single instance, so
+ * this driver ignores the headphone-amplifier node for now.
+ * It's already mandatory in the DT binding to be future proof.
+ */
}
- platform_set_drvdata(rx51_snd_device, &rx51_sound_card);
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (pdata == NULL) {
+ dev_err(card->dev, "failed to create private data\n");
+ return -ENOMEM;
+ }
+ snd_soc_card_set_drvdata(card, pdata);
- err = platform_device_add(rx51_snd_device);
- if (err)
- goto err2;
+ pdata->tvout_selection_gpio = devm_gpiod_get(card->dev,
+ "tvout-selection");
+ if (IS_ERR(pdata->tvout_selection_gpio)) {
+ dev_err(card->dev, "could not get tvout selection gpio\n");
+ return PTR_ERR(pdata->tvout_selection_gpio);
+ }
- return 0;
-err2:
- platform_device_put(rx51_snd_device);
-err1:
- gpio_free(RX51_ECI_SW_GPIO);
-err_gpio_eci_sw:
- gpio_free(RX51_TVOUT_SEL_GPIO);
-err_gpio_tvout_sel:
+ err = gpiod_direction_output(pdata->tvout_selection_gpio, 0);
+ if (err) {
+ dev_err(card->dev, "could not setup tvout selection gpio\n");
+ return err;
+ }
- return err;
+ pdata->jack_detection_gpio = devm_gpiod_get(card->dev,
+ "jack-detection");
+ if (IS_ERR(pdata->jack_detection_gpio)) {
+ dev_err(card->dev, "could not get jack detection gpio\n");
+ return PTR_ERR(pdata->jack_detection_gpio);
+ }
+
+ pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch");
+ if (IS_ERR(pdata->eci_sw_gpio)) {
+ dev_err(card->dev, "could not get eci switch gpio\n");
+ return PTR_ERR(pdata->eci_sw_gpio);
+ }
+
+ err = gpiod_direction_output(pdata->eci_sw_gpio, 1);
+ if (err) {
+ dev_err(card->dev, "could not setup eci switch gpio\n");
+ return err;
+ }
+
+ pdata->speaker_amp_gpio = devm_gpiod_get(card->dev,
+ "speaker-amplifier");
+ if (IS_ERR(pdata->speaker_amp_gpio)) {
+ dev_err(card->dev, "could not get speaker enable gpio\n");
+ return PTR_ERR(pdata->speaker_amp_gpio);
+ }
+
+ err = gpiod_direction_output(pdata->speaker_amp_gpio, 0);
+ if (err) {
+ dev_err(card->dev, "could not setup speaker enable gpio\n");
+ return err;
+ }
+
+ err = devm_snd_soc_register_card(card->dev, card);
+ if (err) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", err);
+ return err;
+ }
+
+ return 0;
}
-static void __exit rx51_soc_exit(void)
+static int rx51_soc_remove(struct platform_device *pdev)
{
snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
rx51_av_jack_gpios);
- platform_device_unregister(rx51_snd_device);
- gpio_free(RX51_ECI_SW_GPIO);
- gpio_free(RX51_TVOUT_SEL_GPIO);
+ return 0;
}
-module_init(rx51_soc_init);
-module_exit(rx51_soc_exit);
+#if defined(CONFIG_OF)
+static const struct of_device_id rx51_audio_of_match[] = {
+ { .compatible = "nokia,n900-audio", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rx51_audio_of_match);
+#endif
+
+static struct platform_driver rx51_soc_driver = {
+ .driver = {
+ .name = "rx51-audio",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rx51_audio_of_match),
+ },
+ .probe = rx51_soc_probe,
+ .remove = rx51_soc_remove,
+};
+
+module_platform_driver(rx51_soc_driver);
MODULE_AUTHOR("Nokia Corporation");
MODULE_DESCRIPTION("ALSA SoC Nokia RX-51");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rx51-audio");
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 6473052b6899..6acb225ec6fd 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -140,7 +140,7 @@ config SND_PXA910_SOC
config SND_SOC_TTC_DKB
bool "SoC Audio support for TTC DKB"
- depends on SND_PXA910_SOC && MACH_TTC_DKB
+ depends on SND_PXA910_SOC && MACH_TTC_DKB && I2C=y
select PXA_SSP
select SND_PXA_SOC_SSP
select SND_MMP_SOC
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c
index 08acdc236bf8..c8dd53f9c35d 100644
--- a/sound/soc/pxa/brownstone.c
+++ b/sound/soc/pxa/brownstone.c
@@ -50,11 +50,6 @@ static int brownstone_wm8994_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_enable_pin(dapm, "Ext Spk");
- snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");
- snd_soc_dapm_enable_pin(dapm, "Headset Mic");
- snd_soc_dapm_enable_pin(dapm, "Main Mic");
-
/* set endpoints to not connected */
snd_soc_dapm_nc_pin(dapm, "HPOUT2P");
snd_soc_dapm_nc_pin(dapm, "HPOUT2N");
@@ -70,8 +65,6 @@ static int brownstone_wm8994_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
snd_soc_dapm_nc_pin(dapm, "IN2LN");
- snd_soc_dapm_sync(dapm);
-
return 0;
}
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c
index 3284c4b901cb..17f9521ff6ea 100644
--- a/sound/soc/pxa/palm27x.c
+++ b/sound/soc/pxa/palm27x.c
@@ -79,14 +79,6 @@ static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dapm_context *dapm = &codec->dapm;
int err;
- /* connected pins */
- if (machine_is_palmld())
- snd_soc_dapm_enable_pin(dapm, "MIC1");
- snd_soc_dapm_enable_pin(dapm, "HPOUTL");
- snd_soc_dapm_enable_pin(dapm, "HPOUTR");
- snd_soc_dapm_enable_pin(dapm, "LOUT2");
- snd_soc_dapm_enable_pin(dapm, "ROUT2");
-
/* not connected pins */
snd_soc_dapm_nc_pin(dapm, "OUT3");
snd_soc_dapm_nc_pin(dapm, "MONOOUT");
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index c6bdc6c0eff6..21f340065318 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -230,7 +230,6 @@ static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "LLINEIN");
snd_soc_dapm_nc_pin(dapm, "RLINEIN");
- snd_soc_dapm_enable_pin(dapm, "MICIN");
return 0;
}
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index a3119a00d8fa..199a8b377553 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -34,8 +34,6 @@
#include <sound/pxa2xx-lib.h>
#include <sound/dmaengine_pcm.h>
-#include <mach/hardware.h>
-
#include "../../arm/pxa2xx-pcm.h"
#include "pxa-ssp.h"
@@ -810,6 +808,7 @@ static const struct snd_soc_component_driver pxa_ssp_component = {
#ifdef CONFIG_OF
static const struct of_device_id pxa_ssp_of_ids[] = {
{ .compatible = "mrvl,pxa-ssp-dai" },
+ {}
};
#endif
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index d58b09f4f7a4..42f2f0175981 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -15,6 +15,8 @@
#include <linux/dmaengine.h>
#include <linux/of.h>
+#include <mach/dma.h>
+
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/pxa2xx-lib.h>
diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c
index 0b535b570622..9d7c5b7e9539 100644
--- a/sound/soc/pxa/ttc-dkb.c
+++ b/sound/soc/pxa/ttc-dkb.c
@@ -78,10 +78,6 @@ static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- /* connected pins */
- snd_soc_dapm_enable_pin(dapm, "Ext Speaker");
- snd_soc_dapm_enable_pin(dapm, "Ext Mic 1");
- snd_soc_dapm_enable_pin(dapm, "Ext Mic 3");
snd_soc_dapm_disable_pin(dapm, "Headset Mic 2");
snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index f2e289180e46..753b8c93ab51 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -64,6 +64,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
config SND_SOC_SAMSUNG_SMDK_WM8580
tristate "SoC I2S Audio support for WM8580 on SMDK"
depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDK6440 || MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110)
+ depends on REGMAP_I2C
select SND_SOC_WM8580
select SND_SAMSUNG_I2S
help
@@ -115,21 +116,21 @@ config SND_SOC_SAMSUNG_SIMTEC
config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
- depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
+ depends on SND_SOC_SAMSUNG && ARCH_S3C24XX && I2C
select SND_S3C24XX_I2S
select SND_SOC_TLV320AIC23_I2C
select SND_SOC_SAMSUNG_SIMTEC
config SND_SOC_SAMSUNG_SIMTEC_HERMES
tristate "SoC I2S Audio support for Simtec Hermes board"
- depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
+ depends on SND_SOC_SAMSUNG && ARCH_S3C24XX && I2C
select SND_S3C24XX_I2S
select SND_SOC_TLV320AIC3X
select SND_SOC_SAMSUNG_SIMTEC
config SND_SOC_SAMSUNG_H1940_UDA1380
tristate "Audio support for the HP iPAQ H1940"
- depends on SND_SOC_SAMSUNG && ARCH_H1940
+ depends on SND_SOC_SAMSUNG && ARCH_H1940 && I2C
select SND_S3C24XX_I2S
select SND_SOC_UDA1380
help
@@ -137,7 +138,7 @@ config SND_SOC_SAMSUNG_H1940_UDA1380
config SND_SOC_SAMSUNG_RX1950_UDA1380
tristate "Audio support for the HP iPAQ RX1950"
- depends on SND_SOC_SAMSUNG && MACH_RX1950
+ depends on SND_SOC_SAMSUNG && MACH_RX1950 && I2C
select SND_S3C24XX_I2S
select SND_SOC_UDA1380
help
@@ -178,6 +179,7 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF
config SND_SOC_SMDK_WM8580_PCM
tristate "SoC PCM Audio support for WM8580 on SMDK"
depends on SND_SOC_SAMSUNG && (MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110)
+ depends on REGMAP_I2C
select SND_SOC_WM8580
select SND_SAMSUNG_PCM
help
@@ -204,7 +206,7 @@ config SND_SOC_SPEYSIDE
config SND_SOC_TOBERMORY
tristate "Audio support for Wolfson Tobermory"
- depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+ depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && INPUT
select SND_SAMSUNG_I2S
select SND_SOC_WM8962
@@ -231,3 +233,13 @@ config SND_SOC_LITTLEMILL
select SND_SAMSUNG_I2S
select MFD_WM8994
select SND_SOC_WM8994
+
+config SND_SOC_SNOW
+ tristate "Audio support for Google Snow boards"
+ depends on SND_SOC_SAMSUNG
+ select SND_SOC_MAX98090
+ select SND_SOC_MAX98095
+ select SND_SAMSUNG_I2S
+ help
+ Say Y if you want to add audio support for various Snow
+ boards based on Exynos5 series of SoCs.
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 86715d8efee6..6d0212ba571c 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -34,6 +34,7 @@ snd-soc-h1940-uda1380-objs := h1940_uda1380.o
snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
snd-soc-smdk-wm8580-objs := smdk_wm8580.o
snd-soc-smdk-wm8994-objs := smdk_wm8994.o
+snd-soc-snow-objs := snow.o
snd-soc-smdk-wm9713-objs := smdk_wm9713.o
snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
snd-soc-goni-wm8994-objs := goni_wm8994.o
@@ -58,6 +59,7 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_H1940_UDA1380) += snd-soc-h1940-uda1380.o
obj-$(CONFIG_SND_SOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o
+obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o
obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index 76b072bd4ba2..68d9303047e8 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -433,7 +433,7 @@ static int s3c_ac97_probe(struct platform_device *pdev)
goto err4;
}
- ret = snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
+ ret = devm_snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
if (ret)
goto err5;
@@ -441,12 +441,10 @@ static int s3c_ac97_probe(struct platform_device *pdev)
ret = samsung_asoc_dma_platform_register(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
- goto err6;
+ goto err5;
}
return 0;
-err6:
- snd_soc_unregister_component(&pdev->dev);
err5:
free_irq(irq_res->start, NULL);
err4:
@@ -461,9 +459,6 @@ static int s3c_ac97_remove(struct platform_device *pdev)
{
struct resource *irq_res;
- samsung_asoc_dma_platform_unregister(&pdev->dev);
- snd_soc_unregister_component(&pdev->dev);
-
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (irq_res)
free_irq(irq_res->start, NULL);
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
index 84f5d8b76679..5b21207cf551 100644
--- a/sound/soc/samsung/bells.c
+++ b/sound/soc/samsung/bells.c
@@ -433,22 +433,13 @@ static int bells_probe(struct platform_device *pdev)
bells_cards[pdev->id].dev = &pdev->dev;
- ret = snd_soc_register_card(&bells_cards[pdev->id]);
- if (ret) {
+ ret = devm_snd_soc_register_card(&pdev->dev, &bells_cards[pdev->id]);
+ if (ret)
dev_err(&pdev->dev,
"snd_soc_register_card(%s) failed: %d\n",
bells_cards[pdev->id].name, ret);
- return ret;
- }
-
- return 0;
-}
-
-static int bells_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_card(&bells_cards[pdev->id]);
- return 0;
+ return ret;
}
static struct platform_driver bells_driver = {
@@ -458,7 +449,6 @@ static struct platform_driver bells_driver = {
.pm = &snd_soc_pm_ops,
},
.probe = bells_probe,
- .remove = bells_remove,
};
module_platform_driver(bells_driver);
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
index dc09b71b7d9f..d9dc7bcc0336 100644
--- a/sound/soc/samsung/dma.c
+++ b/sound/soc/samsung/dma.c
@@ -445,16 +445,10 @@ EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
int samsung_asoc_dma_platform_register(struct device *dev)
{
- return snd_soc_register_platform(dev, &samsung_asoc_platform);
+ return devm_snd_soc_register_platform(dev, &samsung_asoc_platform);
}
EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register);
-void samsung_asoc_dma_platform_unregister(struct device *dev)
-{
- snd_soc_unregister_platform(dev);
-}
-EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_unregister);
-
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("Samsung ASoC DMA Driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h
index ad7c0f04f00d..070ab0f09609 100644
--- a/sound/soc/samsung/dma.h
+++ b/sound/soc/samsung/dma.h
@@ -33,6 +33,5 @@ void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
struct s3c_dma_params *playback,
struct s3c_dma_params *capture);
int samsung_asoc_dma_platform_register(struct device *dev);
-void samsung_asoc_dma_platform_unregister(struct device *dev);
#endif
diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c
index 750ce5808d9f..a0e4e7948909 100644
--- a/sound/soc/samsung/dmaengine.c
+++ b/sound/soc/samsung/dmaengine.c
@@ -66,18 +66,13 @@ EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
int samsung_asoc_dma_platform_register(struct device *dev)
{
- return snd_dmaengine_pcm_register(dev, &samsung_dmaengine_pcm_config,
- SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME |
- SND_DMAENGINE_PCM_FLAG_COMPAT);
+ return devm_snd_dmaengine_pcm_register(dev,
+ &samsung_dmaengine_pcm_config,
+ SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME |
+ SND_DMAENGINE_PCM_FLAG_COMPAT);
}
EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register);
-void samsung_asoc_dma_platform_unregister(struct device *dev)
-{
- return snd_dmaengine_pcm_unregister(dev);
-}
-EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_unregister);
-
MODULE_AUTHOR("Mark Brown <broonie@linaro.org>");
MODULE_DESCRIPTION("Samsung dmaengine ASoC driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c
index 415ad81999c4..9506d7617223 100644
--- a/sound/soc/samsung/goni_wm8994.c
+++ b/sound/soc/samsung/goni_wm8994.c
@@ -274,8 +274,8 @@ static int __init goni_init(void)
return -ENOMEM;
/* register voice DAI here */
- ret = snd_soc_register_component(&goni_snd_device->dev, &voice_component,
- &voice_dai, 1);
+ ret = devm_snd_soc_register_component(&goni_snd_device->dev,
+ &voice_component, &voice_dai, 1);
if (ret) {
platform_device_put(goni_snd_device);
return ret;
@@ -284,17 +284,14 @@ static int __init goni_init(void)
platform_set_drvdata(goni_snd_device, &goni);
ret = platform_device_add(goni_snd_device);
- if (ret) {
- snd_soc_unregister_component(&goni_snd_device->dev);
+ if (ret)
platform_device_put(goni_snd_device);
- }
return ret;
}
static void __exit goni_exit(void)
{
- snd_soc_unregister_component(&goni_snd_device->dev);
platform_device_unregister(goni_snd_device);
}
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index 88b09e022503..9f2fb69dbaae 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -176,11 +176,6 @@ static struct platform_device *s3c24xx_snd_device;
static int h1940_uda1380_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_enable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_enable_pin(dapm, "Speaker");
- snd_soc_dapm_enable_pin(dapm, "Mic Jack");
snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
&hp_jack);
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 048ead967199..07ff3e7cb890 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -451,6 +451,10 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
u32 mod = readl(i2s->addr + I2SMOD);
switch (clk_id) {
+ case SAMSUNG_I2S_OPCLK:
+ mod &= ~MOD_OPCLK_MASK;
+ mod |= dir;
+ break;
case SAMSUNG_I2S_CDCLK:
/* Shouldn't matter in GATING(CLOCK_IN) mode */
if (dir == SND_SOC_CLOCK_IN)
@@ -724,9 +728,6 @@ static int i2s_startup(struct snd_pcm_substream *substream,
else
i2s->mode |= DAI_MANAGER;
- /* Enforce set_sysclk in Master mode */
- i2s->rclk_srcrate = 0;
-
if (!any_active(i2s) && (i2s->quirks & QUIRK_NEED_RSTCLR))
writel(CON_RSTCLR, i2s->addr + I2SCON);
@@ -984,6 +985,7 @@ probe_exit:
/* Reset any constraint on RFS and BFS */
i2s->rfs = 0;
i2s->bfs = 0;
+ i2s->rclk_srcrate = 0;
i2s_txctrl(i2s, 0);
i2s_rxctrl(i2s, 0);
i2s_fifo(i2s, FIC_TXFLUSH);
@@ -1293,8 +1295,6 @@ static int samsung_i2s_remove(struct platform_device *pdev)
i2s->pri_dai = NULL;
i2s->sec_dai = NULL;
- samsung_asoc_dma_platform_unregister(&pdev->dev);
-
return 0;
}
diff --git a/sound/soc/samsung/i2s.h b/sound/soc/samsung/i2s.h
index 7966afc934db..21ff24e930db 100644
--- a/sound/soc/samsung/i2s.h
+++ b/sound/soc/samsung/i2s.h
@@ -18,5 +18,6 @@
#define SAMSUNG_I2S_RCLKSRC_0 0
#define SAMSUNG_I2S_RCLKSRC_1 1
#define SAMSUNG_I2S_CDCLK 2
+#define SAMSUNG_I2S_OPCLK 3
#endif /* __SND_SOC_SAMSUNG_I2S_H */
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index 3d5cf1530b6f..8cc5770abb39 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -274,7 +274,7 @@ static irqreturn_t iis_irq(int irqno, void *dev_id)
addr = readl(idma.regs + I2SLVL0ADDR) - idma.lp_tx_addr;
addr += prtd->periodsz;
- addr %= (prtd->end - prtd->start);
+ addr %= (u32)(prtd->end - prtd->start);
addr += idma.lp_tx_addr;
writel(addr, idma.regs + I2SLVL0ADDR);
@@ -413,13 +413,7 @@ static int asoc_idma_platform_probe(struct platform_device *pdev)
if (idma_irq < 0)
return idma_irq;
- return snd_soc_register_platform(&pdev->dev, &asoc_idma_platform);
-}
-
-static int asoc_idma_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
+ return devm_snd_soc_register_platform(&pdev->dev, &asoc_idma_platform);
}
static struct platform_driver asoc_idma_driver = {
@@ -429,7 +423,6 @@ static struct platform_driver asoc_idma_driver = {
},
.probe = asoc_idma_platform_probe,
- .remove = asoc_idma_platform_remove,
};
module_platform_driver(asoc_idma_driver);
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
index bfb91f34a22a..840787e63cb1 100644
--- a/sound/soc/samsung/littlemill.c
+++ b/sound/soc/samsung/littlemill.c
@@ -304,23 +304,12 @@ static int littlemill_probe(struct platform_device *pdev)
card->dev = &pdev->dev;
- ret = snd_soc_register_card(card);
- if (ret) {
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret)
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
ret);
- return ret;
- }
-
- return 0;
-}
-
-static int littlemill_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
- snd_soc_unregister_card(card);
-
- return 0;
+ return ret;
}
static struct platform_driver littlemill_driver = {
@@ -330,7 +319,6 @@ static struct platform_driver littlemill_driver = {
.pm = &snd_soc_pm_ops,
},
.probe = littlemill_probe,
- .remove = littlemill_remove,
};
module_platform_driver(littlemill_driver);
diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c
index 570cf5229508..bd5f0d643a86 100644
--- a/sound/soc/samsung/lowland.c
+++ b/sound/soc/samsung/lowland.c
@@ -187,23 +187,12 @@ static int lowland_probe(struct platform_device *pdev)
card->dev = &pdev->dev;
- ret = snd_soc_register_card(card);
- if (ret) {
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret)
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
ret);
- return ret;
- }
-
- return 0;
-}
-
-static int lowland_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
- snd_soc_unregister_card(card);
-
- return 0;
+ return ret;
}
static struct platform_driver lowland_driver = {
@@ -213,7 +202,6 @@ static struct platform_driver lowland_driver = {
.pm = &snd_soc_pm_ops,
},
.probe = lowland_probe,
- .remove = lowland_remove,
};
module_platform_driver(lowland_driver);
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index b0800337b79e..9b4a09f14b6c 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -271,15 +271,8 @@ static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = rtd->card;
- /* set up NC codec pins */
- snd_soc_dapm_nc_pin(&codec->dapm, "OUT3");
- snd_soc_dapm_nc_pin(&codec->dapm, "OUT4");
- snd_soc_dapm_nc_pin(&codec->dapm, "LINE1");
- snd_soc_dapm_nc_pin(&codec->dapm, "LINE2");
-
/* set endpoints to default off mode */
snd_soc_dapm_disable_pin(&card->dapm, "GSM Line Out");
snd_soc_dapm_disable_pin(&card->dapm, "GSM Line In");
@@ -355,6 +348,7 @@ static struct snd_soc_card neo1973 = {
.num_dapm_widgets = ARRAY_SIZE(neo1973_wm8753_dapm_widgets),
.dapm_routes = neo1973_wm8753_routes,
.num_dapm_routes = ARRAY_SIZE(neo1973_wm8753_routes),
+ .fully_routed = true,
};
static struct platform_device *neo1973_snd_device;
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index ab54e297957c..a3c9c9cba3b0 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -542,7 +542,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
/* Default is 128fs */
pcm->sclk_per_fs = 128;
- pcm->cclk = clk_get(&pdev->dev, "audio-bus");
+ pcm->cclk = devm_clk_get(&pdev->dev, "audio-bus");
if (IS_ERR(pcm->cclk)) {
dev_err(&pdev->dev, "failed to get audio-bus\n");
ret = PTR_ERR(pcm->cclk);
@@ -567,7 +567,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
goto err3;
}
- pcm->pclk = clk_get(&pdev->dev, "pcm");
+ pcm->pclk = devm_clk_get(&pdev->dev, "pcm");
if (IS_ERR(pcm->pclk)) {
dev_err(&pdev->dev, "failed to get pcm_clock\n");
ret = -ENOENT;
@@ -588,7 +588,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
- ret = snd_soc_register_component(&pdev->dev, &s3c_pcm_component,
+ ret = devm_snd_soc_register_component(&pdev->dev, &s3c_pcm_component,
&s3c_pcm_dai[pdev->id], 1);
if (ret != 0) {
dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret);
@@ -598,23 +598,19 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
ret = samsung_asoc_dma_platform_register(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
- goto err6;
+ goto err5;
}
return 0;
-err6:
- snd_soc_unregister_component(&pdev->dev);
err5:
clk_disable_unprepare(pcm->pclk);
- clk_put(pcm->pclk);
err4:
iounmap(pcm->regs);
err3:
release_mem_region(mem_res->start, resource_size(mem_res));
err2:
clk_disable_unprepare(pcm->cclk);
- clk_put(pcm->cclk);
err1:
return ret;
}
@@ -624,9 +620,6 @@ static int s3c_pcm_dev_remove(struct platform_device *pdev)
struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
struct resource *mem_res;
- samsung_asoc_dma_platform_unregister(&pdev->dev);
- snd_soc_unregister_component(&pdev->dev);
-
pm_runtime_disable(&pdev->dev);
iounmap(pcm->regs);
@@ -636,8 +629,6 @@ static int s3c_pcm_dev_remove(struct platform_device *pdev)
clk_disable_unprepare(pcm->cclk);
clk_disable_unprepare(pcm->pclk);
- clk_put(pcm->pclk);
- clk_put(pcm->cclk);
return 0;
}
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index 2982d9e7f268..5b3e504d3a32 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -221,11 +221,6 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream,
static int rx1950_uda1380_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_enable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_enable_pin(dapm, "Speaker");
- snd_soc_dapm_enable_pin(dapm, "Mic Jack");
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 79e7efb9283c..77a2ae50dc94 100644
--- a/sound/soc/samsung/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -745,7 +745,7 @@ int s3c_i2sv2_register_component(struct device *dev, int id,
dai_drv->suspend = s3c2412_i2s_suspend;
dai_drv->resume = s3c2412_i2s_resume;
- return snd_soc_register_component(dev, cmp_drv, dai_drv, 1);
+ return devm_snd_soc_register_component(dev, cmp_drv, dai_drv, 1);
}
EXPORT_SYMBOL_GPL(s3c_i2sv2_register_component);
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index e9bb5d7a71ee..843f315dcb3a 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -179,27 +179,14 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
}
ret = samsung_asoc_dma_platform_register(&pdev->dev);
- if (ret) {
+ if (ret)
pr_err("failed to register the DMA: %d\n", ret);
- goto err;
- }
- return 0;
-err:
- snd_soc_unregister_component(&pdev->dev);
return ret;
}
-static int s3c2412_iis_dev_remove(struct platform_device *pdev)
-{
- samsung_asoc_dma_platform_unregister(&pdev->dev);
- snd_soc_unregister_component(&pdev->dev);
- return 0;
-}
-
static struct platform_driver s3c2412_iis_driver = {
.probe = s3c2412_iis_dev_probe,
- .remove = 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 d7b8457b5650..4a6d206db222 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -475,35 +475,22 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
{
int ret = 0;
- ret = snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component,
- &s3c24xx_i2s_dai, 1);
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
if (ret) {
pr_err("failed to register the dai\n");
return ret;
}
ret = samsung_asoc_dma_platform_register(&pdev->dev);
- if (ret) {
+ if (ret)
pr_err("failed to register the dma: %d\n", ret);
- goto err;
- }
- return 0;
-err:
- snd_soc_unregister_component(&pdev->dev);
return ret;
}
-static int s3c24xx_iis_dev_remove(struct platform_device *pdev)
-{
- samsung_asoc_dma_platform_unregister(&pdev->dev);
- snd_soc_unregister_component(&pdev->dev);
- return 0;
-}
-
static struct platform_driver s3c24xx_iis_driver = {
.probe = s3c24xx_iis_dev_probe,
- .remove = s3c24xx_iis_dev_remove,
.driver = {
.name = "s3c24xx-iis",
.owner = THIS_MODULE,
diff --git a/sound/soc/samsung/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c
index d8a0543cae5e..2d30b7b6818a 100644
--- a/sound/soc/samsung/s3c24xx_simtec_hermes.c
+++ b/sound/soc/samsung/s3c24xx_simtec_hermes.c
@@ -63,14 +63,6 @@ static const struct snd_soc_dapm_route base_map[] = {
*/
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_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);
return 0;
diff --git a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
index 1ac0d7a63a3a..83f6c7d49cd6 100644
--- a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
+++ b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
@@ -52,14 +52,6 @@ static const struct snd_soc_dapm_route base_map[] = {
*/
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_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);
return 0;
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
index c3b2adafb7b5..df55db5d3554 100644
--- a/sound/soc/samsung/smartq_wm8987.c
+++ b/sound/soc/samsung/smartq_wm8987.c
@@ -162,8 +162,6 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "ROUT1");
/* set endpoints to default off mode */
- snd_soc_dapm_enable_pin(dapm, "Internal Speaker");
- snd_soc_dapm_enable_pin(dapm, "Internal Mic");
snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
/* Headphone jack detection */
diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c
index 23a9204b106d..e119aaa91c28 100644
--- a/sound/soc/samsung/smdk_wm8580pcm.c
+++ b/sound/soc/samsung/smdk_wm8580pcm.c
@@ -164,19 +164,11 @@ static int snd_smdk_probe(struct platform_device *pdev)
xtal_freq = mclk_freq = SMDK_WM8580_EXT_VOICE;
smdk_pcm.dev = &pdev->dev;
- ret = snd_soc_register_card(&smdk_pcm);
- if (ret) {
+ ret = devm_snd_soc_register_card(&pdev->dev, &smdk_pcm);
+ if (ret)
dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret);
- return ret;
- }
- return 0;
-}
-
-static int snd_smdk_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_card(&smdk_pcm);
- return 0;
+ return ret;
}
static struct platform_driver snd_smdk_driver = {
@@ -185,7 +177,6 @@ static struct platform_driver snd_smdk_driver = {
.name = "samsung-smdk-pcm",
},
.probe = snd_smdk_probe,
- .remove = snd_smdk_remove,
};
module_platform_driver(snd_smdk_driver);
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c
index 682eb4f7ba0c..fc25cc00f0f2 100644
--- a/sound/soc/samsung/smdk_wm8994.c
+++ b/sound/soc/samsung/smdk_wm8994.c
@@ -89,18 +89,6 @@ static int smdk_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- /* HeadPhone */
- snd_soc_dapm_enable_pin(dapm, "HPOUT1R");
- snd_soc_dapm_enable_pin(dapm, "HPOUT1L");
-
- /* MicIn */
- snd_soc_dapm_enable_pin(dapm, "IN1LN");
- snd_soc_dapm_enable_pin(dapm, "IN1RN");
-
- /* LineIn */
- snd_soc_dapm_enable_pin(dapm, "IN2LN");
- snd_soc_dapm_enable_pin(dapm, "IN2RN");
-
/* Other pins NC */
snd_soc_dapm_nc_pin(dapm, "HPOUT2P");
snd_soc_dapm_nc_pin(dapm, "HPOUT2N");
diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c
index 0c84ca099612..b6c09979be1f 100644
--- a/sound/soc/samsung/smdk_wm8994pcm.c
+++ b/sound/soc/samsung/smdk_wm8994pcm.c
@@ -134,19 +134,11 @@ static int snd_smdk_probe(struct platform_device *pdev)
int ret = 0;
smdk_pcm.dev = &pdev->dev;
- ret = snd_soc_register_card(&smdk_pcm);
- if (ret) {
+ ret = devm_snd_soc_register_card(&pdev->dev, &smdk_pcm);
+ if (ret)
dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret);
- return ret;
- }
- return 0;
-}
-
-static int snd_smdk_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_card(&smdk_pcm);
- return 0;
+ return ret;
}
static struct platform_driver snd_smdk_driver = {
@@ -155,7 +147,6 @@ static struct platform_driver snd_smdk_driver = {
.name = "samsung-smdk-pcm",
},
.probe = snd_smdk_probe,
- .remove = snd_smdk_remove,
};
module_platform_driver(snd_smdk_driver);
diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c
new file mode 100644
index 000000000000..014c177840ba
--- /dev/null
+++ b/sound/soc/samsung/snow.c
@@ -0,0 +1,123 @@
+/*
+ * ASoC machine driver for Snow boards
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <sound/soc.h>
+
+#include "i2s.h"
+
+#define FIN_PLL_RATE 24000000
+
+static struct snd_soc_dai_link snow_dai[] = {
+ {
+ .name = "Primary",
+ .stream_name = "Primary",
+ .codec_dai_name = "HiFi",
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ },
+};
+
+static int snow_late_probe(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+ struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai;
+ int ret;
+
+ /* Set the MCLK rate for the codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+ FIN_PLL_RATE, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* Select I2S Bus clock to set RCLK and BCLK */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_card snow_snd = {
+ .name = "Snow-I2S",
+ .dai_link = snow_dai,
+ .num_links = ARRAY_SIZE(snow_dai),
+
+ .late_probe = snow_late_probe,
+};
+
+static int snow_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &snow_snd;
+ struct device_node *i2s_node, *codec_node;
+ int i, ret;
+
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
+ "samsung,i2s-controller", 0);
+ if (!i2s_node) {
+ dev_err(&pdev->dev,
+ "Property 'i2s-controller' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ codec_node = of_parse_phandle(pdev->dev.of_node,
+ "samsung,audio-codec", 0);
+ if (!codec_node) {
+ dev_err(&pdev->dev,
+ "Property 'audio-codec' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(snow_dai); i++) {
+ snow_dai[i].codec_of_node = codec_node;
+ snow_dai[i].cpu_of_node = i2s_node;
+ snow_dai[i].platform_of_node = i2s_node;
+ }
+
+ card->dev = &pdev->dev;
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static const struct of_device_id snow_of_match[] = {
+ { .compatible = "google,snow-audio-max98090", },
+ { .compatible = "google,snow-audio-max98095", },
+ {},
+};
+
+static struct platform_driver snow_driver = {
+ .driver = {
+ .name = "snow-audio",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = snow_of_match,
+ },
+ .probe = snow_probe,
+};
+
+module_platform_driver(snow_driver);
+
+MODULE_DESCRIPTION("ALSA SoC Audio machine driver for Snow");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index cfe63b7bcc9f..e93a93e296f4 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -427,8 +427,8 @@ static int spdif_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, spdif);
- ret = snd_soc_register_component(&pdev->dev, &samsung_spdif_component,
- &samsung_spdif_dai, 1);
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &samsung_spdif_component, &samsung_spdif_dai, 1);
if (ret != 0) {
dev_err(&pdev->dev, "fail to register dai\n");
goto err4;
@@ -444,12 +444,10 @@ static int spdif_probe(struct platform_device *pdev)
ret = samsung_asoc_dma_platform_register(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "failed to register DMA: %d\n", ret);
- goto err5;
+ goto err4;
}
return 0;
-err5:
- snd_soc_unregister_component(&pdev->dev);
err4:
iounmap(spdif->regs);
err3:
@@ -467,9 +465,6 @@ static int spdif_remove(struct platform_device *pdev)
struct samsung_spdif_info *spdif = &spdif_info;
struct resource *mem_res;
- samsung_asoc_dma_platform_unregister(&pdev->dev);
- snd_soc_unregister_component(&pdev->dev);
-
iounmap(spdif->regs);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 57df90d6b7c1..9902efcb8ea1 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -327,23 +327,12 @@ static int speyside_probe(struct platform_device *pdev)
card->dev = &pdev->dev;
- ret = snd_soc_register_card(card);
- if (ret) {
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret)
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
ret);
- return ret;
- }
-
- return 0;
-}
-
-static int speyside_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
- snd_soc_unregister_card(card);
-
- return 0;
+ return ret;
}
static struct platform_driver speyside_driver = {
@@ -353,7 +342,6 @@ static struct platform_driver speyside_driver = {
.pm = &snd_soc_pm_ops,
},
.probe = speyside_probe,
- .remove = speyside_remove,
};
module_platform_driver(speyside_driver);
diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c
index 1807b75ccc12..6a2b9f14d624 100644
--- a/sound/soc/samsung/tobermory.c
+++ b/sound/soc/samsung/tobermory.c
@@ -223,23 +223,12 @@ static int tobermory_probe(struct platform_device *pdev)
card->dev = &pdev->dev;
- ret = snd_soc_register_card(card);
- if (ret) {
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret)
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
ret);
- return ret;
- }
-
- return 0;
-}
-
-static int tobermory_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
- snd_soc_unregister_card(card);
-
- return 0;
+ return ret;
}
static struct platform_driver tobermory_driver = {
@@ -249,7 +238,6 @@ static struct platform_driver tobermory_driver = {
.pm = &snd_soc_pm_ops,
},
.probe = tobermory_probe,
- .remove = tobermory_remove,
};
module_platform_driver(tobermory_driver);
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index ff60e11ecb56..b43fdf0d08af 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -56,7 +56,7 @@ config SND_SH7760_AC97
config SND_SIU_MIGOR
tristate "SIU sound support on Migo-R"
- depends on SH_MIGOR
+ depends on SH_MIGOR && I2C
select SND_SOC_SH4_SIU
select SND_SOC_WM8978
help
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index 7d0051ced838..9ac536429800 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,2 +1,2 @@
-snd-soc-rcar-objs := core.o gen.o src.o adg.o ssi.o
+snd-soc-rcar-objs := core.o gen.o src.o adg.o ssi.o dvc.o
obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 69c44269ebdb..fc41a0e8b09f 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -57,6 +57,24 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
return (0x6 + ws) << 8;
}
+int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_dai *rdai,
+ struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io)
+{
+ int id = rsnd_mod_id(mod);
+ int shift = (id % 2) ? 16 : 0;
+ u32 mask, val;
+
+ val = rsnd_adg_ssi_ws_timing_gen2(io);
+
+ val = val << shift;
+ mask = 0xffff << shift;
+
+ rsnd_mod_bset(mod, CMDOUT_TIMSEL, mask, val);
+
+ return 0;
+}
+
static int rsnd_adg_set_src_timsel_gen2(struct rsnd_dai *rdai,
struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
@@ -397,9 +415,8 @@ int rsnd_adg_probe(struct platform_device *pdev,
{
struct rsnd_adg *adg;
struct device *dev = rsnd_priv_to_dev(priv);
- struct clk *clk, *clk_orig;
+ struct clk *clk;
int i;
- bool use_old_style = false;
adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
if (!adg) {
@@ -407,45 +424,13 @@ int rsnd_adg_probe(struct platform_device *pdev,
return -ENOMEM;
}
- clk_orig = devm_clk_get(dev, NULL);
adg->clk[CLKA] = devm_clk_get(dev, "clk_a");
adg->clk[CLKB] = devm_clk_get(dev, "clk_b");
adg->clk[CLKC] = devm_clk_get(dev, "clk_c");
adg->clk[CLKI] = devm_clk_get(dev, "clk_i");
- /*
- * It request device dependent audio clock.
- * But above all clks will indicate rsnd module clock
- * if platform doesn't it
- */
- for_each_rsnd_clk(clk, adg, i) {
- if (clk_orig == clk) {
- dev_warn(dev,
- "doesn't have device dependent clock, use independent clock\n");
- use_old_style = true;
- break;
- }
- }
-
- /*
- * note:
- * these exist in order to keep compatible with
- * platform which has device independent audio clock,
- * but will be removed soon
- */
- if (use_old_style) {
- adg->clk[CLKA] = devm_clk_get(NULL, "audio_clk_a");
- adg->clk[CLKB] = devm_clk_get(NULL, "audio_clk_b");
- adg->clk[CLKC] = devm_clk_get(NULL, "audio_clk_c");
- adg->clk[CLKI] = devm_clk_get(NULL, "audio_clk_internal");
- }
-
- for_each_rsnd_clk(clk, adg, i) {
- if (IS_ERR(clk)) {
- dev_err(dev, "Audio clock failed\n");
- return -EIO;
- }
- }
+ for_each_rsnd_clk(clk, adg, i)
+ dev_dbg(dev, "clk %d : %p\n", i, clk);
rsnd_adg_ssi_clk_init(priv, adg);
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 215b668166be..964463dada87 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -197,13 +197,12 @@ static void rsnd_dma_complete(void *data)
* rsnd_dai_pointer_update() will be called twice,
* ant it will breaks io->byte_pos
*/
-
- rsnd_dai_pointer_update(io, io->byte_per_period);
-
if (dma->submit_loop)
rsnd_dma_continue(dma);
rsnd_unlock(priv, flags);
+
+ rsnd_dai_pointer_update(io, io->byte_per_period);
}
static void __rsnd_dma_start(struct rsnd_dma *dma)
@@ -310,23 +309,49 @@ void rsnd_dma_quit(struct rsnd_priv *priv,
}
/*
+ * settting function
+ */
+u32 rsnd_get_adinr(struct rsnd_mod *mod)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ u32 adinr = runtime->channels;
+
+ switch (runtime->sample_bits) {
+ case 16:
+ adinr |= (8 << 16);
+ break;
+ case 32:
+ adinr |= (0 << 16);
+ break;
+ default:
+ dev_warn(dev, "not supported sample bits\n");
+ return 0;
+ }
+
+ return adinr;
+}
+
+/*
* rsnd_dai functions
*/
-#define __rsnd_mod_call(mod, func, rdai, io) \
+#define __rsnd_mod_call(mod, func, rdai...) \
({ \
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \
struct device *dev = rsnd_priv_to_dev(priv); \
dev_dbg(dev, "%s [%d] %s\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \
- (mod)->ops->func(mod, rdai, io); \
+ (mod)->ops->func(mod, rdai); \
})
-#define rsnd_mod_call(mod, func, rdai, io) \
+#define rsnd_mod_call(mod, func, rdai...) \
(!(mod) ? -ENODEV : \
!((mod)->ops->func) ? 0 : \
- __rsnd_mod_call(mod, func, (rdai), (io)))
+ __rsnd_mod_call(mod, func, rdai))
-#define rsnd_dai_call(rdai, io, fn) \
+#define rsnd_dai_call(fn, io, rdai...) \
({ \
struct rsnd_mod *mod; \
int ret = 0, i; \
@@ -334,7 +359,7 @@ void rsnd_dma_quit(struct rsnd_priv *priv,
mod = (io)->mod[i]; \
if (!mod) \
continue; \
- ret = rsnd_mod_call(mod, fn, (rdai), (io)); \
+ ret = rsnd_mod_call(mod, fn, rdai); \
if (ret < 0) \
break; \
} \
@@ -468,10 +493,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
- struct rsnd_mod *mod = rsnd_ssi_mod_get_frm_dai(priv,
- rsnd_dai_id(priv, rdai),
- rsnd_dai_is_play(rdai, io));
- int ssi_id = rsnd_mod_id(mod);
+ int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io));
int ret;
unsigned long flags;
@@ -487,20 +509,20 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
if (ret < 0)
goto dai_trigger_end;
- ret = rsnd_dai_call(rdai, io, init);
+ ret = rsnd_dai_call(init, io, rdai);
if (ret < 0)
goto dai_trigger_end;
- ret = rsnd_dai_call(rdai, io, start);
+ ret = rsnd_dai_call(start, io, rdai);
if (ret < 0)
goto dai_trigger_end;
break;
case SNDRV_PCM_TRIGGER_STOP:
- ret = rsnd_dai_call(rdai, io, stop);
+ ret = rsnd_dai_call(stop, io, rdai);
if (ret < 0)
goto dai_trigger_end;
- ret = rsnd_dai_call(rdai, io, quit);
+ ret = rsnd_dai_call(quit, io, rdai);
if (ret < 0)
goto dai_trigger_end;
@@ -579,15 +601,27 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
.set_fmt = rsnd_soc_dai_set_fmt,
};
+#define rsnd_path_parse(priv, io, type) \
+({ \
+ struct rsnd_mod *mod; \
+ int ret = 0; \
+ int id = -1; \
+ \
+ if (rsnd_is_enable_path(io, type)) { \
+ id = rsnd_info_id(priv, io, type); \
+ if (id >= 0) { \
+ mod = rsnd_##type##_mod_get(priv, id); \
+ ret = rsnd_dai_connect(mod, io); \
+ } \
+ } \
+ ret; \
+})
+
static int rsnd_path_init(struct rsnd_priv *priv,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io)
{
- struct rsnd_mod *mod;
- struct rsnd_dai_platform_info *dai_info = rdai->info;
int ret;
- int ssi_id = -1;
- int src_id = -1;
/*
* Gen1 is created by SRU/SSI, and this SRU is base module of
@@ -599,38 +633,21 @@ static int rsnd_path_init(struct rsnd_priv *priv,
* Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
* using fixed path.
*/
- if (dai_info) {
- if (rsnd_is_enable_path(io, ssi))
- ssi_id = rsnd_info_id(priv, io, ssi);
- if (rsnd_is_enable_path(io, src))
- src_id = rsnd_info_id(priv, io, src);
- } else {
- /* get SSI's ID */
- mod = rsnd_ssi_mod_get_frm_dai(priv,
- rsnd_dai_id(priv, rdai),
- rsnd_dai_is_play(rdai, io));
- if (!mod)
- return 0;
- ssi_id = src_id = rsnd_mod_id(mod);
- }
-
- ret = 0;
/* SRC */
- if (src_id >= 0) {
- mod = rsnd_src_mod_get(priv, src_id);
- ret = rsnd_dai_connect(mod, io);
- if (ret < 0)
- return ret;
- }
+ ret = rsnd_path_parse(priv, io, src);
+ if (ret < 0)
+ return ret;
/* SSI */
- if (ssi_id >= 0) {
- mod = rsnd_ssi_mod_get(priv, ssi_id);
- ret = rsnd_dai_connect(mod, io);
- if (ret < 0)
- return ret;
- }
+ ret = rsnd_path_parse(priv, io, ssi);
+ if (ret < 0)
+ return ret;
+
+ /* DVC */
+ ret = rsnd_path_parse(priv, io, dvc);
+ if (ret < 0)
+ return ret;
return ret;
}
@@ -726,30 +743,15 @@ static int rsnd_dai_probe(struct platform_device *pdev,
struct snd_soc_dai_driver *drv;
struct rcar_snd_info *info = rsnd_priv_to_info(priv);
struct rsnd_dai *rdai;
- struct rsnd_mod *pmod, *cmod;
+ struct rsnd_ssi_platform_info *pmod, *cmod;
struct device *dev = rsnd_priv_to_dev(priv);
int dai_nr;
int i;
rsnd_of_parse_dai(pdev, of_data, priv);
- /*
- * dai_nr should be set via dai_info_nr,
- * but allow it to keeping compatible
- */
dai_nr = info->dai_info_nr;
if (!dai_nr) {
- /* get max dai nr */
- for (dai_nr = 0; dai_nr < 32; dai_nr++) {
- pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1);
- cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0);
-
- if (!pmod && !cmod)
- break;
- }
- }
-
- if (!dai_nr) {
dev_err(dev, "no dai\n");
return -EIO;
}
@@ -766,11 +768,10 @@ static int rsnd_dai_probe(struct platform_device *pdev,
priv->rdai = rdai;
for (i = 0; i < dai_nr; i++) {
- if (info->dai_info)
- rdai[i].info = &info->dai_info[i];
+ rdai[i].info = &info->dai_info[i];
- pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1);
- cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0);
+ pmod = rdai[i].info->playback.ssi;
+ cmod = rdai[i].info->capture.ssi;
/*
* init rsnd_dai
@@ -788,8 +789,7 @@ static int rsnd_dai_probe(struct platform_device *pdev,
drv[i].playback.channels_min = 2;
drv[i].playback.channels_max = 2;
- if (info->dai_info)
- rdai[i].playback.info = &info->dai_info[i].playback;
+ rdai[i].playback.info = &info->dai_info[i].playback;
rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
}
if (cmod) {
@@ -798,8 +798,7 @@ static int rsnd_dai_probe(struct platform_device *pdev,
drv[i].capture.channels_min = 2;
drv[i].capture.channels_max = 2;
- if (info->dai_info)
- rdai[i].capture.info = &info->dai_info[i].capture;
+ rdai[i].capture.info = &info->dai_info[i].capture;
rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
}
@@ -874,6 +873,20 @@ static struct snd_pcm_ops rsnd_pcm_ops = {
static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct rsnd_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ struct rsnd_dai *rdai;
+ int i, ret;
+
+ for_each_rsnd_dai(rdai, priv, i) {
+ ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd);
+ if (ret)
+ return ret;
+
+ ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd);
+ if (ret)
+ return ret;
+ }
+
return snd_pcm_lib_preallocate_pages_for_all(
rtd->pcm,
SNDRV_DMA_TYPE_DEV,
@@ -913,6 +926,7 @@ static int rsnd_probe(struct platform_device *pdev)
rsnd_gen_probe,
rsnd_ssi_probe,
rsnd_src_probe,
+ rsnd_dvc_probe,
rsnd_adg_probe,
rsnd_dai_probe,
};
@@ -956,11 +970,11 @@ static int rsnd_probe(struct platform_device *pdev)
}
for_each_rsnd_dai(rdai, priv, i) {
- ret = rsnd_dai_call(rdai, &rdai->playback, probe);
+ ret = rsnd_dai_call(probe, &rdai->playback, rdai);
if (ret)
return ret;
- ret = rsnd_dai_call(rdai, &rdai->capture, probe);
+ ret = rsnd_dai_call(probe, &rdai->capture, rdai);
if (ret)
return ret;
}
@@ -1003,11 +1017,11 @@ static int rsnd_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
for_each_rsnd_dai(rdai, priv, i) {
- ret = rsnd_dai_call(rdai, &rdai->playback, remove);
+ ret = rsnd_dai_call(remove, &rdai->playback, rdai);
if (ret)
return ret;
- ret = rsnd_dai_call(rdai, &rdai->capture, remove);
+ ret = rsnd_dai_call(remove, &rdai->capture, rdai);
if (ret)
return ret;
}
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
new file mode 100644
index 000000000000..74769b1be005
--- /dev/null
+++ b/sound/soc/sh/rcar/dvc.c
@@ -0,0 +1,273 @@
+/*
+ * Renesas R-Car DVC support
+ *
+ * Copyright (C) 2014 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 "rsnd.h"
+
+#define RSND_DVC_NAME_SIZE 16
+#define RSND_DVC_VOLUME_MAX 100
+#define RSND_DVC_VOLUME_NUM 2
+struct rsnd_dvc {
+ struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
+ struct rsnd_mod mod;
+ struct clk *clk;
+ long volume[RSND_DVC_VOLUME_NUM];
+};
+
+#define rsnd_mod_to_dvc(_mod) \
+ container_of((_mod), struct rsnd_dvc, mod)
+
+#define for_each_rsnd_dvc(pos, priv, i) \
+ for ((i) = 0; \
+ ((i) < rsnd_dvc_nr(priv)) && \
+ ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \
+ i++)
+
+static void rsnd_dvc_volume_update(struct rsnd_mod *mod)
+{
+ struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+ u32 max = (0x00800000 - 1);
+ u32 vol[RSND_DVC_VOLUME_NUM];
+ int i;
+
+ for (i = 0; i < RSND_DVC_VOLUME_NUM; i++)
+ vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i];
+
+ rsnd_mod_write(mod, DVC_VOL0R, vol[0]);
+ rsnd_mod_write(mod, DVC_VOL1R, vol[1]);
+}
+
+static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
+ struct rsnd_dai *rdai)
+{
+ struct rsnd_dvc *dvc = rsnd_mod_to_dvc(dvc_mod);
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(dvc_mod);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(dvc_mod);
+ struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ int dvc_id = rsnd_mod_id(dvc_mod);
+ int src_id = rsnd_mod_id(src_mod);
+ u32 route[] = {
+ [0] = 0x30000,
+ [1] = 0x30001,
+ [2] = 0x40000,
+ [3] = 0x10000,
+ [4] = 0x20000,
+ [5] = 0x40100
+ };
+
+ if (src_id >= ARRAY_SIZE(route)) {
+ dev_err(dev, "DVC%d isn't connected to SRC%d\n", dvc_id, src_id);
+ return -EINVAL;
+ }
+
+ clk_prepare_enable(dvc->clk);
+
+ /*
+ * fixme
+ * it doesn't support CTU/MIX
+ */
+ rsnd_mod_write(dvc_mod, CMD_ROUTE_SLCT, route[src_id]);
+
+ rsnd_mod_write(dvc_mod, DVC_SWRSR, 0);
+ rsnd_mod_write(dvc_mod, DVC_SWRSR, 1);
+
+ rsnd_mod_write(dvc_mod, DVC_DVUIR, 1);
+
+ rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod));
+
+ /* enable Volume */
+ rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x100);
+
+ /* ch0/ch1 Volume */
+ rsnd_dvc_volume_update(dvc_mod);
+
+ rsnd_mod_write(dvc_mod, DVC_DVUIR, 0);
+
+ rsnd_mod_write(dvc_mod, DVC_DVUER, 1);
+
+ rsnd_adg_set_cmd_timsel_gen2(rdai, dvc_mod, io);
+
+ return 0;
+}
+
+static int rsnd_dvc_quit(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai)
+{
+ struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+
+ clk_disable_unprepare(dvc->clk);
+
+ return 0;
+}
+
+static int rsnd_dvc_start(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai)
+{
+ rsnd_mod_write(mod, CMD_CTRL, 0x10);
+
+ return 0;
+}
+
+static int rsnd_dvc_stop(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai)
+{
+ rsnd_mod_write(mod, CMD_CTRL, 0);
+
+ return 0;
+}
+
+static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = RSND_DVC_VOLUME_NUM;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = RSND_DVC_VOLUME_MAX;
+
+ return 0;
+}
+
+static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
+ struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+ int i;
+
+ for (i = 0; i < RSND_DVC_VOLUME_NUM; i++)
+ ucontrol->value.integer.value[i] = dvc->volume[i];
+
+ return 0;
+}
+
+static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
+ struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+ int i, change = 0;
+
+ for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) {
+ if (ucontrol->value.integer.value[i] < 0 ||
+ ucontrol->value.integer.value[i] > RSND_DVC_VOLUME_MAX)
+ return -EINVAL;
+
+ change |= (ucontrol->value.integer.value[i] != dvc->volume[i]);
+ }
+
+ if (change) {
+ for (i = 0; i < RSND_DVC_VOLUME_NUM; i++)
+ dvc->volume[i] = ucontrol->value.integer.value[i];
+
+ rsnd_dvc_volume_update(mod);
+ }
+
+ return change;
+}
+
+static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct snd_soc_pcm_runtime *rtd)
+{
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_kcontrol *kctrl;
+ static struct snd_kcontrol_new knew = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Playback Volume",
+ .info = rsnd_dvc_volume_info,
+ .get = rsnd_dvc_volume_get,
+ .put = rsnd_dvc_volume_put,
+ };
+ int ret;
+
+ if (!rsnd_dai_is_play(rdai, io)) {
+ dev_err(dev, "DVC%d is connected to Capture DAI\n",
+ rsnd_mod_id(mod));
+ return -EINVAL;
+ }
+
+ kctrl = snd_ctl_new1(&knew, mod);
+ if (!kctrl)
+ return -ENOMEM;
+
+ ret = snd_ctl_add(card, kctrl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct rsnd_mod_ops rsnd_dvc_ops = {
+ .name = "dvc (gen2)",
+ .init = rsnd_dvc_init,
+ .quit = rsnd_dvc_quit,
+ .start = rsnd_dvc_start,
+ .stop = rsnd_dvc_stop,
+ .pcm_new = rsnd_dvc_pcm_new,
+};
+
+struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
+{
+ if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))
+ id = 0;
+
+ return &((struct rsnd_dvc *)(priv->dvc) + id)->mod;
+}
+
+int rsnd_dvc_probe(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv)
+{
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_dvc *dvc;
+ struct clk *clk;
+ char name[RSND_DVC_NAME_SIZE];
+ int i, nr;
+
+ nr = info->dvc_info_nr;
+ if (!nr)
+ return 0;
+
+ /* This driver doesn't support Gen1 at this point */
+ if (rsnd_is_gen1(priv)) {
+ dev_warn(dev, "CMD is not supported on Gen1\n");
+ return -EINVAL;
+ }
+
+ dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL);
+ if (!dvc) {
+ dev_err(dev, "CMD allocate failed\n");
+ return -ENOMEM;
+ }
+
+ priv->dvc_nr = nr;
+ priv->dvc = dvc;
+
+ for_each_rsnd_dvc(dvc, priv, i) {
+ snprintf(name, RSND_DVC_NAME_SIZE, "dvc.%d", i);
+
+ clk = devm_clk_get(dev, name);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ dvc->info = &info->dvc_info[i];
+ dvc->clk = clk;
+
+ rsnd_mod_init(priv, &dvc->mod, &rsnd_dvc_ops, RSND_MOD_DVC, i);
+
+ dev_dbg(dev, "CMD%d probed\n", i);
+ }
+
+ return 0;
+}
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 50a1ef3eb1c6..a1583b57bf8d 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -181,6 +181,8 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
RSND_GEN2_M_REG(gen, SCU, SRC_BUSIF_MODE, 0x0, 0x20),
RSND_GEN2_M_REG(gen, SCU, SRC_ROUTE_MODE0,0xc, 0x20),
RSND_GEN2_M_REG(gen, SCU, SRC_CTRL, 0x10, 0x20),
+ RSND_GEN2_M_REG(gen, SCU, CMD_ROUTE_SLCT, 0x18c, 0x20),
+ RSND_GEN2_M_REG(gen, SCU, CMD_CTRL, 0x190, 0x20),
RSND_GEN2_M_REG(gen, SCU, SRC_SWRSR, 0x200, 0x40),
RSND_GEN2_M_REG(gen, SCU, SRC_SRCIR, 0x204, 0x40),
RSND_GEN2_M_REG(gen, SCU, SRC_ADINR, 0x214, 0x40),
@@ -189,6 +191,14 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
RSND_GEN2_M_REG(gen, SCU, SRC_SRCCR, 0x224, 0x40),
RSND_GEN2_M_REG(gen, SCU, SRC_BSDSR, 0x22c, 0x40),
RSND_GEN2_M_REG(gen, SCU, SRC_BSISR, 0x238, 0x40),
+ RSND_GEN2_M_REG(gen, SCU, DVC_SWRSR, 0xe00, 0x100),
+ RSND_GEN2_M_REG(gen, SCU, DVC_DVUIR, 0xe04, 0x100),
+ RSND_GEN2_M_REG(gen, SCU, DVC_ADINR, 0xe08, 0x100),
+ RSND_GEN2_M_REG(gen, SCU, DVC_DVUCR, 0xe10, 0x100),
+ RSND_GEN2_M_REG(gen, SCU, DVC_ZCMCR, 0xe14, 0x100),
+ RSND_GEN2_M_REG(gen, SCU, DVC_VOL0R, 0xe28, 0x100),
+ RSND_GEN2_M_REG(gen, SCU, DVC_VOL1R, 0xe2c, 0x100),
+ RSND_GEN2_M_REG(gen, SCU, DVC_DVUER, 0xe48, 0x100),
RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00),
RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04),
@@ -207,6 +217,7 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL2, 0x50),
RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL3, 0x54),
RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL4, 0x58),
+ RSND_GEN2_S_REG(gen, ADG, CMDOUT_TIMSEL, 0x5c),
RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40),
RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40),
@@ -252,13 +263,13 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
return ret;
dev_dbg(dev, "Gen2 device probed\n");
- dev_dbg(dev, "SCU : %08x => %p\n", scu_res->start,
+ dev_dbg(dev, "SCU : %pap => %p\n", &scu_res->start,
gen->base[RSND_GEN2_SCU]);
- dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start,
+ dev_dbg(dev, "ADG : %pap => %p\n", &adg_res->start,
gen->base[RSND_GEN2_ADG]);
- dev_dbg(dev, "SSIU : %08x => %p\n", ssiu_res->start,
+ dev_dbg(dev, "SSIU : %pap => %p\n", &ssiu_res->start,
gen->base[RSND_GEN2_SSIU]);
- dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start,
+ dev_dbg(dev, "SSI : %pap => %p\n", &ssi_res->start,
gen->base[RSND_GEN2_SSI]);
return 0;
@@ -345,11 +356,11 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
return ret;
dev_dbg(dev, "Gen1 device probed\n");
- dev_dbg(dev, "SRU : %08x => %p\n", sru_res->start,
+ dev_dbg(dev, "SRU : %pap => %p\n", &sru_res->start,
gen->base[RSND_GEN1_SRU]);
- dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start,
+ dev_dbg(dev, "ADG : %pap => %p\n", &adg_res->start,
gen->base[RSND_GEN1_ADG]);
- dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start,
+ dev_dbg(dev, "SSI : %pap => %p\n", &ssi_res->start,
gen->base[RSND_GEN1_SSI]);
return 0;
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 619d198c7d2e..5aa790170b01 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -44,6 +44,15 @@ enum rsnd_reg {
RSND_REG_SRC_IFSCR,
RSND_REG_SRC_IFSVR,
RSND_REG_SRC_SRCCR,
+ RSND_REG_CMD_ROUTE_SLCT,
+ RSND_REG_DVC_SWRSR,
+ RSND_REG_DVC_DVUIR,
+ RSND_REG_DVC_ADINR,
+ RSND_REG_DVC_DVUCR,
+ RSND_REG_DVC_ZCMCR,
+ RSND_REG_DVC_VOL0R,
+ RSND_REG_DVC_VOL1R,
+ RSND_REG_DVC_DVUER,
/* ADG */
RSND_REG_BRRA,
@@ -79,6 +88,8 @@ enum rsnd_reg {
RSND_REG_SHARE17,
RSND_REG_SHARE18,
RSND_REG_SHARE19,
+ RSND_REG_SHARE20,
+ RSND_REG_SHARE21,
RSND_REG_MAX,
};
@@ -114,6 +125,8 @@ enum rsnd_reg {
#define RSND_REG_SRCOUT_TIMSEL3 RSND_REG_SHARE17
#define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18
#define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19
+#define RSND_REG_CMD_CTRL RSND_REG_SHARE20
+#define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21
struct rsnd_of_data;
struct rsnd_priv;
@@ -136,6 +149,7 @@ void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
enum rsnd_reg reg, u32 data);
void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
u32 mask, u32 data);
+u32 rsnd_get_adinr(struct rsnd_mod *mod);
/*
* R-Car DMA
@@ -165,29 +179,27 @@ void rsnd_dma_quit(struct rsnd_priv *priv,
enum rsnd_mod_type {
RSND_MOD_SRC = 0,
RSND_MOD_SSI,
+ RSND_MOD_DVC,
RSND_MOD_MAX,
};
struct rsnd_mod_ops {
char *name;
int (*probe)(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io);
+ struct rsnd_dai *rdai);
int (*remove)(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io);
+ struct rsnd_dai *rdai);
int (*init)(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io);
+ struct rsnd_dai *rdai);
int (*quit)(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io);
+ struct rsnd_dai *rdai);
int (*start)(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io);
+ struct rsnd_dai *rdai);
int (*stop)(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io);
+ struct rsnd_dai *rdai);
+ int (*pcm_new)(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct snd_soc_pcm_runtime *rtd);
};
struct rsnd_dai_stream;
@@ -228,6 +240,7 @@ struct rsnd_dai_stream {
};
#define rsnd_io_to_mod_ssi(io) ((io)->mod[RSND_MOD_SSI])
#define rsnd_io_to_mod_src(io) ((io)->mod[RSND_MOD_SRC])
+#define rsnd_io_to_mod_dvc(io) ((io)->mod[RSND_MOD_DVC])
struct rsnd_dai {
char name[RSND_DAI_NAME_SIZE];
@@ -291,6 +304,9 @@ int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io);
+int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_dai *rdai,
+ struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io);
/*
* R-Car sound priv
@@ -328,6 +344,12 @@ struct rsnd_priv {
int ssi_nr;
/*
+ * below value will be filled on rsnd_dvc_probe()
+ */
+ void *dvc;
+ int dvc_nr;
+
+ /*
* below value will be filled on rsnd_dai_probe()
*/
struct snd_soc_dai_driver *daidrv;
@@ -364,11 +386,9 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
struct rsnd_dai_stream *io,
struct snd_pcm_runtime *runtime);
int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io);
+ struct rsnd_dai *rdai);
int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io);
+ struct rsnd_dai *rdai);
#define rsnd_src_nr(priv) ((priv)->src_nr)
@@ -379,9 +399,19 @@ int rsnd_ssi_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
-struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
- int dai_id, int is_play);
int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
-int rsnd_ssi_is_play(struct rsnd_mod *mod);
+
+/*
+ * R-Car DVC
+ */
+int rsnd_dvc_probe(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv);
+void rsnd_dvc_remove(struct platform_device *pdev,
+ struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
+
+#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
+
#endif
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 6232b7d307aa..e3b078e7c3aa 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -18,21 +18,9 @@ struct rsnd_src {
#define RSND_SRC_NAME_SIZE 16
-/*
- * ADINR
- */
-#define OTBL_24 (0 << 16)
-#define OTBL_22 (2 << 16)
-#define OTBL_20 (4 << 16)
-#define OTBL_18 (6 << 16)
-#define OTBL_16 (8 << 16)
-
-#define rsnd_src_mode_flags(p) ((p)->info->flags)
#define rsnd_src_convert_rate(p) ((p)->info->convert_rate)
#define rsnd_mod_to_src(_mod) \
container_of((_mod), struct rsnd_src, mod)
-#define rsnd_src_hpbif_is_enable(src) \
- (rsnd_src_mode_flags(src) & RSND_SCU_USE_HPBIF)
#define rsnd_src_dma_available(src) \
rsnd_dma_available(rsnd_mod_to_dma(&(src)->mod))
@@ -80,34 +68,35 @@ struct rsnd_src {
*
* This driver request
* struct rsnd_src_platform_info {
- * u32 flags;
* u32 convert_rate;
+ * int dma_id;
* }
*
- * rsnd_src_hpbif_is_enable() will be true
- * if flags had RSND_SRC_USE_HPBIF,
- * and it controls whether SSIU is used or not.
- *
* rsnd_src_convert_rate() indicates
* above convert_rate, and it controls
* whether SRC is used or not.
*
* ex) doesn't use SRC
- * struct rsnd_src_platform_info info = {
- * .flags = 0,
- * .convert_rate = 0,
+ * static struct rsnd_dai_platform_info rsnd_dai = {
+ * .playback = { .ssi = &rsnd_ssi[0], },
* };
*
* ex) uses SRC
- * struct rsnd_src_platform_info info = {
- * .flags = RSND_SRC_USE_HPBIF,
- * .convert_rate = 48000,
+ * static struct rsnd_src_platform_info rsnd_src[] = {
+ * RSND_SCU(48000, 0),
+ * ...
+ * };
+ * static struct rsnd_dai_platform_info rsnd_dai = {
+ * .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] },
* };
*
* ex) uses SRC bypass mode
- * struct rsnd_src_platform_info info = {
- * .flags = RSND_SRC_USE_HPBIF,
- * .convert_rate = 0,
+ * static struct rsnd_src_platform_info rsnd_src[] = {
+ * RSND_SCU(0, 0),
+ * ...
+ * };
+ * static struct rsnd_dai_platform_info rsnd_dai = {
+ * .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] },
* };
*
*/
@@ -116,27 +105,17 @@ struct rsnd_src {
* Gen1/Gen2 common functions
*/
int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
- struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod);
struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
int ssi_id = rsnd_mod_id(ssi_mod);
- int has_src = 0;
/*
* SSI_MODE0
*/
- if (info->dai_info) {
- has_src = !!src_mod;
- } else {
- struct rsnd_src *src = rsnd_mod_to_src(src_mod);
- has_src = rsnd_src_hpbif_is_enable(src);
- }
-
rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id),
- has_src ? 0 : (1 << ssi_id));
+ src_mod ? 0 : (1 << ssi_id));
/*
* SSI_MODE1
@@ -166,8 +145,7 @@ int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod,
}
int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
@@ -203,13 +181,12 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
}
static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_src *src = rsnd_mod_to_src(mod);
u32 convert_rate = rsnd_src_convert_rate(src);
- u32 adinr = runtime->channels;
u32 fsrate = 0;
if (convert_rate)
@@ -226,17 +203,7 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
rsnd_mod_write(mod, SRC_SRCIR, 1);
/* Set channel number and output bit length */
- switch (runtime->sample_bits) {
- case 16:
- adinr |= OTBL_16;
- break;
- case 32:
- adinr |= OTBL_24;
- break;
- default:
- return -EIO;
- }
- rsnd_mod_write(mod, SRC_ADINR, adinr);
+ rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod));
/* Enable the initial value of IFS */
if (fsrate) {
@@ -253,30 +220,27 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
}
static int rsnd_src_init(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
- clk_enable(src->clk);
+ clk_prepare_enable(src->clk);
return 0;
}
static int rsnd_src_quit(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
- clk_disable(src->clk);
+ clk_disable_unprepare(src->clk);
return 0;
}
static int rsnd_src_start(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
@@ -294,8 +258,7 @@ static int rsnd_src_start(struct rsnd_mod *mod,
static int rsnd_src_stop(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
@@ -313,9 +276,9 @@ static struct rsnd_mod_ops rsnd_src_non_ops = {
* Gen1 functions
*/
static int rsnd_src_set_route_gen1(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct src_route_config {
u32 mask;
int shift;
@@ -351,9 +314,9 @@ static int rsnd_src_set_route_gen1(struct rsnd_mod *mod,
}
static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_src *src = rsnd_mod_to_src(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
@@ -410,12 +373,11 @@ static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod,
}
static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
int ret;
- ret = rsnd_src_set_convert_rate(mod, rdai, io);
+ ret = rsnd_src_set_convert_rate(mod, rdai);
if (ret < 0)
return ret;
@@ -432,24 +394,23 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
}
static int rsnd_src_init_gen1(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
int ret;
- ret = rsnd_src_init(mod, rdai, io);
+ ret = rsnd_src_init(mod, rdai);
if (ret < 0)
return ret;
- ret = rsnd_src_set_route_gen1(mod, rdai, io);
+ ret = rsnd_src_set_route_gen1(mod, rdai);
if (ret < 0)
return ret;
- ret = rsnd_src_set_convert_rate_gen1(mod, rdai, io);
+ ret = rsnd_src_set_convert_rate_gen1(mod, rdai);
if (ret < 0)
return ret;
- ret = rsnd_src_set_convert_timing_gen1(mod, rdai, io);
+ ret = rsnd_src_set_convert_timing_gen1(mod, rdai);
if (ret < 0)
return ret;
@@ -457,25 +418,23 @@ static int rsnd_src_init_gen1(struct rsnd_mod *mod,
}
static int rsnd_src_start_gen1(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
int id = rsnd_mod_id(mod);
rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id));
- return rsnd_src_start(mod, rdai, io);
+ return rsnd_src_start(mod, rdai);
}
static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
int id = rsnd_mod_id(mod);
rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0);
- return rsnd_src_stop(mod, rdai, io);
+ return rsnd_src_stop(mod, rdai);
}
static struct rsnd_mod_ops rsnd_src_gen1_ops = {
@@ -490,17 +449,16 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = {
* Gen2 functions
*/
static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
int ret;
- ret = rsnd_src_set_convert_rate(mod, rdai, io);
+ ret = rsnd_src_set_convert_rate(mod, rdai);
if (ret < 0)
return ret;
- rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_mod_read(mod, SRC_ADINR));
- rsnd_mod_write(mod, SSI_BUSIF_MODE, rsnd_mod_read(mod, SRC_BUSIF_MODE));
+ rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_get_adinr(mod));
+ rsnd_mod_write(mod, SSI_BUSIF_MODE, 1);
rsnd_mod_write(mod, SRC_SRCCR, 0x00011110);
@@ -511,9 +469,9 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
}
static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_src *src = rsnd_mod_to_src(mod);
u32 convert_rate = rsnd_src_convert_rate(src);
@@ -530,25 +488,16 @@ static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod,
}
static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
struct rsnd_src *src = rsnd_mod_to_src(mod);
- struct rsnd_mod *ssi = rsnd_ssi_mod_get(priv, rsnd_mod_id(mod));
struct device *dev = rsnd_priv_to_dev(priv);
int ret;
- int is_play;
-
- if (info->dai_info)
- is_play = rsnd_info_is_playback(priv, src);
- else
- is_play = rsnd_ssi_is_play(ssi);
ret = rsnd_dma_init(priv,
rsnd_mod_to_dma(mod),
- is_play,
+ rsnd_info_is_playback(priv, src),
src->info->dma_id);
if (ret < 0)
dev_err(dev, "SRC DMA failed\n");
@@ -557,8 +506,7 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
}
static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod));
@@ -566,20 +514,19 @@ static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
}
static int rsnd_src_init_gen2(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
int ret;
- ret = rsnd_src_init(mod, rdai, io);
+ ret = rsnd_src_init(mod, rdai);
if (ret < 0)
return ret;
- ret = rsnd_src_set_convert_rate_gen2(mod, rdai, io);
+ ret = rsnd_src_set_convert_rate_gen2(mod, rdai);
if (ret < 0)
return ret;
- ret = rsnd_src_set_convert_timing_gen2(mod, rdai, io);
+ ret = rsnd_src_set_convert_timing_gen2(mod, rdai);
if (ret < 0)
return ret;
@@ -587,22 +534,22 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod,
}
static int rsnd_src_start_gen2(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct rsnd_src *src = rsnd_mod_to_src(mod);
+ u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11;
rsnd_dma_start(rsnd_mod_to_dma(&src->mod));
rsnd_mod_write(mod, SSI_CTRL, 0x1);
- rsnd_mod_write(mod, SRC_CTRL, 0x11);
+ rsnd_mod_write(mod, SRC_CTRL, val);
- return rsnd_src_start(mod, rdai, io);
+ return rsnd_src_start(mod, rdai);
}
static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
@@ -611,7 +558,7 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
rsnd_dma_stop(rsnd_mod_to_dma(&src->mod));
- return rsnd_src_stop(mod, rdai, io);
+ return rsnd_src_stop(mod, rdai);
}
static struct rsnd_mod_ops rsnd_src_gen2_ops = {
@@ -699,11 +646,6 @@ int rsnd_src_probe(struct platform_device *pdev,
snprintf(name, RSND_SRC_NAME_SIZE, "src.%d", i);
clk = devm_clk_get(dev, name);
- if (IS_ERR(clk)) {
- snprintf(name, RSND_SRC_NAME_SIZE, "scu.%d", i);
- clk = devm_clk_get(dev, name);
- }
-
if (IS_ERR(clk))
return PTR_ERR(clk);
@@ -711,12 +653,10 @@ int rsnd_src_probe(struct platform_device *pdev,
src->clk = clk;
ops = &rsnd_src_non_ops;
- if (rsnd_src_hpbif_is_enable(src)) {
- if (rsnd_is_gen1(priv))
- ops = &rsnd_src_gen1_ops;
- if (rsnd_is_gen2(priv))
- ops = &rsnd_src_gen2_ops;
- }
+ if (rsnd_is_gen1(priv))
+ ops = &rsnd_src_gen1_ops;
+ if (rsnd_is_gen2(priv))
+ ops = &rsnd_src_gen2_ops;
rsnd_mod_init(priv, &src->mod, ops, RSND_MOD_SRC, i);
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 4b7e20603dd7..36654bd4e428 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -171,7 +171,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
u32 cr;
if (0 == ssi->usrcnt) {
- clk_enable(ssi->clk);
+ clk_prepare_enable(ssi->clk);
if (rsnd_dai_is_clk_master(rdai)) {
if (rsnd_ssi_clk_from_parent(ssi))
@@ -230,7 +230,7 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
rsnd_ssi_master_clk_stop(ssi);
}
- clk_disable(ssi->clk);
+ clk_disable_unprepare(ssi->clk);
}
dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod));
@@ -240,10 +240,10 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
* SSI mod common functions
*/
static int rsnd_ssi_init(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
u32 cr;
@@ -287,14 +287,13 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
ssi->cr_own = cr;
ssi->err = -1; /* ignore 1st error */
- rsnd_src_ssi_mode_init(mod, rdai, io);
+ rsnd_src_ssi_mode_init(mod, rdai);
return 0;
}
static int rsnd_ssi_quit(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
@@ -359,8 +358,7 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
}
static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
@@ -379,15 +377,15 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
}
static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
/* enable PIO IRQ */
ssi->cr_etc = UIEN | OIEN | DIEN;
- rsnd_src_enable_ssi_irq(mod, rdai, io);
+ rsnd_src_enable_ssi_irq(mod, rdai);
rsnd_ssi_hw_start(ssi, rdai, io);
@@ -395,8 +393,7 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
}
static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
@@ -417,25 +414,17 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
};
static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
struct device *dev = rsnd_priv_to_dev(priv);
int dma_id = ssi->info->dma_id;
- int is_play;
int ret;
- if (info->dai_info)
- is_play = rsnd_info_is_playback(priv, ssi);
- else
- is_play = rsnd_ssi_is_play(&ssi->mod);
-
ret = rsnd_dma_init(
priv, rsnd_mod_to_dma(mod),
- is_play,
+ rsnd_info_is_playback(priv, ssi),
dma_id);
if (ret < 0)
@@ -445,8 +434,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
}
static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod));
@@ -454,11 +442,11 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
}
static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
/* enable DMA transfer */
ssi->cr_etc = DMEN;
@@ -475,8 +463,7 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
}
static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai *rdai)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
@@ -512,41 +499,6 @@ static struct rsnd_mod_ops rsnd_ssi_non_ops = {
/*
* ssi mod function
*/
-struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
- int dai_id, int is_play)
-{
- struct rsnd_dai_platform_info *dai_info = NULL;
- struct rsnd_dai_path_info *path_info = NULL;
- struct rsnd_ssi_platform_info *target_info = NULL;
- struct rsnd_ssi *ssi;
- int i, has_play;
-
- if (priv->rdai)
- dai_info = priv->rdai[dai_id].info;
- if (dai_info)
- path_info = (is_play) ? &dai_info->playback : &dai_info->capture;
- if (path_info)
- target_info = path_info->ssi;
-
- is_play = !!is_play;
-
- for_each_rsnd_ssi(ssi, priv, i) {
- if (target_info == ssi->info)
- return &ssi->mod;
-
- /* for compatible */
- if (rsnd_ssi_dai_id(ssi) != dai_id)
- continue;
-
- has_play = rsnd_ssi_is_play(&ssi->mod);
-
- if (is_play == has_play)
- return &ssi->mod;
- }
-
- return NULL;
-}
-
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
{
if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
@@ -562,13 +514,6 @@ int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
}
-int rsnd_ssi_is_play(struct rsnd_mod *mod)
-{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
- return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY);
-}
-
static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi)
{
if (!rsnd_ssi_is_pin_sharing(&ssi->mod))
diff --git a/sound/soc/sirf/sirf-audio-port.c b/sound/soc/sirf/sirf-audio-port.c
index b04a53f2b4f6..b4afa31b2bc1 100644
--- a/sound/soc/sirf/sirf-audio-port.c
+++ b/sound/soc/sirf/sirf-audio-port.c
@@ -6,60 +6,15 @@
* Licensed under GPLv2 or later.
*/
#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/regmap.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
-#include "sirf-audio-port.h"
-
struct sirf_audio_port {
struct regmap *regmap;
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct snd_dmaengine_dai_dma_data capture_dma_data;
};
-static void sirf_audio_port_tx_enable(struct sirf_audio_port *port)
-{
- regmap_update_bits(port->regmap, AUDIO_PORT_IC_TXFIFO_OP,
- AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
- regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0);
- regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
- regmap_update_bits(port->regmap, AUDIO_PORT_IC_TXFIFO_OP,
- AUDIO_FIFO_START, AUDIO_FIFO_START);
- regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_TX_CTRL,
- IC_TX_ENABLE, IC_TX_ENABLE);
-}
-
-static void sirf_audio_port_tx_disable(struct sirf_audio_port *port)
-{
- regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
- regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_TX_CTRL,
- IC_TX_ENABLE, ~IC_TX_ENABLE);
-}
-
-static void sirf_audio_port_rx_enable(struct sirf_audio_port *port,
- int channels)
-{
- regmap_update_bits(port->regmap, AUDIO_PORT_IC_RXFIFO_OP,
- AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
- regmap_write(port->regmap, AUDIO_PORT_IC_RXFIFO_INT_MSK, 0);
- regmap_write(port->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0);
- regmap_update_bits(port->regmap, AUDIO_PORT_IC_RXFIFO_OP,
- AUDIO_FIFO_START, AUDIO_FIFO_START);
- if (channels == 1)
- regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL,
- IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO);
- else
- regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL,
- IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO);
-}
-
-static void sirf_audio_port_rx_disable(struct sirf_audio_port *port)
-{
- regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL,
- IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO);
-}
static int sirf_audio_port_dai_probe(struct snd_soc_dai *dai)
{
@@ -69,41 +24,6 @@ static int sirf_audio_port_dai_probe(struct snd_soc_dai *dai)
return 0;
}
-static int sirf_audio_port_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai);
- int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (playback)
- sirf_audio_port_tx_disable(port);
- else
- sirf_audio_port_rx_disable(port);
- break;
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (playback)
- sirf_audio_port_tx_enable(port);
- else
- sirf_audio_port_rx_enable(port,
- substream->runtime->channels);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static const struct snd_soc_dai_ops sirf_audio_port_dai_ops = {
- .trigger = sirf_audio_port_trigger,
-};
-
static struct snd_soc_dai_driver sirf_audio_port_dai = {
.probe = sirf_audio_port_dai_probe,
.name = "sirf-audio-port",
@@ -120,49 +40,22 @@ static struct snd_soc_dai_driver sirf_audio_port_dai = {
.rates = SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
- .ops = &sirf_audio_port_dai_ops,
};
static const struct snd_soc_component_driver sirf_audio_port_component = {
.name = "sirf-audio-port",
};
-static const struct regmap_config sirf_audio_port_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK,
- .cache_type = REGCACHE_NONE,
-};
-
static int sirf_audio_port_probe(struct platform_device *pdev)
{
int ret;
struct sirf_audio_port *port;
- void __iomem *base;
- struct resource *mem_res;
port = devm_kzalloc(&pdev->dev,
sizeof(struct sirf_audio_port), GFP_KERNEL);
if (!port)
return -ENOMEM;
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- dev_err(&pdev->dev, "no mem resource?\n");
- return -ENODEV;
- }
-
- base = devm_ioremap(&pdev->dev, mem_res->start,
- resource_size(mem_res));
- if (base == NULL)
- return -ENOMEM;
-
- port->regmap = devm_regmap_init_mmio(&pdev->dev, base,
- &sirf_audio_port_regmap_config);
- if (IS_ERR(port->regmap))
- return PTR_ERR(port->regmap);
-
ret = devm_snd_soc_register_component(&pdev->dev,
&sirf_audio_port_component, &sirf_audio_port_dai, 1);
if (ret)
diff --git a/sound/soc/sirf/sirf-audio-port.h b/sound/soc/sirf/sirf-audio-port.h
deleted file mode 100644
index f32dc54f4499..000000000000
--- a/sound/soc/sirf/sirf-audio-port.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SiRF Audio port controllers define
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- *
- * Licensed under GPLv2 or later.
- */
-
-#ifndef _SIRF_AUDIO_PORT_H
-#define _SIRF_AUDIO_PORT_H
-
-#define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK 0x3F
-#define AUDIO_PORT_TX_FIFO_SC_OFFSET 0
-#define AUDIO_PORT_TX_FIFO_LC_OFFSET 10
-#define AUDIO_PORT_TX_FIFO_HC_OFFSET 20
-
-#define TX_FIFO_SC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
- << AUDIO_PORT_TX_FIFO_SC_OFFSET)
-#define TX_FIFO_LC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
- << AUDIO_PORT_TX_FIFO_LC_OFFSET)
-#define TX_FIFO_HC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
- << AUDIO_PORT_TX_FIFO_HC_OFFSET)
-
-#define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK 0x0F
-#define AUDIO_PORT_RX_FIFO_SC_OFFSET 0
-#define AUDIO_PORT_RX_FIFO_LC_OFFSET 10
-#define AUDIO_PORT_RX_FIFO_HC_OFFSET 20
-
-#define RX_FIFO_SC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
- << AUDIO_PORT_RX_FIFO_SC_OFFSET)
-#define RX_FIFO_LC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
- << AUDIO_PORT_RX_FIFO_LC_OFFSET)
-#define RX_FIFO_HC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
- << AUDIO_PORT_RX_FIFO_HC_OFFSET)
-#define AUDIO_PORT_IC_CODEC_TX_CTRL (0x00F4)
-#define AUDIO_PORT_IC_CODEC_RX_CTRL (0x00F8)
-
-#define AUDIO_PORT_IC_TXFIFO_OP (0x00FC)
-#define AUDIO_PORT_IC_TXFIFO_LEV_CHK (0x0100)
-#define AUDIO_PORT_IC_TXFIFO_STS (0x0104)
-#define AUDIO_PORT_IC_TXFIFO_INT (0x0108)
-#define AUDIO_PORT_IC_TXFIFO_INT_MSK (0x010C)
-
-#define AUDIO_PORT_IC_RXFIFO_OP (0x0110)
-#define AUDIO_PORT_IC_RXFIFO_LEV_CHK (0x0114)
-#define AUDIO_PORT_IC_RXFIFO_STS (0x0118)
-#define AUDIO_PORT_IC_RXFIFO_INT (0x011C)
-#define AUDIO_PORT_IC_RXFIFO_INT_MSK (0x0120)
-
-#define AUDIO_FIFO_START (1 << 0)
-#define AUDIO_FIFO_RESET (1 << 1)
-
-#define AUDIO_FIFO_FULL (1 << 0)
-#define AUDIO_FIFO_EMPTY (1 << 1)
-#define AUDIO_FIFO_OFLOW (1 << 2)
-#define AUDIO_FIFO_UFLOW (1 << 3)
-
-#define IC_TX_ENABLE (0x03)
-#define IC_RX_ENABLE_MONO (0x01)
-#define IC_RX_ENABLE_STEREO (0x03)
-
-#endif /*__SIRF_AUDIO_PORT_H*/
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index bfed3e4c45ff..00e70b6c7da2 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -72,6 +72,9 @@ int snd_soc_cache_init(struct snd_soc_codec *codec)
reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
+ if (!reg_size)
+ return 0;
+
mutex_init(&codec->cache_rw_mutex);
dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n",
@@ -162,8 +165,6 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
i, codec_drv->reg_word_size) == val)
continue;
- WARN_ON(!snd_soc_codec_writable_register(codec, i));
-
ret = snd_soc_write(codec, i, val);
if (ret)
return ret;
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 91083e6a6b38..10f7f1da2aca 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -203,7 +203,6 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
if (platform->driver->compr_ops && platform->driver->compr_ops->free)
platform->driver->compr_ops->free(cstream);
- cpu_dai->runtime = NULL;
if (cstream->direction == SND_COMPRESS_PLAYBACK) {
if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
@@ -317,8 +316,9 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
cmd == SND_COMPR_TRIGGER_DRAIN) {
if (platform->driver->compr_ops &&
- platform->driver->compr_ops->trigger)
- return platform->driver->compr_ops->trigger(cstream, cmd);
+ platform->driver->compr_ops->trigger)
+ return platform->driver->compr_ops->trigger(cstream,
+ cmd);
}
if (cstream->direction == SND_COMPRESS_PLAYBACK)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 051c006281f5..b87d7d882e6d 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -154,22 +154,15 @@ 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 (!snd_soc_codec_readable_register(codec, i))
- continue;
- if (codec->driver->display_register) {
- count += codec->driver->display_register(codec, buf + count,
- PAGE_SIZE - count, i);
- } else {
- /* only support larger than PAGE_SIZE bytes debugfs
- * entries for the default case */
- if (p >= pos) {
- if (total + len >= count - 1)
- break;
- format_register_str(codec, i, buf + total, len);
- total += len;
- }
- p += len;
+ /* only support larger than PAGE_SIZE bytes debugfs
+ * entries for the default case */
+ if (p >= pos) {
+ if (total + len >= count - 1)
+ break;
+ format_register_str(codec, i, buf + total, len);
+ total += len;
}
+ p += len;
}
total = min(total, count - 1);
@@ -663,8 +656,8 @@ int snd_soc_suspend(struct device *dev)
codec->driver->suspend(codec);
codec->suspended = 1;
codec->cache_sync = 1;
- if (codec->using_regmap)
- regcache_mark_dirty(codec->control_data);
+ if (codec->component.regmap)
+ regcache_mark_dirty(codec->component.regmap);
/* deactivate pins to sleep state */
pinctrl_pm_select_sleep_state(codec->dev);
break;
@@ -854,14 +847,47 @@ EXPORT_SYMBOL_GPL(snd_soc_resume);
static const struct snd_soc_dai_ops null_dai_ops = {
};
+static struct snd_soc_codec *soc_find_codec(const struct device_node *codec_of_node,
+ const char *codec_name)
+{
+ struct snd_soc_codec *codec;
+
+ list_for_each_entry(codec, &codec_list, list) {
+ if (codec_of_node) {
+ if (codec->dev->of_node != codec_of_node)
+ continue;
+ } else {
+ if (strcmp(codec->name, codec_name))
+ continue;
+ }
+
+ return codec;
+ }
+
+ return NULL;
+}
+
+static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec,
+ const char *codec_dai_name)
+{
+ struct snd_soc_dai *codec_dai;
+
+ list_for_each_entry(codec_dai, &codec->component.dai_list, list) {
+ if (!strcmp(codec_dai->name, codec_dai_name)) {
+ return codec_dai;
+ }
+ }
+
+ return NULL;
+}
+
static int soc_bind_dai_link(struct snd_soc_card *card, int num)
{
struct snd_soc_dai_link *dai_link = &card->dai_link[num];
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_component *component;
- struct snd_soc_codec *codec;
struct snd_soc_platform *platform;
- struct snd_soc_dai *codec_dai, *cpu_dai;
+ struct snd_soc_dai *cpu_dai;
const char *platform_name;
dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
@@ -889,42 +915,24 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
return -EPROBE_DEFER;
}
- /* Find CODEC from registered CODECs */
- list_for_each_entry(codec, &codec_list, list) {
- if (dai_link->codec_of_node) {
- if (codec->dev->of_node != dai_link->codec_of_node)
- continue;
- } else {
- if (strcmp(codec->name, dai_link->codec_name))
- continue;
- }
-
- rtd->codec = codec;
-
- /*
- * CODEC found, so find CODEC DAI from registered DAIs from
- * this CODEC
- */
- list_for_each_entry(codec_dai, &codec->component.dai_list, list) {
- if (!strcmp(codec_dai->name, dai_link->codec_dai_name)) {
- rtd->codec_dai = codec_dai;
- break;
- }
- }
-
- if (!rtd->codec_dai) {
- dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
- dai_link->codec_dai_name);
- return -EPROBE_DEFER;
- }
- }
-
+ /* Find CODEC from registered list */
+ rtd->codec = soc_find_codec(dai_link->codec_of_node,
+ dai_link->codec_name);
if (!rtd->codec) {
dev_err(card->dev, "ASoC: CODEC %s not registered\n",
dai_link->codec_name);
return -EPROBE_DEFER;
}
+ /* Find CODEC DAI from registered list */
+ rtd->codec_dai = soc_find_codec_dai(rtd->codec,
+ dai_link->codec_dai_name);
+ if (!rtd->codec_dai) {
+ dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
+ dai_link->codec_dai_name);
+ return -EPROBE_DEFER;
+ }
+
/* if there's no platform we match on the empty platform */
platform_name = dai_link->platform_name;
if (!platform_name && !dai_link->platform_of_node)
@@ -995,6 +1003,23 @@ static void soc_remove_codec(struct snd_soc_codec *codec)
module_put(codec->dev->driver->owner);
}
+static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order)
+{
+ int err;
+
+ if (codec_dai && codec_dai->probed &&
+ codec_dai->driver->remove_order == order) {
+ if (codec_dai->driver->remove) {
+ err = codec_dai->driver->remove(codec_dai);
+ if (err < 0)
+ dev_err(codec_dai->dev,
+ "ASoC: failed to remove %s: %d\n",
+ codec_dai->name, err);
+ }
+ codec_dai->probed = 0;
+ }
+}
+
static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
{
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
@@ -1010,18 +1035,7 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
}
/* remove the CODEC DAI */
- if (codec_dai && codec_dai->probed &&
- codec_dai->driver->remove_order == order) {
- if (codec_dai->driver->remove) {
- err = codec_dai->driver->remove(codec_dai);
- if (err < 0)
- dev_err(codec_dai->dev,
- "ASoC: failed to remove %s: %d\n",
- codec_dai->name, err);
- }
- codec_dai->probed = 0;
- list_del(&codec_dai->card_list);
- }
+ soc_remove_codec_dai(codec_dai, order);
/* remove the cpu_dai */
if (cpu_dai && cpu_dai->probed &&
@@ -1034,7 +1048,6 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
cpu_dai->name, err);
}
cpu_dai->probed = 0;
- list_del(&cpu_dai->card_list);
if (!cpu_dai->codec) {
snd_soc_dapm_free(&cpu_dai->dapm);
@@ -1104,10 +1117,12 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
for (i = 0; i < card->num_configs; i++) {
struct snd_soc_codec_conf *map = &card->codec_conf[i];
- if (map->dev_name && !strcmp(codec->name, map->dev_name)) {
- codec->name_prefix = map->name_prefix;
- break;
- }
+ if (map->of_node && codec->dev->of_node != map->of_node)
+ continue;
+ if (map->dev_name && strcmp(codec->name, map->dev_name))
+ continue;
+ codec->name_prefix = map->name_prefix;
+ break;
}
}
@@ -1127,26 +1142,31 @@ static int soc_probe_codec(struct snd_soc_card *card,
soc_init_codec_debugfs(codec);
- if (driver->dapm_widgets)
- snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
- driver->num_dapm_widgets);
+ if (driver->dapm_widgets) {
+ ret = snd_soc_dapm_new_controls(&codec->dapm,
+ driver->dapm_widgets,
+ driver->num_dapm_widgets);
- /* Create DAPM widgets for each DAI stream */
- list_for_each_entry(dai, &codec->component.dai_list, list)
- snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to create new controls %d\n", ret);
+ goto err_probe;
+ }
+ }
- codec->dapm.idle_bias_off = driver->idle_bias_off;
+ /* Create DAPM widgets for each DAI stream */
+ list_for_each_entry(dai, &codec->component.dai_list, list) {
+ ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
- if (!codec->write && dev_get_regmap(codec->dev, NULL)) {
- /* Set the default I/O up try regmap */
- ret = snd_soc_codec_set_cache_io(codec, NULL);
- if (ret < 0) {
+ if (ret != 0) {
dev_err(codec->dev,
- "Failed to set cache I/O: %d\n", ret);
+ "Failed to create DAI widgets %d\n", ret);
goto err_probe;
}
}
+ codec->dapm.idle_bias_off = driver->idle_bias_off;
+
if (driver->probe) {
ret = driver->probe(codec);
if (ret < 0) {
@@ -1246,6 +1266,50 @@ static void rtd_release(struct device *dev)
kfree(dev);
}
+static int soc_aux_dev_init(struct snd_soc_card *card,
+ struct snd_soc_codec *codec,
+ int num)
+{
+ struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+ struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
+ int ret;
+
+ rtd->card = card;
+
+ /* do machine specific initialization */
+ if (aux_dev->init) {
+ ret = aux_dev->init(&codec->dapm);
+ if (ret < 0)
+ return ret;
+ }
+
+ rtd->codec = codec;
+
+ return 0;
+}
+
+static int soc_dai_link_init(struct snd_soc_card *card,
+ struct snd_soc_codec *codec,
+ int num)
+{
+ struct snd_soc_dai_link *dai_link = &card->dai_link[num];
+ struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+ int ret;
+
+ rtd->card = card;
+
+ /* do machine specific initialization */
+ if (dai_link->init) {
+ ret = dai_link->init(rtd);
+ if (ret < 0)
+ return ret;
+ }
+
+ rtd->codec = codec;
+
+ return 0;
+}
+
static int soc_post_component_init(struct snd_soc_card *card,
struct snd_soc_codec *codec,
int num, int dailess)
@@ -1260,26 +1324,20 @@ static int soc_post_component_init(struct snd_soc_card *card,
dai_link = &card->dai_link[num];
rtd = &card->rtd[num];
name = dai_link->name;
+ ret = soc_dai_link_init(card, codec, num);
} else {
aux_dev = &card->aux_dev[num];
rtd = &card->rtd_aux[num];
name = aux_dev->name;
+ ret = soc_aux_dev_init(card, codec, num);
}
- rtd->card = card;
- /* do machine specific initialization */
- if (!dailess && dai_link->init)
- ret = dai_link->init(rtd);
- else if (dailess && aux_dev->init)
- ret = aux_dev->init(&codec->dapm);
if (ret < 0) {
dev_err(card->dev, "ASoC: failed to init %s: %d\n", name, ret);
return ret;
}
/* register the rtd device */
- rtd->codec = codec;
-
rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
if (!rtd->dev)
return -ENOMEM;
@@ -1366,6 +1424,66 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num,
return 0;
}
+static int soc_probe_codec_dai(struct snd_soc_card *card,
+ struct snd_soc_dai *codec_dai,
+ int order)
+{
+ int ret;
+
+ if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
+ if (codec_dai->driver->probe) {
+ ret = codec_dai->driver->probe(codec_dai);
+ if (ret < 0) {
+ dev_err(codec_dai->dev,
+ "ASoC: failed to probe CODEC DAI %s: %d\n",
+ codec_dai->name, ret);
+ return ret;
+ }
+ }
+
+ /* mark codec_dai as probed and add to card dai list */
+ codec_dai->probed = 1;
+ }
+
+ return 0;
+}
+
+static int soc_link_dai_widgets(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link,
+ struct snd_soc_dai *cpu_dai,
+ struct snd_soc_dai *codec_dai)
+{
+ struct snd_soc_dapm_widget *play_w, *capture_w;
+ int ret;
+
+ /* link the DAI widgets */
+ play_w = codec_dai->playback_widget;
+ capture_w = cpu_dai->capture_widget;
+ if (play_w && capture_w) {
+ ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+ capture_w, play_w);
+ if (ret != 0) {
+ dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
+ play_w->name, capture_w->name, ret);
+ return ret;
+ }
+ }
+
+ play_w = cpu_dai->playback_widget;
+ capture_w = codec_dai->capture_widget;
+ if (play_w && capture_w) {
+ ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+ capture_w, play_w);
+ if (ret != 0) {
+ dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
+ play_w->name, capture_w->name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
{
struct snd_soc_dai_link *dai_link = &card->dai_link[num];
@@ -1374,7 +1492,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dapm_widget *play_w, *capture_w;
int ret;
dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
@@ -1410,26 +1527,12 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
}
}
cpu_dai->probed = 1;
- /* mark cpu_dai as probed and add to card dai list */
- list_add(&cpu_dai->card_list, &card->dai_dev_list);
}
/* probe the CODEC DAI */
- if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
- if (codec_dai->driver->probe) {
- ret = codec_dai->driver->probe(codec_dai);
- if (ret < 0) {
- dev_err(codec_dai->dev,
- "ASoC: failed to probe CODEC DAI %s: %d\n",
- codec_dai->name, ret);
- return ret;
- }
- }
-
- /* mark codec_dai as probed and add to card dai list */
- codec_dai->probed = 1;
- list_add(&codec_dai->card_list, &card->dai_dev_list);
- }
+ ret = soc_probe_codec_dai(card, codec_dai, order);
+ if (ret)
+ return ret;
/* complete DAI probe during last probe */
if (order != SND_SOC_COMP_ORDER_LAST)
@@ -1467,29 +1570,10 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
codec2codec_close_delayed_work);
/* link the DAI widgets */
- play_w = codec_dai->playback_widget;
- capture_w = cpu_dai->capture_widget;
- if (play_w && capture_w) {
- ret = snd_soc_dapm_new_pcm(card, dai_link->params,
- capture_w, play_w);
- if (ret != 0) {
- dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
- play_w->name, capture_w->name, ret);
- return ret;
- }
- }
-
- play_w = cpu_dai->playback_widget;
- capture_w = codec_dai->capture_widget;
- if (play_w && capture_w) {
- ret = snd_soc_dapm_new_pcm(card, dai_link->params,
- capture_w, play_w);
- if (ret != 0) {
- dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
- play_w->name, capture_w->name, ret);
- return ret;
- }
- }
+ ret = soc_link_dai_widgets(card, dai_link,
+ cpu_dai, codec_dai);
+ if (ret)
+ return ret;
}
}
@@ -1501,14 +1585,15 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
}
#ifdef CONFIG_SND_SOC_AC97_BUS
-static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
+static int soc_register_ac97_codec(struct snd_soc_codec *codec,
+ struct snd_soc_dai *codec_dai)
{
int ret;
/* Only instantiate AC97 if not already done by the adaptor
* for the generic AC97 subsystem.
*/
- if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) {
+ if (codec_dai->driver->ac97_control && !codec->ac97_registered) {
/*
* It is possible that the AC97 device is already registered to
* the device subsystem. This happens when the device is created
@@ -1517,76 +1602,101 @@ static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
*
* In those cases we don't try to register the device again.
*/
- if (!rtd->codec->ac97_created)
+ if (!codec->ac97_created)
return 0;
- ret = soc_ac97_dev_register(rtd->codec);
+ ret = soc_ac97_dev_register(codec);
if (ret < 0) {
- dev_err(rtd->codec->dev,
+ dev_err(codec->dev,
"ASoC: AC97 device register failed: %d\n", ret);
return ret;
}
- rtd->codec->ac97_registered = 1;
+ codec->ac97_registered = 1;
}
return 0;
}
-static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
+static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
+{
+ return soc_register_ac97_codec(rtd->codec, rtd->codec_dai);
+}
+
+static void soc_unregister_ac97_codec(struct snd_soc_codec *codec)
{
if (codec->ac97_registered) {
soc_ac97_dev_unregister(codec);
codec->ac97_registered = 0;
}
}
+
+static void soc_unregister_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
+{
+ soc_unregister_ac97_codec(rtd->codec);
+}
#endif
-static int soc_check_aux_dev(struct snd_soc_card *card, int num)
+static struct snd_soc_codec *soc_find_matching_codec(struct snd_soc_card *card,
+ int num)
{
struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
struct snd_soc_codec *codec;
- /* find CODEC from registered CODECs*/
+ /* find CODEC from registered CODECs */
list_for_each_entry(codec, &codec_list, list) {
- if (!strcmp(codec->name, aux_dev->codec_name))
- return 0;
+ if (aux_dev->codec_of_node &&
+ (codec->dev->of_node != aux_dev->codec_of_node))
+ continue;
+ if (aux_dev->codec_name && strcmp(codec->name, aux_dev->codec_name))
+ continue;
+ return codec;
}
- dev_err(card->dev, "ASoC: %s not registered\n", aux_dev->codec_name);
+ return NULL;
+}
+static int soc_check_aux_dev(struct snd_soc_card *card, int num)
+{
+ struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+ const char *codecname = aux_dev->codec_name;
+ struct snd_soc_codec *codec = soc_find_matching_codec(card, num);
+
+ if (codec)
+ return 0;
+ if (aux_dev->codec_of_node)
+ codecname = of_node_full_name(aux_dev->codec_of_node);
+
+ dev_err(card->dev, "ASoC: %s not registered\n", codecname);
return -EPROBE_DEFER;
}
static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
{
struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
- struct snd_soc_codec *codec;
+ const char *codecname = aux_dev->codec_name;
int ret = -ENODEV;
+ struct snd_soc_codec *codec = soc_find_matching_codec(card, num);
- /* find CODEC from registered CODECs*/
- list_for_each_entry(codec, &codec_list, list) {
- if (!strcmp(codec->name, aux_dev->codec_name)) {
- if (codec->probed) {
- dev_err(codec->dev,
- "ASoC: codec already probed");
- ret = -EBUSY;
- goto out;
- }
- goto found;
- }
+ if (!codec) {
+ if (aux_dev->codec_of_node)
+ codecname = of_node_full_name(aux_dev->codec_of_node);
+
+ /* codec not found */
+ dev_err(card->dev, "ASoC: codec %s not found", codecname);
+ return -EPROBE_DEFER;
+ }
+
+ if (codec->probed) {
+ dev_err(codec->dev, "ASoC: codec already probed");
+ return -EBUSY;
}
- /* codec not found */
- dev_err(card->dev, "ASoC: codec %s not found", aux_dev->codec_name);
- return -EPROBE_DEFER;
-found:
ret = soc_probe_codec(card, codec);
if (ret < 0)
return ret;
ret = soc_post_component_init(card, codec, num, 1);
-out:
return ret;
}
@@ -1837,7 +1947,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
dev_err(card->dev,
"ASoC: failed to register AC97: %d\n", ret);
while (--i >= 0)
- soc_unregister_ac97_dai_link(card->rtd[i].codec);
+ soc_unregister_ac97_dai_link(&card->rtd[i]);
goto probe_aux_dev_err;
}
}
@@ -1980,92 +2090,6 @@ static struct platform_driver soc_driver = {
};
/**
- * snd_soc_codec_volatile_register: Report if a register is volatile.
- *
- * @codec: CODEC to query.
- * @reg: Register to query.
- *
- * Boolean function indiciating if a CODEC register is volatile.
- */
-int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- if (codec->volatile_register)
- return codec->volatile_register(codec, reg);
- else
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register);
-
-/**
- * snd_soc_codec_readable_register: Report if a register is readable.
- *
- * @codec: CODEC to query.
- * @reg: Register to query.
- *
- * Boolean function indicating if a CODEC register is readable.
- */
-int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- if (codec->readable_register)
- return codec->readable_register(codec, reg);
- else
- return 1;
-}
-EXPORT_SYMBOL_GPL(snd_soc_codec_readable_register);
-
-/**
- * snd_soc_codec_writable_register: Report if a register is writable.
- *
- * @codec: CODEC to query.
- * @reg: Register to query.
- *
- * Boolean function indicating if a CODEC register is writable.
- */
-int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- if (codec->writable_register)
- return codec->writable_register(codec, reg);
- else
- return 1;
-}
-EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register);
-
-int snd_soc_platform_read(struct snd_soc_platform *platform,
- unsigned int reg)
-{
- unsigned int ret;
-
- if (!platform->driver->read) {
- dev_err(platform->dev, "ASoC: platform has no read back\n");
- return -1;
- }
-
- ret = platform->driver->read(platform, reg);
- dev_dbg(platform->dev, "read %x => %x\n", reg, ret);
- trace_snd_soc_preg_read(platform, reg, ret);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_platform_read);
-
-int snd_soc_platform_write(struct snd_soc_platform *platform,
- unsigned int reg, unsigned int val)
-{
- if (!platform->driver->write) {
- dev_err(platform->dev, "ASoC: platform has no write back\n");
- return -1;
- }
-
- dev_dbg(platform->dev, "write %x = %x\n", reg, val);
- trace_snd_soc_preg_write(platform, reg, val);
- return platform->driver->write(platform, reg, val);
-}
-EXPORT_SYMBOL_GPL(snd_soc_platform_write);
-
-/**
* snd_soc_new_ac97_codec - initailise AC97 device
* @codec: audio codec
* @ops: AC97 bus operations
@@ -2153,28 +2177,28 @@ static int snd_soc_ac97_parse_pinctl(struct device *dev,
p = devm_pinctrl_get(dev);
if (IS_ERR(p)) {
dev_err(dev, "Failed to get pinctrl\n");
- return PTR_RET(p);
+ return PTR_ERR(p);
}
cfg->pctl = p;
state = pinctrl_lookup_state(p, "ac97-reset");
if (IS_ERR(state)) {
dev_err(dev, "Can't find pinctrl state ac97-reset\n");
- return PTR_RET(state);
+ return PTR_ERR(state);
}
cfg->pstate_reset = state;
state = pinctrl_lookup_state(p, "ac97-warm-reset");
if (IS_ERR(state)) {
dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n");
- return PTR_RET(state);
+ return PTR_ERR(state);
}
cfg->pstate_warm_reset = state;
state = pinctrl_lookup_state(p, "ac97-running");
if (IS_ERR(state)) {
dev_err(dev, "Can't find pinctrl state ac97-running\n");
- return PTR_RET(state);
+ return PTR_ERR(state);
}
cfg->pstate_run = state;
@@ -2273,7 +2297,7 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
{
mutex_lock(&codec->mutex);
#ifdef CONFIG_SND_SOC_AC97_BUS
- soc_unregister_ac97_dai_link(codec);
+ soc_unregister_ac97_codec(codec);
#endif
kfree(codec->ac97->bus);
kfree(codec->ac97);
@@ -2283,118 +2307,6 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
}
EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
-unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg)
-{
- unsigned int ret;
-
- ret = codec->read(codec, reg);
- dev_dbg(codec->dev, "read %x => %x\n", reg, ret);
- trace_snd_soc_reg_read(codec, reg, ret);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_read);
-
-unsigned int snd_soc_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int val)
-{
- dev_dbg(codec->dev, "write %x = %x\n", reg, val);
- trace_snd_soc_reg_write(codec, reg, val);
- return codec->write(codec, reg, val);
-}
-EXPORT_SYMBOL_GPL(snd_soc_write);
-
-/**
- * snd_soc_update_bits - update codec register bits
- * @codec: audio codec
- * @reg: codec register
- * @mask: register mask
- * @value: new value
- *
- * Writes new register value.
- *
- * Returns 1 for change, 0 for no change, or negative error code.
- */
-int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
- unsigned int mask, unsigned int value)
-{
- bool change;
- unsigned int old, new;
- int ret;
-
- if (codec->using_regmap) {
- ret = regmap_update_bits_check(codec->control_data, reg,
- mask, value, &change);
- } else {
- ret = snd_soc_read(codec, reg);
- if (ret < 0)
- return ret;
-
- old = ret;
- new = (old & ~mask) | (value & mask);
- change = old != new;
- if (change)
- ret = snd_soc_write(codec, reg, new);
- }
-
- if (ret < 0)
- return ret;
-
- return change;
-}
-EXPORT_SYMBOL_GPL(snd_soc_update_bits);
-
-/**
- * snd_soc_update_bits_locked - update codec register bits
- * @codec: audio codec
- * @reg: codec register
- * @mask: register mask
- * @value: new value
- *
- * Writes new register value, and takes the codec mutex.
- *
- * Returns 1 for change else 0.
- */
-int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
- unsigned short reg, unsigned int mask,
- unsigned int value)
-{
- int change;
-
- mutex_lock(&codec->mutex);
- change = snd_soc_update_bits(codec, reg, mask, value);
- mutex_unlock(&codec->mutex);
-
- return change;
-}
-EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked);
-
-/**
- * snd_soc_test_bits - test register for change
- * @codec: audio codec
- * @reg: codec register
- * @mask: register mask
- * @value: new value
- *
- * Tests a register with a new value and checks if the new value is
- * different from the old value.
- *
- * Returns 1 for change else 0.
- */
-int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
- unsigned int mask, unsigned int value)
-{
- int change;
- unsigned int old, new;
-
- old = snd_soc_read(codec, reg);
- new = (old & ~mask) | value;
- change = old != new;
-
- return change;
-}
-EXPORT_SYMBOL_GPL(snd_soc_test_bits);
-
/**
* snd_soc_cnew - create new control
* @_template: control template
@@ -2491,7 +2403,7 @@ int snd_soc_add_codec_controls(struct snd_soc_codec *codec,
struct snd_card *card = codec->card->snd_card;
return snd_soc_add_controls(card, codec->dev, controls, num_controls,
- codec->name_prefix, codec);
+ codec->name_prefix, &codec->component);
}
EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls);
@@ -2511,7 +2423,7 @@ int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
struct snd_card *card = platform->card->snd_card;
return snd_soc_add_controls(card, platform->dev, controls, num_controls,
- NULL, platform);
+ NULL, &platform->component);
}
EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls);
@@ -2595,12 +2507,15 @@ EXPORT_SYMBOL_GPL(snd_soc_info_enum_double);
int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, item;
unsigned int reg_val;
+ int ret;
- reg_val = snd_soc_read(codec, e->reg);
+ ret = snd_soc_component_read(component, e->reg, &reg_val);
+ if (ret)
+ return ret;
val = (reg_val >> e->shift_l) & e->mask;
item = snd_soc_enum_val_to_item(e, val);
ucontrol->value.enumerated.item[0] = item;
@@ -2626,7 +2541,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_enum_double);
int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
unsigned int val;
@@ -2643,38 +2558,48 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
mask |= e->mask << e->shift_r;
}
- return snd_soc_update_bits_locked(codec, e->reg, mask, val);
+ return snd_soc_component_update_bits(component, e->reg, mask, val);
}
EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
/**
* snd_soc_read_signed - Read a codec register and interprete as signed value
- * @codec: codec
+ * @component: component
* @reg: Register to read
* @mask: Mask to use after shifting the register value
* @shift: Right shift of register value
* @sign_bit: Bit that describes if a number is negative or not.
+ * @signed_val: Pointer to where the read value should be stored
*
* This functions reads a codec register. The register value is shifted right
* by 'shift' bits and masked with the given 'mask'. Afterwards it translates
* the given registervalue into a signed integer if sign_bit is non-zero.
*
- * Returns the register value as signed int.
+ * Returns 0 on sucess, otherwise an error value
*/
-static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int mask, unsigned int shift, unsigned int sign_bit)
+static int snd_soc_read_signed(struct snd_soc_component *component,
+ unsigned int reg, unsigned int mask, unsigned int shift,
+ unsigned int sign_bit, int *signed_val)
{
int ret;
unsigned int val;
- val = (snd_soc_read(codec, reg) >> shift) & mask;
+ ret = snd_soc_component_read(component, reg, &val);
+ if (ret < 0)
+ return ret;
- if (!sign_bit)
- return val;
+ val = (val >> shift) & mask;
+
+ if (!sign_bit) {
+ *signed_val = val;
+ return 0;
+ }
/* non-negative number */
- if (!(val & BIT(sign_bit)))
- return val;
+ if (!(val & BIT(sign_bit))) {
+ *signed_val = val;
+ return 0;
+ }
ret = val;
@@ -2686,7 +2611,9 @@ static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg,
*/
ret |= ~((int)(BIT(sign_bit) - 1));
- return ret;
+ *signed_val = ret;
+
+ return 0;
}
/**
@@ -2735,9 +2662,9 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
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;
@@ -2747,25 +2674,32 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
int sign_bit = mc->sign_bit;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
+ int val;
+ int ret;
if (sign_bit)
mask = BIT(sign_bit + 1) - 1;
- ucontrol->value.integer.value[0] = snd_soc_read_signed(codec, reg, mask,
- shift, sign_bit) - min;
+ ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[0] = val - min;
if (invert)
ucontrol->value.integer.value[0] =
max - ucontrol->value.integer.value[0];
if (snd_soc_volsw_is_stereo(mc)) {
if (reg == reg2)
- ucontrol->value.integer.value[1] =
- snd_soc_read_signed(codec, reg, mask, rshift,
- sign_bit) - min;
+ ret = snd_soc_read_signed(component, reg, mask, rshift,
+ sign_bit, &val);
else
- ucontrol->value.integer.value[1] =
- snd_soc_read_signed(codec, reg2, mask, shift,
- sign_bit) - min;
+ ret = snd_soc_read_signed(component, reg2, mask, shift,
+ sign_bit, &val);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[1] = val - min;
if (invert)
ucontrol->value.integer.value[1] =
max - ucontrol->value.integer.value[1];
@@ -2788,9 +2722,9 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
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;
@@ -2825,12 +2759,13 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
type_2r = true;
}
}
- err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
+ err = snd_soc_component_update_bits(component, reg, val_mask, val);
if (err < 0)
return err;
if (type_2r)
- err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2);
+ err = snd_soc_component_update_bits(component, reg2, val_mask,
+ val2);
return err;
}
@@ -2849,10 +2784,9 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
-
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
@@ -2860,13 +2794,23 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
int max = mc->max;
int min = mc->min;
int mask = (1 << (fls(min + max) - 1)) - 1;
+ unsigned int val;
+ int ret;
- ucontrol->value.integer.value[0] =
- ((snd_soc_read(codec, reg) >> shift) - min) & mask;
+ ret = snd_soc_component_read(component, reg, &val);
+ if (ret < 0)
+ return ret;
- if (snd_soc_volsw_is_stereo(mc))
- ucontrol->value.integer.value[1] =
- ((snd_soc_read(codec, reg2) >> rshift) - min) & mask;
+ ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask;
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ ret = snd_soc_component_read(component, reg2, &val);
+ if (ret < 0)
+ return ret;
+
+ val = ((val >> rshift) - min) & mask;
+ ucontrol->value.integer.value[1] = val;
+ }
return 0;
}
@@ -2884,7 +2828,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -2896,13 +2840,13 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
int min = mc->min;
int mask = (1 << (fls(min + max) - 1)) - 1;
int err = 0;
- unsigned short val, val_mask, val2 = 0;
+ unsigned int val, val_mask, val2 = 0;
val_mask = mask << shift;
val = (ucontrol->value.integer.value[0] + min) & mask;
val = val << shift;
- err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
+ err = snd_soc_component_update_bits(component, reg, val_mask, val);
if (err < 0)
return err;
@@ -2911,10 +2855,10 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
val2 = (ucontrol->value.integer.value[1] + min) & mask;
val2 = val2 << rshift;
- if (snd_soc_update_bits_locked(codec, reg2, val_mask, val2))
- return err;
+ err = snd_soc_component_update_bits(component, reg2, val_mask,
+ val2);
}
- return 0;
+ return err;
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx);
@@ -2961,10 +2905,15 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
+ unsigned int val;
int min = mc->min;
- int val = snd_soc_read(codec, reg);
+ int ret;
+
+ ret = snd_soc_component_read(component, reg, &val);
+ if (ret)
+ return ret;
ucontrol->value.integer.value[0] =
((signed char)(val & 0xff))-min;
@@ -2988,7 +2937,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
int min = mc->min;
unsigned int val;
@@ -2996,7 +2945,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
val = (ucontrol->value.integer.value[0]+min) & 0xff;
val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;
- return snd_soc_update_bits_locked(codec, reg, 0xffff, val);
+ return snd_soc_component_update_bits(component, reg, 0xffff, val);
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
@@ -3045,7 +2994,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int rreg = mc->rreg;
unsigned int shift = mc->shift;
@@ -3062,7 +3011,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
val_mask = mask << shift;
val = val << shift;
- ret = snd_soc_update_bits_locked(codec, reg, val_mask, val);
+ ret = snd_soc_component_update_bits(component, reg, val_mask, val);
if (ret < 0)
return ret;
@@ -3073,7 +3022,8 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
val_mask = mask << shift;
val = val << shift;
- ret = snd_soc_update_bits_locked(codec, rreg, val_mask, val);
+ ret = snd_soc_component_update_bits(component, rreg, val_mask,
+ val);
}
return ret;
@@ -3092,9 +3042,9 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range);
int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
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 rreg = mc->rreg;
unsigned int shift = mc->shift;
@@ -3102,9 +3052,14 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
+ unsigned int val;
+ int ret;
- ucontrol->value.integer.value[0] =
- (snd_soc_read(codec, reg) >> shift) & mask;
+ ret = snd_soc_component_read(component, reg, &val);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[0] = (val >> shift) & mask;
if (invert)
ucontrol->value.integer.value[0] =
max - ucontrol->value.integer.value[0];
@@ -3112,8 +3067,11 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] - min;
if (snd_soc_volsw_is_stereo(mc)) {
- ucontrol->value.integer.value[1] =
- (snd_soc_read(codec, rreg) >> shift) & mask;
+ ret = snd_soc_component_read(component, rreg, &val);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[1] = (val >> shift) & mask;
if (invert)
ucontrol->value.integer.value[1] =
max - ucontrol->value.integer.value[1];
@@ -3167,11 +3125,11 @@ EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_bytes *params = (void *)kcontrol->private_value;
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
- uinfo->count = params->num_regs * codec->val_bytes;
+ uinfo->count = params->num_regs * component->val_bytes;
return 0;
}
@@ -3180,20 +3138,20 @@ EXPORT_SYMBOL_GPL(snd_soc_bytes_info);
int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_bytes *params = (void *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int ret;
- if (codec->using_regmap)
- ret = regmap_raw_read(codec->control_data, params->base,
+ if (component->regmap)
+ ret = regmap_raw_read(component->regmap, params->base,
ucontrol->value.bytes.data,
- params->num_regs * codec->val_bytes);
+ params->num_regs * component->val_bytes);
else
ret = -EINVAL;
/* Hide any masked bytes to ensure consistent data reporting */
if (ret == 0 && params->mask) {
- switch (codec->val_bytes) {
+ switch (component->val_bytes) {
case 1:
ucontrol->value.bytes.data[0] &= ~params->mask;
break;
@@ -3217,16 +3175,16 @@ EXPORT_SYMBOL_GPL(snd_soc_bytes_get);
int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_bytes *params = (void *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int ret, len;
unsigned int val, mask;
void *data;
- if (!codec->using_regmap)
+ if (!component->regmap)
return -EINVAL;
- len = params->num_regs * codec->val_bytes;
+ len = params->num_regs * component->val_bytes;
data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
if (!data)
@@ -3238,27 +3196,27 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
* copy.
*/
if (params->mask) {
- ret = regmap_read(codec->control_data, params->base, &val);
+ ret = regmap_read(component->regmap, params->base, &val);
if (ret != 0)
goto out;
val &= params->mask;
- switch (codec->val_bytes) {
+ switch (component->val_bytes) {
case 1:
((u8 *)data)[0] &= ~params->mask;
((u8 *)data)[0] |= val;
break;
case 2:
mask = ~params->mask;
- ret = regmap_parse_val(codec->control_data,
+ ret = regmap_parse_val(component->regmap,
&mask, &mask);
if (ret != 0)
goto out;
((u16 *)data)[0] &= mask;
- ret = regmap_parse_val(codec->control_data,
+ ret = regmap_parse_val(component->regmap,
&val, &val);
if (ret != 0)
goto out;
@@ -3267,14 +3225,14 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
break;
case 4:
mask = ~params->mask;
- ret = regmap_parse_val(codec->control_data,
+ ret = regmap_parse_val(component->regmap,
&mask, &mask);
if (ret != 0)
goto out;
((u32 *)data)[0] &= mask;
- ret = regmap_parse_val(codec->control_data,
+ ret = regmap_parse_val(component->regmap,
&val, &val);
if (ret != 0)
goto out;
@@ -3287,7 +3245,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
}
}
- ret = regmap_raw_write(codec->control_data, params->base,
+ ret = regmap_raw_write(component->regmap, params->base,
data, len);
out:
@@ -3297,6 +3255,18 @@ out:
}
EXPORT_SYMBOL_GPL(snd_soc_bytes_put);
+int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *ucontrol)
+{
+ struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+
+ ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ ucontrol->count = params->max;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext);
+
/**
* snd_soc_info_xr_sx - signed multi register info callback
* @kcontrol: mreg control
@@ -3338,24 +3308,27 @@ EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx);
int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int regbase = mc->regbase;
unsigned int regcount = mc->regcount;
- unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE;
+ unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
unsigned int regwmask = (1<<regwshift)-1;
unsigned int invert = mc->invert;
unsigned long mask = (1UL<<mc->nbits)-1;
long min = mc->min;
long max = mc->max;
long val = 0;
- unsigned long regval;
+ unsigned int regval;
unsigned int i;
+ int ret;
for (i = 0; i < regcount; i++) {
- regval = snd_soc_read(codec, regbase+i) & regwmask;
- val |= regval << (regwshift*(regcount-i-1));
+ ret = snd_soc_component_read(component, regbase+i, &regval);
+ if (ret)
+ return ret;
+ val |= (regval & regwmask) << (regwshift*(regcount-i-1));
}
val &= mask;
if (min < 0 && val > max)
@@ -3384,12 +3357,12 @@ EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx);
int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int regbase = mc->regbase;
unsigned int regcount = mc->regcount;
- unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE;
+ unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
unsigned int regwmask = (1<<regwshift)-1;
unsigned int invert = mc->invert;
unsigned long mask = (1UL<<mc->nbits)-1;
@@ -3404,7 +3377,7 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
for (i = 0; i < regcount; i++) {
regval = (val >> (regwshift*(regcount-i-1))) & regwmask;
regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask;
- err = snd_soc_update_bits_locked(codec, regbase+i,
+ err = snd_soc_component_update_bits(component, regbase+i,
regmask, regval);
if (err < 0)
return err;
@@ -3426,14 +3399,21 @@ EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx);
int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
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 shift = mc->shift;
unsigned int mask = 1 << shift;
unsigned int invert = mc->invert != 0;
- unsigned int val = snd_soc_read(codec, reg) & mask;
+ unsigned int val;
+ int ret;
+
+ ret = snd_soc_component_read(component, reg, &val);
+ if (ret)
+ return ret;
+
+ val &= mask;
if (shift != 0 && val != 0)
val = val >> shift;
@@ -3456,9 +3436,9 @@ EXPORT_SYMBOL_GPL(snd_soc_get_strobe);
int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
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 shift = mc->shift;
unsigned int mask = 1 << shift;
@@ -3468,12 +3448,11 @@ int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
unsigned int val2 = (strobe ^ invert) ? 0 : mask;
int err;
- err = snd_soc_update_bits_locked(codec, reg, mask, val1);
+ err = snd_soc_component_update_bits(component, reg, mask, val1);
if (err < 0)
return err;
- err = snd_soc_update_bits_locked(codec, reg, mask, val2);
- return err;
+ return snd_soc_component_update_bits(component, reg, mask, val2);
}
EXPORT_SYMBOL_GPL(snd_soc_put_strobe);
@@ -3821,7 +3800,6 @@ int snd_soc_register_card(struct snd_soc_card *card)
for (i = 0; i < card->num_links; i++)
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);
@@ -4037,6 +4015,8 @@ __snd_soc_register_component(struct device *dev,
return -ENOMEM;
}
+ mutex_init(&cmpnt->io_mutex);
+
cmpnt->name = fmt_single_name(dev, &cmpnt->id);
if (!cmpnt->name) {
dev_err(dev, "ASoC: Failed to simplifying name\n");
@@ -4084,12 +4064,25 @@ int snd_soc_register_component(struct device *dev,
}
cmpnt->ignore_pmdown_time = true;
+ cmpnt->registered_as_component = true;
return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL,
dai_drv, num_dai, true);
}
EXPORT_SYMBOL_GPL(snd_soc_register_component);
+static void __snd_soc_unregister_component(struct snd_soc_component *cmpnt)
+{
+ snd_soc_unregister_dais(cmpnt);
+
+ mutex_lock(&client_mutex);
+ list_del(&cmpnt->list);
+ mutex_unlock(&client_mutex);
+
+ dev_dbg(cmpnt->dev, "ASoC: Unregistered component '%s'\n", cmpnt->name);
+ kfree(cmpnt->name);
+}
+
/**
* snd_soc_unregister_component - Unregister a component from the ASoC core
*
@@ -4099,22 +4092,33 @@ void snd_soc_unregister_component(struct device *dev)
struct snd_soc_component *cmpnt;
list_for_each_entry(cmpnt, &component_list, list) {
- if (dev == cmpnt->dev)
+ if (dev == cmpnt->dev && cmpnt->registered_as_component)
goto found;
}
return;
found:
- snd_soc_unregister_dais(cmpnt);
+ __snd_soc_unregister_component(cmpnt);
+}
+EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
- mutex_lock(&client_mutex);
- list_del(&cmpnt->list);
- mutex_unlock(&client_mutex);
+static int snd_soc_platform_drv_write(struct snd_soc_component *component,
+ unsigned int reg, unsigned int val)
+{
+ struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
- dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name);
- kfree(cmpnt->name);
+ return platform->driver->write(platform, reg, val);
+}
+
+static int snd_soc_platform_drv_read(struct snd_soc_component *component,
+ unsigned int reg, unsigned int *val)
+{
+ struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
+
+ *val = platform->driver->read(platform, reg);
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
/**
* snd_soc_add_platform - Add a platform to the ASoC core
@@ -4125,6 +4129,8 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
const struct snd_soc_platform_driver *platform_drv)
{
+ int ret;
+
/* create platform component name */
platform->name = fmt_single_name(dev, &platform->id);
if (platform->name == NULL)
@@ -4134,8 +4140,22 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
platform->driver = platform_drv;
platform->dapm.dev = dev;
platform->dapm.platform = platform;
+ platform->dapm.component = &platform->component;
platform->dapm.stream_event = platform_drv->stream_event;
- mutex_init(&platform->mutex);
+ if (platform_drv->write)
+ platform->component.write = snd_soc_platform_drv_write;
+ if (platform_drv->read)
+ platform->component.read = snd_soc_platform_drv_read;
+
+ /* register component */
+ ret = __snd_soc_register_component(dev, &platform->component,
+ &platform_drv->component_driver,
+ NULL, NULL, 0, false);
+ if (ret < 0) {
+ dev_err(platform->component.dev,
+ "ASoC: Failed to register component: %d\n", ret);
+ return ret;
+ }
mutex_lock(&client_mutex);
list_add(&platform->list, &platform_list);
@@ -4178,6 +4198,8 @@ EXPORT_SYMBOL_GPL(snd_soc_register_platform);
*/
void snd_soc_remove_platform(struct snd_soc_platform *platform)
{
+ __snd_soc_unregister_component(&platform->component);
+
mutex_lock(&client_mutex);
list_del(&platform->list);
mutex_unlock(&client_mutex);
@@ -4252,6 +4274,24 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)
stream->formats |= codec_format_map[i];
}
+static int snd_soc_codec_drv_write(struct snd_soc_component *component,
+ unsigned int reg, unsigned int val)
+{
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+ return codec->driver->write(codec, reg, val);
+}
+
+static int snd_soc_codec_drv_read(struct snd_soc_component *component,
+ unsigned int reg, unsigned int *val)
+{
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+ *val = codec->driver->read(codec, reg);
+
+ return 0;
+}
+
/**
* snd_soc_register_codec - Register a codec with the ASoC core
*
@@ -4263,6 +4303,7 @@ int snd_soc_register_codec(struct device *dev,
int num_dai)
{
struct snd_soc_codec *codec;
+ struct regmap *regmap;
int ret, i;
dev_dbg(dev, "codec register %s\n", dev_name(dev));
@@ -4278,22 +4319,40 @@ int snd_soc_register_codec(struct device *dev,
goto fail_codec;
}
- codec->write = codec_drv->write;
- codec->read = codec_drv->read;
- codec->volatile_register = codec_drv->volatile_register;
- codec->readable_register = codec_drv->readable_register;
- codec->writable_register = codec_drv->writable_register;
+ if (codec_drv->write)
+ codec->component.write = snd_soc_codec_drv_write;
+ if (codec_drv->read)
+ codec->component.read = snd_soc_codec_drv_read;
codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
codec->dapm.dev = dev;
codec->dapm.codec = codec;
+ codec->dapm.component = &codec->component;
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;
+ codec->component.val_bytes = codec_drv->reg_word_size;
mutex_init(&codec->mutex);
+ if (!codec->component.write) {
+ if (codec_drv->get_regmap)
+ regmap = codec_drv->get_regmap(dev);
+ else
+ regmap = dev_get_regmap(dev, NULL);
+
+ if (regmap) {
+ ret = snd_soc_component_init_io(&codec->component,
+ regmap);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to set cache I/O:%d\n",
+ ret);
+ return ret;
+ }
+ }
+ }
+
for (i = 0; i < num_dai; i++) {
fixup_codec_formats(&dai_drv[i].playback);
fixup_codec_formats(&dai_drv[i].capture);
@@ -4343,7 +4402,7 @@ void snd_soc_unregister_codec(struct device *dev)
return;
found:
- snd_soc_unregister_component(dev);
+ __snd_soc_unregister_component(&codec->component);
mutex_lock(&client_mutex);
list_del(&codec->list);
@@ -4554,7 +4613,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
- const char *prefix)
+ const char *prefix,
+ struct device_node **bitclkmaster,
+ struct device_node **framemaster)
{
int ret, i;
char prop[128];
@@ -4637,9 +4698,13 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
*/
snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);
bit = !!of_get_property(np, prop, NULL);
+ if (bit && bitclkmaster)
+ *bitclkmaster = of_parse_phandle(np, prop, 0);
snprintf(prop, sizeof(prop), "%sframe-master", prefix);
frame = !!of_get_property(np, prop, NULL);
+ if (frame && framemaster)
+ *framemaster = of_parse_phandle(np, prop, 0);
switch ((bit << 4) + frame) {
case 0x11:
@@ -4698,7 +4763,7 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
if (id < 0 || id >= pos->num_dai) {
ret = -EINVAL;
- break;
+ continue;
}
ret = 0;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c8a780d0d057..a74b9bf23d9f 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -254,7 +254,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
- kfree(data->widget);
kfree(data->wlist);
kfree(data);
}
@@ -379,86 +378,24 @@ static void dapm_reset(struct snd_soc_card *card)
static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg,
unsigned int *value)
{
- if (w->codec) {
- *value = snd_soc_read(w->codec, reg);
- return 0;
- } else if (w->platform) {
- *value = snd_soc_platform_read(w->platform, reg);
- return 0;
- }
-
- dev_err(w->dapm->dev, "ASoC: no valid widget read method\n");
- return -1;
-}
-
-static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg,
- unsigned int val)
-{
- if (w->codec)
- return snd_soc_write(w->codec, reg, val);
- else if (w->platform)
- return snd_soc_platform_write(w->platform, reg, val);
-
- dev_err(w->dapm->dev, "ASoC: no valid widget write method\n");
- return -1;
-}
-
-static inline void soc_widget_lock(struct snd_soc_dapm_widget *w)
-{
- if (w->codec && !w->codec->using_regmap)
- mutex_lock(&w->codec->mutex);
- else if (w->platform)
- mutex_lock(&w->platform->mutex);
+ if (!w->dapm->component)
+ return -EIO;
+ return snd_soc_component_read(w->dapm->component, reg, value);
}
-static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w)
+static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
+ int reg, unsigned int mask, unsigned int value)
{
- if (w->codec && !w->codec->using_regmap)
- mutex_unlock(&w->codec->mutex);
- else if (w->platform)
- mutex_unlock(&w->platform->mutex);
+ if (!w->dapm->component)
+ return -EIO;
+ return snd_soc_component_update_bits_async(w->dapm->component, reg,
+ mask, value);
}
static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
{
- if (dapm->codec && dapm->codec->using_regmap)
- regmap_async_complete(dapm->codec->control_data);
-}
-
-static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
- unsigned short reg, unsigned int mask, unsigned int value)
-{
- bool change;
- unsigned int old, new;
- int ret;
-
- if (w->codec && w->codec->using_regmap) {
- ret = regmap_update_bits_check_async(w->codec->control_data,
- reg, mask, value,
- &change);
- if (ret != 0)
- return ret;
- } else {
- soc_widget_lock(w);
- ret = soc_widget_read(w, reg, &old);
- if (ret < 0) {
- soc_widget_unlock(w);
- return ret;
- }
-
- new = (old & ~mask) | (value & mask);
- change = old != new;
- if (change) {
- ret = soc_widget_write(w, reg, new);
- if (ret < 0) {
- soc_widget_unlock(w);
- return ret;
- }
- }
- soc_widget_unlock(w);
- }
-
- return change;
+ if (dapm->component)
+ snd_soc_component_async_complete(dapm->component);
}
/**
@@ -1121,26 +1058,6 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
}
/*
- * Handler for generic register modifier widget.
- */
-int dapm_reg_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- unsigned int val;
-
- if (SND_SOC_DAPM_EVENT_ON(event))
- val = w->on_val;
- else
- val = w->off_val;
-
- soc_widget_update_bits_locked(w, -(w->reg + 1),
- w->mask << w->shift, val << w->shift);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(dapm_reg_event);
-
-/*
* Handler for regulator supply widget.
*/
int dapm_regulator_event(struct snd_soc_dapm_widget *w,
@@ -1429,7 +1346,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card,
"pop test : Applying 0x%x/0x%x to %x in %dms\n",
value, mask, reg, card->pop_time);
pop_wait(card->pop_time);
- soc_widget_update_bits_locked(w, reg, mask, value);
+ soc_widget_update_bits(w, reg, mask, value);
}
list_for_each_entry(w, pending, power_list) {
@@ -1575,8 +1492,7 @@ static void dapm_widget_update(struct snd_soc_card *card)
if (!w)
return;
- ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
- update->val);
+ ret = soc_widget_update_bits(w, update->reg, update->mask, update->val);
if (ret < 0)
dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
w->name, ret);
@@ -1613,8 +1529,11 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
"ASoC: Failed to turn on bias: %d\n", ret);
}
- /* Prepare for a STADDBY->ON or ON->STANDBY transition */
- if (d->bias_level != d->target_bias_level) {
+ /* Prepare for a transition to ON or away from ON */
+ if ((d->target_bias_level == SND_SOC_BIAS_ON &&
+ d->bias_level != SND_SOC_BIAS_ON) ||
+ (d->target_bias_level != SND_SOC_BIAS_ON &&
+ d->bias_level == SND_SOC_BIAS_ON)) {
ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
if (ret != 0)
dev_err(d->dev,
@@ -2444,8 +2363,7 @@ err:
}
static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
- const struct snd_soc_dapm_route *route,
- unsigned int is_prefixed)
+ const struct snd_soc_dapm_route *route)
{
struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
@@ -2455,7 +2373,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
char prefixed_source[80];
int ret;
- if (dapm->codec && dapm->codec->name_prefix && !is_prefixed) {
+ if (dapm->codec && dapm->codec->name_prefix) {
snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
dapm->codec->name_prefix, route->sink);
sink = prefixed_sink;
@@ -2583,7 +2501,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
- r = snd_soc_dapm_add_route(dapm, route, false);
+ r = snd_soc_dapm_add_route(dapm, route);
if (r < 0) {
dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
route->source,
@@ -2855,22 +2773,19 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
change = dapm_kcontrol_set_value(kcontrol, val);
-
- if (reg != SND_SOC_NOPM) {
- mask = mask << shift;
- val = val << shift;
-
- change = snd_soc_test_bits(codec, reg, mask, val);
- }
-
if (change) {
if (reg != SND_SOC_NOPM) {
- update.kcontrol = kcontrol;
- update.reg = reg;
- update.mask = mask;
- update.val = val;
+ mask = mask << shift;
+ val = val << shift;
+
+ if (snd_soc_test_bits(codec, reg, mask, val)) {
+ update.kcontrol = kcontrol;
+ update.reg = reg;
+ update.mask = mask;
+ update.val = val;
+ card->update = &update;
+ }
- card->update = &update;
}
ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
@@ -3309,11 +3224,11 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
- struct snd_soc_dapm_route routes[2];
struct snd_soc_dapm_widget template;
struct snd_soc_dapm_widget *w;
size_t len;
char *link_name;
+ int ret;
len = strlen(source->name) + strlen(sink->name) + 2;
link_name = devm_kzalloc(card->dev, len, GFP_KERNEL);
@@ -3340,15 +3255,10 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
w->params = params;
- memset(&routes, 0, sizeof(routes));
-
- routes[0].source = source->name;
- routes[0].sink = link_name;
- routes[1].source = link_name;
- routes[1].sink = sink->name;
-
- return snd_soc_dapm_add_routes(&card->dapm, routes,
- ARRAY_SIZE(routes));
+ ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
+ if (ret)
+ return ret;
+ return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
}
int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
@@ -3406,6 +3316,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
{
struct snd_soc_dapm_widget *dai_w, *w;
+ struct snd_soc_dapm_widget *src, *sink;
struct snd_soc_dai *dai;
/* For each DAI widget... */
@@ -3436,25 +3347,15 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
if (!w->sname || !strstr(w->sname, dai_w->name))
continue;
- if (dai->driver->playback.stream_name &&
- strstr(w->sname,
- dai->driver->playback.stream_name)) {
- dev_dbg(dai->dev, "%s -> %s\n",
- dai->playback_widget->name, w->name);
-
- snd_soc_dapm_add_path(w->dapm,
- dai->playback_widget, w, NULL, NULL);
- }
-
- if (dai->driver->capture.stream_name &&
- strstr(w->sname,
- dai->driver->capture.stream_name)) {
- dev_dbg(dai->dev, "%s -> %s\n",
- w->name, dai->capture_widget->name);
-
- snd_soc_dapm_add_path(w->dapm, w,
- dai->capture_widget, NULL, NULL);
+ if (dai_w->id == snd_soc_dapm_dai_in) {
+ src = dai_w;
+ sink = w;
+ } else {
+ src = w;
+ sink = dai_w;
}
+ dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
+ snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
}
}
@@ -3464,20 +3365,21 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd = card->rtd;
+ struct snd_soc_dapm_widget *sink, *source;
struct snd_soc_dai *cpu_dai, *codec_dai;
- struct snd_soc_dapm_route r;
int i;
- memset(&r, 0, sizeof(r));
-
/* for each BE DAI link... */
for (i = 0; i < card->num_rtd; i++) {
rtd = &card->rtd[i];
cpu_dai = rtd->cpu_dai;
codec_dai = rtd->codec_dai;
- /* dynamic FE links have no fixed DAI mapping */
- if (rtd->dai_link->dynamic)
+ /*
+ * dynamic FE links have no fixed DAI mapping.
+ * CODEC<->CODEC links have no direct connection.
+ */
+ if (rtd->dai_link->dynamic || rtd->dai_link->params)
continue;
/* there is no point in connecting BE DAI links with dummies */
@@ -3487,55 +3389,49 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
/* connect BE DAI playback if widgets are valid */
if (codec_dai->playback_widget && cpu_dai->playback_widget) {
- r.source = cpu_dai->playback_widget->name;
- r.sink = codec_dai->playback_widget->name;
+ source = cpu_dai->playback_widget;
+ sink = codec_dai->playback_widget;
dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
- cpu_dai->codec->name, r.source,
- codec_dai->platform->name, r.sink);
+ cpu_dai->codec->name, source->name,
+ codec_dai->platform->name, sink->name);
- snd_soc_dapm_add_route(&card->dapm, &r, true);
+ snd_soc_dapm_add_path(&card->dapm, source, sink,
+ NULL, NULL);
}
/* connect BE DAI capture if widgets are valid */
if (codec_dai->capture_widget && cpu_dai->capture_widget) {
- r.source = codec_dai->capture_widget->name;
- r.sink = cpu_dai->capture_widget->name;
+ source = codec_dai->capture_widget;
+ sink = cpu_dai->capture_widget;
dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
- codec_dai->codec->name, r.source,
- cpu_dai->platform->name, r.sink);
+ codec_dai->codec->name, source->name,
+ cpu_dai->platform->name, sink->name);
- snd_soc_dapm_add_route(&card->dapm, &r, true);
+ snd_soc_dapm_add_path(&card->dapm, source, sink,
+ NULL, NULL);
}
-
}
}
-static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
int event)
{
+ struct snd_soc_dapm_widget *w;
- struct snd_soc_dapm_widget *w_cpu, *w_codec;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- w_cpu = cpu_dai->playback_widget;
- w_codec = codec_dai->playback_widget;
- } else {
- w_cpu = cpu_dai->capture_widget;
- w_codec = codec_dai->capture_widget;
- }
-
- if (w_cpu) {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ w = dai->playback_widget;
+ else
+ w = dai->capture_widget;
- dapm_mark_dirty(w_cpu, "stream event");
+ if (w) {
+ dapm_mark_dirty(w, "stream event");
switch (event) {
case SND_SOC_DAPM_STREAM_START:
- w_cpu->active = 1;
+ w->active = 1;
break;
case SND_SOC_DAPM_STREAM_STOP:
- w_cpu->active = 0;
+ w->active = 0;
break;
case SND_SOC_DAPM_STREAM_SUSPEND:
case SND_SOC_DAPM_STREAM_RESUME:
@@ -3544,25 +3440,13 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
break;
}
}
+}
- if (w_codec) {
-
- dapm_mark_dirty(w_codec, "stream event");
-
- switch (event) {
- case SND_SOC_DAPM_STREAM_START:
- w_codec->active = 1;
- break;
- case SND_SOC_DAPM_STREAM_STOP:
- w_codec->active = 0;
- break;
- case SND_SOC_DAPM_STREAM_SUSPEND:
- case SND_SOC_DAPM_STREAM_RESUME:
- case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
- case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
- break;
- }
- }
+static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+ int event)
+{
+ soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
+ soc_dapm_dai_stream_event(rtd->codec_dai, stream, event);
dapm_power_widgets(rtd->card, event);
}
diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c
index 7ac745df1412..057e5ef7dcce 100644
--- a/sound/soc/soc-devres.c
+++ b/sound/soc/soc-devres.c
@@ -52,6 +52,41 @@ int devm_snd_soc_register_component(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_snd_soc_register_component);
+static void devm_platform_release(struct device *dev, void *res)
+{
+ snd_soc_unregister_platform(*(struct device **)res);
+}
+
+/**
+ * devm_snd_soc_register_platform - resource managed platform registration
+ * @dev: Device used to manage platform
+ * @platform: platform to register
+ *
+ * Register a platform driver with automatic unregistration when the device is
+ * unregistered.
+ */
+int devm_snd_soc_register_platform(struct device *dev,
+ const struct snd_soc_platform_driver *platform_drv)
+{
+ struct device **ptr;
+ int ret;
+
+ ptr = devres_alloc(devm_platform_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = snd_soc_register_platform(dev, platform_drv);
+ if (ret == 0) {
+ *ptr = dev;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_snd_soc_register_platform);
+
static void devm_card_release(struct device *dev, void *res)
{
snd_soc_unregister_card(*(struct snd_soc_card **)res);
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index 260efc8466fc..7767fbd73eb7 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -17,77 +17,285 @@
#include <linux/export.h>
#include <sound/soc.h>
-#include <trace/events/asoc.h>
+/**
+ * snd_soc_component_read() - Read register value
+ * @component: Component to read from
+ * @reg: Register to read
+ * @val: Pointer to where the read value is stored
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+int snd_soc_component_read(struct snd_soc_component *component,
+ unsigned int reg, unsigned int *val)
+{
+ int ret;
+
+ if (component->regmap)
+ ret = regmap_read(component->regmap, reg, val);
+ else if (component->read)
+ ret = component->read(component, reg, val);
+ else
+ ret = -EIO;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_read);
-#ifdef CONFIG_REGMAP
-static int hw_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
+/**
+ * snd_soc_component_write() - Write register value
+ * @component: Component to write to
+ * @reg: Register to write
+ * @val: Value to write to the register
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+int snd_soc_component_write(struct snd_soc_component *component,
+ unsigned int reg, unsigned int val)
{
- return regmap_write(codec->control_data, reg, value);
+ if (component->regmap)
+ return regmap_write(component->regmap, reg, val);
+ else if (component->write)
+ return component->write(component, reg, val);
+ else
+ return -EIO;
}
+EXPORT_SYMBOL_GPL(snd_soc_component_write);
-static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
+static int snd_soc_component_update_bits_legacy(
+ struct snd_soc_component *component, unsigned int reg,
+ unsigned int mask, unsigned int val, bool *change)
{
+ unsigned int old, new;
int ret;
- unsigned int val;
- ret = regmap_read(codec->control_data, reg, &val);
- if (ret == 0)
- return val;
+ if (!component->read || !component->write)
+ return -EIO;
+
+ mutex_lock(&component->io_mutex);
+
+ ret = component->read(component, reg, &old);
+ if (ret < 0)
+ goto out_unlock;
+
+ new = (old & ~mask) | (val & mask);
+ *change = old != new;
+ if (*change)
+ ret = component->write(component, reg, new);
+out_unlock:
+ mutex_unlock(&component->io_mutex);
+
+ return ret;
+}
+
+/**
+ * snd_soc_component_update_bits() - Perform read/modify/write cycle
+ * @component: Component to update
+ * @reg: Register to update
+ * @mask: Mask that specifies which bits to update
+ * @val: New value for the bits specified by mask
+ *
+ * Return: 1 if the operation was successful and the value of the register
+ * changed, 0 if the operation was successful, but the value did not change.
+ * Returns a negative error code otherwise.
+ */
+int snd_soc_component_update_bits(struct snd_soc_component *component,
+ unsigned int reg, unsigned int mask, unsigned int val)
+{
+ bool change;
+ int ret;
+
+ if (component->regmap)
+ ret = regmap_update_bits_check(component->regmap, reg, mask,
+ val, &change);
+ else
+ ret = snd_soc_component_update_bits_legacy(component, reg,
+ mask, val, &change);
+
+ if (ret < 0)
+ return ret;
+ return change;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_update_bits);
+
+/**
+ * snd_soc_component_update_bits_async() - Perform asynchronous
+ * read/modify/write cycle
+ * @component: Component to update
+ * @reg: Register to update
+ * @mask: Mask that specifies which bits to update
+ * @val: New value for the bits specified by mask
+ *
+ * This function is similar to snd_soc_component_update_bits(), but the update
+ * operation is scheduled asynchronously. This means it may not be completed
+ * when the function returns. To make sure that all scheduled updates have been
+ * completed snd_soc_component_async_complete() must be called.
+ *
+ * Return: 1 if the operation was successful and the value of the register
+ * changed, 0 if the operation was successful, but the value did not change.
+ * Returns a negative error code otherwise.
+ */
+int snd_soc_component_update_bits_async(struct snd_soc_component *component,
+ unsigned int reg, unsigned int mask, unsigned int val)
+{
+ bool change;
+ int ret;
+
+ if (component->regmap)
+ ret = regmap_update_bits_check_async(component->regmap, reg,
+ mask, val, &change);
else
+ ret = snd_soc_component_update_bits_legacy(component, reg,
+ mask, val, &change);
+
+ if (ret < 0)
+ return ret;
+ return change;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async);
+
+/**
+ * snd_soc_component_async_complete() - Ensure asynchronous I/O has completed
+ * @component: Component for which to wait
+ *
+ * This function blocks until all asynchronous I/O which has previously been
+ * scheduled using snd_soc_component_update_bits_async() has completed.
+ */
+void snd_soc_component_async_complete(struct snd_soc_component *component)
+{
+ if (component->regmap)
+ regmap_async_complete(component->regmap);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_async_complete);
+
+/**
+ * snd_soc_component_test_bits - Test register for change
+ * @component: component
+ * @reg: Register to test
+ * @mask: Mask that specifies which bits to test
+ * @value: Value to test against
+ *
+ * Tests a register with a new value and checks if the new value is
+ * different from the old value.
+ *
+ * Return: 1 for change, otherwise 0.
+ */
+int snd_soc_component_test_bits(struct snd_soc_component *component,
+ unsigned int reg, unsigned int mask, unsigned int value)
+{
+ unsigned int old, new;
+ int ret;
+
+ ret = snd_soc_component_read(component, reg, &old);
+ if (ret < 0)
+ return ret;
+ new = (old & ~mask) | value;
+ return old != new;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_test_bits);
+
+unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+ unsigned int val;
+ int ret;
+
+ ret = snd_soc_component_read(&codec->component, reg, &val);
+ if (ret < 0)
return -1;
+
+ return val;
}
+EXPORT_SYMBOL_GPL(snd_soc_read);
+
+int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int val)
+{
+ return snd_soc_component_write(&codec->component, reg, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_write);
/**
- * snd_soc_codec_set_cache_io: Set up standard I/O functions.
+ * snd_soc_update_bits - update codec register bits
+ * @codec: audio codec
+ * @reg: codec register
+ * @mask: register mask
+ * @value: new value
*
- * @codec: CODEC to configure.
- * @map: Register map to write to
+ * Writes new register value.
*
- * Register formats are frequently shared between many I2C and SPI
- * devices. In order to promote code reuse the ASoC core provides
- * some standard implementations of CODEC read and write operations
- * which can be set up using this function.
+ * Returns 1 for change, 0 for no change, or negative error code.
+ */
+int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int mask, unsigned int value)
+{
+ return snd_soc_component_update_bits(&codec->component, reg, mask,
+ value);
+}
+EXPORT_SYMBOL_GPL(snd_soc_update_bits);
+
+/**
+ * snd_soc_test_bits - test register for change
+ * @codec: audio codec
+ * @reg: codec register
+ * @mask: register mask
+ * @value: new value
*
- * The caller is responsible for allocating and initialising the
- * actual cache.
+ * Tests a register with a new value and checks if the new value is
+ * different from the old value.
*
- * Note that at present this code cannot be used by CODECs with
- * volatile registers.
+ * Returns 1 for change else 0.
*/
-int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
- struct regmap *regmap)
+int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int mask, unsigned int value)
+{
+ return snd_soc_component_test_bits(&codec->component, reg, mask, value);
+}
+EXPORT_SYMBOL_GPL(snd_soc_test_bits);
+
+int snd_soc_platform_read(struct snd_soc_platform *platform,
+ unsigned int reg)
{
+ unsigned int val;
int ret;
- /* Device has made its own regmap arrangements */
- if (!regmap)
- codec->control_data = dev_get_regmap(codec->dev, NULL);
- else
- codec->control_data = regmap;
+ ret = snd_soc_component_read(&platform->component, reg, &val);
+ if (ret < 0)
+ return -1;
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(snd_soc_platform_read);
+
+int snd_soc_platform_write(struct snd_soc_platform *platform,
+ unsigned int reg, unsigned int val)
+{
+ return snd_soc_component_write(&platform->component, reg, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_platform_write);
- if (IS_ERR(codec->control_data))
- return PTR_ERR(codec->control_data);
+/**
+ * snd_soc_component_init_io() - Initialize regmap IO
+ *
+ * @component: component to initialize
+ * @regmap: regmap instance to use for IO operations
+ *
+ * Return: 0 on success, a negative error code otherwise
+ */
+int snd_soc_component_init_io(struct snd_soc_component *component,
+ struct regmap *regmap)
+{
+ int ret;
- codec->write = hw_write;
- codec->read = hw_read;
+ if (!regmap)
+ return -EINVAL;
- ret = regmap_get_val_bytes(codec->control_data);
+ ret = regmap_get_val_bytes(regmap);
/* Errors are legitimate for non-integer byte
* multiples */
if (ret > 0)
- codec->val_bytes = ret;
+ component->val_bytes = ret;
- codec->using_regmap = true;
+ component->regmap = regmap;
return 0;
}
-EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
-#else
-int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
- struct regmap *regmap)
-{
- return -ENOTSUPP;
-}
-EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
-#endif
+EXPORT_SYMBOL_GPL(snd_soc_component_init_io);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 2cedf09f6d96..54d18f22a33e 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -555,7 +555,6 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
if (platform->driver->ops && platform->driver->ops->close)
platform->driver->ops->close(substream);
- cpu_dai->runtime = NULL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
@@ -819,6 +818,13 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if (ret < 0)
return ret;
}
+
+ if (rtd->dai_link->ops && rtd->dai_link->ops->trigger) {
+ ret = rtd->dai_link->ops->trigger(substream, cmd);
+ if (ret < 0)
+ return ret;
+ }
+
return 0;
}
@@ -1012,21 +1018,12 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
}
static inline struct snd_soc_dapm_widget *
- rtd_get_cpu_widget(struct snd_soc_pcm_runtime *rtd, int stream)
-{
- if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- return rtd->cpu_dai->playback_widget;
- else
- return rtd->cpu_dai->capture_widget;
-}
-
-static inline struct snd_soc_dapm_widget *
- rtd_get_codec_widget(struct snd_soc_pcm_runtime *rtd, int stream)
+ dai_get_widget(struct snd_soc_dai *dai, int stream)
{
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- return rtd->codec_dai->playback_widget;
+ return dai->playback_widget;
else
- return rtd->codec_dai->capture_widget;
+ return dai->capture_widget;
}
static int widget_in_list(struct snd_soc_dapm_widget_list *list,
@@ -1076,14 +1073,14 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
/* is there a valid CPU DAI widget for this BE */
- widget = rtd_get_cpu_widget(dpcm->be, stream);
+ widget = dai_get_widget(dpcm->be->cpu_dai, stream);
/* prune the BE if it's no longer in our active list */
if (widget && widget_in_list(list, widget))
continue;
/* is there a valid CODEC DAI widget for this BE */
- widget = rtd_get_codec_widget(dpcm->be, stream);
+ widget = dai_get_widget(dpcm->be->codec_dai, stream);
/* prune the BE if it's no longer in our active list */
if (widget && widget_in_list(list, widget))
@@ -1675,7 +1672,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
- if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)
+ if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
continue;
if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c
index 25a7f8211ecf..de087ee3458a 100644
--- a/sound/soc/tegra/tegra_wm9712.c
+++ b/sound/soc/tegra/tegra_wm9712.c
@@ -50,9 +50,7 @@ static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_codec *codec = codec_dai->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
-
- return snd_soc_dapm_sync(dapm);
+ return snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
}
static struct snd_soc_dai_link tegra_wm9712_dai = {
diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c
index 7e923ecf8901..be4f1ac7cd5e 100644
--- a/sound/soc/ux500/mop500_ab8500.c
+++ b/sound/soc/ux500/mop500_ab8500.c
@@ -411,7 +411,7 @@ int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd)
drvdata->mclk_sel = MCLK_ULPCLK;
/* Add controls */
- ret = snd_soc_add_card_controls(codec->card, mop500_ab8500_ctrls,
+ ret = snd_soc_add_card_controls(rtd->card, mop500_ab8500_ctrls,
ARRAY_SIZE(mop500_ab8500_ctrls));
if (ret < 0) {
pr_err("%s: Failed to add machine-controls (%d)!\n",
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 893d5a1afc3c..c3b5b7dca1c3 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -651,7 +651,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
int err = -ENODEV;
down_read(&chip->shutdown_rwsem);
- if (chip->probing)
+ if (chip->probing && chip->in_pm)
err = 0;
else if (!chip->shutdown)
err = usb_autopm_get_interface(chip->pm_intf);
@@ -663,7 +663,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
void snd_usb_autosuspend(struct snd_usb_audio *chip)
{
down_read(&chip->shutdown_rwsem);
- if (!chip->shutdown && !chip->probing)
+ if (!chip->shutdown && !chip->probing && !chip->in_pm)
usb_autopm_put_interface(chip->pm_intf);
up_read(&chip->shutdown_rwsem);
}
@@ -695,8 +695,9 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
chip->autosuspended = 1;
}
- list_for_each_entry(mixer, &chip->mixer_list, list)
- snd_usb_mixer_suspend(mixer);
+ if (chip->num_suspended_intf == 1)
+ list_for_each_entry(mixer, &chip->mixer_list, list)
+ snd_usb_mixer_suspend(mixer);
return 0;
}
@@ -711,6 +712,8 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
return 0;
if (--chip->num_suspended_intf)
return 0;
+
+ chip->in_pm = 1;
/*
* ALSA leaves material resumption to user space
* we just notify and restart the mixers
@@ -726,6 +729,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
chip->autosuspended = 0;
err_out:
+ chip->in_pm = 0;
return err;
}
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 9867ab866857..97acb906acc2 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -92,6 +92,7 @@ struct snd_usb_endpoint {
unsigned int curframesize; /* current packet size in frames (for capture) */
unsigned int syncmaxsize; /* sync endpoint packet size */
unsigned int fill_max:1; /* fill max packet size always */
+ unsigned int udh01_fb_quirk:1; /* corrupted feedback data */
unsigned int datainterval; /* log_2 of data packet interval */
unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
unsigned char silence_value;
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index e70a87e0d9fe..289f582c9130 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -471,6 +471,10 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
ep->syncinterval = 3;
ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
+
+ if (chip->usb_id == USB_ID(0x0644, 0x8038) /* TEAC UD-H01 */ &&
+ ep->syncmaxsize == 4)
+ ep->udh01_fb_quirk = 1;
}
list_add_tail(&ep->list, &chip->ep_list);
@@ -1105,7 +1109,16 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
if (f == 0)
return;
- if (unlikely(ep->freqshift == INT_MIN)) {
+ if (unlikely(sender->udh01_fb_quirk)) {
+ /*
+ * The TEAC UD-H01 firmware sometimes changes the feedback value
+ * by +/- 0x1.0000.
+ */
+ if (f < ep->freqn - 0x8000)
+ f += 0x10000;
+ else if (f > ep->freqn + 0x8000)
+ f -= 0x10000;
+ } else if (unlikely(ep->freqshift == INT_MIN)) {
/*
* The first time we see a feedback value, determine its format
* by shifting it left or right until it matches the nominal
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 131336d40492..c62a1659106d 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -1501,9 +1501,8 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
* The error should be lower than 2ms since the estimate relies
* on two reads of a counter updated every ms.
*/
- if (printk_ratelimit() &&
- abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
- dev_dbg(&subs->dev->dev,
+ if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
+ dev_dbg_ratelimited(&subs->dev->dev,
"delay: estimated %d, actual %d\n",
est_delay, subs->last_delay);
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 25c4c7e217de..91d0380431b4 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -40,6 +40,7 @@ struct snd_usb_audio {
struct rw_semaphore shutdown_rwsem;
unsigned int shutdown:1;
unsigned int probing:1;
+ unsigned int in_pm:1;
unsigned int autosuspended:1;
unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */