]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'asoc-ab8500' into for-3.6
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Tue, 12 Jun 2012 03:46:58 +0000 (11:46 +0800)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Tue, 12 Jun 2012 03:46:58 +0000 (11:46 +0800)
62 files changed:
MAINTAINERS
include/sound/pcm.h
include/sound/soc-dapm.h
include/sound/soc.h
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c [new file with mode: 0644]
sound/soc/codecs/ab8500-codec.h [new file with mode: 0644]
sound/soc/codecs/ac97.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/da732x.c [new file with mode: 0644]
sound/soc/codecs/da732x.h [new file with mode: 0644]
sound/soc/codecs/da732x_reg.h [new file with mode: 0644]
sound/soc/codecs/isabelle.c [new file with mode: 0644]
sound/soc/codecs/isabelle.h [new file with mode: 0644]
sound/soc/codecs/lm49453.c
sound/soc/codecs/max98095.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm5100-tables.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8996.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_hubs.c
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/sh/fsi.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-io.c
sound/soc/tegra/tegra20_i2s.c
sound/soc/tegra/tegra20_i2s.h
sound/soc/tegra/tegra20_spdif.c
sound/soc/tegra/tegra20_spdif.h
sound/soc/tegra/tegra30_i2s.c
sound/soc/tegra/tegra30_i2s.h
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_wm8753.c
sound/soc/tegra/tegra_wm8903.c
sound/soc/tegra/trimslice.c
sound/soc/ux500/Kconfig
sound/soc/ux500/Makefile
sound/soc/ux500/ux500_pcm.c [new file with mode: 0644]
sound/soc/ux500/ux500_pcm.h [new file with mode: 0644]

index 14bc7071f9dfe692b495b50159d1799621d8ba04..62b94662506ff1faa3625492eaae1e356f4144c2 100644 (file)
@@ -6739,9 +6739,11 @@ F:       include/linux/tifm.h
 
 TI LM49xxx FAMILY ASoC CODEC DRIVERS
 M:     M R Swami Reddy <mr.swami.reddy@ti.com>
+M:     Vishwas A Deshpande <vishwas.a.deshpande@ti.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Maintained
 F:     sound/soc/codecs/lm49453*
+F:     sound/soc/codecs/isabelle*
 
 TI TWL4030 SERIES SOC CODEC DRIVER
 M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
index 0d1112815be3be6ea96a5ec1768382bb70aea571..a55d5db7eb5a835e659ce63cd88d403313f7a296 100644 (file)
@@ -1073,4 +1073,15 @@ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
 
 const char *snd_pcm_format_name(snd_pcm_format_t format);
 
+/**
+ * Get a string naming the direction of a stream
+ */
+static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream)
+{
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return "Playback";
+       else
+               return "Capture";
+}
+
 #endif /* __SOUND_PCM_H */
index e3833d9f1914ce8d529e27c319d9038bddb8ef3b..05559e571d44d78e09df8e2ea1f42961f71274fb 100644 (file)
@@ -229,6 +229,10 @@ struct device;
 {      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
        .shift = wshift, .invert = winvert, \
        .event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \
+{      .id = snd_soc_dapm_clock_supply, .name = wname, \
+       .reg = SND_SOC_NOPM, .event = dapm_clock_event, \
+       .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
 
 /* generic widgets */
 #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
@@ -245,6 +249,7 @@ struct device;
        .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
 
+
 /* dapm kcontrol types */
 #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -327,6 +332,8 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event);
 int dapm_regulator_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event);
+int dapm_clock_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event);
 
 /* dapm controls */
 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
@@ -432,6 +439,7 @@ enum snd_soc_dapm_type {
        snd_soc_dapm_post,                      /* machine specific post widget - exec last */
        snd_soc_dapm_supply,            /* power/clock supply */
        snd_soc_dapm_regulator_supply,  /* external regulator */
+       snd_soc_dapm_clock_supply,      /* external clock */
        snd_soc_dapm_aif_in,            /* audio interface input */
        snd_soc_dapm_aif_out,           /* audio interface output */
        snd_soc_dapm_siggen,            /* signal generator */
@@ -537,6 +545,8 @@ struct snd_soc_dapm_widget {
        struct list_head dirty;
        int inputs;
        int outputs;
+
+       struct clk *clk;
 };
 
 struct snd_soc_dapm_update {
index c703871f5f6556bbcf5386b3e8bb96aca35486b7..e4348d25fca3d9e8f065445d0507284a19afb19c 100644 (file)
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
        .put = snd_soc_put_volsw, \
        .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+#define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+       .info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \
+       .put = snd_soc_put_volsw_range, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = xreg, .shift = xshift, .min = xmin,\
+                .max = xmax, .platform_max = xmax, .invert = xinvert} }
 #define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
                {.reg = xreg, .rreg = xreg, \
                .shift = xshift, .rshift = xshift, \
                .max = xmax, .min = xmin} }
+#define SOC_SINGLE_RANGE_TLV(xname, xreg, xshift, xmin, xmax, xinvert, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+                SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw_range, \
+       .get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = xreg, .shift = xshift, .min = xmin,\
+                .max = xmax, .platform_max = xmax, .invert = xinvert} }
 #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
@@ -460,6 +477,12 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
+int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo);
+int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
 int snd_soc_limit_volume(struct snd_soc_codec *codec,
        const char *name, int max);
 int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
@@ -785,13 +808,36 @@ struct snd_soc_dai_link {
        /* config - must be set by machine driver */
        const char *name;                       /* Codec name */
        const char *stream_name;                /* Stream name */
-       const char *codec_name;         /* for multi-codec */
-       const struct device_node *codec_of_node;
-       const char *platform_name;      /* for multi-platform */
-       const struct device_node *platform_of_node;
+       /*
+        * You MAY specify the link's CPU-side device, either by device name,
+        * or by DT/OF node, but not both. If this information is omitted,
+        * the CPU-side DAI is matched using .cpu_dai_name only, which hence
+        * must be globally unique. These fields are currently typically used
+        * only for codec to codec links, or systems using device tree.
+        */
+       const char *cpu_name;
+       const struct device_node *cpu_of_node;
+       /*
+        * You MAY specify the DAI name of the CPU DAI. If this information is
+        * omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node
+        * only, which only works well when that device exposes a single DAI.
+        */
        const char *cpu_dai_name;
-       const struct device_node *cpu_dai_of_node;
+       /*
+        * You MUST specify the link's codec, either by device name, or by
+        * DT/OF node, but not both.
+        */
+       const char *codec_name;
+       const struct device_node *codec_of_node;
+       /* You MUST specify the DAI name within the codec */
        const char *codec_dai_name;
+       /*
+        * You MAY specify the link's platform/PCM/DMA driver, either by
+        * device name, or by DT/OF node, but not both. Some forms of link
+        * do not need a platform.
+        */
+       const char *platform_name;
+       const struct device_node *platform_of_node;
        int be_id;      /* optional ID for machine driver BE identification */
 
        const struct snd_soc_pcm_stream *params;
index 1e1613a438ddbf5a0eb42ab81a72020a792fb074..43f5240e6942cd7569e1589565d16a042c6d16f9 100644 (file)
@@ -12,6 +12,7 @@ config SND_SOC_ALL_CODECS
        tristate "Build all ASoC CODEC drivers"
        select SND_SOC_88PM860X if MFD_88PM860X
        select SND_SOC_L3
+       select SND_SOC_AB8500_CODEC if ABX500_CORE
        select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
        select SND_SOC_AD1836 if SPI_MASTER
        select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
@@ -35,7 +36,9 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
        select SND_SOC_CX20442
        select SND_SOC_DA7210 if I2C
+       select SND_SOC_DA732X if I2C
        select SND_SOC_DFBMCS320
+       select SND_SOC_ISABELLE if I2C
        select SND_SOC_JZ4740_CODEC
        select SND_SOC_LM4857 if I2C
        select SND_SOC_LM49453 if I2C
@@ -131,6 +134,9 @@ config SND_SOC_WM_HUBS
        default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
        default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m
 
+config SND_SOC_AB8500_CODEC
+       tristate
+
 config SND_SOC_AC97_CODEC
        tristate
        select SND_AC97_CODEC
@@ -219,12 +225,18 @@ config SND_SOC_L3
 config SND_SOC_DA7210
         tristate
 
+config SND_SOC_DA732X
+        tristate
+
 config SND_SOC_DFBMCS320
        tristate
 
 config SND_SOC_DMIC
        tristate
 
+config SND_SOC_ISABELLE
+        tristate
+
 config SND_SOC_LM49453
        tristate
 
index fc27fec39487bf1bd9e9e8a9fd4551d45777a159..3d30654f6fcc590eede1b748c2700cb6b6a63c89 100644 (file)
@@ -1,4 +1,5 @@
 snd-soc-88pm860x-objs := 88pm860x-codec.o
+snd-soc-ab8500-codec-objs := ab8500-codec.o
 snd-soc-ac97-objs := ac97.o
 snd-soc-ad1836-objs := ad1836.o
 snd-soc-ad193x-objs := ad193x.o
@@ -21,8 +22,10 @@ snd-soc-cs4270-objs := cs4270.o
 snd-soc-cs4271-objs := cs4271.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
+snd-soc-da732x-objs := da732x.o
 snd-soc-dfbmcs320-objs := dfbmcs320.o
 snd-soc-dmic-objs := dmic.o
+snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
 snd-soc-lm4857-objs := lm4857.o
@@ -108,6 +111,7 @@ snd-soc-max9877-objs := max9877.o
 snd-soc-tpa6130a2-objs := tpa6130a2.o
 
 obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
+obj-$(CONFIG_SND_SOC_AB8500_CODEC)     += snd-soc-ab8500-codec.o
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1836)   += snd-soc-ad1836.o
 obj-$(CONFIG_SND_SOC_AD193X)   += snd-soc-ad193x.o
@@ -132,8 +136,10 @@ obj-$(CONFIG_SND_SOC_CS4270)       += snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CS4271)   += snd-soc-cs4271.o
 obj-$(CONFIG_SND_SOC_CX20442)  += snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)   += snd-soc-da7210.o
+obj-$(CONFIG_SND_SOC_DA732X)   += snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DFBMCS320)        += snd-soc-dfbmcs320.o
 obj-$(CONFIG_SND_SOC_DMIC)     += snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)     += snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_LM4857)   += snd-soc-lm4857.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
new file mode 100644 (file)
index 0000000..95dc7d5
--- /dev/null
@@ -0,0 +1,2521 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>,
+ *         for ST-Ericsson.
+ *
+ *         Based on the early work done by:
+ *         Mikko J. Lehto <mikko.lehto@symbio.com>,
+ *         Mikko Sarmanne <mikko.sarmanne@symbio.com>,
+ *         Jarmo K. Kuronen <jarmo.kuronen@symbio.com>,
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500-sysctrl.h>
+#include <linux/mfd/abx500/ab8500-codec.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "ab8500-codec.h"
+
+/* Macrocell value definitions */
+#define CLK_32K_OUT2_DISABLE                   0x01
+#define INACTIVE_RESET_AUDIO                   0x02
+#define ENABLE_AUDIO_CLK_TO_AUDIO_BLK          0x10
+#define ENABLE_VINTCORE12_SUPPLY               0x04
+#define GPIO27_DIR_OUTPUT                      0x04
+#define GPIO29_DIR_OUTPUT                      0x10
+#define GPIO31_DIR_OUTPUT                      0x40
+
+/* Macrocell register definitions */
+#define AB8500_CTRL3_REG                       0x0200
+#define AB8500_GPIO_DIR4_REG                   0x1013
+
+/* Nr of FIR/IIR-coeff banks in ANC-block */
+#define AB8500_NR_OF_ANC_COEFF_BANKS           2
+
+/* Minimum duration to keep ANC IIR Init bit high or
+low before proceeding with the configuration sequence */
+#define AB8500_ANC_SM_DELAY                    2000
+
+#define AB8500_FILTER_CONTROL(xname, xcount, xmin, xmax) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .info = filter_control_info, \
+       .get = filter_control_get, .put = filter_control_put, \
+       .private_value = (unsigned long)&(struct filter_control) \
+               {.count = xcount, .min = xmin, .max = xmax} }
+
+struct filter_control {
+       long min, max;
+       unsigned int count;
+       long value[128];
+};
+
+/* Sidetone states */
+static const char * const enum_sid_state[] = {
+       "Unconfigured",
+       "Apply FIR",
+       "FIR is configured",
+};
+enum sid_state {
+       SID_UNCONFIGURED = 0,
+       SID_APPLY_FIR = 1,
+       SID_FIR_CONFIGURED = 2,
+};
+
+static const char * const enum_anc_state[] = {
+       "Unconfigured",
+       "Apply FIR and IIR",
+       "FIR and IIR are configured",
+       "Apply FIR",
+       "FIR is configured",
+       "Apply IIR",
+       "IIR is configured"
+};
+enum anc_state {
+       ANC_UNCONFIGURED = 0,
+       ANC_APPLY_FIR_IIR = 1,
+       ANC_FIR_IIR_CONFIGURED = 2,
+       ANC_APPLY_FIR = 3,
+       ANC_FIR_CONFIGURED = 4,
+       ANC_APPLY_IIR = 5,
+       ANC_IIR_CONFIGURED = 6
+};
+
+/* Analog microphones */
+enum amic_idx {
+       AMIC_IDX_1A,
+       AMIC_IDX_1B,
+       AMIC_IDX_2
+};
+
+struct ab8500_codec_drvdata_dbg {
+       struct regulator *vaud;
+       struct regulator *vamic1;
+       struct regulator *vamic2;
+       struct regulator *vdmic;
+};
+
+/* Private data for AB8500 device-driver */
+struct ab8500_codec_drvdata {
+       /* Sidetone */
+       long *sid_fir_values;
+       enum sid_state sid_status;
+
+       /* ANC */
+       struct mutex anc_lock;
+       long *anc_fir_values;
+       long *anc_iir_values;
+       enum anc_state anc_status;
+};
+
+static inline const char *amic_micbias_str(enum amic_micbias micbias)
+{
+       switch (micbias) {
+       case AMIC_MICBIAS_VAMIC1:
+               return "VAMIC1";
+       case AMIC_MICBIAS_VAMIC2:
+               return "VAMIC2";
+       default:
+               return "Unknown";
+       }
+}
+
+static inline const char *amic_type_str(enum amic_type type)
+{
+       switch (type) {
+       case AMIC_TYPE_DIFFERENTIAL:
+               return "DIFFERENTIAL";
+       case AMIC_TYPE_SINGLE_ENDED:
+               return "SINGLE ENDED";
+       default:
+               return "Unknown";
+       }
+}
+
+/*
+ * Read'n'write functions
+ */
+
+/* Read a register from the audio-bank of AB8500 */
+static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec,
+                                       unsigned int reg)
+{
+       int status;
+       unsigned int value = 0;
+
+       u8 value8;
+       status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO,
+                                               reg, &value8);
+       if (status < 0) {
+               dev_err(codec->dev,
+                       "%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n",
+                       __func__, (u8)AB8500_AUDIO, (u8)reg, status);
+       } else {
+               dev_dbg(codec->dev,
+                       "%s: Read 0x%02x from register 0x%02x:0x%02x\n",
+                       __func__, value8, (u8)AB8500_AUDIO, (u8)reg);
+               value = (unsigned int)value8;
+       }
+
+       return value;
+}
+
+/* Write to a register in the audio-bank of AB8500 */
+static int ab8500_codec_write_reg(struct snd_soc_codec *codec,
+                               unsigned int reg, unsigned int value)
+{
+       int status;
+
+       status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO,
+                                               reg, value);
+       if (status < 0)
+               dev_err(codec->dev,
+                       "%s: ERROR: Register (%02x:%02x) write failed (%d).\n",
+                       __func__, (u8)AB8500_AUDIO, (u8)reg, status);
+       else
+               dev_dbg(codec->dev,
+                       "%s: Wrote 0x%02x into register %02x:%02x\n",
+                       __func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg);
+
+       return status;
+}
+
+/*
+ * Controls - DAPM
+ */
+
+/* Earpiece */
+
+/* Earpiece source selector */
+static const char * const enum_ear_lineout_source[] = {"Headset Left",
+                                               "Speaker Left"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ear_lineout_source, AB8500_DMICFILTCONF,
+                       AB8500_DMICFILTCONF_DA3TOEAR, enum_ear_lineout_source);
+static const struct snd_kcontrol_new dapm_ear_lineout_source =
+       SOC_DAPM_ENUM("Earpiece or LineOut Mono Source",
+               dapm_enum_ear_lineout_source);
+
+/* LineOut */
+
+/* LineOut source selector */
+static const char * const enum_lineout_source[] = {"Mono Path", "Stereo Path"};
+static SOC_ENUM_DOUBLE_DECL(dapm_enum_lineout_source, AB8500_ANACONF5,
+                       AB8500_ANACONF5_HSLDACTOLOL,
+                       AB8500_ANACONF5_HSRDACTOLOR, enum_lineout_source);
+static const struct snd_kcontrol_new dapm_lineout_source[] = {
+       SOC_DAPM_ENUM("LineOut Source", dapm_enum_lineout_source),
+};
+
+/* Handsfree */
+
+/* Speaker Left - ANC selector */
+static const char * const enum_HFx_sel[] = {"Audio Path", "ANC"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_HFl_sel, AB8500_DIGMULTCONF2,
+                       AB8500_DIGMULTCONF2_HFLSEL, enum_HFx_sel);
+static const struct snd_kcontrol_new dapm_HFl_select[] = {
+       SOC_DAPM_ENUM("Speaker Left Source", dapm_enum_HFl_sel),
+};
+
+/* Speaker Right - ANC selector */
+static SOC_ENUM_SINGLE_DECL(dapm_enum_HFr_sel, AB8500_DIGMULTCONF2,
+                       AB8500_DIGMULTCONF2_HFRSEL, enum_HFx_sel);
+static const struct snd_kcontrol_new dapm_HFr_select[] = {
+       SOC_DAPM_ENUM("Speaker Right Source", dapm_enum_HFr_sel),
+};
+
+/* Mic 1 */
+
+/* Mic 1 - Mic 1a or 1b selector */
+static const char * const enum_mic1ab_sel[] = {"Mic 1b", "Mic 1a"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_mic1ab_sel, AB8500_ANACONF3,
+                       AB8500_ANACONF3_MIC1SEL, enum_mic1ab_sel);
+static const struct snd_kcontrol_new dapm_mic1ab_mux[] = {
+       SOC_DAPM_ENUM("Mic 1a or 1b Select", dapm_enum_mic1ab_sel),
+};
+
+/* Mic 1 - AD3 - Mic 1 or DMic 3 selector */
+static const char * const enum_ad3_sel[] = {"Mic 1", "DMic 3"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad3_sel, AB8500_DIGMULTCONF1,
+                       AB8500_DIGMULTCONF1_AD3SEL, enum_ad3_sel);
+static const struct snd_kcontrol_new dapm_ad3_select[] = {
+       SOC_DAPM_ENUM("AD3 Source Select", dapm_enum_ad3_sel),
+};
+
+/* Mic 1 - AD6 - Mic 1 or DMic 6 selector */
+static const char * const enum_ad6_sel[] = {"Mic 1", "DMic 6"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad6_sel, AB8500_DIGMULTCONF1,
+                       AB8500_DIGMULTCONF1_AD6SEL, enum_ad6_sel);
+static const struct snd_kcontrol_new dapm_ad6_select[] = {
+       SOC_DAPM_ENUM("AD6 Source Select", dapm_enum_ad6_sel),
+};
+
+/* Mic 2 */
+
+/* Mic 2 - AD5 - Mic 2 or DMic 5 selector */
+static const char * const enum_ad5_sel[] = {"Mic 2", "DMic 5"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad5_sel, AB8500_DIGMULTCONF1,
+                       AB8500_DIGMULTCONF1_AD5SEL, enum_ad5_sel);
+static const struct snd_kcontrol_new dapm_ad5_select[] = {
+       SOC_DAPM_ENUM("AD5 Source Select", dapm_enum_ad5_sel),
+};
+
+/* LineIn */
+
+/* LineIn left - AD1 - LineIn Left or DMic 1 selector */
+static const char * const enum_ad1_sel[] = {"LineIn Left", "DMic 1"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad1_sel, AB8500_DIGMULTCONF1,
+                       AB8500_DIGMULTCONF1_AD1SEL, enum_ad1_sel);
+static const struct snd_kcontrol_new dapm_ad1_select[] = {
+       SOC_DAPM_ENUM("AD1 Source Select", dapm_enum_ad1_sel),
+};
+
+/* LineIn right - Mic 2 or LineIn Right selector */
+static const char * const enum_mic2lr_sel[] = {"Mic 2", "LineIn Right"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_mic2lr_sel, AB8500_ANACONF3,
+                       AB8500_ANACONF3_LINRSEL, enum_mic2lr_sel);
+static const struct snd_kcontrol_new dapm_mic2lr_select[] = {
+       SOC_DAPM_ENUM("Mic 2 or LINR Select", dapm_enum_mic2lr_sel),
+};
+
+/* LineIn right - AD2 - LineIn Right or DMic2 selector */
+static const char * const enum_ad2_sel[] = {"LineIn Right", "DMic 2"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad2_sel, AB8500_DIGMULTCONF1,
+                       AB8500_DIGMULTCONF1_AD2SEL, enum_ad2_sel);
+static const struct snd_kcontrol_new dapm_ad2_select[] = {
+       SOC_DAPM_ENUM("AD2 Source Select", dapm_enum_ad2_sel),
+};
+
+
+/* ANC */
+
+static const char * const enum_anc_in_sel[] = {"Mic 1 / DMic 6",
+                                       "Mic 2 / DMic 5"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_anc_in_sel, AB8500_DMICFILTCONF,
+                       AB8500_DMICFILTCONF_ANCINSEL, enum_anc_in_sel);
+static const struct snd_kcontrol_new dapm_anc_in_select[] = {
+       SOC_DAPM_ENUM("ANC Source", dapm_enum_anc_in_sel),
+};
+
+/* ANC - Enable/Disable */
+static const struct snd_kcontrol_new dapm_anc_enable[] = {
+       SOC_DAPM_SINGLE("Switch", AB8500_ANCCONF1,
+                       AB8500_ANCCONF1_ENANC, 0, 0),
+};
+
+/* ANC to Earpiece - Mute */
+static const struct snd_kcontrol_new dapm_anc_ear_mute[] = {
+       SOC_DAPM_SINGLE("Switch", AB8500_DIGMULTCONF1,
+                       AB8500_DIGMULTCONF1_ANCSEL, 1, 0),
+};
+
+
+
+/* Sidetone left */
+
+/* Sidetone left - Input selector */
+static const char * const enum_stfir1_in_sel[] = {
+       "LineIn Left", "LineIn Right", "Mic 1", "Headset Left"
+};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_stfir1_in_sel, AB8500_DIGMULTCONF2,
+                       AB8500_DIGMULTCONF2_FIRSID1SEL, enum_stfir1_in_sel);
+static const struct snd_kcontrol_new dapm_stfir1_in_select[] = {
+       SOC_DAPM_ENUM("Sidetone Left Source", dapm_enum_stfir1_in_sel),
+};
+
+/* Sidetone right path */
+
+/* Sidetone right - Input selector */
+static const char * const enum_stfir2_in_sel[] = {
+       "LineIn Right", "Mic 1", "DMic 4", "Headset Right"
+};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_stfir2_in_sel, AB8500_DIGMULTCONF2,
+                       AB8500_DIGMULTCONF2_FIRSID2SEL, enum_stfir2_in_sel);
+static const struct snd_kcontrol_new dapm_stfir2_in_select[] = {
+       SOC_DAPM_ENUM("Sidetone Right Source", dapm_enum_stfir2_in_sel),
+};
+
+/* Vibra */
+
+static const char * const enum_pwm2vibx[] = {"Audio Path", "PWM Generator"};
+
+static SOC_ENUM_SINGLE_DECL(dapm_enum_pwm2vib1, AB8500_PWMGENCONF1,
+                       AB8500_PWMGENCONF1_PWMTOVIB1, enum_pwm2vibx);
+
+static const struct snd_kcontrol_new dapm_pwm2vib1[] = {
+       SOC_DAPM_ENUM("Vibra 1 Controller", dapm_enum_pwm2vib1),
+};
+
+static SOC_ENUM_SINGLE_DECL(dapm_enum_pwm2vib2, AB8500_PWMGENCONF1,
+                       AB8500_PWMGENCONF1_PWMTOVIB2, enum_pwm2vibx);
+
+static const struct snd_kcontrol_new dapm_pwm2vib2[] = {
+       SOC_DAPM_ENUM("Vibra 2 Controller", dapm_enum_pwm2vib2),
+};
+
+/*
+ * DAPM-widgets
+ */
+
+static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = {
+
+       /* Clocks */
+       SND_SOC_DAPM_CLOCK_SUPPLY("audioclk"),
+
+       /* Regulators */
+       SND_SOC_DAPM_REGULATOR_SUPPLY("V-AUD", 0),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC1", 0),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC2", 0),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("V-DMIC", 0),
+
+       /* Power */
+       SND_SOC_DAPM_SUPPLY("Audio Power",
+                       AB8500_POWERUP, AB8500_POWERUP_POWERUP, 0,
+                       NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("Audio Analog Power",
+                       AB8500_POWERUP, AB8500_POWERUP_ENANA, 0,
+                       NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* Main supply node */
+       SND_SOC_DAPM_SUPPLY("Main Supply", SND_SOC_NOPM, 0, 0,
+                       NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* DA/AD */
+
+       SND_SOC_DAPM_INPUT("ADC Input"),
+       SND_SOC_DAPM_ADC("ADC", "ab8500_0c", SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_OUTPUT("DAC Output"),
+
+       SND_SOC_DAPM_AIF_IN("DA_IN1", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("DA_IN2", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("DA_IN3", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("DA_IN4", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("DA_IN5", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("DA_IN6", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AD_OUT1", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AD_OUT2", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AD_OUT3", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AD_OUT4", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AD_OUT57", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AD_OUT68", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+       /* Headset path */
+
+       SND_SOC_DAPM_SUPPLY("Charge Pump", AB8500_ANACONF5,
+                       AB8500_ANACONF5_ENCPHS, 0, NULL, 0),
+
+       SND_SOC_DAPM_DAC("DA1 Enable", "ab8500_0p",
+                       AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA1, 0),
+       SND_SOC_DAPM_DAC("DA2 Enable", "ab8500_0p",
+                       AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA2, 0),
+
+       SND_SOC_DAPM_PGA("HSL Digital Volume", SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_PGA("HSR Digital Volume", SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+
+       SND_SOC_DAPM_DAC("HSL DAC", "ab8500_0p",
+                       AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHSL, 0),
+       SND_SOC_DAPM_DAC("HSR DAC", "ab8500_0p",
+                       AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHSR, 0),
+       SND_SOC_DAPM_MIXER("HSL DAC Mute", AB8500_MUTECONF,
+                       AB8500_MUTECONF_MUTDACHSL, 1,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("HSR DAC Mute", AB8500_MUTECONF,
+                       AB8500_MUTECONF_MUTDACHSR, 1,
+                       NULL, 0),
+       SND_SOC_DAPM_DAC("HSL DAC Driver", "ab8500_0p",
+                       AB8500_ANACONF3, AB8500_ANACONF3_ENDRVHSL, 0),
+       SND_SOC_DAPM_DAC("HSR DAC Driver", "ab8500_0p",
+                       AB8500_ANACONF3, AB8500_ANACONF3_ENDRVHSR, 0),
+
+       SND_SOC_DAPM_MIXER("HSL Mute",
+                       AB8500_MUTECONF, AB8500_MUTECONF_MUTHSL, 1,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("HSR Mute",
+                       AB8500_MUTECONF, AB8500_MUTECONF_MUTHSR, 1,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("HSL Enable",
+                       AB8500_ANACONF4, AB8500_ANACONF4_ENHSL, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("HSR Enable",
+                       AB8500_ANACONF4, AB8500_ANACONF4_ENHSR, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_PGA("HSL Volume",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_PGA("HSR Volume",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("Headset Left"),
+       SND_SOC_DAPM_OUTPUT("Headset Right"),
+
+       /* LineOut path */
+
+       SND_SOC_DAPM_MUX("LineOut Source",
+                       SND_SOC_NOPM, 0, 0, dapm_lineout_source),
+
+       SND_SOC_DAPM_MIXER("LOL Disable HFL",
+                       AB8500_ANACONF4, AB8500_ANACONF4_ENHFL, 1,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("LOR Disable HFR",
+                       AB8500_ANACONF4, AB8500_ANACONF4_ENHFR, 1,
+                       NULL, 0),
+
+       SND_SOC_DAPM_MIXER("LOL Enable",
+                       AB8500_ANACONF5, AB8500_ANACONF5_ENLOL, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("LOR Enable",
+                       AB8500_ANACONF5, AB8500_ANACONF5_ENLOR, 0,
+                       NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("LineOut Left"),
+       SND_SOC_DAPM_OUTPUT("LineOut Right"),
+
+       /* Earpiece path */
+
+       SND_SOC_DAPM_MUX("Earpiece or LineOut Mono Source",
+                       SND_SOC_NOPM, 0, 0, &dapm_ear_lineout_source),
+       SND_SOC_DAPM_MIXER("EAR DAC",
+                       AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACEAR, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("EAR Mute",
+                       AB8500_MUTECONF, AB8500_MUTECONF_MUTEAR, 1,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("EAR Enable",
+                       AB8500_ANACONF4, AB8500_ANACONF4_ENEAR, 0,
+                       NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("Earpiece"),
+
+       /* Handsfree path */
+
+       SND_SOC_DAPM_MIXER("DA3 Channel Volume",
+                       AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA3, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("DA4 Channel Volume",
+                       AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA4, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MUX("Speaker Left Source",
+                       SND_SOC_NOPM, 0, 0, dapm_HFl_select),
+       SND_SOC_DAPM_MUX("Speaker Right Source",
+                       SND_SOC_NOPM, 0, 0, dapm_HFr_select),
+       SND_SOC_DAPM_MIXER("HFL DAC", AB8500_DAPATHCONF,
+                       AB8500_DAPATHCONF_ENDACHFL, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("HFR DAC",
+                       AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHFR, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("DA4 or ANC path to HfR",
+                       AB8500_DIGMULTCONF2, AB8500_DIGMULTCONF2_DATOHFREN, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("DA3 or ANC path to HfL",
+                       AB8500_DIGMULTCONF2, AB8500_DIGMULTCONF2_DATOHFLEN, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("HFL Enable",
+                       AB8500_ANACONF4, AB8500_ANACONF4_ENHFL, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("HFR Enable",
+                       AB8500_ANACONF4, AB8500_ANACONF4_ENHFR, 0,
+                       NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("Speaker Left"),
+       SND_SOC_DAPM_OUTPUT("Speaker Right"),
+
+       /* Vibrator path */
+
+       SND_SOC_DAPM_INPUT("PWMGEN1"),
+       SND_SOC_DAPM_INPUT("PWMGEN2"),
+
+       SND_SOC_DAPM_MIXER("DA5 Channel Volume",
+                       AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA5, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("DA6 Channel Volume",
+                       AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA6, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("VIB1 DAC",
+                       AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACVIB1, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("VIB2 DAC",
+                       AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACVIB2, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MUX("Vibra 1 Controller",
+                       SND_SOC_NOPM, 0, 0, dapm_pwm2vib1),
+       SND_SOC_DAPM_MUX("Vibra 2 Controller",
+                       SND_SOC_NOPM, 0, 0, dapm_pwm2vib2),
+       SND_SOC_DAPM_MIXER("VIB1 Enable",
+                       AB8500_ANACONF4, AB8500_ANACONF4_ENVIB1, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("VIB2 Enable",
+                       AB8500_ANACONF4, AB8500_ANACONF4_ENVIB2, 0,
+                       NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("Vibra 1"),
+       SND_SOC_DAPM_OUTPUT("Vibra 2"),
+
+       /* Mic 1 */
+
+       SND_SOC_DAPM_INPUT("Mic 1"),
+
+       SND_SOC_DAPM_MUX("Mic 1a or 1b Select",
+                       SND_SOC_NOPM, 0, 0, dapm_mic1ab_mux),
+       SND_SOC_DAPM_MIXER("MIC1 Mute",
+                       AB8500_ANACONF2, AB8500_ANACONF2_MUTMIC1, 1,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("MIC1A V-AMICx Enable",
+                       AB8500_ANACONF2, AB8500_ANACONF2_ENMIC1, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("MIC1B V-AMICx Enable",
+                       AB8500_ANACONF2, AB8500_ANACONF2_ENMIC1, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("MIC1 ADC",
+                       AB8500_ANACONF3, AB8500_ANACONF3_ENADCMIC, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MUX("AD3 Source Select",
+                       SND_SOC_NOPM, 0, 0, dapm_ad3_select),
+       SND_SOC_DAPM_MIXER("AD3 Channel Volume",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("AD3 Enable",
+                       AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD34, 0,
+                       NULL, 0),
+
+       /* Mic 2 */
+
+       SND_SOC_DAPM_INPUT("Mic 2"),
+
+       SND_SOC_DAPM_MIXER("MIC2 Mute",
+                       AB8500_ANACONF2, AB8500_ANACONF2_MUTMIC2, 1,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("MIC2 V-AMICx Enable", AB8500_ANACONF2,
+                       AB8500_ANACONF2_ENMIC2, 0,
+                       NULL, 0),
+
+       /* LineIn */
+
+       SND_SOC_DAPM_INPUT("LineIn Left"),
+       SND_SOC_DAPM_INPUT("LineIn Right"),
+
+       SND_SOC_DAPM_MIXER("LINL Mute",
+                       AB8500_ANACONF2, AB8500_ANACONF2_MUTLINL, 1,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("LINR Mute",
+                       AB8500_ANACONF2, AB8500_ANACONF2_MUTLINR, 1,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("LINL Enable", AB8500_ANACONF2,
+                       AB8500_ANACONF2_ENLINL, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("LINR Enable", AB8500_ANACONF2,
+                       AB8500_ANACONF2_ENLINR, 0,
+                       NULL, 0),
+
+       /* LineIn Bypass path */
+       SND_SOC_DAPM_MIXER("LINL to HSL Volume",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("LINR to HSR Volume",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+
+       /* LineIn, Mic 2 */
+       SND_SOC_DAPM_MUX("Mic 2 or LINR Select",
+                       SND_SOC_NOPM, 0, 0, dapm_mic2lr_select),
+       SND_SOC_DAPM_MIXER("LINL ADC", AB8500_ANACONF3,
+                       AB8500_ANACONF3_ENADCLINL, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("LINR ADC", AB8500_ANACONF3,
+                       AB8500_ANACONF3_ENADCLINR, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MUX("AD1 Source Select",
+                       SND_SOC_NOPM, 0, 0, dapm_ad1_select),
+       SND_SOC_DAPM_MUX("AD2 Source Select",
+                       SND_SOC_NOPM, 0, 0, dapm_ad2_select),
+       SND_SOC_DAPM_MIXER("AD1 Channel Volume",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("AD2 Channel Volume",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+
+       SND_SOC_DAPM_MIXER("AD12 Enable",
+                       AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD12, 0,
+                       NULL, 0),
+
+       /* HD Capture path */
+
+       SND_SOC_DAPM_MUX("AD5 Source Select",
+                       SND_SOC_NOPM, 0, 0, dapm_ad5_select),
+       SND_SOC_DAPM_MUX("AD6 Source Select",
+                       SND_SOC_NOPM, 0, 0, dapm_ad6_select),
+       SND_SOC_DAPM_MIXER("AD5 Channel Volume",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("AD6 Channel Volume",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("AD57 Enable",
+                       AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD5768, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("AD68 Enable",
+                       AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD5768, 0,
+                       NULL, 0),
+
+       /* Digital Microphone path */
+
+       SND_SOC_DAPM_INPUT("DMic 1"),
+       SND_SOC_DAPM_INPUT("DMic 2"),
+       SND_SOC_DAPM_INPUT("DMic 3"),
+       SND_SOC_DAPM_INPUT("DMic 4"),
+       SND_SOC_DAPM_INPUT("DMic 5"),
+       SND_SOC_DAPM_INPUT("DMic 6"),
+
+       SND_SOC_DAPM_MIXER("DMIC1",
+                       AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC1, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("DMIC2",
+                       AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC2, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("DMIC3",
+                       AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC3, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("DMIC4",
+                       AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC4, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("DMIC5",
+                       AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC5, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("DMIC6",
+                       AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC6, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("AD4 Channel Volume",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("AD4 Enable",
+                       AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD34,
+                       0, NULL, 0),
+
+       /* Acoustical Noise Cancellation path */
+
+       SND_SOC_DAPM_INPUT("ANC Configure Input"),
+       SND_SOC_DAPM_OUTPUT("ANC Configure Output"),
+
+       SND_SOC_DAPM_MUX("ANC Source",
+                       SND_SOC_NOPM, 0, 0,
+                       dapm_anc_in_select),
+       SND_SOC_DAPM_SWITCH("ANC",
+                       SND_SOC_NOPM, 0, 0,
+                       dapm_anc_enable),
+       SND_SOC_DAPM_SWITCH("ANC to Earpiece",
+                       SND_SOC_NOPM, 0, 0,
+                       dapm_anc_ear_mute),
+
+       /* Sidetone Filter path */
+
+       SND_SOC_DAPM_MUX("Sidetone Left Source",
+                       SND_SOC_NOPM, 0, 0,
+                       dapm_stfir1_in_select),
+       SND_SOC_DAPM_MUX("Sidetone Right Source",
+                       SND_SOC_NOPM, 0, 0,
+                       dapm_stfir2_in_select),
+       SND_SOC_DAPM_MIXER("STFIR1 Control",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("STFIR2 Control",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("STFIR1 Volume",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+       SND_SOC_DAPM_MIXER("STFIR2 Volume",
+                       SND_SOC_NOPM, 0, 0,
+                       NULL, 0),
+};
+
+/*
+ * DAPM-routes
+ */
+static const struct snd_soc_dapm_route ab8500_dapm_routes[] = {
+       /* Power AB8500 audio-block when AD/DA is active */
+       {"Main Supply", NULL, "V-AUD"},
+       {"Main Supply", NULL, "audioclk"},
+       {"Main Supply", NULL, "Audio Power"},
+       {"Main Supply", NULL, "Audio Analog Power"},
+
+       {"DAC", NULL, "ab8500_0p"},
+       {"DAC", NULL, "Main Supply"},
+       {"ADC", NULL, "ab8500_0c"},
+       {"ADC", NULL, "Main Supply"},
+
+       /* ANC Configure */
+       {"ANC Configure Input", NULL, "Main Supply"},
+       {"ANC Configure Output", NULL, "ANC Configure Input"},
+
+       /* AD/DA */
+       {"ADC", NULL, "ADC Input"},
+       {"DAC Output", NULL, "DAC"},
+
+       /* Powerup charge pump if DA1/2 is in use */
+
+       {"DA_IN1", NULL, "ab8500_0p"},
+       {"DA_IN1", NULL, "Charge Pump"},
+       {"DA_IN2", NULL, "ab8500_0p"},
+       {"DA_IN2", NULL, "Charge Pump"},
+
+       /* Headset path */
+
+       {"DA1 Enable", NULL, "DA_IN1"},
+       {"DA2 Enable", NULL, "DA_IN2"},
+
+       {"HSL Digital Volume", NULL, "DA1 Enable"},
+       {"HSR Digital Volume", NULL, "DA2 Enable"},
+
+       {"HSL DAC", NULL, "HSL Digital Volume"},
+       {"HSR DAC", NULL, "HSR Digital Volume"},
+
+       {"HSL DAC Mute", NULL, "HSL DAC"},
+       {"HSR DAC Mute", NULL, "HSR DAC"},
+
+       {"HSL DAC Driver", NULL, "HSL DAC Mute"},
+       {"HSR DAC Driver", NULL, "HSR DAC Mute"},
+
+       {"HSL Mute", NULL, "HSL DAC Driver"},
+       {"HSR Mute", NULL, "HSR DAC Driver"},
+
+       {"HSL Enable", NULL, "HSL Mute"},
+       {"HSR Enable", NULL, "HSR Mute"},
+
+       {"HSL Volume", NULL, "HSL Enable"},
+       {"HSR Volume", NULL, "HSR Enable"},
+
+       {"Headset Left", NULL, "HSL Volume"},
+       {"Headset Right", NULL, "HSR Volume"},
+
+       /* HF or LineOut path */
+
+       {"DA_IN3", NULL, "ab8500_0p"},
+       {"DA3 Channel Volume", NULL, "DA_IN3"},
+       {"DA_IN4", NULL, "ab8500_0p"},
+       {"DA4 Channel Volume", NULL, "DA_IN4"},
+
+       {"Speaker Left Source", "Audio Path", "DA3 Channel Volume"},
+       {"Speaker Right Source", "Audio Path", "DA4 Channel Volume"},
+
+       {"DA3 or ANC path to HfL", NULL, "Speaker Left Source"},
+       {"DA4 or ANC path to HfR", NULL, "Speaker Right Source"},
+
+       /* HF path */
+
+       {"HFL DAC", NULL, "DA3 or ANC path to HfL"},
+       {"HFR DAC", NULL, "DA4 or ANC path to HfR"},
+
+       {"HFL Enable", NULL, "HFL DAC"},
+       {"HFR Enable", NULL, "HFR DAC"},
+
+       {"Speaker Left", NULL, "HFL Enable"},
+       {"Speaker Right", NULL, "HFR Enable"},
+
+       /* Earpiece path */
+
+       {"Earpiece or LineOut Mono Source", "Headset Left",
+               "HSL Digital Volume"},
+       {"Earpiece or LineOut Mono Source", "Speaker Left",
+               "DA3 or ANC path to HfL"},
+
+       {"EAR DAC", NULL, "Earpiece or LineOut Mono Source"},
+
+       {"EAR Mute", NULL, "EAR DAC"},
+
+       {"EAR Enable", NULL, "EAR Mute"},
+
+       {"Earpiece", NULL, "EAR Enable"},
+
+       /* LineOut path stereo */
+
+       {"LineOut Source", "Stereo Path", "HSL DAC Driver"},
+       {"LineOut Source", "Stereo Path", "HSR DAC Driver"},
+
+       /* LineOut path mono */
+
+       {"LineOut Source", "Mono Path", "EAR DAC"},
+
+       /* LineOut path */
+
+       {"LOL Disable HFL", NULL, "LineOut Source"},
+       {"LOR Disable HFR", NULL, "LineOut Source"},
+
+       {"LOL Enable", NULL, "LOL Disable HFL"},
+       {"LOR Enable", NULL, "LOR Disable HFR"},
+
+       {"LineOut Left", NULL, "LOL Enable"},
+       {"LineOut Right", NULL, "LOR Enable"},
+
+       /* Vibrator path */
+
+       {"DA_IN5", NULL, "ab8500_0p"},
+       {"DA5 Channel Volume", NULL, "DA_IN5"},
+       {"DA_IN6", NULL, "ab8500_0p"},
+       {"DA6 Channel Volume", NULL, "DA_IN6"},
+
+       {"VIB1 DAC", NULL, "DA5 Channel Volume"},
+       {"VIB2 DAC", NULL, "DA6 Channel Volume"},
+
+       {"Vibra 1 Controller", "Audio Path", "VIB1 DAC"},
+       {"Vibra 2 Controller", "Audio Path", "VIB2 DAC"},
+       {"Vibra 1 Controller", "PWM Generator", "PWMGEN1"},
+       {"Vibra 2 Controller", "PWM Generator", "PWMGEN2"},
+
+       {"VIB1 Enable", NULL, "Vibra 1 Controller"},
+       {"VIB2 Enable", NULL, "Vibra 2 Controller"},
+
+       {"Vibra 1", NULL, "VIB1 Enable"},
+       {"Vibra 2", NULL, "VIB2 Enable"},
+
+
+       /* Mic 2 */
+
+       {"MIC2 V-AMICx Enable", NULL, "Mic 2"},
+
+       /* LineIn */
+       {"LINL Mute", NULL, "LineIn Left"},
+       {"LINR Mute", NULL, "LineIn Right"},
+
+       {"LINL Enable", NULL, "LINL Mute"},
+       {"LINR Enable", NULL, "LINR Mute"},
+
+       /* LineIn, Mic 2 */
+       {"Mic 2 or LINR Select", "LineIn Right", "LINR Enable"},
+       {"Mic 2 or LINR Select", "Mic 2", "MIC2 V-AMICx Enable"},
+
+       {"LINL ADC", NULL, "LINL Enable"},
+       {"LINR ADC", NULL, "Mic 2 or LINR Select"},
+
+       {"AD1 Source Select", "LineIn Left", "LINL ADC"},
+       {"AD2 Source Select", "LineIn Right", "LINR ADC"},
+
+       {"AD1 Channel Volume", NULL, "AD1 Source Select"},
+       {"AD2 Channel Volume", NULL, "AD2 Source Select"},
+
+       {"AD12 Enable", NULL, "AD1 Channel Volume"},
+       {"AD12 Enable", NULL, "AD2 Channel Volume"},
+
+       {"AD_OUT1", NULL, "ab8500_0c"},
+       {"AD_OUT1", NULL, "AD12 Enable"},
+       {"AD_OUT2", NULL, "ab8500_0c"},
+       {"AD_OUT2", NULL, "AD12 Enable"},
+
+       /* Mic 1 */
+
+       {"MIC1 Mute", NULL, "Mic 1"},
+
+       {"MIC1A V-AMICx Enable", NULL, "MIC1 Mute"},
+       {"MIC1B V-AMICx Enable", NULL, "MIC1 Mute"},
+
+       {"Mic 1a or 1b Select", "Mic 1a", "MIC1A V-AMICx Enable"},
+       {"Mic 1a or 1b Select", "Mic 1b", "MIC1B V-AMICx Enable"},
+
+       {"MIC1 ADC", NULL, "Mic 1a or 1b Select"},
+
+       {"AD3 Source Select", "Mic 1", "MIC1 ADC"},
+
+       {"AD3 Channel Volume", NULL, "AD3 Source Select"},
+
+       {"AD3 Enable", NULL, "AD3 Channel Volume"},
+
+       {"AD_OUT3", NULL, "ab8500_0c"},
+       {"AD_OUT3", NULL, "AD3 Enable"},
+
+       /* HD Capture path */
+
+       {"AD5 Source Select", "Mic 2", "LINR ADC"},
+       {"AD6 Source Select", "Mic 1", "MIC1 ADC"},
+
+       {"AD5 Channel Volume", NULL, "AD5 Source Select"},
+       {"AD6 Channel Volume", NULL, "AD6 Source Select"},
+
+       {"AD57 Enable", NULL, "AD5 Channel Volume"},
+       {"AD68 Enable", NULL, "AD6 Channel Volume"},
+
+       {"AD_OUT57", NULL, "ab8500_0c"},
+       {"AD_OUT57", NULL, "AD57 Enable"},
+       {"AD_OUT68", NULL, "ab8500_0c"},
+       {"AD_OUT68", NULL, "AD68 Enable"},
+
+       /* Digital Microphone path */
+
+       {"DMic 1", NULL, "V-DMIC"},
+       {"DMic 2", NULL, "V-DMIC"},
+       {"DMic 3", NULL, "V-DMIC"},
+       {"DMic 4", NULL, "V-DMIC"},
+       {"DMic 5", NULL, "V-DMIC"},
+       {"DMic 6", NULL, "V-DMIC"},
+
+       {"AD1 Source Select", NULL, "DMic 1"},
+       {"AD2 Source Select", NULL, "DMic 2"},
+       {"AD3 Source Select", NULL, "DMic 3"},
+       {"AD5 Source Select", NULL, "DMic 5"},
+       {"AD6 Source Select", NULL, "DMic 6"},
+
+       {"AD4 Channel Volume", NULL, "DMic 4"},
+       {"AD4 Enable", NULL, "AD4 Channel Volume"},
+
+       {"AD_OUT4", NULL, "ab8500_0c"},
+       {"AD_OUT4", NULL, "AD4 Enable"},
+
+       /* LineIn Bypass path */
+
+       {"LINL to HSL Volume", NULL, "LINL Enable"},
+       {"LINR to HSR Volume", NULL, "LINR Enable"},
+
+       {"HSL DAC Driver", NULL, "LINL to HSL Volume"},
+       {"HSR DAC Driver", NULL, "LINR to HSR Volume"},
+
+       /* ANC path (Acoustic Noise Cancellation) */
+
+       {"ANC Source", "Mic 2 / DMic 5", "AD5 Channel Volume"},
+       {"ANC Source", "Mic 1 / DMic 6", "AD6 Channel Volume"},
+
+       {"ANC", "Switch", "ANC Source"},
+
+       {"Speaker Left Source", "ANC", "ANC"},
+       {"Speaker Right Source", "ANC", "ANC"},
+       {"ANC to Earpiece", "Switch", "ANC"},
+
+       {"HSL Digital Volume", NULL, "ANC to Earpiece"},
+
+       /* Sidetone Filter path */
+
+       {"Sidetone Left Source", "LineIn Left", "AD12 Enable"},
+       {"Sidetone Left Source", "LineIn Right", "AD12 Enable"},
+       {"Sidetone Left Source", "Mic 1", "AD3 Enable"},
+       {"Sidetone Left Source", "Headset Left", "DA_IN1"},
+       {"Sidetone Right Source", "LineIn Right", "AD12 Enable"},
+       {"Sidetone Right Source", "Mic 1", "AD3 Enable"},
+       {"Sidetone Right Source", "DMic 4", "AD4 Enable"},
+       {"Sidetone Right Source", "Headset Right", "DA_IN2"},
+
+       {"STFIR1 Control", NULL, "Sidetone Left Source"},
+       {"STFIR2 Control", NULL, "Sidetone Right Source"},
+
+       {"STFIR1 Volume", NULL, "STFIR1 Control"},
+       {"STFIR2 Volume", NULL, "STFIR2 Control"},
+
+       {"DA1 Enable", NULL, "STFIR1 Volume"},
+       {"DA2 Enable", NULL, "STFIR2 Volume"},
+};
+
+static const struct snd_soc_dapm_route ab8500_dapm_routes_mic1a_vamicx[] = {
+       {"MIC1A V-AMICx Enable", NULL, "V-AMIC1"},
+       {"MIC1A V-AMICx Enable", NULL, "V-AMIC2"},
+};
+
+static const struct snd_soc_dapm_route ab8500_dapm_routes_mic1b_vamicx[] = {
+       {"MIC1B V-AMICx Enable", NULL, "V-AMIC1"},
+       {"MIC1B V-AMICx Enable", NULL, "V-AMIC2"},
+};
+
+static const struct snd_soc_dapm_route ab8500_dapm_routes_mic2_vamicx[] = {
+       {"MIC2 V-AMICx Enable", NULL, "V-AMIC1"},
+       {"MIC2 V-AMICx Enable", NULL, "V-AMIC2"},
+};
+
+/* ANC FIR-coefficients configuration sequence */
+static void anc_fir(struct snd_soc_codec *codec,
+               unsigned int bnk, unsigned int par, unsigned int val)
+{
+       if (par == 0 && bnk == 0)
+               snd_soc_update_bits(codec, AB8500_ANCCONF1,
+                       BIT(AB8500_ANCCONF1_ANCFIRUPDATE),
+                       BIT(AB8500_ANCCONF1_ANCFIRUPDATE));
+
+       snd_soc_write(codec, AB8500_ANCCONF5, val >> 8 & 0xff);
+       snd_soc_write(codec, AB8500_ANCCONF6, val &  0xff);
+
+       if (par == AB8500_ANC_FIR_COEFFS - 1 && bnk == 1)
+               snd_soc_update_bits(codec, AB8500_ANCCONF1,
+                       BIT(AB8500_ANCCONF1_ANCFIRUPDATE), 0);
+}
+
+/* ANC IIR-coefficients configuration sequence */
+static void anc_iir(struct snd_soc_codec *codec, unsigned int bnk,
+               unsigned int par, unsigned int val)
+{
+       if (par == 0) {
+               if (bnk == 0) {
+                       snd_soc_update_bits(codec, AB8500_ANCCONF1,
+                                       BIT(AB8500_ANCCONF1_ANCIIRINIT),
+                                       BIT(AB8500_ANCCONF1_ANCIIRINIT));
+                       usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY);
+                       snd_soc_update_bits(codec, AB8500_ANCCONF1,
+                                       BIT(AB8500_ANCCONF1_ANCIIRINIT), 0);
+                       usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY);
+               } else {
+                       snd_soc_update_bits(codec, AB8500_ANCCONF1,
+                                       BIT(AB8500_ANCCONF1_ANCIIRUPDATE),
+                                       BIT(AB8500_ANCCONF1_ANCIIRUPDATE));
+               }
+       } else if (par > 3) {
+               snd_soc_write(codec, AB8500_ANCCONF7, 0);
+               snd_soc_write(codec, AB8500_ANCCONF8, val >> 16 & 0xff);
+       }
+
+       snd_soc_write(codec, AB8500_ANCCONF7, val >> 8 & 0xff);
+       snd_soc_write(codec, AB8500_ANCCONF8, val & 0xff);
+
+       if (par == AB8500_ANC_IIR_COEFFS - 1 && bnk == 1)
+               snd_soc_update_bits(codec, AB8500_ANCCONF1,
+                       BIT(AB8500_ANCCONF1_ANCIIRUPDATE), 0);
+}
+
+/* ANC IIR-/FIR-coefficients configuration sequence */
+static void anc_configure(struct snd_soc_codec *codec,
+                       bool apply_fir, bool apply_iir)
+{
+       struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+       unsigned int bnk, par, val;
+
+       dev_dbg(codec->dev, "%s: Enter.\n", __func__);
+
+       if (apply_fir)
+               snd_soc_update_bits(codec, AB8500_ANCCONF1,
+                       BIT(AB8500_ANCCONF1_ENANC), 0);
+
+       snd_soc_update_bits(codec, AB8500_ANCCONF1,
+               BIT(AB8500_ANCCONF1_ENANC), BIT(AB8500_ANCCONF1_ENANC));
+
+       if (apply_fir)
+               for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++)
+                       for (par = 0; par < AB8500_ANC_FIR_COEFFS; par++) {
+                               val = snd_soc_read(codec,
+                                               drvdata->anc_fir_values[par]);
+                               anc_fir(codec, bnk, par, val);
+                       }
+
+       if (apply_iir)
+               for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++)
+                       for (par = 0; par < AB8500_ANC_IIR_COEFFS; par++) {
+                               val = snd_soc_read(codec,
+                                               drvdata->anc_iir_values[par]);
+                               anc_iir(codec, bnk, par, val);
+                       }
+
+       dev_dbg(codec->dev, "%s: Exit.\n", __func__);
+}
+
+/*
+ * Control-events
+ */
+
+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 ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+
+       mutex_lock(&codec->mutex);
+       ucontrol->value.integer.value[0] = drvdata->sid_status;
+       mutex_unlock(&codec->mutex);
+
+       return 0;
+}
+
+/* Write sidetone FIR-coefficients configuration sequence */
+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 ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+       unsigned int param, sidconf, val;
+       int status = 1;
+
+       dev_dbg(codec->dev, "%s: Enter\n", __func__);
+
+       if (ucontrol->value.integer.value[0] != SID_APPLY_FIR) {
+               dev_err(codec->dev,
+                       "%s: ERROR: This control supports '%s' only!\n",
+                       __func__, enum_sid_state[SID_APPLY_FIR]);
+               return -EIO;
+       }
+
+       mutex_lock(&codec->mutex);
+
+       sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF);
+       if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) {
+               if ((sidconf & BIT(AB8500_SIDFIRCONF_ENFIRSIDS)) == 0) {
+                       dev_err(codec->dev, "%s: Sidetone busy while off!\n",
+                               __func__);
+                       status = -EPERM;
+               } else {
+                       status = -EBUSY;
+               }
+               goto out;
+       }
+
+       snd_soc_write(codec, AB8500_SIDFIRADR, 0);
+
+       for (param = 0; param < AB8500_SID_FIR_COEFFS; param++) {
+               val = snd_soc_read(codec, drvdata->sid_fir_values[param]);
+               snd_soc_write(codec, AB8500_SIDFIRCOEF1, val >> 8 & 0xff);
+               snd_soc_write(codec, AB8500_SIDFIRCOEF2, val & 0xff);
+       }
+
+       snd_soc_update_bits(codec, AB8500_SIDFIRADR,
+               BIT(AB8500_SIDFIRADR_FIRSIDSET),
+               BIT(AB8500_SIDFIRADR_FIRSIDSET));
+       snd_soc_update_bits(codec, AB8500_SIDFIRADR,
+               BIT(AB8500_SIDFIRADR_FIRSIDSET), 0);
+
+       drvdata->sid_status = SID_FIR_CONFIGURED;
+
+out:
+       mutex_unlock(&codec->mutex);
+
+       dev_dbg(codec->dev, "%s: Exit\n", __func__);
+
+       return status;
+}
+
+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 ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+
+       mutex_lock(&codec->mutex);
+       ucontrol->value.integer.value[0] = drvdata->anc_status;
+       mutex_unlock(&codec->mutex);
+
+       return 0;
+}
+
+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 ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
+       struct device *dev = codec->dev;
+       bool apply_fir, apply_iir;
+       int req, status;
+
+       dev_dbg(dev, "%s: Enter.\n", __func__);
+
+       mutex_lock(&drvdata->anc_lock);
+
+       req = ucontrol->value.integer.value[0];
+       if (req != ANC_APPLY_FIR_IIR && req != ANC_APPLY_FIR &&
+               req != ANC_APPLY_IIR) {
+               dev_err(dev, "%s: ERROR: Unsupported status to set '%s'!\n",
+                       __func__, enum_anc_state[req]);
+               return -EINVAL;
+       }
+       apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR;
+       apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR;
+
+       status = snd_soc_dapm_force_enable_pin(&codec->dapm,
+                                       "ANC Configure Input");
+       if (status < 0) {
+               dev_err(dev,
+                       "%s: ERROR: Failed to enable power (status = %d)!\n",
+                       __func__, status);
+               goto cleanup;
+       }
+       snd_soc_dapm_sync(&codec->dapm);
+
+       mutex_lock(&codec->mutex);
+       anc_configure(codec, apply_fir, apply_iir);
+       mutex_unlock(&codec->mutex);
+
+       if (apply_fir) {
+               if (drvdata->anc_status == ANC_IIR_CONFIGURED)
+                       drvdata->anc_status = ANC_FIR_IIR_CONFIGURED;
+               else if (drvdata->anc_status != ANC_FIR_IIR_CONFIGURED)
+                       drvdata->anc_status =  ANC_FIR_CONFIGURED;
+       }
+       if (apply_iir) {
+               if (drvdata->anc_status == ANC_FIR_CONFIGURED)
+                       drvdata->anc_status = ANC_FIR_IIR_CONFIGURED;
+               else if (drvdata->anc_status != ANC_FIR_IIR_CONFIGURED)
+                       drvdata->anc_status =  ANC_IIR_CONFIGURED;
+       }
+
+       status = snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
+       snd_soc_dapm_sync(&codec->dapm);
+
+cleanup:
+       mutex_unlock(&drvdata->anc_lock);
+
+       if (status < 0)
+               dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n",
+                       __func__, status);
+
+       dev_dbg(dev, "%s: Exit.\n", __func__);
+
+       return (status < 0) ? status : 1;
+}
+
+static int filter_control_info(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo)
+{
+       struct filter_control *fc =
+                       (struct filter_control *)kcontrol->private_value;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = fc->count;
+       uinfo->value.integer.min = fc->min;
+       uinfo->value.integer.max = fc->max;
+
+       return 0;
+}
+
+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 filter_control *fc =
+                       (struct filter_control *)kcontrol->private_value;
+       unsigned int i;
+
+       mutex_lock(&codec->mutex);
+       for (i = 0; i < fc->count; i++)
+               ucontrol->value.integer.value[i] = fc->value[i];
+       mutex_unlock(&codec->mutex);
+
+       return 0;
+}
+
+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 filter_control *fc =
+                       (struct filter_control *)kcontrol->private_value;
+       unsigned int i;
+
+       mutex_lock(&codec->mutex);
+       for (i = 0; i < fc->count; i++)
+               fc->value[i] = ucontrol->value.integer.value[i];
+       mutex_unlock(&codec->mutex);
+
+       return 0;
+}
+
+/*
+ * Controls - Non-DAPM ASoC
+ */
+
+static DECLARE_TLV_DB_SCALE(adx_dig_gain_tlv, -3200, 100, 1);
+/* -32dB = Mute */
+
+static DECLARE_TLV_DB_SCALE(dax_dig_gain_tlv, -6300, 100, 1);
+/* -63dB = Mute */
+
+static DECLARE_TLV_DB_SCALE(hs_ear_dig_gain_tlv, -100, 100, 1);
+/* -1dB = Mute */
+
+static const unsigned int hs_gain_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 3, TLV_DB_SCALE_ITEM(-3200, 400, 0),
+       4, 15, TLV_DB_SCALE_ITEM(-1800, 200, 0),
+};
+
+static DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(lin_gain_tlv, -1000, 200, 0);
+
+static DECLARE_TLV_DB_SCALE(lin2hs_gain_tlv, -3800, 200, 1);
+/* -38dB = Mute */
+
+static const char * const enum_hsfadspeed[] = {"2ms", "0.5ms", "10.6ms",
+                                       "5ms"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_hsfadspeed,
+       AB8500_DIGMICCONF, AB8500_DIGMICCONF_HSFADSPEED, enum_hsfadspeed);
+
+static const char * const enum_envdetthre[] = {
+       "250mV", "300mV", "350mV", "400mV",
+       "450mV", "500mV", "550mV", "600mV",
+       "650mV", "700mV", "750mV", "800mV",
+       "850mV", "900mV", "950mV", "1.00V" };
+static SOC_ENUM_SINGLE_DECL(soc_enum_envdeththre,
+       AB8500_ENVCPCONF, AB8500_ENVCPCONF_ENVDETHTHRE, enum_envdetthre);
+static SOC_ENUM_SINGLE_DECL(soc_enum_envdetlthre,
+       AB8500_ENVCPCONF, AB8500_ENVCPCONF_ENVDETLTHRE, enum_envdetthre);
+static const char * const enum_envdettime[] = {
+       "26.6us", "53.2us", "106us",  "213us",
+       "426us",  "851us",  "1.70ms", "3.40ms",
+       "6.81ms", "13.6ms", "27.2ms", "54.5ms",
+       "109ms",  "218ms",  "436ms",  "872ms" };
+static SOC_ENUM_SINGLE_DECL(soc_enum_envdettime,
+       AB8500_SIGENVCONF, AB8500_SIGENVCONF_ENVDETTIME, enum_envdettime);
+
+static const char * const enum_sinc31[] = {"Sinc 3", "Sinc 1"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_hsesinc, AB8500_HSLEARDIGGAIN,
+                       AB8500_HSLEARDIGGAIN_HSSINC1, enum_sinc31);
+
+static const char * const enum_fadespeed[] = {"1ms", "4ms", "8ms", "16ms"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_fadespeed, AB8500_HSRDIGGAIN,
+                       AB8500_HSRDIGGAIN_FADESPEED, enum_fadespeed);
+
+/* Earpiece */
+
+static const char * const enum_lowpow[] = {"Normal", "Low Power"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_eardaclowpow, AB8500_ANACONF1,
+                       AB8500_ANACONF1_EARDACLOWPOW, enum_lowpow);
+static SOC_ENUM_SINGLE_DECL(soc_enum_eardrvlowpow, AB8500_ANACONF1,
+                       AB8500_ANACONF1_EARDRVLOWPOW, enum_lowpow);
+
+static const char * const enum_av_mode[] = {"Audio", "Voice"};
+static SOC_ENUM_DOUBLE_DECL(soc_enum_ad12voice, AB8500_ADFILTCONF,
+       AB8500_ADFILTCONF_AD1VOICE, AB8500_ADFILTCONF_AD2VOICE, enum_av_mode);
+static SOC_ENUM_DOUBLE_DECL(soc_enum_ad34voice, AB8500_ADFILTCONF,
+       AB8500_ADFILTCONF_AD3VOICE, AB8500_ADFILTCONF_AD4VOICE, enum_av_mode);
+
+/* DA */
+
+static SOC_ENUM_SINGLE_DECL(soc_enum_da12voice,
+                       AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_DA12VOICE,
+                       enum_av_mode);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da34voice,
+                       AB8500_DASLOTCONF3, AB8500_DASLOTCONF3_DA34VOICE,
+                       enum_av_mode);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da56voice,
+                       AB8500_DASLOTCONF5, AB8500_DASLOTCONF5_DA56VOICE,
+                       enum_av_mode);
+
+static const char * const enum_da2hslr[] = {"Sidetone", "Audio Path"};
+static SOC_ENUM_DOUBLE_DECL(soc_enum_da2hslr, AB8500_DIGMULTCONF1,
+                       AB8500_DIGMULTCONF1_DATOHSLEN,
+                       AB8500_DIGMULTCONF1_DATOHSREN, enum_da2hslr);
+
+static const char * const enum_sinc53[] = {"Sinc 5", "Sinc 3"};
+static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic12sinc, AB8500_DMICFILTCONF,
+                       AB8500_DMICFILTCONF_DMIC1SINC3,
+                       AB8500_DMICFILTCONF_DMIC2SINC3, enum_sinc53);
+static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic34sinc, AB8500_DMICFILTCONF,
+                       AB8500_DMICFILTCONF_DMIC3SINC3,
+                       AB8500_DMICFILTCONF_DMIC4SINC3, enum_sinc53);
+static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic56sinc, AB8500_DMICFILTCONF,
+                       AB8500_DMICFILTCONF_DMIC5SINC3,
+                       AB8500_DMICFILTCONF_DMIC6SINC3, enum_sinc53);
+
+/* Digital interface - DA from slot mapping */
+static const char * const enum_da_from_slot_map[] = {"SLOT0",
+                                       "SLOT1",
+                                       "SLOT2",
+                                       "SLOT3",
+                                       "SLOT4",
+                                       "SLOT5",
+                                       "SLOT6",
+                                       "SLOT7",
+                                       "SLOT8",
+                                       "SLOT9",
+                                       "SLOT10",
+                                       "SLOT11",
+                                       "SLOT12",
+                                       "SLOT13",
+                                       "SLOT14",
+                                       "SLOT15",
+                                       "SLOT16",
+                                       "SLOT17",
+                                       "SLOT18",
+                                       "SLOT19",
+                                       "SLOT20",
+                                       "SLOT21",
+                                       "SLOT22",
+                                       "SLOT23",
+                                       "SLOT24",
+                                       "SLOT25",
+                                       "SLOT26",
+                                       "SLOT27",
+                                       "SLOT28",
+                                       "SLOT29",
+                                       "SLOT30",
+                                       "SLOT31"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_da1slotmap,
+                       AB8500_DASLOTCONF1, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+                       enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da2slotmap,
+                       AB8500_DASLOTCONF2, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+                       enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da3slotmap,
+                       AB8500_DASLOTCONF3, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+                       enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da4slotmap,
+                       AB8500_DASLOTCONF4, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+                       enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da5slotmap,
+                       AB8500_DASLOTCONF5, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+                       enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da6slotmap,
+                       AB8500_DASLOTCONF6, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+                       enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da7slotmap,
+                       AB8500_DASLOTCONF7, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+                       enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da8slotmap,
+                       AB8500_DASLOTCONF8, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+                       enum_da_from_slot_map);
+
+/* Digital interface - AD to slot mapping */
+static const char * const enum_ad_to_slot_map[] = {"AD_OUT1",
+                                       "AD_OUT2",
+                                       "AD_OUT3",
+                                       "AD_OUT4",
+                                       "AD_OUT5",
+                                       "AD_OUT6",
+                                       "AD_OUT7",
+                                       "AD_OUT8",
+                                       "zeroes",
+                                       "tristate"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot0map,
+                       AB8500_ADSLOTSEL1, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot1map,
+                       AB8500_ADSLOTSEL1, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot2map,
+                       AB8500_ADSLOTSEL2, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot3map,
+                       AB8500_ADSLOTSEL2, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot4map,
+                       AB8500_ADSLOTSEL3, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot5map,
+                       AB8500_ADSLOTSEL3, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot6map,
+                       AB8500_ADSLOTSEL4, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot7map,
+                       AB8500_ADSLOTSEL4, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot8map,
+                       AB8500_ADSLOTSEL5, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot9map,
+                       AB8500_ADSLOTSEL5, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot10map,
+                       AB8500_ADSLOTSEL6, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot11map,
+                       AB8500_ADSLOTSEL6, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot12map,
+                       AB8500_ADSLOTSEL7, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot13map,
+                       AB8500_ADSLOTSEL7, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot14map,
+                       AB8500_ADSLOTSEL8, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot15map,
+                       AB8500_ADSLOTSEL8, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot16map,
+                       AB8500_ADSLOTSEL9, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot17map,
+                       AB8500_ADSLOTSEL9, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot18map,
+                       AB8500_ADSLOTSEL10, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot19map,
+                       AB8500_ADSLOTSEL10, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot20map,
+                       AB8500_ADSLOTSEL11, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot21map,
+                       AB8500_ADSLOTSEL11, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot22map,
+                       AB8500_ADSLOTSEL12, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot23map,
+                       AB8500_ADSLOTSEL12, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot24map,
+                       AB8500_ADSLOTSEL13, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot25map,
+                       AB8500_ADSLOTSEL13, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot26map,
+                       AB8500_ADSLOTSEL14, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot27map,
+                       AB8500_ADSLOTSEL14, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot28map,
+                       AB8500_ADSLOTSEL15, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot29map,
+                       AB8500_ADSLOTSEL15, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot30map,
+                       AB8500_ADSLOTSEL16, AB8500_ADSLOTSELX_EVEN_SHIFT,
+                       enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot31map,
+                       AB8500_ADSLOTSEL16, AB8500_ADSLOTSELX_ODD_SHIFT,
+                       enum_ad_to_slot_map);
+
+/* Digital interface - Burst mode */
+static const char * const enum_mask[] = {"Unmasked", "Masked"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomask,
+                       AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFOMASK,
+                       enum_mask);
+static const char * const enum_bitclk0[] = {"19_2_MHz", "38_4_MHz"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_bfifo19m2,
+                       AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFO19M2,
+                       enum_bitclk0);
+static const char * const enum_slavemaster[] = {"Slave", "Master"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomast,
+                       AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOMAST_SHIFT,
+                       enum_slavemaster);
+
+/* Sidetone */
+static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_sidstate, enum_sid_state);
+
+/* ANC */
+static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_ancstate, enum_anc_state);
+
+static struct snd_kcontrol_new ab8500_ctrls[] = {
+       /* Charge pump */
+       SOC_ENUM("Charge Pump High Threshold For Low Voltage",
+               soc_enum_envdeththre),
+       SOC_ENUM("Charge Pump Low Threshold For Low Voltage",
+               soc_enum_envdetlthre),
+       SOC_SINGLE("Charge Pump Envelope Detection Switch",
+               AB8500_SIGENVCONF, AB8500_SIGENVCONF_ENVDETCPEN,
+               1, 0),
+       SOC_ENUM("Charge Pump Envelope Detection Decay Time",
+               soc_enum_envdettime),
+
+       /* Headset */
+       SOC_ENUM("Headset Mode", soc_enum_da12voice),
+       SOC_SINGLE("Headset High Pass Switch",
+               AB8500_ANACONF1, AB8500_ANACONF1_HSHPEN,
+               1, 0),
+       SOC_SINGLE("Headset Low Power Switch",
+               AB8500_ANACONF1, AB8500_ANACONF1_HSLOWPOW,
+               1, 0),
+       SOC_SINGLE("Headset DAC Low Power Switch",
+               AB8500_ANACONF1, AB8500_ANACONF1_DACLOWPOW1,
+               1, 0),
+       SOC_SINGLE("Headset DAC Drv Low Power Switch",
+               AB8500_ANACONF1, AB8500_ANACONF1_DACLOWPOW0,
+               1, 0),
+       SOC_ENUM("Headset Fade Speed", soc_enum_hsfadspeed),
+       SOC_ENUM("Headset Source", soc_enum_da2hslr),
+       SOC_ENUM("Headset Filter", soc_enum_hsesinc),
+       SOC_DOUBLE_R_TLV("Headset Master Volume",
+               AB8500_DADIGGAIN1, AB8500_DADIGGAIN2,
+               0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv),
+       SOC_DOUBLE_R_TLV("Headset Digital Volume",
+               AB8500_HSLEARDIGGAIN, AB8500_HSRDIGGAIN,
+               0, AB8500_HSLEARDIGGAIN_HSLDGAIN_MAX, 1, hs_ear_dig_gain_tlv),
+       SOC_DOUBLE_TLV("Headset Volume",
+               AB8500_ANAGAIN3,
+               AB8500_ANAGAIN3_HSLGAIN, AB8500_ANAGAIN3_HSRGAIN,
+               AB8500_ANAGAIN3_HSXGAIN_MAX, 1, hs_gain_tlv),
+
+       /* Earpiece */
+       SOC_ENUM("Earpiece DAC Mode",
+               soc_enum_eardaclowpow),
+       SOC_ENUM("Earpiece DAC Drv Mode",
+               soc_enum_eardrvlowpow),
+
+       /* HandsFree */
+       SOC_ENUM("HF Mode", soc_enum_da34voice),
+       SOC_SINGLE("HF and Headset Swap Switch",
+               AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_SWAPDA12_34,
+               1, 0),
+       SOC_DOUBLE("HF Low EMI Mode Switch",
+               AB8500_CLASSDCONF1,
+               AB8500_CLASSDCONF1_HFLSWAPEN, AB8500_CLASSDCONF1_HFRSWAPEN,
+               1, 0),
+       SOC_DOUBLE("HF FIR Bypass Switch",
+               AB8500_CLASSDCONF2,
+               AB8500_CLASSDCONF2_FIRBYP0, AB8500_CLASSDCONF2_FIRBYP1,
+               1, 0),
+       SOC_DOUBLE("HF High Volume Switch",
+               AB8500_CLASSDCONF2,
+               AB8500_CLASSDCONF2_HIGHVOLEN0, AB8500_CLASSDCONF2_HIGHVOLEN1,
+               1, 0),
+       SOC_SINGLE("HF L and R Bridge Switch",
+               AB8500_CLASSDCONF1, AB8500_CLASSDCONF1_PARLHF,
+               1, 0),
+       SOC_DOUBLE_R_TLV("HF Master Volume",
+               AB8500_DADIGGAIN3, AB8500_DADIGGAIN4,
+               0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv),
+
+       /* Vibra */
+       SOC_DOUBLE("Vibra High Volume Switch",
+               AB8500_CLASSDCONF2,
+               AB8500_CLASSDCONF2_HIGHVOLEN2, AB8500_CLASSDCONF2_HIGHVOLEN3,
+               1, 0),
+       SOC_DOUBLE("Vibra Low EMI Mode Switch",
+               AB8500_CLASSDCONF1,
+               AB8500_CLASSDCONF1_VIB1SWAPEN, AB8500_CLASSDCONF1_VIB2SWAPEN,
+               1, 0),
+       SOC_DOUBLE("Vibra FIR Bypass Switch",
+               AB8500_CLASSDCONF2,
+               AB8500_CLASSDCONF2_FIRBYP2, AB8500_CLASSDCONF2_FIRBYP3,
+               1, 0),
+       SOC_ENUM("Vibra Mode", soc_enum_da56voice),
+       SOC_DOUBLE_R("Vibra PWM Duty Cycle N",
+               AB8500_PWMGENCONF3, AB8500_PWMGENCONF5,
+               AB8500_PWMGENCONFX_PWMVIBXDUTCYC,
+               AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX, 0),
+       SOC_DOUBLE_R("Vibra PWM Duty Cycle P",
+               AB8500_PWMGENCONF2, AB8500_PWMGENCONF4,
+               AB8500_PWMGENCONFX_PWMVIBXDUTCYC,
+               AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX, 0),
+       SOC_SINGLE("Vibra 1 and 2 Bridge Switch",
+               AB8500_CLASSDCONF1, AB8500_CLASSDCONF1_PARLVIB,
+               1, 0),
+       SOC_DOUBLE_R_TLV("Vibra Master Volume",
+               AB8500_DADIGGAIN5, AB8500_DADIGGAIN6,
+               0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv),
+
+       /* HandsFree, Vibra */
+       SOC_SINGLE("ClassD High Pass Volume",
+               AB8500_CLASSDCONF3, AB8500_CLASSDCONF3_DITHHPGAIN,
+               AB8500_CLASSDCONF3_DITHHPGAIN_MAX, 0),
+       SOC_SINGLE("ClassD White Volume",
+               AB8500_CLASSDCONF3, AB8500_CLASSDCONF3_DITHWGAIN,
+               AB8500_CLASSDCONF3_DITHWGAIN_MAX, 0),
+
+       /* Mic 1, Mic 2, LineIn */
+       SOC_DOUBLE_R_TLV("Mic Master Volume",
+               AB8500_ADDIGGAIN3, AB8500_ADDIGGAIN4,
+               0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv),
+
+       /* Mic 1 */
+       SOC_SINGLE_TLV("Mic 1",
+               AB8500_ANAGAIN1,
+               AB8500_ANAGAINX_MICXGAIN,
+               AB8500_ANAGAINX_MICXGAIN_MAX, 0, mic_gain_tlv),
+       SOC_SINGLE("Mic 1 Low Power Switch",
+               AB8500_ANAGAIN1, AB8500_ANAGAINX_LOWPOWMICX,
+               1, 0),
+
+       /* Mic 2 */
+       SOC_DOUBLE("Mic High Pass Switch",
+               AB8500_ADFILTCONF,
+               AB8500_ADFILTCONF_AD3NH, AB8500_ADFILTCONF_AD4NH,
+               1, 1),
+       SOC_ENUM("Mic Mode", soc_enum_ad34voice),
+       SOC_ENUM("Mic Filter", soc_enum_dmic34sinc),
+       SOC_SINGLE_TLV("Mic 2",
+               AB8500_ANAGAIN2,
+               AB8500_ANAGAINX_MICXGAIN,
+               AB8500_ANAGAINX_MICXGAIN_MAX, 0, mic_gain_tlv),
+       SOC_SINGLE("Mic 2 Low Power Switch",
+               AB8500_ANAGAIN2, AB8500_ANAGAINX_LOWPOWMICX,
+               1, 0),
+
+       /* LineIn */
+       SOC_DOUBLE("LineIn High Pass Switch",
+               AB8500_ADFILTCONF,
+               AB8500_ADFILTCONF_AD1NH, AB8500_ADFILTCONF_AD2NH,
+               1, 1),
+       SOC_ENUM("LineIn Filter", soc_enum_dmic12sinc),
+       SOC_ENUM("LineIn Mode", soc_enum_ad12voice),
+       SOC_DOUBLE_R_TLV("LineIn Master Volume",
+               AB8500_ADDIGGAIN1, AB8500_ADDIGGAIN2,
+               0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv),
+       SOC_DOUBLE_TLV("LineIn",
+               AB8500_ANAGAIN4,
+               AB8500_ANAGAIN4_LINLGAIN, AB8500_ANAGAIN4_LINRGAIN,
+               AB8500_ANAGAIN4_LINXGAIN_MAX, 0, lin_gain_tlv),
+       SOC_DOUBLE_R_TLV("LineIn to Headset Volume",
+               AB8500_DIGLINHSLGAIN, AB8500_DIGLINHSRGAIN,
+               AB8500_DIGLINHSXGAIN_LINTOHSXGAIN,
+               AB8500_DIGLINHSXGAIN_LINTOHSXGAIN_MAX,
+               1, lin2hs_gain_tlv),
+
+       /* DMic */
+       SOC_ENUM("DMic Filter", soc_enum_dmic56sinc),
+       SOC_DOUBLE_R_TLV("DMic Master Volume",
+               AB8500_ADDIGGAIN5, AB8500_ADDIGGAIN6,
+               0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv),
+
+       /* Digital gains */
+       SOC_ENUM("Digital Gain Fade Speed", soc_enum_fadespeed),
+
+       /* Analog loopback */
+       SOC_DOUBLE_R_TLV("Analog Loopback Volume",
+               AB8500_ADDIGLOOPGAIN1, AB8500_ADDIGLOOPGAIN2,
+               0, AB8500_ADDIGLOOPGAINX_ADXLBGAIN_MAX, 1, dax_dig_gain_tlv),
+
+       /* Digital interface - DA from slot mapping */
+       SOC_ENUM("Digital Interface DA 1 From Slot Map", soc_enum_da1slotmap),
+       SOC_ENUM("Digital Interface DA 2 From Slot Map", soc_enum_da2slotmap),
+       SOC_ENUM("Digital Interface DA 3 From Slot Map", soc_enum_da3slotmap),
+       SOC_ENUM("Digital Interface DA 4 From Slot Map", soc_enum_da4slotmap),
+       SOC_ENUM("Digital Interface DA 5 From Slot Map", soc_enum_da5slotmap),
+       SOC_ENUM("Digital Interface DA 6 From Slot Map", soc_enum_da6slotmap),
+       SOC_ENUM("Digital Interface DA 7 From Slot Map", soc_enum_da7slotmap),
+       SOC_ENUM("Digital Interface DA 8 From Slot Map", soc_enum_da8slotmap),
+
+       /* Digital interface - AD to slot mapping */
+       SOC_ENUM("Digital Interface AD To Slot 0 Map", soc_enum_adslot0map),
+       SOC_ENUM("Digital Interface AD To Slot 1 Map", soc_enum_adslot1map),
+       SOC_ENUM("Digital Interface AD To Slot 2 Map", soc_enum_adslot2map),
+       SOC_ENUM("Digital Interface AD To Slot 3 Map", soc_enum_adslot3map),
+       SOC_ENUM("Digital Interface AD To Slot 4 Map", soc_enum_adslot4map),
+       SOC_ENUM("Digital Interface AD To Slot 5 Map", soc_enum_adslot5map),
+       SOC_ENUM("Digital Interface AD To Slot 6 Map", soc_enum_adslot6map),
+       SOC_ENUM("Digital Interface AD To Slot 7 Map", soc_enum_adslot7map),
+       SOC_ENUM("Digital Interface AD To Slot 8 Map", soc_enum_adslot8map),
+       SOC_ENUM("Digital Interface AD To Slot 9 Map", soc_enum_adslot9map),
+       SOC_ENUM("Digital Interface AD To Slot 10 Map", soc_enum_adslot10map),
+       SOC_ENUM("Digital Interface AD To Slot 11 Map", soc_enum_adslot11map),
+       SOC_ENUM("Digital Interface AD To Slot 12 Map", soc_enum_adslot12map),
+       SOC_ENUM("Digital Interface AD To Slot 13 Map", soc_enum_adslot13map),
+       SOC_ENUM("Digital Interface AD To Slot 14 Map", soc_enum_adslot14map),
+       SOC_ENUM("Digital Interface AD To Slot 15 Map", soc_enum_adslot15map),
+       SOC_ENUM("Digital Interface AD To Slot 16 Map", soc_enum_adslot16map),
+       SOC_ENUM("Digital Interface AD To Slot 17 Map", soc_enum_adslot17map),
+       SOC_ENUM("Digital Interface AD To Slot 18 Map", soc_enum_adslot18map),
+       SOC_ENUM("Digital Interface AD To Slot 19 Map", soc_enum_adslot19map),
+       SOC_ENUM("Digital Interface AD To Slot 20 Map", soc_enum_adslot20map),
+       SOC_ENUM("Digital Interface AD To Slot 21 Map", soc_enum_adslot21map),
+       SOC_ENUM("Digital Interface AD To Slot 22 Map", soc_enum_adslot22map),
+       SOC_ENUM("Digital Interface AD To Slot 23 Map", soc_enum_adslot23map),
+       SOC_ENUM("Digital Interface AD To Slot 24 Map", soc_enum_adslot24map),
+       SOC_ENUM("Digital Interface AD To Slot 25 Map", soc_enum_adslot25map),
+       SOC_ENUM("Digital Interface AD To Slot 26 Map", soc_enum_adslot26map),
+       SOC_ENUM("Digital Interface AD To Slot 27 Map", soc_enum_adslot27map),
+       SOC_ENUM("Digital Interface AD To Slot 28 Map", soc_enum_adslot28map),
+       SOC_ENUM("Digital Interface AD To Slot 29 Map", soc_enum_adslot29map),
+       SOC_ENUM("Digital Interface AD To Slot 30 Map", soc_enum_adslot30map),
+       SOC_ENUM("Digital Interface AD To Slot 31 Map", soc_enum_adslot31map),
+
+       /* Digital interface - Loopback */
+       SOC_SINGLE("Digital Interface AD 1 Loopback Switch",
+               AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_DAI7TOADO1,
+               1, 0),
+       SOC_SINGLE("Digital Interface AD 2 Loopback Switch",
+               AB8500_DASLOTCONF2, AB8500_DASLOTCONF2_DAI8TOADO2,
+               1, 0),
+       SOC_SINGLE("Digital Interface AD 3 Loopback Switch",
+               AB8500_DASLOTCONF3, AB8500_DASLOTCONF3_DAI7TOADO3,
+               1, 0),
+       SOC_SINGLE("Digital Interface AD 4 Loopback Switch",
+               AB8500_DASLOTCONF4, AB8500_DASLOTCONF4_DAI8TOADO4,
+               1, 0),
+       SOC_SINGLE("Digital Interface AD 5 Loopback Switch",
+               AB8500_DASLOTCONF5, AB8500_DASLOTCONF5_DAI7TOADO5,
+               1, 0),
+       SOC_SINGLE("Digital Interface AD 6 Loopback Switch",
+               AB8500_DASLOTCONF6, AB8500_DASLOTCONF6_DAI8TOADO6,
+               1, 0),
+       SOC_SINGLE("Digital Interface AD 7 Loopback Switch",
+               AB8500_DASLOTCONF7, AB8500_DASLOTCONF7_DAI8TOADO7,
+               1, 0),
+       SOC_SINGLE("Digital Interface AD 8 Loopback Switch",
+               AB8500_DASLOTCONF8, AB8500_DASLOTCONF8_DAI7TOADO8,
+               1, 0),
+
+       /* Digital interface - Burst FIFO */
+       SOC_SINGLE("Digital Interface 0 FIFO Enable Switch",
+               AB8500_DIGIFCONF3, AB8500_DIGIFCONF3_IF0BFIFOEN,
+               1, 0),
+       SOC_ENUM("Burst FIFO Mask", soc_enum_bfifomask),
+       SOC_ENUM("Burst FIFO Bit-clock Frequency", soc_enum_bfifo19m2),
+       SOC_SINGLE("Burst FIFO Threshold",
+               AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFOINT_SHIFT,
+               AB8500_FIFOCONF1_BFIFOINT_MAX, 0),
+       SOC_SINGLE("Burst FIFO Length",
+               AB8500_FIFOCONF2, AB8500_FIFOCONF2_BFIFOTX_SHIFT,
+               AB8500_FIFOCONF2_BFIFOTX_MAX, 0),
+       SOC_SINGLE("Burst FIFO EOS Extra Slots",
+               AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOEXSL_SHIFT,
+               AB8500_FIFOCONF3_BFIFOEXSL_MAX, 0),
+       SOC_SINGLE("Burst FIFO FS Extra Bit-clocks",
+               AB8500_FIFOCONF3, AB8500_FIFOCONF3_PREBITCLK0_SHIFT,
+               AB8500_FIFOCONF3_PREBITCLK0_MAX, 0),
+       SOC_ENUM("Burst FIFO Interface Mode", soc_enum_bfifomast),
+
+       SOC_SINGLE("Burst FIFO Interface Switch",
+               AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFORUN_SHIFT,
+               1, 0),
+       SOC_SINGLE("Burst FIFO Switch Frame Number",
+               AB8500_FIFOCONF4, AB8500_FIFOCONF4_BFIFOFRAMSW_SHIFT,
+               AB8500_FIFOCONF4_BFIFOFRAMSW_MAX, 0),
+       SOC_SINGLE("Burst FIFO Wake Up Delay",
+               AB8500_FIFOCONF5, AB8500_FIFOCONF5_BFIFOWAKEUP_SHIFT,
+               AB8500_FIFOCONF5_BFIFOWAKEUP_MAX, 0),
+       SOC_SINGLE("Burst FIFO Samples In FIFO",
+               AB8500_FIFOCONF6, AB8500_FIFOCONF6_BFIFOSAMPLE_SHIFT,
+               AB8500_FIFOCONF6_BFIFOSAMPLE_MAX, 0),
+
+       /* ANC */
+       SOC_ENUM_EXT("ANC Status", soc_enum_ancstate,
+               anc_status_control_get, anc_status_control_put),
+       SOC_SINGLE_XR_SX("ANC Warp Delay Shift",
+               AB8500_ANCCONF2, 1, AB8500_ANCCONF2_SHIFT,
+               AB8500_ANCCONF2_MIN, AB8500_ANCCONF2_MAX, 0),
+       SOC_SINGLE_XR_SX("ANC FIR Output Shift",
+               AB8500_ANCCONF3, 1, AB8500_ANCCONF3_SHIFT,
+               AB8500_ANCCONF3_MIN, AB8500_ANCCONF3_MAX, 0),
+       SOC_SINGLE_XR_SX("ANC IIR Output Shift",
+               AB8500_ANCCONF4, 1, AB8500_ANCCONF4_SHIFT,
+               AB8500_ANCCONF4_MIN, AB8500_ANCCONF4_MAX, 0),
+       SOC_SINGLE_XR_SX("ANC Warp Delay",
+               AB8500_ANCCONF9, 2, AB8500_ANC_WARP_DELAY_SHIFT,
+               AB8500_ANC_WARP_DELAY_MIN, AB8500_ANC_WARP_DELAY_MAX, 0),
+
+       /* Sidetone */
+       SOC_ENUM_EXT("Sidetone Status", soc_enum_sidstate,
+               sid_status_control_get, sid_status_control_put),
+       SOC_SINGLE_STROBE("Sidetone Reset",
+               AB8500_SIDFIRADR, AB8500_SIDFIRADR_FIRSIDSET, 0),
+};
+
+static struct snd_kcontrol_new ab8500_filter_controls[] = {
+       AB8500_FILTER_CONTROL("ANC FIR Coefficients", AB8500_ANC_FIR_COEFFS,
+               AB8500_ANC_FIR_COEFF_MIN, AB8500_ANC_FIR_COEFF_MAX),
+       AB8500_FILTER_CONTROL("ANC IIR Coefficients", AB8500_ANC_IIR_COEFFS,
+               AB8500_ANC_IIR_COEFF_MIN, AB8500_ANC_IIR_COEFF_MAX),
+       AB8500_FILTER_CONTROL("Sidetone FIR Coefficients",
+                       AB8500_SID_FIR_COEFFS, AB8500_SID_FIR_COEFF_MIN,
+                       AB8500_SID_FIR_COEFF_MAX)
+};
+enum ab8500_filter {
+       AB8500_FILTER_ANC_FIR = 0,
+       AB8500_FILTER_ANC_IIR = 1,
+       AB8500_FILTER_SID_FIR = 2,
+};
+
+/*
+ * Extended interface for codec-driver
+ */
+
+static int ab8500_audio_init_audioblock(struct snd_soc_codec *codec)
+{
+       int status;
+
+       dev_dbg(codec->dev, "%s: Enter.\n", __func__);
+
+       /* Reset audio-registers and disable 32kHz-clock output 2 */
+       status = ab8500_sysctrl_write(AB8500_STW4500CTRL3,
+                               AB8500_STW4500CTRL3_CLK32KOUT2DIS |
+                                       AB8500_STW4500CTRL3_RESETAUDN,
+                               AB8500_STW4500CTRL3_RESETAUDN);
+       if (status < 0)
+               return status;
+
+       return 0;
+}
+
+static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
+                       struct amic_settings *amics)
+{
+       u8 value8;
+       unsigned int value;
+       int status;
+       const struct snd_soc_dapm_route *route;
+
+       dev_dbg(codec->dev, "%s: Enter.\n", __func__);
+
+       /* Set DMic-clocks to outputs */
+       status = abx500_get_register_interruptible(codec->dev, (u8)AB8500_MISC,
+                                               (u8)AB8500_GPIO_DIR4_REG,
+                                               &value8);
+       if (status < 0)
+               return status;
+       value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT |
+               GPIO31_DIR_OUTPUT;
+       status = abx500_set_register_interruptible(codec->dev,
+                                               (u8)AB8500_MISC,
+                                               (u8)AB8500_GPIO_DIR4_REG,
+                                               value);
+       if (status < 0)
+               return status;
+
+       /* Attach regulators to AMic DAPM-paths */
+       dev_dbg(codec->dev, "%s: Mic 1a regulator: %s\n", __func__,
+               amic_micbias_str(amics->mic1a_micbias));
+       route = &ab8500_dapm_routes_mic1a_vamicx[amics->mic1a_micbias];
+       status = snd_soc_dapm_add_routes(&codec->dapm, route, 1);
+       dev_dbg(codec->dev, "%s: Mic 1b regulator: %s\n", __func__,
+               amic_micbias_str(amics->mic1b_micbias));
+       route = &ab8500_dapm_routes_mic1b_vamicx[amics->mic1b_micbias];
+       status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1);
+       dev_dbg(codec->dev, "%s: Mic 2 regulator: %s\n", __func__,
+               amic_micbias_str(amics->mic2_micbias));
+       route = &ab8500_dapm_routes_mic2_vamicx[amics->mic2_micbias];
+       status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1);
+       if (status < 0) {
+               dev_err(codec->dev,
+                       "%s: Failed to add AMic-regulator DAPM-routes (%d).\n",
+                       __func__, status);
+               return status;
+       }
+
+       /* Set AMic-configuration */
+       dev_dbg(codec->dev, "%s: Mic 1 mic-type: %s\n", __func__,
+               amic_type_str(amics->mic1_type));
+       snd_soc_update_bits(codec, AB8500_ANAGAIN1, AB8500_ANAGAINX_ENSEMICX,
+                       amics->mic1_type == AMIC_TYPE_DIFFERENTIAL ?
+                               0 : AB8500_ANAGAINX_ENSEMICX);
+       dev_dbg(codec->dev, "%s: Mic 2 mic-type: %s\n", __func__,
+               amic_type_str(amics->mic2_type));
+       snd_soc_update_bits(codec, AB8500_ANAGAIN2, AB8500_ANAGAINX_ENSEMICX,
+                       amics->mic2_type == AMIC_TYPE_DIFFERENTIAL ?
+                               0 : AB8500_ANAGAINX_ENSEMICX);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ab8500_audio_setup_mics);
+
+static int ab8500_audio_set_ear_cmv(struct snd_soc_codec *codec,
+                               enum ear_cm_voltage ear_cmv)
+{
+       char *cmv_str;
+
+       switch (ear_cmv) {
+       case EAR_CMV_0_95V:
+               cmv_str = "0.95V";
+               break;
+       case EAR_CMV_1_10V:
+               cmv_str = "1.10V";
+               break;
+       case EAR_CMV_1_27V:
+               cmv_str = "1.27V";
+               break;
+       case EAR_CMV_1_58V:
+               cmv_str = "1.58V";
+               break;
+       default:
+               dev_err(codec->dev,
+                       "%s: Unknown earpiece CM-voltage (%d)!\n",
+                       __func__, (int)ear_cmv);
+               return -EINVAL;
+       }
+       dev_dbg(codec->dev, "%s: Earpiece CM-voltage: %s\n", __func__,
+               cmv_str);
+       snd_soc_update_bits(codec, AB8500_ANACONF1, AB8500_ANACONF1_EARSELCM,
+                       ear_cmv);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ab8500_audio_set_ear_cmv);
+
+static int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai,
+                               unsigned int delay)
+{
+       unsigned int mask, val;
+       struct snd_soc_codec *codec = dai->codec;
+
+       mask = BIT(AB8500_DIGIFCONF2_IF0DEL);
+       val = 0;
+
+       switch (delay) {
+       case 0:
+               break;
+       case 1:
+               val |= BIT(AB8500_DIGIFCONF2_IF0DEL);
+               break;
+       default:
+               dev_err(dai->codec->dev,
+                       "%s: ERROR: Unsupported bit-delay (0x%x)!\n",
+                       __func__, delay);
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->codec->dev, "%s: IF0 Bit-delay: %d bits.\n",
+               __func__, delay);
+       snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val);
+
+       return 0;
+}
+
+/* Gates clocking according format mask */
+static int ab8500_codec_set_dai_clock_gate(struct snd_soc_codec *codec,
+                                       unsigned int fmt)
+{
+       unsigned int mask;
+       unsigned int val;
+
+       mask = BIT(AB8500_DIGIFCONF1_ENMASTGEN) |
+                       BIT(AB8500_DIGIFCONF1_ENFSBITCLK0);
+
+       val = BIT(AB8500_DIGIFCONF1_ENMASTGEN);
+
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+       case SND_SOC_DAIFMT_CONT: /* continuous clock */
+               dev_dbg(codec->dev, "%s: IF0 Clock is continuous.\n",
+                       __func__);
+               val |= BIT(AB8500_DIGIFCONF1_ENFSBITCLK0);
+               break;
+       case SND_SOC_DAIFMT_GATED: /* clock is gated */
+               dev_dbg(codec->dev, "%s: IF0 Clock is gated.\n",
+                       __func__);
+               break;
+       default:
+               dev_err(codec->dev,
+                       "%s: ERROR: Unsupported clock mask (0x%x)!\n",
+                       __func__, fmt & SND_SOC_DAIFMT_CLOCK_MASK);
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val);
+
+       return 0;
+}
+
+static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       unsigned int mask;
+       unsigned int val;
+       struct snd_soc_codec *codec = dai->codec;
+       int status;
+
+       dev_dbg(codec->dev, "%s: Enter (fmt = 0x%x)\n", __func__, fmt);
+
+       mask = BIT(AB8500_DIGIFCONF3_IF1DATOIF0AD) |
+                       BIT(AB8500_DIGIFCONF3_IF1CLKTOIF0CLK) |
+                       BIT(AB8500_DIGIFCONF3_IF0BFIFOEN) |
+                       BIT(AB8500_DIGIFCONF3_IF0MASTER);
+       val = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & FRM master */
+               dev_dbg(dai->codec->dev,
+                       "%s: IF0 Master-mode: AB8500 master.\n", __func__);
+               val |= BIT(AB8500_DIGIFCONF3_IF0MASTER);
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & FRM slave */
+               dev_dbg(dai->codec->dev,
+                       "%s: IF0 Master-mode: AB8500 slave.\n", __func__);
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & FRM master */
+       case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
+               dev_err(dai->codec->dev,
+                       "%s: ERROR: The device is either a master or a slave.\n",
+                       __func__);
+       default:
+               dev_err(dai->codec->dev,
+                       "%s: ERROR: Unsupporter master mask 0x%x\n",
+                       __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+               return -EINVAL;
+               break;
+       }
+
+       snd_soc_update_bits(codec, AB8500_DIGIFCONF3, mask, val);
+
+       /* Set clock gating */
+       status = ab8500_codec_set_dai_clock_gate(codec, fmt);
+       if (status) {
+               dev_err(dai->codec->dev,
+                       "%s: ERRROR: Failed to set clock gate (%d).\n",
+                       __func__, status);
+               return status;
+       }
+
+       /* Setting data transfer format */
+
+       mask = BIT(AB8500_DIGIFCONF2_IF0FORMAT0) |
+               BIT(AB8500_DIGIFCONF2_IF0FORMAT1) |
+               BIT(AB8500_DIGIFCONF2_FSYNC0P) |
+               BIT(AB8500_DIGIFCONF2_BITCLK0P);
+       val = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S: /* I2S mode */
+               dev_dbg(dai->codec->dev, "%s: IF0 Protocol: I2S\n", __func__);
+               val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT1);
+               ab8500_audio_set_bit_delay(dai, 0);
+               break;
+
+       case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */
+               dev_dbg(dai->codec->dev,
+                       "%s: IF0 Protocol: DSP A (TDM)\n", __func__);
+               val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0);
+               ab8500_audio_set_bit_delay(dai, 1);
+               break;
+
+       case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */
+               dev_dbg(dai->codec->dev,
+                       "%s: IF0 Protocol: DSP B (TDM)\n", __func__);
+               val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0);
+               ab8500_audio_set_bit_delay(dai, 0);
+               break;
+
+       default:
+               dev_err(dai->codec->dev,
+                       "%s: ERROR: Unsupported format (0x%x)!\n",
+                       __func__, fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
+               dev_dbg(dai->codec->dev,
+                       "%s: IF0: Normal bit clock, normal frame\n",
+                       __func__);
+               break;
+       case SND_SOC_DAIFMT_NB_IF: /* normal BCLK + inv FRM */
+               dev_dbg(dai->codec->dev,
+                       "%s: IF0: Normal bit clock, inverted frame\n",
+                       __func__);
+               val |= BIT(AB8500_DIGIFCONF2_FSYNC0P);
+               break;
+       case SND_SOC_DAIFMT_IB_NF: /* invert BCLK + nor FRM */
+               dev_dbg(dai->codec->dev,
+                       "%s: IF0: Inverted bit clock, normal frame\n",
+                       __func__);
+               val |= BIT(AB8500_DIGIFCONF2_BITCLK0P);
+               break;
+       case SND_SOC_DAIFMT_IB_IF: /* invert BCLK + FRM */
+               dev_dbg(dai->codec->dev,
+                       "%s: IF0: Inverted bit clock, inverted frame\n",
+                       __func__);
+               val |= BIT(AB8500_DIGIFCONF2_FSYNC0P);
+               val |= BIT(AB8500_DIGIFCONF2_BITCLK0P);
+               break;
+       default:
+               dev_err(dai->codec->dev,
+                       "%s: ERROR: Unsupported INV mask 0x%x\n",
+                       __func__, fmt & SND_SOC_DAIFMT_INV_MASK);
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val);
+
+       return 0;
+}
+
+static int ab8500_codec_set_dai_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, mask, slots_active;
+
+       mask = BIT(AB8500_DIGIFCONF2_IF0WL0) |
+               BIT(AB8500_DIGIFCONF2_IF0WL1);
+       val = 0;
+
+       switch (slot_width) {
+       case 16:
+               break;
+       case 20:
+               val |= BIT(AB8500_DIGIFCONF2_IF0WL0);
+               break;
+       case 24:
+               val |= BIT(AB8500_DIGIFCONF2_IF0WL1);
+               break;
+       case 32:
+               val |= BIT(AB8500_DIGIFCONF2_IF0WL1) |
+                       BIT(AB8500_DIGIFCONF2_IF0WL0);
+               break;
+       default:
+               dev_err(dai->codec->dev, "%s: Unsupported slot-width 0x%x\n",
+                       __func__, slot_width);
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->codec->dev, "%s: IF0 slot-width: %d bits.\n",
+               __func__, slot_width);
+       snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val);
+
+       /* Setup TDM clocking according to slot count */
+       dev_dbg(dai->codec->dev, "%s: Slots, total: %d\n", __func__, slots);
+       mask = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) |
+                       BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
+       switch (slots) {
+       case 2:
+               val = AB8500_MASK_NONE;
+               break;
+       case 4:
+               val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0);
+               break;
+       case 8:
+               val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
+               break;
+       case 16:
+               val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) |
+                       BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
+               break;
+       default:
+               dev_err(dai->codec->dev,
+                       "%s: ERROR: Unsupported number of slots (%d)!\n",
+                       __func__, slots);
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val);
+
+       /* Setup TDM DA according to active tx slots */
+       mask = AB8500_DASLOTCONFX_SLTODAX_MASK;
+       slots_active = hweight32(tx_mask);
+       dev_dbg(dai->codec->dev, "%s: Slots, active, TX: %d\n", __func__,
+               slots_active);
+       switch (slots_active) {
+       case 0:
+               break;
+       case 1:
+               /* Slot 9 -> DA_IN1 & DA_IN3 */
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 11);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 11);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11);
+               break;
+       case 2:
+               /* Slot 9 -> DA_IN1 & DA_IN3, Slot 11 -> DA_IN2 & DA_IN4 */
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 9);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 9);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11);
+
+               break;
+       case 8:
+               dev_dbg(dai->codec->dev,
+                       "%s: In 8-channel mode DA-from-slot mapping is set manually.",
+                       __func__);
+               break;
+       default:
+               dev_err(dai->codec->dev,
+                       "%s: Unsupported number of active TX-slots (%d)!\n",
+                       __func__, slots_active);
+               return -EINVAL;
+       }
+
+       /* Setup TDM AD according to active RX-slots */
+       slots_active = hweight32(rx_mask);
+       dev_dbg(dai->codec->dev, "%s: Slots, active, RX: %d\n", __func__,
+               slots_active);
+       switch (slots_active) {
+       case 0:
+               break;
+       case 1:
+               /* AD_OUT3 -> slot 0 & 1 */
+               snd_soc_update_bits(codec, AB8500_ADSLOTSEL1, AB8500_MASK_ALL,
+                               AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN |
+                               AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD);
+               break;
+       case 2:
+               /* AD_OUT3 -> slot 0, AD_OUT2 -> slot 1 */
+               snd_soc_update_bits(codec,
+                               AB8500_ADSLOTSEL1,
+                               AB8500_MASK_ALL,
+                               AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN |
+                               AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD);
+               break;
+       case 8:
+               dev_dbg(dai->codec->dev,
+                       "%s: In 8-channel mode AD-to-slot mapping is set manually.",
+                       __func__);
+               break;
+       default:
+               dev_err(dai->codec->dev,
+                       "%s: Unsupported number of active RX-slots (%d)!\n",
+                       __func__, slots_active);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+struct snd_soc_dai_driver ab8500_codec_dai[] = {
+       {
+               .name = "ab8500-codec-dai.0",
+               .id = 0,
+               .playback = {
+                       .stream_name = "ab8500_0p",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = AB8500_SUPPORTED_RATE,
+                       .formats = AB8500_SUPPORTED_FMT,
+               },
+               .ops = (struct snd_soc_dai_ops[]) {
+                       {
+                               .set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
+                               .set_fmt = ab8500_codec_set_dai_fmt,
+                       }
+               },
+               .symmetric_rates = 1
+       },
+       {
+               .name = "ab8500-codec-dai.1",
+               .id = 1,
+               .capture = {
+                       .stream_name = "ab8500_0c",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = AB8500_SUPPORTED_RATE,
+                       .formats = AB8500_SUPPORTED_FMT,
+               },
+               .ops = (struct snd_soc_dai_ops[]) {
+                       {
+                               .set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
+                               .set_fmt = ab8500_codec_set_dai_fmt,
+                       }
+               },
+               .symmetric_rates = 1
+       }
+};
+
+static int ab8500_codec_probe(struct snd_soc_codec *codec)
+{
+       struct device *dev = codec->dev;
+       struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
+       struct ab8500_platform_data *pdata;
+       struct filter_control *fc;
+       int status;
+
+       dev_dbg(dev, "%s: Enter.\n", __func__);
+
+       /* Setup AB8500 according to board-settings */
+       pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent);
+       status = ab8500_audio_setup_mics(codec, &pdata->codec->amics);
+       if (status < 0) {
+               pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);
+               return status;
+       }
+       status = ab8500_audio_set_ear_cmv(codec, pdata->codec->ear_cmv);
+       if (status < 0) {
+               pr_err("%s: Failed to set earpiece CM-voltage (%d)!\n",
+                       __func__, status);
+               return status;
+       }
+
+       status = ab8500_audio_init_audioblock(codec);
+       if (status < 0) {
+               dev_err(dev, "%s: failed to init audio-block (%d)!\n",
+                       __func__, status);
+               return status;
+       }
+
+       /* Override HW-defaults */
+       ab8500_codec_write_reg(codec,
+                               AB8500_ANACONF5,
+                               BIT(AB8500_ANACONF5_HSAUTOEN));
+       ab8500_codec_write_reg(codec,
+                               AB8500_SHORTCIRCONF,
+                               BIT(AB8500_SHORTCIRCONF_HSZCDDIS));
+
+       /* Add filter controls */
+       status = snd_soc_add_codec_controls(codec, ab8500_filter_controls,
+                               ARRAY_SIZE(ab8500_filter_controls));
+       if (status < 0) {
+               dev_err(dev,
+                       "%s: failed to add ab8500 filter controls (%d).\n",
+                       __func__, status);
+               return status;
+       }
+       fc = (struct filter_control *)
+               &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value;
+       drvdata->anc_fir_values = (long *)fc->value;
+       fc = (struct filter_control *)
+               &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value;
+       drvdata->anc_iir_values = (long *)fc->value;
+       fc = (struct filter_control *)
+               &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value;
+       drvdata->sid_fir_values = (long *)fc->value;
+
+       (void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
+
+       mutex_init(&drvdata->anc_lock);
+
+       return status;
+}
+
+static struct snd_soc_codec_driver ab8500_codec_driver = {
+       .probe =                ab8500_codec_probe,
+       .read =                 ab8500_codec_read_reg,
+       .write =                ab8500_codec_write_reg,
+       .reg_word_size =        sizeof(u8),
+       .controls =             ab8500_ctrls,
+       .num_controls =         ARRAY_SIZE(ab8500_ctrls),
+       .dapm_widgets =         ab8500_dapm_widgets,
+       .num_dapm_widgets =     ARRAY_SIZE(ab8500_dapm_widgets),
+       .dapm_routes =          ab8500_dapm_routes,
+       .num_dapm_routes =      ARRAY_SIZE(ab8500_dapm_routes),
+};
+
+static int __devinit ab8500_codec_driver_probe(struct platform_device *pdev)
+{
+       int status;
+       struct ab8500_codec_drvdata *drvdata;
+
+       dev_dbg(&pdev->dev, "%s: Enter.\n", __func__);
+
+       /* Create driver private-data struct */
+       drvdata = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_codec_drvdata),
+                       GFP_KERNEL);
+       drvdata->sid_status = SID_UNCONFIGURED;
+       drvdata->anc_status = ANC_UNCONFIGURED;
+       dev_set_drvdata(&pdev->dev, drvdata);
+
+       dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__);
+       status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver,
+                               ab8500_codec_dai,
+                               ARRAY_SIZE(ab8500_codec_dai));
+       if (status < 0)
+               dev_err(&pdev->dev,
+                       "%s: Error: Failed to register codec (%d).\n",
+                       __func__, status);
+
+       return status;
+}
+
+static int __devexit ab8500_codec_driver_remove(struct platform_device *pdev)
+{
+       dev_info(&pdev->dev, "%s Enter.\n", __func__);
+
+       snd_soc_unregister_codec(&pdev->dev);
+
+       return 0;
+}
+
+static struct platform_driver ab8500_codec_platform_driver = {
+       .driver = {
+               .name   = "ab8500-codec",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ab8500_codec_driver_probe,
+       .remove         = __devexit_p(ab8500_codec_driver_remove),
+       .suspend        = NULL,
+       .resume         = NULL,
+};
+module_platform_driver(ab8500_codec_platform_driver);
+
+MODULE_LICENSE("GPLv2");
diff --git a/sound/soc/codecs/ab8500-codec.h b/sound/soc/codecs/ab8500-codec.h
new file mode 100644 (file)
index 0000000..114f69a
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>,
+ *         for ST-Ericsson.
+ *
+ *         Based on the early work done by:
+ *         Mikko J. Lehto <mikko.lehto@symbio.com>,
+ *         Mikko Sarmanne <mikko.sarmanne@symbio.com>,
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 AB8500_CODEC_REGISTERS_H
+#define AB8500_CODEC_REGISTERS_H
+
+#define AB8500_SUPPORTED_RATE                  (SNDRV_PCM_RATE_48000)
+#define AB8500_SUPPORTED_FMT                   (SNDRV_PCM_FMTBIT_S16_LE)
+
+/* AB8500 audio bank (0x0d) register definitions */
+
+#define AB8500_POWERUP                         0x00
+#define AB8500_AUDSWRESET                      0x01
+#define AB8500_ADPATHENA                       0x02
+#define AB8500_DAPATHENA                       0x03
+#define AB8500_ANACONF1                                0x04
+#define AB8500_ANACONF2                                0x05
+#define AB8500_DIGMICCONF                      0x06
+#define AB8500_ANACONF3                                0x07
+#define AB8500_ANACONF4                                0x08
+#define AB8500_DAPATHCONF                      0x09
+#define AB8500_MUTECONF                                0x0A
+#define AB8500_SHORTCIRCONF                    0x0B
+#define AB8500_ANACONF5                                0x0C
+#define AB8500_ENVCPCONF                       0x0D
+#define AB8500_SIGENVCONF                      0x0E
+#define AB8500_PWMGENCONF1                     0x0F
+#define AB8500_PWMGENCONF2                     0x10
+#define AB8500_PWMGENCONF3                     0x11
+#define AB8500_PWMGENCONF4                     0x12
+#define AB8500_PWMGENCONF5                     0x13
+#define AB8500_ANAGAIN1                                0x14
+#define AB8500_ANAGAIN2                                0x15
+#define AB8500_ANAGAIN3                                0x16
+#define AB8500_ANAGAIN4                                0x17
+#define AB8500_DIGLINHSLGAIN                   0x18
+#define AB8500_DIGLINHSRGAIN                   0x19
+#define AB8500_ADFILTCONF                      0x1A
+#define AB8500_DIGIFCONF1                      0x1B
+#define AB8500_DIGIFCONF2                      0x1C
+#define AB8500_DIGIFCONF3                      0x1D
+#define AB8500_DIGIFCONF4                      0x1E
+#define AB8500_ADSLOTSEL1                      0x1F
+#define AB8500_ADSLOTSEL2                      0x20
+#define AB8500_ADSLOTSEL3                      0x21
+#define AB8500_ADSLOTSEL4                      0x22
+#define AB8500_ADSLOTSEL5                      0x23
+#define AB8500_ADSLOTSEL6                      0x24
+#define AB8500_ADSLOTSEL7                      0x25
+#define AB8500_ADSLOTSEL8                      0x26
+#define AB8500_ADSLOTSEL9                      0x27
+#define AB8500_ADSLOTSEL10                     0x28
+#define AB8500_ADSLOTSEL11                     0x29
+#define AB8500_ADSLOTSEL12                     0x2A
+#define AB8500_ADSLOTSEL13                     0x2B
+#define AB8500_ADSLOTSEL14                     0x2C
+#define AB8500_ADSLOTSEL15                     0x2D
+#define AB8500_ADSLOTSEL16                     0x2E
+#define AB8500_ADSLOTHIZCTRL1                  0x2F
+#define AB8500_ADSLOTHIZCTRL2                  0x30
+#define AB8500_ADSLOTHIZCTRL3                  0x31
+#define AB8500_ADSLOTHIZCTRL4                  0x32
+#define AB8500_DASLOTCONF1                     0x33
+#define AB8500_DASLOTCONF2                     0x34
+#define AB8500_DASLOTCONF3                     0x35
+#define AB8500_DASLOTCONF4                     0x36
+#define AB8500_DASLOTCONF5                     0x37
+#define AB8500_DASLOTCONF6                     0x38
+#define AB8500_DASLOTCONF7                     0x39
+#define AB8500_DASLOTCONF8                     0x3A
+#define AB8500_CLASSDCONF1                     0x3B
+#define AB8500_CLASSDCONF2                     0x3C
+#define AB8500_CLASSDCONF3                     0x3D
+#define AB8500_DMICFILTCONF                    0x3E
+#define AB8500_DIGMULTCONF1                    0x3F
+#define AB8500_DIGMULTCONF2                    0x40
+#define AB8500_ADDIGGAIN1                      0x41
+#define AB8500_ADDIGGAIN2                      0x42
+#define AB8500_ADDIGGAIN3                      0x43
+#define AB8500_ADDIGGAIN4                      0x44
+#define AB8500_ADDIGGAIN5                      0x45
+#define AB8500_ADDIGGAIN6                      0x46
+#define AB8500_DADIGGAIN1                      0x47
+#define AB8500_DADIGGAIN2                      0x48
+#define AB8500_DADIGGAIN3                      0x49
+#define AB8500_DADIGGAIN4                      0x4A
+#define AB8500_DADIGGAIN5                      0x4B
+#define AB8500_DADIGGAIN6                      0x4C
+#define AB8500_ADDIGLOOPGAIN1                  0x4D
+#define AB8500_ADDIGLOOPGAIN2                  0x4E
+#define AB8500_HSLEARDIGGAIN                   0x4F
+#define AB8500_HSRDIGGAIN                      0x50
+#define AB8500_SIDFIRGAIN1                     0x51
+#define AB8500_SIDFIRGAIN2                     0x52
+#define AB8500_ANCCONF1                                0x53
+#define AB8500_ANCCONF2                                0x54
+#define AB8500_ANCCONF3                                0x55
+#define AB8500_ANCCONF4                                0x56
+#define AB8500_ANCCONF5                                0x57
+#define AB8500_ANCCONF6                                0x58
+#define AB8500_ANCCONF7                                0x59
+#define AB8500_ANCCONF8                                0x5A
+#define AB8500_ANCCONF9                                0x5B
+#define AB8500_ANCCONF10                       0x5C
+#define AB8500_ANCCONF11                       0x5D
+#define AB8500_ANCCONF12                       0x5E
+#define AB8500_ANCCONF13                       0x5F
+#define AB8500_ANCCONF14                       0x60
+#define AB8500_SIDFIRADR                       0x61
+#define AB8500_SIDFIRCOEF1                     0x62
+#define AB8500_SIDFIRCOEF2                     0x63
+#define AB8500_SIDFIRCONF                      0x64
+#define AB8500_AUDINTMASK1                     0x65
+#define AB8500_AUDINTSOURCE1                   0x66
+#define AB8500_AUDINTMASK2                     0x67
+#define AB8500_AUDINTSOURCE2                   0x68
+#define AB8500_FIFOCONF1                       0x69
+#define AB8500_FIFOCONF2                       0x6A
+#define AB8500_FIFOCONF3                       0x6B
+#define AB8500_FIFOCONF4                       0x6C
+#define AB8500_FIFOCONF5                       0x6D
+#define AB8500_FIFOCONF6                       0x6E
+#define AB8500_AUDREV                          0x6F
+
+#define AB8500_FIRST_REG                       AB8500_POWERUP
+#define AB8500_LAST_REG                                AB8500_AUDREV
+#define AB8500_CACHEREGNUM                     (AB8500_LAST_REG + 1)
+
+#define AB8500_MASK_ALL                                0xFF
+#define AB8500_MASK_NONE                       0x00
+
+/* AB8500_POWERUP */
+#define AB8500_POWERUP_POWERUP                 7
+#define AB8500_POWERUP_ENANA                   3
+
+/* AB8500_AUDSWRESET */
+#define AB8500_AUDSWRESET_SWRESET              7
+
+/* AB8500_ADPATHENA */
+#define AB8500_ADPATHENA_ENAD12                        7
+#define AB8500_ADPATHENA_ENAD34                        5
+#define AB8500_ADPATHENA_ENAD5768              3
+
+/* AB8500_DAPATHENA */
+#define AB8500_DAPATHENA_ENDA1                 7
+#define AB8500_DAPATHENA_ENDA2                 6
+#define AB8500_DAPATHENA_ENDA3                 5
+#define AB8500_DAPATHENA_ENDA4                 4
+#define AB8500_DAPATHENA_ENDA5                 3
+#define AB8500_DAPATHENA_ENDA6                 2
+
+/* AB8500_ANACONF1 */
+#define AB8500_ANACONF1_HSLOWPOW               7
+#define AB8500_ANACONF1_DACLOWPOW1             6
+#define AB8500_ANACONF1_DACLOWPOW0             5
+#define AB8500_ANACONF1_EARDACLOWPOW           4
+#define AB8500_ANACONF1_EARSELCM               2
+#define AB8500_ANACONF1_HSHPEN                 1
+#define AB8500_ANACONF1_EARDRVLOWPOW           0
+
+/* AB8500_ANACONF2 */
+#define AB8500_ANACONF2_ENMIC1                 7
+#define AB8500_ANACONF2_ENMIC2                 6
+#define AB8500_ANACONF2_ENLINL                 5
+#define AB8500_ANACONF2_ENLINR                 4
+#define AB8500_ANACONF2_MUTMIC1                        3
+#define AB8500_ANACONF2_MUTMIC2                        2
+#define AB8500_ANACONF2_MUTLINL                        1
+#define AB8500_ANACONF2_MUTLINR                        0
+
+/* AB8500_DIGMICCONF */
+#define AB8500_DIGMICCONF_ENDMIC1              7
+#define AB8500_DIGMICCONF_ENDMIC2              6
+#define AB8500_DIGMICCONF_ENDMIC3              5
+#define AB8500_DIGMICCONF_ENDMIC4              4
+#define AB8500_DIGMICCONF_ENDMIC5              3
+#define AB8500_DIGMICCONF_ENDMIC6              2
+#define AB8500_DIGMICCONF_HSFADSPEED           0
+
+/* AB8500_ANACONF3 */
+#define AB8500_ANACONF3_MIC1SEL                        7
+#define AB8500_ANACONF3_LINRSEL                        6
+#define AB8500_ANACONF3_ENDRVHSL               5
+#define AB8500_ANACONF3_ENDRVHSR               4
+#define AB8500_ANACONF3_ENADCMIC               2
+#define AB8500_ANACONF3_ENADCLINL              1
+#define AB8500_ANACONF3_ENADCLINR              0
+
+/* AB8500_ANACONF4 */
+#define AB8500_ANACONF4_DISPDVSS               7
+#define AB8500_ANACONF4_ENEAR                  6
+#define AB8500_ANACONF4_ENHSL                  5
+#define AB8500_ANACONF4_ENHSR                  4
+#define AB8500_ANACONF4_ENHFL                  3
+#define AB8500_ANACONF4_ENHFR                  2
+#define AB8500_ANACONF4_ENVIB1                 1
+#define AB8500_ANACONF4_ENVIB2                 0
+
+/* AB8500_DAPATHCONF */
+#define AB8500_DAPATHCONF_ENDACEAR             6
+#define AB8500_DAPATHCONF_ENDACHSL             5
+#define AB8500_DAPATHCONF_ENDACHSR             4
+#define AB8500_DAPATHCONF_ENDACHFL             3
+#define AB8500_DAPATHCONF_ENDACHFR             2
+#define AB8500_DAPATHCONF_ENDACVIB1            1
+#define AB8500_DAPATHCONF_ENDACVIB2            0
+
+/* AB8500_MUTECONF */
+#define AB8500_MUTECONF_MUTEAR                 6
+#define AB8500_MUTECONF_MUTHSL                 5
+#define AB8500_MUTECONF_MUTHSR                 4
+#define AB8500_MUTECONF_MUTDACEAR              2
+#define AB8500_MUTECONF_MUTDACHSL              1
+#define AB8500_MUTECONF_MUTDACHSR              0
+
+/* AB8500_SHORTCIRCONF */
+#define AB8500_SHORTCIRCONF_ENSHORTPWD         7
+#define AB8500_SHORTCIRCONF_EARSHORTDIS                6
+#define AB8500_SHORTCIRCONF_HSSHORTDIS         5
+#define AB8500_SHORTCIRCONF_HSPULLDEN          4
+#define AB8500_SHORTCIRCONF_HSOSCEN            2
+#define AB8500_SHORTCIRCONF_HSFADDIS           1
+#define AB8500_SHORTCIRCONF_HSZCDDIS           0
+/* Zero cross should be disabled */
+
+/* AB8500_ANACONF5 */
+#define AB8500_ANACONF5_ENCPHS                 7
+#define AB8500_ANACONF5_HSLDACTOLOL            5
+#define AB8500_ANACONF5_HSRDACTOLOR            4
+#define AB8500_ANACONF5_ENLOL                  3
+#define AB8500_ANACONF5_ENLOR                  2
+#define AB8500_ANACONF5_HSAUTOEN               0
+
+/* AB8500_ENVCPCONF */
+#define AB8500_ENVCPCONF_ENVDETHTHRE           4
+#define AB8500_ENVCPCONF_ENVDETLTHRE           0
+#define AB8500_ENVCPCONF_ENVDETHTHRE_MAX       0x0F
+#define AB8500_ENVCPCONF_ENVDETLTHRE_MAX       0x0F
+
+/* AB8500_SIGENVCONF */
+#define AB8500_SIGENVCONF_CPLVEN               5
+#define AB8500_SIGENVCONF_ENVDETCPEN           4
+#define AB8500_SIGENVCONF_ENVDETTIME           0
+#define AB8500_SIGENVCONF_ENVDETTIME_MAX       0x0F
+
+/* AB8500_PWMGENCONF1 */
+#define AB8500_PWMGENCONF1_PWMTOVIB1           7
+#define AB8500_PWMGENCONF1_PWMTOVIB2           6
+#define AB8500_PWMGENCONF1_PWM1CTRL            5
+#define AB8500_PWMGENCONF1_PWM2CTRL            4
+#define AB8500_PWMGENCONF1_PWM1NCTRL           3
+#define AB8500_PWMGENCONF1_PWM1PCTRL           2
+#define AB8500_PWMGENCONF1_PWM2NCTRL           1
+#define AB8500_PWMGENCONF1_PWM2PCTRL           0
+
+/* AB8500_PWMGENCONF2 */
+/* AB8500_PWMGENCONF3 */
+/* AB8500_PWMGENCONF4 */
+/* AB8500_PWMGENCONF5 */
+#define AB8500_PWMGENCONFX_PWMVIBXPOL          7
+#define AB8500_PWMGENCONFX_PWMVIBXDUTCYC       0
+#define AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX   0x64
+
+/* AB8500_ANAGAIN1 */
+/* AB8500_ANAGAIN2 */
+#define AB8500_ANAGAINX_ENSEMICX               7
+#define AB8500_ANAGAINX_LOWPOWMICX             6
+#define AB8500_ANAGAINX_MICXGAIN               0
+#define AB8500_ANAGAINX_MICXGAIN_MAX           0x1F
+
+/* AB8500_ANAGAIN3 */
+#define AB8500_ANAGAIN3_HSLGAIN                        4
+#define AB8500_ANAGAIN3_HSRGAIN                        0
+#define AB8500_ANAGAIN3_HSXGAIN_MAX            0x0F
+
+/* AB8500_ANAGAIN4 */
+#define AB8500_ANAGAIN4_LINLGAIN               4
+#define AB8500_ANAGAIN4_LINRGAIN               0
+#define AB8500_ANAGAIN4_LINXGAIN_MAX           0x0F
+
+/* AB8500_DIGLINHSLGAIN */
+/* AB8500_DIGLINHSRGAIN */
+#define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN      0
+#define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN_MAX  0x13
+
+/* AB8500_ADFILTCONF */
+#define AB8500_ADFILTCONF_AD1NH                        7
+#define AB8500_ADFILTCONF_AD2NH                        6
+#define AB8500_ADFILTCONF_AD3NH                        5
+#define AB8500_ADFILTCONF_AD4NH                        4
+#define AB8500_ADFILTCONF_AD1VOICE             3
+#define AB8500_ADFILTCONF_AD2VOICE             2
+#define AB8500_ADFILTCONF_AD3VOICE             1
+#define AB8500_ADFILTCONF_AD4VOICE             0
+
+/* AB8500_DIGIFCONF1 */
+#define AB8500_DIGIFCONF1_ENMASTGEN            7
+#define AB8500_DIGIFCONF1_IF1BITCLKOS1         6
+#define AB8500_DIGIFCONF1_IF1BITCLKOS0         5
+#define AB8500_DIGIFCONF1_ENFSBITCLK1          4
+#define AB8500_DIGIFCONF1_IF0BITCLKOS1         2
+#define AB8500_DIGIFCONF1_IF0BITCLKOS0         1
+#define AB8500_DIGIFCONF1_ENFSBITCLK0          0
+
+/* AB8500_DIGIFCONF2 */
+#define AB8500_DIGIFCONF2_FSYNC0P              6
+#define AB8500_DIGIFCONF2_BITCLK0P             5
+#define AB8500_DIGIFCONF2_IF0DEL               4
+#define AB8500_DIGIFCONF2_IF0FORMAT1           3
+#define AB8500_DIGIFCONF2_IF0FORMAT0           2
+#define AB8500_DIGIFCONF2_IF0WL1               1
+#define AB8500_DIGIFCONF2_IF0WL0               0
+
+/* AB8500_DIGIFCONF3 */
+#define AB8500_DIGIFCONF3_IF0DATOIF1AD         7
+#define AB8500_DIGIFCONF3_IF0CLKTOIF1CLK       6
+#define AB8500_DIGIFCONF3_IF1MASTER            5
+#define AB8500_DIGIFCONF3_IF1DATOIF0AD         3
+#define AB8500_DIGIFCONF3_IF1CLKTOIF0CLK       2
+#define AB8500_DIGIFCONF3_IF0MASTER            1
+#define AB8500_DIGIFCONF3_IF0BFIFOEN           0
+
+/* AB8500_DIGIFCONF4 */
+#define AB8500_DIGIFCONF4_FSYNC1P              6
+#define AB8500_DIGIFCONF4_BITCLK1P             5
+#define AB8500_DIGIFCONF4_IF1DEL               4
+#define AB8500_DIGIFCONF4_IF1FORMAT1           3
+#define AB8500_DIGIFCONF4_IF1FORMAT0           2
+#define AB8500_DIGIFCONF4_IF1WL1               1
+#define AB8500_DIGIFCONF4_IF1WL0               0
+
+/* AB8500_ADSLOTSELX */
+#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_ODD  0x00
+#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD  0x01
+#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD  0x02
+#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_ODD  0x03
+#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_ODD  0x04
+#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_ODD  0x05
+#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_ODD  0x06
+#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_ODD  0x07
+#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_ODD   0x08
+#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_ODD 0x0F
+#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_EVEN 0x00
+#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_EVEN 0x10
+#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN 0x20
+#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_EVEN 0x30
+#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_EVEN 0x40
+#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_EVEN 0x50
+#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_EVEN 0x60
+#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_EVEN 0x70
+#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_EVEN  0x80
+#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_EVEN        0xF0
+#define AB8500_ADSLOTSELX_EVEN_SHIFT           0
+#define AB8500_ADSLOTSELX_ODD_SHIFT            4
+
+/* AB8500_ADSLOTHIZCTRL1 */
+/* AB8500_ADSLOTHIZCTRL2 */
+/* AB8500_ADSLOTHIZCTRL3 */
+/* AB8500_ADSLOTHIZCTRL4 */
+/* AB8500_DASLOTCONF1 */
+#define AB8500_DASLOTCONF1_DA12VOICE           7
+#define AB8500_DASLOTCONF1_SWAPDA12_34         6
+#define AB8500_DASLOTCONF1_DAI7TOADO1          5
+
+/* AB8500_DASLOTCONF2 */
+#define AB8500_DASLOTCONF2_DAI8TOADO2          5
+
+/* AB8500_DASLOTCONF3 */
+#define AB8500_DASLOTCONF3_DA34VOICE           7
+#define AB8500_DASLOTCONF3_DAI7TOADO3          5
+
+/* AB8500_DASLOTCONF4 */
+#define AB8500_DASLOTCONF4_DAI8TOADO4          5
+
+/* AB8500_DASLOTCONF5 */
+#define AB8500_DASLOTCONF5_DA56VOICE           7
+#define AB8500_DASLOTCONF5_DAI7TOADO5          5
+
+/* AB8500_DASLOTCONF6 */
+#define AB8500_DASLOTCONF6_DAI8TOADO6          5
+
+/* AB8500_DASLOTCONF7 */
+#define AB8500_DASLOTCONF7_DAI8TOADO7          5
+
+/* AB8500_DASLOTCONF8 */
+#define AB8500_DASLOTCONF8_DAI7TOADO8          5
+
+#define AB8500_DASLOTCONFX_SLTODAX_SHIFT       0
+#define AB8500_DASLOTCONFX_SLTODAX_MASK                0x1F
+
+/* AB8500_CLASSDCONF1 */
+#define AB8500_CLASSDCONF1_PARLHF              7
+#define AB8500_CLASSDCONF1_PARLVIB             6
+#define AB8500_CLASSDCONF1_VIB1SWAPEN          3
+#define AB8500_CLASSDCONF1_VIB2SWAPEN          2
+#define AB8500_CLASSDCONF1_HFLSWAPEN           1
+#define AB8500_CLASSDCONF1_HFRSWAPEN           0
+
+/* AB8500_CLASSDCONF2 */
+#define AB8500_CLASSDCONF2_FIRBYP3             7
+#define AB8500_CLASSDCONF2_FIRBYP2             6
+#define AB8500_CLASSDCONF2_FIRBYP1             5
+#define AB8500_CLASSDCONF2_FIRBYP0             4
+#define AB8500_CLASSDCONF2_HIGHVOLEN3          3
+#define AB8500_CLASSDCONF2_HIGHVOLEN2          2
+#define AB8500_CLASSDCONF2_HIGHVOLEN1          1
+#define AB8500_CLASSDCONF2_HIGHVOLEN0          0
+
+/* AB8500_CLASSDCONF3 */
+#define AB8500_CLASSDCONF3_DITHHPGAIN          4
+#define AB8500_CLASSDCONF3_DITHHPGAIN_MAX      0x0A
+#define AB8500_CLASSDCONF3_DITHWGAIN           0
+#define AB8500_CLASSDCONF3_DITHWGAIN_MAX       0x0A
+
+/* AB8500_DMICFILTCONF */
+#define AB8500_DMICFILTCONF_ANCINSEL           7
+#define AB8500_DMICFILTCONF_DA3TOEAR           6
+#define AB8500_DMICFILTCONF_DMIC1SINC3         5
+#define AB8500_DMICFILTCONF_DMIC2SINC3         4
+#define AB8500_DMICFILTCONF_DMIC3SINC3         3
+#define AB8500_DMICFILTCONF_DMIC4SINC3         2
+#define AB8500_DMICFILTCONF_DMIC5SINC3         1
+#define AB8500_DMICFILTCONF_DMIC6SINC3         0
+
+/* AB8500_DIGMULTCONF1 */
+#define AB8500_DIGMULTCONF1_DATOHSLEN          7
+#define AB8500_DIGMULTCONF1_DATOHSREN          6
+#define AB8500_DIGMULTCONF1_AD1SEL             5
+#define AB8500_DIGMULTCONF1_AD2SEL             4
+#define AB8500_DIGMULTCONF1_AD3SEL             3
+#define AB8500_DIGMULTCONF1_AD5SEL             2
+#define AB8500_DIGMULTCONF1_AD6SEL             1
+#define AB8500_DIGMULTCONF1_ANCSEL             0
+
+/* AB8500_DIGMULTCONF2 */
+#define AB8500_DIGMULTCONF2_DATOHFREN          7
+#define AB8500_DIGMULTCONF2_DATOHFLEN          6
+#define AB8500_DIGMULTCONF2_HFRSEL             5
+#define AB8500_DIGMULTCONF2_HFLSEL             4
+#define AB8500_DIGMULTCONF2_FIRSID1SEL         2
+#define AB8500_DIGMULTCONF2_FIRSID2SEL         0
+
+/* AB8500_ADDIGGAIN1 */
+/* AB8500_ADDIGGAIN2 */
+/* AB8500_ADDIGGAIN3 */
+/* AB8500_ADDIGGAIN4 */
+/* AB8500_ADDIGGAIN5 */
+/* AB8500_ADDIGGAIN6 */
+#define AB8500_ADDIGGAINX_FADEDISADX           6
+#define AB8500_ADDIGGAINX_ADXGAIN_MAX          0x3F
+
+/* AB8500_DADIGGAIN1 */
+/* AB8500_DADIGGAIN2 */
+/* AB8500_DADIGGAIN3 */
+/* AB8500_DADIGGAIN4 */
+/* AB8500_DADIGGAIN5 */
+/* AB8500_DADIGGAIN6 */
+#define AB8500_DADIGGAINX_FADEDISDAX           6
+#define AB8500_DADIGGAINX_DAXGAIN_MAX          0x3F
+
+/* AB8500_ADDIGLOOPGAIN1 */
+/* AB8500_ADDIGLOOPGAIN2 */
+#define AB8500_ADDIGLOOPGAINX_FADEDISADXL      6
+#define AB8500_ADDIGLOOPGAINX_ADXLBGAIN_MAX    0x3F
+
+/* AB8500_HSLEARDIGGAIN */
+#define AB8500_HSLEARDIGGAIN_HSSINC1           7
+#define AB8500_HSLEARDIGGAIN_FADEDISHSL                4
+#define AB8500_HSLEARDIGGAIN_HSLDGAIN_MAX      0x09
+
+/* AB8500_HSRDIGGAIN */
+#define AB8500_HSRDIGGAIN_FADESPEED            6
+#define AB8500_HSRDIGGAIN_FADEDISHSR           4
+#define AB8500_HSRDIGGAIN_HSRDGAIN_MAX         0x09
+
+/* AB8500_SIDFIRGAIN1 */
+/* AB8500_SIDFIRGAIN2 */
+#define AB8500_SIDFIRGAINX_FIRSIDXGAIN_MAX     0x1F
+
+/* AB8500_ANCCONF1 */
+#define AB8500_ANCCONF1_ANCIIRUPDATE           3
+#define AB8500_ANCCONF1_ENANC                  2
+#define AB8500_ANCCONF1_ANCIIRINIT             1
+#define AB8500_ANCCONF1_ANCFIRUPDATE           0
+
+/* AB8500_ANCCONF2 */
+#define AB8500_ANCCONF2_SHIFT                  5
+#define AB8500_ANCCONF2_MIN                    -0x10
+#define AB8500_ANCCONF2_MAX                    0xF
+
+/* AB8500_ANCCONF3 */
+#define AB8500_ANCCONF3_SHIFT                  5
+#define AB8500_ANCCONF3_MIN                    -0x10
+#define AB8500_ANCCONF3_MAX                    0xF
+
+/* AB8500_ANCCONF4 */
+#define AB8500_ANCCONF4_SHIFT                  5
+#define AB8500_ANCCONF4_MIN                    -0x10
+#define AB8500_ANCCONF4_MAX                    0xF
+
+/* AB8500_ANC_FIR_COEFFS */
+#define AB8500_ANC_FIR_COEFF_MIN               -0x8000
+#define AB8500_ANC_FIR_COEFF_MAX               0x7FFF
+#define AB8500_ANC_FIR_COEFFS                  15
+
+/* AB8500_ANC_IIR_COEFFS */
+#define AB8500_ANC_IIR_COEFF_MIN               -0x800000
+#define AB8500_ANC_IIR_COEFF_MAX               0x7FFFFF
+#define AB8500_ANC_IIR_COEFFS                  24
+/* AB8500_ANC_WARP_DELAY */
+#define AB8500_ANC_WARP_DELAY_SHIFT            16
+#define AB8500_ANC_WARP_DELAY_MIN              0x0000
+#define AB8500_ANC_WARP_DELAY_MAX              0xFFFF
+
+/* AB8500_ANCCONF11 */
+/* AB8500_ANCCONF12 */
+/* AB8500_ANCCONF13 */
+/* AB8500_ANCCONF14 */
+
+/* AB8500_SIDFIRADR */
+#define AB8500_SIDFIRADR_FIRSIDSET             7
+#define AB8500_SIDFIRADR_ADDRESS_SHIFT         0
+#define AB8500_SIDFIRADR_ADDRESS_MAX           0x7F
+
+/* AB8500_SIDFIRCOEF1 */
+/* AB8500_SIDFIRCOEF2 */
+#define AB8500_SID_FIR_COEFF_MIN               0
+#define AB8500_SID_FIR_COEFF_MAX               0xFFFF
+#define AB8500_SID_FIR_COEFFS                  128
+
+/* AB8500_SIDFIRCONF */
+#define AB8500_SIDFIRCONF_ENFIRSIDS            2
+#define AB8500_SIDFIRCONF_FIRSIDSTOIF1         1
+#define AB8500_SIDFIRCONF_FIRSIDBUSY           0
+
+/* AB8500_AUDINTMASK1 */
+/* AB8500_AUDINTSOURCE1 */
+/* AB8500_AUDINTMASK2 */
+/* AB8500_AUDINTSOURCE2 */
+
+/* AB8500_FIFOCONF1 */
+#define AB8500_FIFOCONF1_BFIFOMASK             0x80
+#define AB8500_FIFOCONF1_BFIFO19M2             0x40
+#define AB8500_FIFOCONF1_BFIFOINT_SHIFT                0
+#define AB8500_FIFOCONF1_BFIFOINT_MAX          0x3F
+
+/* AB8500_FIFOCONF2 */
+#define AB8500_FIFOCONF2_BFIFOTX_SHIFT         0
+#define AB8500_FIFOCONF2_BFIFOTX_MAX           0xFF
+
+/* AB8500_FIFOCONF3 */
+#define AB8500_FIFOCONF3_BFIFOEXSL_SHIFT       5
+#define AB8500_FIFOCONF3_BFIFOEXSL_MAX         0x5
+#define AB8500_FIFOCONF3_PREBITCLK0_SHIFT      2
+#define AB8500_FIFOCONF3_PREBITCLK0_MAX                0x7
+#define AB8500_FIFOCONF3_BFIFOMAST_SHIFT       1
+#define AB8500_FIFOCONF3_BFIFORUN_SHIFT                0
+
+/* AB8500_FIFOCONF4 */
+#define AB8500_FIFOCONF4_BFIFOFRAMSW_SHIFT     0
+#define AB8500_FIFOCONF4_BFIFOFRAMSW_MAX       0xFF
+
+/* AB8500_FIFOCONF5 */
+#define AB8500_FIFOCONF5_BFIFOWAKEUP_SHIFT     0
+#define AB8500_FIFOCONF5_BFIFOWAKEUP_MAX       0xFF
+
+/* AB8500_FIFOCONF6 */
+#define AB8500_FIFOCONF6_BFIFOSAMPLE_SHIFT     0
+#define AB8500_FIFOCONF6_BFIFOSAMPLE_MAX       0xFF
+
+/* AB8500_AUDREV */
+
+#endif
index 2023c749f23278e77dacee56feb5df139c43a47f..ea06b834a7de45c216e8922927a7aad892be411b 100644 (file)
@@ -91,11 +91,6 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int ac97_soc_remove(struct snd_soc_codec *codec)
-{
-       return 0;
-}
-
 #ifdef CONFIG_PM
 static int ac97_soc_suspend(struct snd_soc_codec *codec)
 {
@@ -119,7 +114,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
        .write =        ac97_write,
        .read =         ac97_read,
        .probe =        ac97_soc_probe,
-       .remove =       ac97_soc_remove,
        .suspend =      ac97_soc_suspend,
        .resume =       ac97_soc_resume,
 };
index a7109413aef17b09efda5acc36b3885a075ddae2..628daf6a1d97e8fee699f8d87ea92ec6dbf5fdaf 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -1217,11 +1216,11 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
                return -ENOMEM;
        cs42l52->dev = &i2c_client->dev;
 
-       cs42l52->regmap = regmap_init_i2c(i2c_client, &cs42l52_regmap);
+       cs42l52->regmap = devm_regmap_init_i2c(i2c_client, &cs42l52_regmap);
        if (IS_ERR(cs42l52->regmap)) {
                ret = PTR_ERR(cs42l52->regmap);
                dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        i2c_set_clientdata(i2c_client, cs42l52);
@@ -1243,7 +1242,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
                dev_err(&i2c_client->dev,
                        "CS42L52 Device ID (%X). Expected %X\n",
                        devid, CS42L52_CHIP_ID);
-               goto err_regmap;
+               return ret;
        }
 
        regcache_cache_only(cs42l52->regmap, true);
@@ -1251,23 +1250,13 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
        ret =  snd_soc_register_codec(&i2c_client->dev,
                        &soc_codec_dev_cs42l52, &cs42l52_dai, 1);
        if (ret < 0)
-               goto err_regmap;
+               return ret;
        return 0;
-
-err_regmap:
-       regmap_exit(cs42l52->regmap);
-
-err:
-       return ret;
 }
 
 static int cs42l52_i2c_remove(struct i2c_client *client)
 {
-       struct cs42l52_private *cs42l52 = i2c_get_clientdata(client);
-
        snd_soc_unregister_codec(&client->dev);
-       regmap_exit(cs42l52->regmap);
-
        return 0;
 }
 
index e0d45fdaa750842eb342dc9ced8116ff1a21e212..2c08c4cb465a1995b5b8897c72fea887dcdfbe80 100644 (file)
@@ -1362,11 +1362,11 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client,
 
        i2c_set_clientdata(i2c_client, cs42l73);
 
-       cs42l73->regmap = regmap_init_i2c(i2c_client, &cs42l73_regmap);
+       cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap);
        if (IS_ERR(cs42l73->regmap)) {
                ret = PTR_ERR(cs42l73->regmap);
                dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
-               goto err;
+               return ret;
        }
        /* initialize codec */
        ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, &reg);
@@ -1384,13 +1384,13 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client,
                dev_err(&i2c_client->dev,
                        "CS42L73 Device ID (%X). Expected %X\n",
                        devid, CS42L73_DEVID);
-               goto err_regmap;
+               return ret;
        }
 
        ret = regmap_read(cs42l73->regmap, CS42L73_REVID, &reg);
        if (ret < 0) {
                dev_err(&i2c_client->dev, "Get Revision ID failed\n");
-               goto err_regmap;
+               return ret;;
        }
 
        dev_info(&i2c_client->dev,
@@ -1402,23 +1402,13 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client,
                        &soc_codec_dev_cs42l73, cs42l73_dai,
                        ARRAY_SIZE(cs42l73_dai));
        if (ret < 0)
-               goto err_regmap;
+               return ret;
        return 0;
-
-err_regmap:
-       regmap_exit(cs42l73->regmap);
-
-err:
-       return ret;
 }
 
 static __devexit int cs42l73_i2c_remove(struct i2c_client *client)
 {
-       struct cs42l73_private *cs42l73 = i2c_get_clientdata(client);
-
        snd_soc_unregister_codec(&client->dev);
-       regmap_exit(cs42l73->regmap);
-
        return 0;
 }
 
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
new file mode 100644 (file)
index 0000000..04af369
--- /dev/null
@@ -0,0 +1,1627 @@
+/*
+ * da732x.c --- Dialog DA732X ALSA SoC Audio Driver
+ *
+ * Copyright (C) 2012 Dialog Semiconductor GmbH
+ *
+ * Author: Michal Hajduk <Michal.Hajduk@diasemi.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/slab.h>
+#include <linux/sysfs.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 <asm/div64.h>
+
+#include "da732x.h"
+#include "da732x_reg.h"
+
+
+struct da732x_priv {
+       struct regmap *regmap;
+       struct snd_soc_codec *codec;
+
+       unsigned int sysclk;
+       bool pll_en;
+};
+
+/*
+ * da732x register cache - default settings
+ */
+static struct reg_default da732x_reg_cache[] = {
+       { DA732X_REG_REF1               , 0x02 },
+       { DA732X_REG_BIAS_EN            , 0x80 },
+       { DA732X_REG_BIAS1              , 0x00 },
+       { DA732X_REG_BIAS2              , 0x00 },
+       { DA732X_REG_BIAS3              , 0x00 },
+       { DA732X_REG_BIAS4              , 0x00 },
+       { DA732X_REG_MICBIAS2           , 0x00 },
+       { DA732X_REG_MICBIAS1           , 0x00 },
+       { DA732X_REG_MICDET             , 0x00 },
+       { DA732X_REG_MIC1_PRE           , 0x01 },
+       { DA732X_REG_MIC1               , 0x40 },
+       { DA732X_REG_MIC2_PRE           , 0x01 },
+       { DA732X_REG_MIC2               , 0x40 },
+       { DA732X_REG_AUX1L              , 0x75 },
+       { DA732X_REG_AUX1R              , 0x75 },
+       { DA732X_REG_MIC3_PRE           , 0x01 },
+       { DA732X_REG_MIC3               , 0x40 },
+       { DA732X_REG_INP_PINBIAS        , 0x00 },
+       { DA732X_REG_INP_ZC_EN          , 0x00 },
+       { DA732X_REG_INP_MUX            , 0x50 },
+       { DA732X_REG_HP_DET             , 0x00 },
+       { DA732X_REG_HPL_DAC_OFFSET     , 0x00 },
+       { DA732X_REG_HPL_DAC_OFF_CNTL   , 0x00 },
+       { DA732X_REG_HPL_OUT_OFFSET     , 0x00 },
+       { DA732X_REG_HPL                , 0x40 },
+       { DA732X_REG_HPL_VOL            , 0x0F },
+       { DA732X_REG_HPR_DAC_OFFSET     , 0x00 },
+       { DA732X_REG_HPR_DAC_OFF_CNTL   , 0x00 },
+       { DA732X_REG_HPR_OUT_OFFSET     , 0x00 },
+       { DA732X_REG_HPR                , 0x40 },
+       { DA732X_REG_HPR_VOL            , 0x0F },
+       { DA732X_REG_LIN2               , 0x4F },
+       { DA732X_REG_LIN3               , 0x4F },
+       { DA732X_REG_LIN4               , 0x4F },
+       { DA732X_REG_OUT_ZC_EN          , 0x00 },
+       { DA732X_REG_HP_LIN1_GNDSEL     , 0x00 },
+       { DA732X_REG_CP_HP1             , 0x0C },
+       { DA732X_REG_CP_HP2             , 0x03 },
+       { DA732X_REG_CP_CTRL1           , 0x00 },
+       { DA732X_REG_CP_CTRL2           , 0x99 },
+       { DA732X_REG_CP_CTRL3           , 0x25 },
+       { DA732X_REG_CP_LEVEL_MASK      , 0x3F },
+       { DA732X_REG_CP_DET             , 0x00 },
+       { DA732X_REG_CP_STATUS          , 0x00 },
+       { DA732X_REG_CP_THRESH1         , 0x00 },
+       { DA732X_REG_CP_THRESH2         , 0x00 },
+       { DA732X_REG_CP_THRESH3         , 0x00 },
+       { DA732X_REG_CP_THRESH4         , 0x00 },
+       { DA732X_REG_CP_THRESH5         , 0x00 },
+       { DA732X_REG_CP_THRESH6         , 0x00 },
+       { DA732X_REG_CP_THRESH7         , 0x00 },
+       { DA732X_REG_CP_THRESH8         , 0x00 },
+       { DA732X_REG_PLL_DIV_LO         , 0x00 },
+       { DA732X_REG_PLL_DIV_MID        , 0x00 },
+       { DA732X_REG_PLL_DIV_HI         , 0x00 },
+       { DA732X_REG_PLL_CTRL           , 0x02 },
+       { DA732X_REG_CLK_CTRL           , 0xaa },
+       { DA732X_REG_CLK_DSP            , 0x07 },
+       { DA732X_REG_CLK_EN1            , 0x00 },
+       { DA732X_REG_CLK_EN2            , 0x00 },
+       { DA732X_REG_CLK_EN3            , 0x00 },
+       { DA732X_REG_CLK_EN4            , 0x00 },
+       { DA732X_REG_CLK_EN5            , 0x00 },
+       { DA732X_REG_AIF_MCLK           , 0x00 },
+       { DA732X_REG_AIFA1              , 0x02 },
+       { DA732X_REG_AIFA2              , 0x00 },
+       { DA732X_REG_AIFA3              , 0x08 },
+       { DA732X_REG_AIFB1              , 0x02 },
+       { DA732X_REG_AIFB2              , 0x00 },
+       { DA732X_REG_AIFB3              , 0x08 },
+       { DA732X_REG_PC_CTRL            , 0xC0 },
+       { DA732X_REG_DATA_ROUTE         , 0x00 },
+       { DA732X_REG_DSP_CTRL           , 0x00 },
+       { DA732X_REG_CIF_CTRL2          , 0x00 },
+       { DA732X_REG_HANDSHAKE          , 0x00 },
+       { DA732X_REG_SPARE1_OUT         , 0x00 },
+       { DA732X_REG_SPARE2_OUT         , 0x00 },
+       { DA732X_REG_SPARE1_IN          , 0x00 },
+       { DA732X_REG_ADC1_PD            , 0x00 },
+       { DA732X_REG_ADC1_HPF           , 0x00 },
+       { DA732X_REG_ADC1_SEL           , 0x00 },
+       { DA732X_REG_ADC1_EQ12          , 0x00 },
+       { DA732X_REG_ADC1_EQ34          , 0x00 },
+       { DA732X_REG_ADC1_EQ5           , 0x00 },
+       { DA732X_REG_ADC2_PD            , 0x00 },
+       { DA732X_REG_ADC2_HPF           , 0x00 },
+       { DA732X_REG_ADC2_SEL           , 0x00 },
+       { DA732X_REG_ADC2_EQ12          , 0x00 },
+       { DA732X_REG_ADC2_EQ34          , 0x00 },
+       { DA732X_REG_ADC2_EQ5           , 0x00 },
+       { DA732X_REG_DAC1_HPF           , 0x00 },
+       { DA732X_REG_DAC1_L_VOL         , 0x00 },
+       { DA732X_REG_DAC1_R_VOL         , 0x00 },
+       { DA732X_REG_DAC1_SEL           , 0x00 },
+       { DA732X_REG_DAC1_SOFTMUTE      , 0x00 },
+       { DA732X_REG_DAC1_EQ12          , 0x00 },
+       { DA732X_REG_DAC1_EQ34          , 0x00 },
+       { DA732X_REG_DAC1_EQ5           , 0x00 },
+       { DA732X_REG_DAC2_HPF           , 0x00 },
+       { DA732X_REG_DAC2_L_VOL         , 0x00 },
+       { DA732X_REG_DAC2_R_VOL         , 0x00 },
+       { DA732X_REG_DAC2_SEL           , 0x00 },
+       { DA732X_REG_DAC2_SOFTMUTE      , 0x00 },
+       { DA732X_REG_DAC2_EQ12          , 0x00 },
+       { DA732X_REG_DAC2_EQ34          , 0x00 },
+       { DA732X_REG_DAC2_EQ5           , 0x00 },
+       { DA732X_REG_DAC3_HPF           , 0x00 },
+       { DA732X_REG_DAC3_VOL           , 0x00 },
+       { DA732X_REG_DAC3_SEL           , 0x00 },
+       { DA732X_REG_DAC3_SOFTMUTE      , 0x00 },
+       { DA732X_REG_DAC3_EQ12          , 0x00 },
+       { DA732X_REG_DAC3_EQ34          , 0x00 },
+       { DA732X_REG_DAC3_EQ5           , 0x00 },
+       { DA732X_REG_BIQ_BYP            , 0x00 },
+       { DA732X_REG_DMA_CMD            , 0x00 },
+       { DA732X_REG_DMA_ADDR0          , 0x00 },
+       { DA732X_REG_DMA_ADDR1          , 0x00 },
+       { DA732X_REG_DMA_DATA0          , 0x00 },
+       { DA732X_REG_DMA_DATA1          , 0x00 },
+       { DA732X_REG_DMA_DATA2          , 0x00 },
+       { DA732X_REG_DMA_DATA3          , 0x00 },
+       { DA732X_REG_UNLOCK             , 0x00 },
+};
+
+static inline int da732x_get_input_div(struct snd_soc_codec *codec, int sysclk)
+{
+       int val;
+       int ret;
+
+       if (sysclk < DA732X_MCLK_10MHZ) {
+               val = DA732X_MCLK_RET_0_10MHZ;
+               ret = DA732X_MCLK_VAL_0_10MHZ;
+       } else if ((sysclk >= DA732X_MCLK_10MHZ) &&
+           (sysclk < DA732X_MCLK_20MHZ)) {
+               val = DA732X_MCLK_RET_10_20MHZ;
+               ret = DA732X_MCLK_VAL_10_20MHZ;
+       } else if ((sysclk >= DA732X_MCLK_20MHZ) &&
+           (sysclk < DA732X_MCLK_40MHZ)) {
+               val = DA732X_MCLK_RET_20_40MHZ;
+               ret = DA732X_MCLK_VAL_20_40MHZ;
+       } else if ((sysclk >= DA732X_MCLK_40MHZ) &&
+           (sysclk <= DA732X_MCLK_54MHZ)) {
+               val = DA732X_MCLK_RET_40_54MHZ;
+               ret = DA732X_MCLK_VAL_40_54MHZ;
+       } else {
+               return -EINVAL;
+       }
+
+       snd_soc_write(codec, DA732X_REG_PLL_CTRL, val);
+
+       return ret;
+}
+
+static void da732x_set_charge_pump(struct snd_soc_codec *codec, int state)
+{
+       switch (state) {
+       case DA732X_ENABLE_CP:
+               snd_soc_write(codec, DA732X_REG_CLK_EN2, DA732X_CP_CLK_EN);
+               snd_soc_write(codec, DA732X_REG_CP_HP2, DA732X_HP_CP_EN |
+                             DA732X_HP_CP_REG | DA732X_HP_CP_PULSESKIP);
+               snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA732X_CP_EN |
+                             DA732X_CP_CTRL_CPVDD1);
+               snd_soc_write(codec, DA732X_REG_CP_CTRL2,
+                             DA732X_CP_MANAGE_MAGNITUDE | DA732X_CP_BOOST);
+               snd_soc_write(codec, DA732X_REG_CP_CTRL3, DA732X_CP_1MHZ);
+               break;
+       case DA732X_DISABLE_CP:
+               snd_soc_write(codec, DA732X_REG_CLK_EN2, DA732X_CP_CLK_DIS);
+               snd_soc_write(codec, DA732X_REG_CP_HP2, DA732X_HP_CP_DIS);
+               snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA723X_CP_DIS);
+               break;
+       default:
+               pr_err(KERN_ERR "Wrong charge pump state\n");
+               break;
+       }
+}
+
+static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, DA732X_MIC_PRE_VOL_DB_MIN,
+                                 DA732X_MIC_PRE_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, DA732X_MIC_VOL_DB_MIN,
+                                 DA732X_MIC_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(aux_pga_tlv, DA732X_AUX_VOL_DB_MIN,
+                                 DA732X_AUX_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(hp_pga_tlv, DA732X_HP_VOL_DB_MIN,
+                                 DA732X_AUX_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(lin2_pga_tlv, DA732X_LIN2_VOL_DB_MIN,
+                                 DA732X_LIN2_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(lin3_pga_tlv, DA732X_LIN3_VOL_DB_MIN,
+                                 DA732X_LIN3_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(lin4_pga_tlv, DA732X_LIN4_VOL_DB_MIN,
+                                 DA732X_LIN4_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(adc_pga_tlv, DA732X_ADC_VOL_DB_MIN,
+                                 DA732X_ADC_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(dac_pga_tlv, DA732X_DAC_VOL_DB_MIN,
+                                 DA732X_DAC_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(eq_band_pga_tlv, DA732X_EQ_BAND_VOL_DB_MIN,
+                                 DA732X_EQ_BAND_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(eq_overall_tlv, DA732X_EQ_OVERALL_VOL_DB_MIN,
+                                 DA732X_EQ_OVERALL_VOL_DB_INC, 0);
+
+/* High Pass Filter */
+static const char *da732x_hpf_mode[] = {
+       "Disable", "Music", "Voice",
+};
+
+static const char *da732x_hpf_music[] = {
+       "1.8Hz", "3.75Hz", "7.5Hz", "15Hz",
+};
+
+static const char *da732x_hpf_voice[] = {
+       "2.5Hz", "25Hz", "50Hz", "100Hz",
+       "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static const struct soc_enum da732x_dac1_hpf_mode_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT,
+                       DA732X_HPF_MODE_MAX, da732x_hpf_mode)
+};
+
+static const struct soc_enum da732x_dac2_hpf_mode_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT,
+                       DA732X_HPF_MODE_MAX, da732x_hpf_mode)
+};
+
+static const struct soc_enum da732x_dac3_hpf_mode_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT,
+                       DA732X_HPF_MODE_MAX, da732x_hpf_mode)
+};
+
+static const struct soc_enum da732x_adc1_hpf_mode_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT,
+                       DA732X_HPF_MODE_MAX, da732x_hpf_mode)
+};
+
+static const struct soc_enum da732x_adc2_hpf_mode_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT,
+                       DA732X_HPF_MODE_MAX, da732x_hpf_mode)
+};
+
+static const struct soc_enum da732x_dac1_hp_filter_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT,
+                       DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
+};
+
+static const struct soc_enum da732x_dac2_hp_filter_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT,
+                       DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
+};
+
+static const struct soc_enum da732x_dac3_hp_filter_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT,
+                       DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
+};
+
+static const struct soc_enum da732x_adc1_hp_filter_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT,
+                       DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
+};
+
+static const struct soc_enum da732x_adc2_hp_filter_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT,
+                       DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
+};
+
+static const struct soc_enum da732x_dac1_voice_filter_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT,
+                       DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
+};
+
+static const struct soc_enum da732x_dac2_voice_filter_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT,
+                       DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
+};
+
+static const struct soc_enum da732x_dac3_voice_filter_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT,
+                       DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
+};
+
+static const struct soc_enum da732x_adc1_voice_filter_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT,
+                       DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
+};
+
+static const struct soc_enum da732x_adc2_voice_filter_enum[] = {
+       SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT,
+                       DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
+};
+
+
+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 soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
+       unsigned int reg = enum_ctrl->reg;
+       unsigned int sel = ucontrol->value.integer.value[0];
+       unsigned int bits;
+
+       switch (sel) {
+       case DA732X_HPF_DISABLED:
+               bits = DA732X_HPF_DIS;
+               break;
+       case DA732X_HPF_VOICE:
+               bits = DA732X_HPF_VOICE_EN;
+               break;
+       case DA732X_HPF_MUSIC:
+               bits = DA732X_HPF_MUSIC_EN;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, reg, DA732X_HPF_MASK, bits);
+
+       return 0;
+}
+
+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 soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
+       unsigned int reg = enum_ctrl->reg;
+       int val;
+
+       val = snd_soc_read(codec, reg) & DA732X_HPF_MASK;
+
+       switch (val) {
+       case DA732X_HPF_VOICE_EN:
+               ucontrol->value.integer.value[0] = DA732X_HPF_VOICE;
+               break;
+       case DA732X_HPF_MUSIC_EN:
+               ucontrol->value.integer.value[0] = DA732X_HPF_MUSIC;
+               break;
+       default:
+               ucontrol->value.integer.value[0] = DA732X_HPF_DISABLED;
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new da732x_snd_controls[] = {
+       /* Input PGAs */
+       SOC_SINGLE_RANGE_TLV("MIC1 Boost Volume", DA732X_REG_MIC1_PRE,
+                            DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN,
+                            DA732X_MICBOOST_MAX, 0, mic_boost_tlv),
+       SOC_SINGLE_RANGE_TLV("MIC2 Boost Volume", DA732X_REG_MIC2_PRE,
+                            DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN,
+                            DA732X_MICBOOST_MAX, 0, mic_boost_tlv),
+       SOC_SINGLE_RANGE_TLV("MIC3 Boost Volume", DA732X_REG_MIC3_PRE,
+                            DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN,
+                            DA732X_MICBOOST_MAX, 0, mic_boost_tlv),
+
+       /* MICs */
+       SOC_SINGLE("MIC1 Switch", DA732X_REG_MIC1, DA732X_MIC_MUTE_SHIFT,
+                  DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_SINGLE_RANGE_TLV("MIC1 Volume", DA732X_REG_MIC1,
+                            DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN,
+                            DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv),
+       SOC_SINGLE("MIC2 Switch", DA732X_REG_MIC2, DA732X_MIC_MUTE_SHIFT,
+                  DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_SINGLE_RANGE_TLV("MIC2 Volume", DA732X_REG_MIC2,
+                            DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN,
+                            DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv),
+       SOC_SINGLE("MIC3 Switch", DA732X_REG_MIC3, DA732X_MIC_MUTE_SHIFT,
+                  DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_SINGLE_RANGE_TLV("MIC3 Volume", DA732X_REG_MIC3,
+                            DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN,
+                            DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv),
+
+       /* AUXs */
+       SOC_SINGLE("AUX1L Switch", DA732X_REG_AUX1L, DA732X_AUX_MUTE_SHIFT,
+                  DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_SINGLE_TLV("AUX1L Volume", DA732X_REG_AUX1L,
+                      DA732X_AUX_VOL_SHIFT, DA732X_AUX_VOL_VAL_MAX,
+                      DA732X_NO_INVERT, aux_pga_tlv),
+       SOC_SINGLE("AUX1R Switch", DA732X_REG_AUX1R, DA732X_AUX_MUTE_SHIFT,
+                  DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_SINGLE_TLV("AUX1R Volume", DA732X_REG_AUX1R,
+                      DA732X_AUX_VOL_SHIFT, DA732X_AUX_VOL_VAL_MAX,
+                      DA732X_NO_INVERT, aux_pga_tlv),
+
+       /* ADCs */
+       SOC_DOUBLE_TLV("ADC1 Volume", DA732X_REG_ADC1_SEL,
+                      DA732X_ADCL_VOL_SHIFT, DA732X_ADCR_VOL_SHIFT,
+                      DA732X_ADC_VOL_VAL_MAX, DA732X_INVERT, adc_pga_tlv),
+
+       SOC_DOUBLE_TLV("ADC2 Volume", DA732X_REG_ADC2_SEL,
+                      DA732X_ADCL_VOL_SHIFT, DA732X_ADCR_VOL_SHIFT,
+                      DA732X_ADC_VOL_VAL_MAX, DA732X_INVERT, adc_pga_tlv),
+
+       /* DACs */
+       SOC_DOUBLE("Digital Playback DAC12 Switch", DA732X_REG_DAC1_SEL,
+                  DA732X_DACL_MUTE_SHIFT, DA732X_DACR_MUTE_SHIFT,
+                  DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_DOUBLE_R_TLV("Digital Playback DAC12 Volume", DA732X_REG_DAC1_L_VOL,
+                        DA732X_REG_DAC1_R_VOL, DA732X_DAC_VOL_SHIFT,
+                        DA732X_DAC_VOL_VAL_MAX, DA732X_INVERT, dac_pga_tlv),
+       SOC_SINGLE("Digital Playback DAC3 Switch", DA732X_REG_DAC2_SEL,
+                  DA732X_DACL_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_SINGLE_TLV("Digital Playback DAC3 Volume", DA732X_REG_DAC2_L_VOL,
+                       DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX,
+                       DA732X_INVERT, dac_pga_tlv),
+       SOC_SINGLE("Digital Playback DAC4 Switch", DA732X_REG_DAC2_SEL,
+                  DA732X_DACR_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_SINGLE_TLV("Digital Playback DAC4 Volume", DA732X_REG_DAC2_R_VOL,
+                      DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX,
+                      DA732X_INVERT, dac_pga_tlv),
+       SOC_SINGLE("Digital Playback DAC5 Switch", DA732X_REG_DAC3_SEL,
+                  DA732X_DACL_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_SINGLE_TLV("Digital Playback DAC5 Volume", DA732X_REG_DAC3_VOL,
+                      DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX,
+                      DA732X_INVERT, dac_pga_tlv),
+
+       /* High Pass Filters */
+       SOC_ENUM_EXT("DAC1 High Pass Filter Mode",
+                    da732x_dac1_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+       SOC_ENUM("DAC1 High Pass Filter", da732x_dac1_hp_filter_enum),
+       SOC_ENUM("DAC1 Voice Filter", da732x_dac1_voice_filter_enum),
+
+       SOC_ENUM_EXT("DAC2 High Pass Filter Mode",
+                    da732x_dac2_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+       SOC_ENUM("DAC2 High Pass Filter", da732x_dac2_hp_filter_enum),
+       SOC_ENUM("DAC2 Voice Filter", da732x_dac2_voice_filter_enum),
+
+       SOC_ENUM_EXT("DAC3 High Pass Filter Mode",
+                    da732x_dac3_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+       SOC_ENUM("DAC3 High Pass Filter", da732x_dac3_hp_filter_enum),
+       SOC_ENUM("DAC3 Filter Mode", da732x_dac3_voice_filter_enum),
+
+       SOC_ENUM_EXT("ADC1 High Pass Filter Mode",
+                    da732x_adc1_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+       SOC_ENUM("ADC1 High Pass Filter", da732x_adc1_hp_filter_enum),
+       SOC_ENUM("ADC1 Voice Filter", da732x_adc1_voice_filter_enum),
+
+       SOC_ENUM_EXT("ADC2 High Pass Filter Mode",
+                    da732x_adc2_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+       SOC_ENUM("ADC2 High Pass Filter", da732x_adc2_hp_filter_enum),
+       SOC_ENUM("ADC2 Voice Filter", da732x_adc2_voice_filter_enum),
+
+       /* Equalizers */
+       SOC_SINGLE("ADC1 EQ Switch", DA732X_REG_ADC1_EQ5,
+                  DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+       SOC_SINGLE_TLV("ADC1 EQ Band 1 Volume", DA732X_REG_ADC1_EQ12,
+                      DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("ADC1 EQ Band 2 Volume", DA732X_REG_ADC1_EQ12,
+                      DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("ADC1 EQ Band 3 Volume", DA732X_REG_ADC1_EQ34,
+                      DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("ADC1 EQ Band 4 Volume", DA732X_REG_ADC1_EQ34,
+                      DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("ADC1 EQ Band 5 Volume", DA732X_REG_ADC1_EQ5,
+                      DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("ADC1 EQ Overall Volume", DA732X_REG_ADC1_EQ5,
+                      DA732X_EQ_OVERALL_SHIFT, DA732X_EQ_OVERALL_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_overall_tlv),
+
+       SOC_SINGLE("ADC2 EQ Switch", DA732X_REG_ADC2_EQ5,
+                  DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+       SOC_SINGLE_TLV("ADC2 EQ Band 1 Volume", DA732X_REG_ADC2_EQ12,
+                      DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("ADC2 EQ Band 2 Volume", DA732X_REG_ADC2_EQ12,
+                      DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("ADC2 EQ Band 3 Volume", DA732X_REG_ADC2_EQ34,
+                      DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("ACD2 EQ Band 4 Volume", DA732X_REG_ADC2_EQ34,
+                      DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("ACD2 EQ Band 5 Volume", DA732X_REG_ADC2_EQ5,
+                      DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("ADC2 EQ Overall Volume", DA732X_REG_ADC1_EQ5,
+                      DA732X_EQ_OVERALL_SHIFT, DA732X_EQ_OVERALL_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_overall_tlv),
+
+       SOC_SINGLE("DAC1 EQ Switch", DA732X_REG_DAC1_EQ5,
+                  DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+       SOC_SINGLE_TLV("DAC1 EQ Band 1 Volume", DA732X_REG_DAC1_EQ12,
+                      DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("DAC1 EQ Band 2 Volume", DA732X_REG_DAC1_EQ12,
+                      DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("DAC1 EQ Band 3 Volume", DA732X_REG_DAC1_EQ34,
+                      DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("DAC1 EQ Band 4 Volume", DA732X_REG_DAC1_EQ34,
+                      DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("DAC1 EQ Band 5 Volume", DA732X_REG_DAC1_EQ5,
+                      DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+
+       SOC_SINGLE("DAC2 EQ Switch", DA732X_REG_DAC2_EQ5,
+                  DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+       SOC_SINGLE_TLV("DAC2 EQ Band 1 Volume", DA732X_REG_DAC2_EQ12,
+                      DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("DAC2 EQ Band 2 Volume", DA732X_REG_DAC2_EQ12,
+                      DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("DAC2 EQ Band 3 Volume", DA732X_REG_DAC2_EQ34,
+                      DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("DAC2 EQ Band 4 Volume", DA732X_REG_DAC2_EQ34,
+                      DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("DAC2 EQ Band 5 Volume", DA732X_REG_DAC2_EQ5,
+                      DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+
+       SOC_SINGLE("DAC3 EQ Switch", DA732X_REG_DAC3_EQ5,
+                  DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+       SOC_SINGLE_TLV("DAC3 EQ Band 1 Volume", DA732X_REG_DAC3_EQ12,
+                      DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("DAC3 EQ Band 2 Volume", DA732X_REG_DAC3_EQ12,
+                      DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("DAC3 EQ Band 3 Volume", DA732X_REG_DAC3_EQ34,
+                      DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("DAC3 EQ Band 4 Volume", DA732X_REG_DAC3_EQ34,
+                      DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+       SOC_SINGLE_TLV("DAC3 EQ Band 5 Volume", DA732X_REG_DAC3_EQ5,
+                      DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+                      DA732X_INVERT, eq_band_pga_tlv),
+
+       /* Lineout 2 Reciever*/
+       SOC_SINGLE("Lineout 2 Switch", DA732X_REG_LIN2, DA732X_LOUT_MUTE_SHIFT,
+                  DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_SINGLE_TLV("Lineout 2 Volume", DA732X_REG_LIN2,
+                      DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX,
+                      DA732X_NO_INVERT, lin2_pga_tlv),
+
+       /* Lineout 3 SPEAKER*/
+       SOC_SINGLE("Lineout 3 Switch", DA732X_REG_LIN3, DA732X_LOUT_MUTE_SHIFT,
+                  DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_SINGLE_TLV("Lineout 3 Volume", DA732X_REG_LIN3,
+                      DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX,
+                      DA732X_NO_INVERT, lin3_pga_tlv),
+
+       /* Lineout 4 */
+       SOC_SINGLE("Lineout 4 Switch", DA732X_REG_LIN4, DA732X_LOUT_MUTE_SHIFT,
+                  DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_SINGLE_TLV("Lineout 4 Volume", DA732X_REG_LIN4,
+                      DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX,
+                      DA732X_NO_INVERT, lin4_pga_tlv),
+
+       /* Headphones */
+       SOC_DOUBLE_R("Headphone Switch", DA732X_REG_HPR, DA732X_REG_HPL,
+                    DA732X_HP_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT),
+       SOC_DOUBLE_R_TLV("Headphone Volume", DA732X_REG_HPL_VOL,
+                        DA732X_REG_HPR_VOL, DA732X_HP_VOL_SHIFT,
+                        DA732X_HP_VOL_VAL_MAX, DA732X_NO_INVERT, hp_pga_tlv),
+};
+
+static int da732x_adc_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:
+               switch (w->reg) {
+               case DA732X_REG_ADC1_PD:
+                       snd_soc_update_bits(codec, DA732X_REG_CLK_EN3,
+                                           DA732X_ADCA_BB_CLK_EN,
+                                           DA732X_ADCA_BB_CLK_EN);
+                       break;
+               case DA732X_REG_ADC2_PD:
+                       snd_soc_update_bits(codec, DA732X_REG_CLK_EN3,
+                                           DA732X_ADCC_BB_CLK_EN,
+                                           DA732X_ADCC_BB_CLK_EN);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               snd_soc_update_bits(codec, w->reg, DA732X_ADC_RST_MASK,
+                                   DA732X_ADC_SET_ACT);
+               snd_soc_update_bits(codec, w->reg, DA732X_ADC_PD_MASK,
+                                   DA732X_ADC_ON);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, w->reg, DA732X_ADC_PD_MASK,
+                                   DA732X_ADC_OFF);
+               snd_soc_update_bits(codec, w->reg, DA732X_ADC_RST_MASK,
+                                   DA732X_ADC_SET_RST);
+
+               switch (w->reg) {
+               case DA732X_REG_ADC1_PD:
+                       snd_soc_update_bits(codec, DA732X_REG_CLK_EN3,
+                                           DA732X_ADCA_BB_CLK_EN, 0);
+                       break;
+               case DA732X_REG_ADC2_PD:
+                       snd_soc_update_bits(codec, DA732X_REG_CLK_EN3,
+                                           DA732X_ADCC_BB_CLK_EN, 0);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int da732x_out_pga_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, w->reg,
+                                   (1 << w->shift) | DA732X_OUT_HIZ_EN,
+                                   (1 << w->shift) | DA732X_OUT_HIZ_EN);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, w->reg,
+                                   (1 << w->shift) | DA732X_OUT_HIZ_EN,
+                                   (1 << w->shift) | DA732X_OUT_HIZ_DIS);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const char *adcl_text[] = {
+       "AUX1L", "MIC1"
+};
+
+static const char *adcr_text[] = {
+       "AUX1R", "MIC2", "MIC3"
+};
+
+static const char *enable_text[] = {
+       "Disabled",
+       "Enabled"
+};
+
+/* ADC1LMUX */
+static const struct soc_enum adc1l_enum =
+       SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT,
+                       DA732X_ADCL_MUX_MAX, adcl_text);
+static const struct snd_kcontrol_new adc1l_mux =
+       SOC_DAPM_ENUM("ADC Route", adc1l_enum);
+
+/* ADC1RMUX */
+static const struct soc_enum adc1r_enum =
+       SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT,
+                       DA732X_ADCR_MUX_MAX, adcr_text);
+static const struct snd_kcontrol_new adc1r_mux =
+       SOC_DAPM_ENUM("ADC Route", adc1r_enum);
+
+/* ADC2LMUX */
+static const struct soc_enum adc2l_enum =
+       SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT,
+                       DA732X_ADCL_MUX_MAX, adcl_text);
+static const struct snd_kcontrol_new adc2l_mux =
+       SOC_DAPM_ENUM("ADC Route", adc2l_enum);
+
+/* ADC2RMUX */
+static const struct soc_enum adc2r_enum =
+       SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT,
+                       DA732X_ADCR_MUX_MAX, adcr_text);
+
+static const struct snd_kcontrol_new adc2r_mux =
+       SOC_DAPM_ENUM("ADC Route", adc2r_enum);
+
+static const struct soc_enum da732x_hp_left_output =
+       SOC_ENUM_SINGLE(DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT,
+                       DA732X_DAC_EN_MAX, enable_text);
+
+static const struct snd_kcontrol_new hpl_mux =
+       SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output);
+
+static const struct soc_enum da732x_hp_right_output =
+       SOC_ENUM_SINGLE(DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT,
+                       DA732X_DAC_EN_MAX, enable_text);
+
+static const struct snd_kcontrol_new hpr_mux =
+       SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output);
+
+static const struct soc_enum da732x_speaker_output =
+       SOC_ENUM_SINGLE(DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT,
+                       DA732X_DAC_EN_MAX, enable_text);
+
+static const struct snd_kcontrol_new spk_mux =
+       SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output);
+
+static const struct soc_enum da732x_lout4_output =
+       SOC_ENUM_SINGLE(DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT,
+                       DA732X_DAC_EN_MAX, enable_text);
+
+static const struct snd_kcontrol_new lout4_mux =
+       SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output);
+
+static const struct soc_enum da732x_lout2_output =
+       SOC_ENUM_SINGLE(DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT,
+                       DA732X_DAC_EN_MAX, enable_text);
+
+static const struct snd_kcontrol_new lout2_mux =
+       SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output);
+
+static const struct snd_soc_dapm_widget da732x_dapm_widgets[] = {
+       /* Supplies */
+       SND_SOC_DAPM_SUPPLY("ADC1 Supply", DA732X_REG_ADC1_PD, 0,
+                           DA732X_NO_INVERT, da732x_adc_event,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("ADC2 Supply", DA732X_REG_ADC2_PD, 0,
+                           DA732X_NO_INVERT, da732x_adc_event,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("DAC1 CLK", DA732X_REG_CLK_EN4,
+                           DA732X_DACA_BB_CLK_SHIFT, DA732X_NO_INVERT,
+                           NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC2 CLK", DA732X_REG_CLK_EN4,
+                           DA732X_DACC_BB_CLK_SHIFT, DA732X_NO_INVERT,
+                           NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC3 CLK", DA732X_REG_CLK_EN5,
+                           DA732X_DACE_BB_CLK_SHIFT, DA732X_NO_INVERT,
+                           NULL, 0),
+
+       /* Micbias */
+       SND_SOC_DAPM_SUPPLY("MICBIAS1", DA732X_REG_MICBIAS1,
+                           DA732X_MICBIAS_EN_SHIFT,
+                           DA732X_NO_INVERT, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS2", DA732X_REG_MICBIAS2,
+                           DA732X_MICBIAS_EN_SHIFT,
+                           DA732X_NO_INVERT, NULL, 0),
+
+       /* Inputs */
+       SND_SOC_DAPM_INPUT("MIC1"),
+       SND_SOC_DAPM_INPUT("MIC2"),
+       SND_SOC_DAPM_INPUT("MIC3"),
+       SND_SOC_DAPM_INPUT("AUX1L"),
+       SND_SOC_DAPM_INPUT("AUX1R"),
+
+       /* Outputs */
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+       SND_SOC_DAPM_OUTPUT("LOUTL"),
+       SND_SOC_DAPM_OUTPUT("LOUTR"),
+       SND_SOC_DAPM_OUTPUT("ClassD"),
+
+       /* ADCs */
+       SND_SOC_DAPM_ADC("ADC1L", NULL, DA732X_REG_ADC1_SEL,
+                        DA732X_ADCL_EN_SHIFT, DA732X_NO_INVERT),
+       SND_SOC_DAPM_ADC("ADC1R", NULL, DA732X_REG_ADC1_SEL,
+                        DA732X_ADCR_EN_SHIFT, DA732X_NO_INVERT),
+       SND_SOC_DAPM_ADC("ADC2L", NULL, DA732X_REG_ADC2_SEL,
+                        DA732X_ADCL_EN_SHIFT, DA732X_NO_INVERT),
+       SND_SOC_DAPM_ADC("ADC2R", NULL, DA732X_REG_ADC2_SEL,
+                        DA732X_ADCR_EN_SHIFT, DA732X_NO_INVERT),
+
+       /* DACs */
+       SND_SOC_DAPM_DAC("DAC1L", NULL, DA732X_REG_DAC1_SEL,
+                        DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT),
+       SND_SOC_DAPM_DAC("DAC1R", NULL, DA732X_REG_DAC1_SEL,
+                        DA732X_DACR_EN_SHIFT, DA732X_NO_INVERT),
+       SND_SOC_DAPM_DAC("DAC2L", NULL, DA732X_REG_DAC2_SEL,
+                        DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT),
+       SND_SOC_DAPM_DAC("DAC2R", NULL, DA732X_REG_DAC2_SEL,
+                        DA732X_DACR_EN_SHIFT, DA732X_NO_INVERT),
+       SND_SOC_DAPM_DAC("DAC3", NULL, DA732X_REG_DAC3_SEL,
+                        DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT),
+
+       /* Input Pgas */
+       SND_SOC_DAPM_PGA("MIC1 PGA", DA732X_REG_MIC1, DA732X_MIC_EN_SHIFT,
+                        0, NULL, 0),
+       SND_SOC_DAPM_PGA("MIC2 PGA", DA732X_REG_MIC2, DA732X_MIC_EN_SHIFT,
+                        0, NULL, 0),
+       SND_SOC_DAPM_PGA("MIC3 PGA", DA732X_REG_MIC3, DA732X_MIC_EN_SHIFT,
+                        0, NULL, 0),
+       SND_SOC_DAPM_PGA("AUX1L PGA", DA732X_REG_AUX1L, DA732X_AUX_EN_SHIFT,
+                        0, NULL, 0),
+       SND_SOC_DAPM_PGA("AUX1R PGA", DA732X_REG_AUX1R, DA732X_AUX_EN_SHIFT,
+                        0, NULL, 0),
+
+       SND_SOC_DAPM_PGA_E("HP Left", DA732X_REG_HPL, DA732X_HP_OUT_EN_SHIFT,
+                          0, NULL, 0, da732x_out_pga_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("HP Right", DA732X_REG_HPR, DA732X_HP_OUT_EN_SHIFT,
+                          0, NULL, 0, da732x_out_pga_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("LIN2", DA732X_REG_LIN2, DA732X_LIN_OUT_EN_SHIFT,
+                          0, NULL, 0, da732x_out_pga_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("LIN3", DA732X_REG_LIN3, DA732X_LIN_OUT_EN_SHIFT,
+                          0, NULL, 0, da732x_out_pga_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("LIN4", DA732X_REG_LIN4, DA732X_LIN_OUT_EN_SHIFT,
+                          0, NULL, 0, da732x_out_pga_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* MUXs */
+       SND_SOC_DAPM_MUX("ADC1 Left MUX", SND_SOC_NOPM, 0, 0, &adc1l_mux),
+       SND_SOC_DAPM_MUX("ADC1 Right MUX", SND_SOC_NOPM, 0, 0, &adc1r_mux),
+       SND_SOC_DAPM_MUX("ADC2 Left MUX", SND_SOC_NOPM, 0, 0, &adc2l_mux),
+       SND_SOC_DAPM_MUX("ADC2 Right MUX", SND_SOC_NOPM, 0, 0, &adc2r_mux),
+
+       SND_SOC_DAPM_MUX("HP Left MUX", SND_SOC_NOPM, 0, 0, &hpl_mux),
+       SND_SOC_DAPM_MUX("HP Right MUX", SND_SOC_NOPM, 0, 0, &hpr_mux),
+       SND_SOC_DAPM_MUX("Speaker MUX", SND_SOC_NOPM, 0, 0, &spk_mux),
+       SND_SOC_DAPM_MUX("LOUT2 MUX", SND_SOC_NOPM, 0, 0, &lout2_mux),
+       SND_SOC_DAPM_MUX("LOUT4 MUX", SND_SOC_NOPM, 0, 0, &lout4_mux),
+
+       /* AIF interfaces */
+       SND_SOC_DAPM_AIF_OUT("AIFA Output", "AIFA Capture", 0, DA732X_REG_AIFA3,
+                            DA732X_AIF_EN_SHIFT, 0),
+       SND_SOC_DAPM_AIF_IN("AIFA Input", "AIFA Playback", 0, DA732X_REG_AIFA3,
+                           DA732X_AIF_EN_SHIFT, 0),
+
+       SND_SOC_DAPM_AIF_OUT("AIFB Output", "AIFB Capture", 0, DA732X_REG_AIFB3,
+                            DA732X_AIF_EN_SHIFT, 0),
+       SND_SOC_DAPM_AIF_IN("AIFB Input", "AIFB Playback", 0, DA732X_REG_AIFB3,
+                           DA732X_AIF_EN_SHIFT, 0),
+};
+
+static const struct snd_soc_dapm_route da732x_dapm_routes[] = {
+       /* Inputs */
+       {"AUX1L PGA", "NULL", "AUX1L"},
+       {"AUX1R PGA", "NULL", "AUX1R"},
+       {"MIC1 PGA", NULL, "MIC1"},
+       {"MIC2 PGA", "NULL", "MIC2"},
+       {"MIC3 PGA", "NULL", "MIC3"},
+
+       /* Capture Path */
+       {"ADC1 Left MUX", "MIC1", "MIC1 PGA"},
+       {"ADC1 Left MUX", "AUX1L", "AUX1L PGA"},
+
+       {"ADC1 Right MUX", "AUX1R", "AUX1R PGA"},
+       {"ADC1 Right MUX", "MIC2", "MIC2 PGA"},
+       {"ADC1 Right MUX", "MIC3", "MIC3 PGA"},
+
+       {"ADC2 Left MUX", "AUX1L", "AUX1L PGA"},
+       {"ADC2 Left MUX", "MIC1", "MIC1 PGA"},
+
+       {"ADC2 Right MUX", "AUX1R", "AUX1R PGA"},
+       {"ADC2 Right MUX", "MIC2", "MIC2 PGA"},
+       {"ADC2 Right MUX", "MIC3", "MIC3 PGA"},
+
+       {"ADC1L", NULL, "ADC1 Supply"},
+       {"ADC1R", NULL, "ADC1 Supply"},
+       {"ADC2L", NULL, "ADC2 Supply"},
+       {"ADC2R", NULL, "ADC2 Supply"},
+
+       {"ADC1L", NULL, "ADC1 Left MUX"},
+       {"ADC1R", NULL, "ADC1 Right MUX"},
+       {"ADC2L", NULL, "ADC2 Left MUX"},
+       {"ADC2R", NULL, "ADC2 Right MUX"},
+
+       {"AIFA Output", NULL, "ADC1L"},
+       {"AIFA Output", NULL, "ADC1R"},
+       {"AIFB Output", NULL, "ADC2L"},
+       {"AIFB Output", NULL, "ADC2R"},
+
+       {"HP Left MUX", "Enabled", "AIFA Input"},
+       {"HP Right MUX", "Enabled", "AIFA Input"},
+       {"Speaker MUX", "Enabled", "AIFB Input"},
+       {"LOUT2 MUX", "Enabled", "AIFB Input"},
+       {"LOUT4 MUX", "Enabled", "AIFB Input"},
+
+       {"DAC1L", NULL, "DAC1 CLK"},
+       {"DAC1R", NULL, "DAC1 CLK"},
+       {"DAC2L", NULL, "DAC2 CLK"},
+       {"DAC2R", NULL, "DAC2 CLK"},
+       {"DAC3", NULL, "DAC3 CLK"},
+
+       {"DAC1L", NULL, "HP Left MUX"},
+       {"DAC1R", NULL, "HP Right MUX"},
+       {"DAC2L", NULL, "Speaker MUX"},
+       {"DAC2R", NULL, "LOUT4 MUX"},
+       {"DAC3", NULL, "LOUT2 MUX"},
+
+       /* Output Pgas */
+       {"HP Left", NULL, "DAC1L"},
+       {"HP Right", NULL, "DAC1R"},
+       {"LIN3", NULL, "DAC2L"},
+       {"LIN4", NULL, "DAC2R"},
+       {"LIN2", NULL, "DAC3"},
+
+       /* Outputs */
+       {"ClassD", NULL, "LIN3"},
+       {"LOUTL", NULL, "LIN2"},
+       {"LOUTR", NULL, "LIN4"},
+       {"HPL", NULL, "HP Left"},
+       {"HPR", NULL, "HP Right"},
+};
+
+static int da732x_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;
+       u32 aif = 0;
+       u32 reg_aif;
+       u32 fs;
+
+       reg_aif = dai->driver->base;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               aif |= DA732X_AIF_WORD_16;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               aif |= DA732X_AIF_WORD_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               aif |= DA732X_AIF_WORD_24;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               aif |= DA732X_AIF_WORD_32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params_rate(params)) {
+       case 8000:
+               fs = DA732X_SR_8KHZ;
+               break;
+       case 11025:
+               fs = DA732X_SR_11_025KHZ;
+               break;
+       case 12000:
+               fs = DA732X_SR_12KHZ;
+               break;
+       case 16000:
+               fs = DA732X_SR_16KHZ;
+               break;
+       case 22050:
+               fs = DA732X_SR_22_05KHZ;
+               break;
+       case 24000:
+               fs = DA732X_SR_24KHZ;
+               break;
+       case 32000:
+               fs = DA732X_SR_32KHZ;
+               break;
+       case 44100:
+               fs = DA732X_SR_44_1KHZ;
+               break;
+       case 48000:
+               fs = DA732X_SR_48KHZ;
+               break;
+       case 88100:
+               fs = DA732X_SR_88_1KHZ;
+               break;
+       case 96000:
+               fs = DA732X_SR_96KHZ;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, reg_aif, DA732X_AIF_WORD_MASK, aif);
+       snd_soc_update_bits(codec, DA732X_REG_CLK_CTRL, DA732X_SR1_MASK, fs);
+
+       return 0;
+}
+
+static int da732x_set_dai_fmt(struct snd_soc_dai *dai, u32 fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u32 aif_mclk, pc_count;
+       u32 reg_aif1, aif1;
+       u32 reg_aif3, aif3;
+
+       switch (dai->id) {
+       case DA732X_DAI_ID1:
+               reg_aif1 = DA732X_REG_AIFA1;
+               reg_aif3 = DA732X_REG_AIFA3;
+               pc_count = DA732X_PC_PULSE_AIFA | DA732X_PC_RESYNC_NOT_AUT |
+                          DA732X_PC_SAME;
+               break;
+       case DA732X_DAI_ID2:
+               reg_aif1 = DA732X_REG_AIFB1;
+               reg_aif3 = DA732X_REG_AIFB3;
+               pc_count = DA732X_PC_PULSE_AIFB | DA732X_PC_RESYNC_NOT_AUT |
+                          DA732X_PC_SAME;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               aif1 = DA732X_AIF_SLAVE;
+               aif_mclk = DA732X_AIFM_FRAME_64 | DA732X_AIFM_SRC_SEL_AIFA;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               aif1 = DA732X_AIF_CLK_FROM_SRC;
+               aif_mclk = DA732X_CLK_GENERATION_AIF_A;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               aif3 = DA732X_AIF_I2S_MODE;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               aif3 = DA732X_AIF_RIGHT_J_MODE;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aif3 = DA732X_AIF_LEFT_J_MODE;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               aif3 = DA732X_AIF_DSP_MODE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_B:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif3 |= DA732X_AIF_BCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       aif3 |= DA732X_AIF_BCLK_INV | DA732X_AIF_WCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif3 |= DA732X_AIF_BCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       aif3 |= DA732X_AIF_WCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_write(codec, DA732X_REG_AIF_MCLK, aif_mclk);
+       snd_soc_update_bits(codec, reg_aif1, DA732X_AIF1_CLK_MASK, aif1);
+       snd_soc_update_bits(codec, reg_aif3, DA732X_AIF_BCLK_INV |
+                           DA732X_AIF_WCLK_INV | DA732X_AIF_MODE_MASK, aif3);
+       snd_soc_write(codec, DA732X_REG_PC_CTRL, pc_count);
+
+       return 0;
+}
+
+
+
+static int da732x_set_dai_pll(struct snd_soc_codec *codec, int pll_id,
+                             int source, unsigned int freq_in,
+                             unsigned int freq_out)
+{
+       struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
+       int fref, indiv;
+       u8 div_lo, div_mid, div_hi;
+       u64 frac_div;
+
+       /* Disable PLL */
+       if (freq_out == 0) {
+               snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL,
+                                   DA732X_PLL_EN, 0);
+               da732x->pll_en = false;
+               return 0;
+       }
+
+       if (da732x->pll_en)
+               return -EBUSY;
+
+       if (source == DA732X_SRCCLK_MCLK) {
+               /* Validate Sysclk rate */
+               switch (da732x->sysclk) {
+               case 11290000:
+               case 12288000:
+               case 22580000:
+               case 24576000:
+               case 45160000:
+               case 49152000:
+                       snd_soc_write(codec, DA732X_REG_PLL_CTRL,
+                                     DA732X_PLL_BYPASS);
+                       return 0;
+               default:
+                       dev_err(codec->dev,
+                               "Cannot use PLL Bypass, invalid SYSCLK rate\n");
+                       return -EINVAL;
+               }
+       }
+
+       indiv = da732x_get_input_div(codec, da732x->sysclk);
+       if (indiv < 0)
+               return indiv;
+
+       fref = (da732x->sysclk / indiv);
+       div_hi = freq_out / fref;
+       frac_div = (u64)(freq_out % fref) * 8192ULL;
+       do_div(frac_div, fref);
+       div_mid = (frac_div >> DA732X_1BYTE_SHIFT) & DA732X_U8_MASK;
+       div_lo = (frac_div) & DA732X_U8_MASK;
+
+       snd_soc_write(codec, DA732X_REG_PLL_DIV_LO, div_lo);
+       snd_soc_write(codec, DA732X_REG_PLL_DIV_MID, div_mid);
+       snd_soc_write(codec, DA732X_REG_PLL_DIV_HI, div_hi);
+
+       snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL, DA732X_PLL_EN,
+                           DA732X_PLL_EN);
+
+       da732x->pll_en = true;
+
+       return 0;
+}
+
+static int da732x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+                                unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
+
+       da732x->sysclk = freq;
+
+       return 0;
+}
+
+#define DA732X_RATES   SNDRV_PCM_RATE_8000_96000
+
+#define        DA732X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops da732x_dai1_ops = {
+       .hw_params      = da732x_hw_params,
+       .set_fmt        = da732x_set_dai_fmt,
+       .set_sysclk     = da732x_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops da732x_dai2_ops = {
+       .hw_params      = da732x_hw_params,
+       .set_fmt        = da732x_set_dai_fmt,
+       .set_sysclk     = da732x_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver da732x_dai[] = {
+       {
+               .name   = "DA732X_AIFA",
+               .id     = DA732X_DAI_ID1,
+               .base   = DA732X_REG_AIFA1,
+               .playback = {
+                       .stream_name = "AIFA Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = DA732X_RATES,
+                       .formats = DA732X_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIFA Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = DA732X_RATES,
+                       .formats = DA732X_FORMATS,
+               },
+               .ops = &da732x_dai1_ops,
+       },
+       {
+               .name   = "DA732X_AIFB",
+               .id     = DA732X_DAI_ID2,
+               .base   = DA732X_REG_AIFB1,
+               .playback = {
+                       .stream_name = "AIFB Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = DA732X_RATES,
+                       .formats = DA732X_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIFB Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = DA732X_RATES,
+                       .formats = DA732X_FORMATS,
+               },
+               .ops = &da732x_dai2_ops,
+       },
+};
+
+static const struct regmap_config da732x_regmap = {
+       .reg_bits               = 8,
+       .val_bits               = 8,
+
+       .max_register           = DA732X_MAX_REG,
+       .reg_defaults           = da732x_reg_cache,
+       .num_reg_defaults       = ARRAY_SIZE(da732x_reg_cache),
+       .cache_type             = REGCACHE_RBTREE,
+};
+
+
+static void da732x_dac_offset_adjust(struct snd_soc_codec *codec)
+{
+       u8 offset[DA732X_HP_DACS];
+       u8 sign[DA732X_HP_DACS];
+       u8 step = DA732X_DAC_OFFSET_STEP;
+
+       /* Initialize DAC offset calibration circuits and registers */
+       snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET,
+                     DA732X_HP_DAC_OFFSET_TRIM_VAL);
+       snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET,
+                     DA732X_HP_DAC_OFFSET_TRIM_VAL);
+       snd_soc_write(codec, DA732X_REG_HPL_DAC_OFF_CNTL,
+                     DA732X_HP_DAC_OFF_CALIBRATION |
+                     DA732X_HP_DAC_OFF_SCALE_STEPS);
+       snd_soc_write(codec, DA732X_REG_HPR_DAC_OFF_CNTL,
+                     DA732X_HP_DAC_OFF_CALIBRATION |
+                     DA732X_HP_DAC_OFF_SCALE_STEPS);
+
+       /* Wait for voltage stabilization */
+       msleep(DA732X_WAIT_FOR_STABILIZATION);
+
+       /* Check DAC offset sign */
+       sign[DA732X_HPL_DAC] = (codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
+                               DA732X_HP_DAC_OFF_CNTL_COMPO);
+       sign[DA732X_HPR_DAC] = (codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
+                               DA732X_HP_DAC_OFF_CNTL_COMPO);
+
+       /* Binary search DAC offset values (both channels at once) */
+       offset[DA732X_HPL_DAC] = sign[DA732X_HPL_DAC] << DA732X_HP_DAC_COMPO_SHIFT;
+       offset[DA732X_HPR_DAC] = sign[DA732X_HPR_DAC] << DA732X_HP_DAC_COMPO_SHIFT;
+
+       do {
+               offset[DA732X_HPL_DAC] |= step;
+               offset[DA732X_HPR_DAC] |= step;
+               snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET,
+                             ~offset[DA732X_HPL_DAC] & DA732X_HP_DAC_OFF_MASK);
+               snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET,
+                             ~offset[DA732X_HPR_DAC] & DA732X_HP_DAC_OFF_MASK);
+
+               msleep(DA732X_WAIT_FOR_STABILIZATION);
+
+               if ((codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
+                    DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPL_DAC])
+                       offset[DA732X_HPL_DAC] &= ~step;
+               if ((codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
+                    DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPR_DAC])
+                       offset[DA732X_HPR_DAC] &= ~step;
+
+               step >>= 1;
+       } while (step);
+
+       /* Write final DAC offsets to registers */
+       snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET,
+                     ~offset[DA732X_HPL_DAC] & DA732X_HP_DAC_OFF_MASK);
+       snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET,
+                     ~offset[DA732X_HPR_DAC] & DA732X_HP_DAC_OFF_MASK);
+
+       /* End DAC calibration mode */
+       snd_soc_write(codec, DA732X_REG_HPL_DAC_OFF_CNTL,
+               DA732X_HP_DAC_OFF_SCALE_STEPS);
+       snd_soc_write(codec, DA732X_REG_HPR_DAC_OFF_CNTL,
+               DA732X_HP_DAC_OFF_SCALE_STEPS);
+}
+
+static void da732x_output_offset_adjust(struct snd_soc_codec *codec)
+{
+       u8 offset[DA732X_HP_AMPS];
+       u8 sign[DA732X_HP_AMPS];
+       u8 step = DA732X_OUTPUT_OFFSET_STEP;
+
+       offset[DA732X_HPL_AMP] = DA732X_HP_OUT_TRIM_VAL;
+       offset[DA732X_HPR_AMP] = DA732X_HP_OUT_TRIM_VAL;
+
+       /* Initialize output offset calibration circuits and registers  */
+       snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL);
+       snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL);
+       snd_soc_write(codec, DA732X_REG_HPL,
+                     DA732X_HP_OUT_COMP | DA732X_HP_OUT_EN);
+       snd_soc_write(codec, DA732X_REG_HPR,
+                     DA732X_HP_OUT_COMP | DA732X_HP_OUT_EN);
+
+       /* Wait for voltage stabilization */
+       msleep(DA732X_WAIT_FOR_STABILIZATION);
+
+       /* Check output offset sign */
+       sign[DA732X_HPL_AMP] = codec->hw_read(codec, DA732X_REG_HPL) &
+                              DA732X_HP_OUT_COMPO;
+       sign[DA732X_HPR_AMP] = codec->hw_read(codec, DA732X_REG_HPR) &
+                              DA732X_HP_OUT_COMPO;
+
+       snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_COMP |
+                     (sign[DA732X_HPL_AMP] >> DA732X_HP_OUT_COMPO_SHIFT) |
+                     DA732X_HP_OUT_EN);
+       snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_OUT_COMP |
+                     (sign[DA732X_HPR_AMP] >> DA732X_HP_OUT_COMPO_SHIFT) |
+                     DA732X_HP_OUT_EN);
+
+       /* Binary search output offset values (both channels at once) */
+       do {
+               offset[DA732X_HPL_AMP] |= step;
+               offset[DA732X_HPR_AMP] |= step;
+               snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET,
+                             offset[DA732X_HPL_AMP]);
+               snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET,
+                             offset[DA732X_HPR_AMP]);
+
+               msleep(DA732X_WAIT_FOR_STABILIZATION);
+
+               if ((codec->hw_read(codec, DA732X_REG_HPL) &
+                    DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPL_AMP])
+                       offset[DA732X_HPL_AMP] &= ~step;
+               if ((codec->hw_read(codec, DA732X_REG_HPR) &
+                    DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPR_AMP])
+                       offset[DA732X_HPR_AMP] &= ~step;
+
+               step >>= 1;
+       } while (step);
+
+       /* Write final DAC offsets to registers */
+       snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET, offset[DA732X_HPL_AMP]);
+       snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET, offset[DA732X_HPR_AMP]);
+}
+
+static void da732x_hp_dc_offset_cancellation(struct snd_soc_codec *codec)
+{
+       /* Make sure that we have Soft Mute enabled */
+       snd_soc_write(codec, DA732X_REG_DAC1_SOFTMUTE, DA732X_SOFTMUTE_EN |
+                     DA732X_GAIN_RAMPED | DA732X_16_SAMPLES);
+       snd_soc_write(codec, DA732X_REG_DAC1_SEL, DA732X_DACL_EN |
+                     DA732X_DACR_EN | DA732X_DACL_SDM | DA732X_DACR_SDM |
+                     DA732X_DACL_MUTE | DA732X_DACR_MUTE);
+       snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN |
+                     DA732X_HP_OUT_MUTE | DA732X_HP_OUT_EN);
+       snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_OUT_EN |
+                     DA732X_HP_OUT_MUTE | DA732X_HP_OUT_DAC_EN);
+
+       da732x_dac_offset_adjust(codec);
+       da732x_output_offset_adjust(codec);
+
+       snd_soc_write(codec, DA732X_REG_DAC1_SEL, DA732X_DACS_DIS);
+       snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_DIS);
+       snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_DIS);
+}
+
+static int da732x_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               snd_soc_update_bits(codec, DA732X_REG_BIAS_EN,
+                                   DA732X_BIAS_BOOST_MASK,
+                                   DA732X_BIAS_BOOST_100PC);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       /* Init Codec */
+                       snd_soc_write(codec, DA732X_REG_REF1,
+                                     DA732X_VMID_FASTCHG);
+                       snd_soc_write(codec, DA732X_REG_BIAS_EN,
+                                     DA732X_BIAS_EN);
+
+                       mdelay(DA732X_STARTUP_DELAY);
+
+                       /* Disable Fast Charge and enable DAC ref voltage */
+                       snd_soc_write(codec, DA732X_REG_REF1,
+                                     DA732X_REFBUFX2_EN);
+
+                       /* Enable bypass DSP routing */
+                       snd_soc_write(codec, DA732X_REG_DATA_ROUTE,
+                                     DA732X_BYPASS_DSP);
+
+                       /* Enable Digital subsystem */
+                       snd_soc_write(codec, DA732X_REG_DSP_CTRL,
+                                     DA732X_DIGITAL_EN);
+
+                       snd_soc_write(codec, DA732X_REG_SPARE1_OUT,
+                                     DA732X_HP_DRIVER_EN |
+                                     DA732X_HP_GATE_LOW |
+                                     DA732X_HP_LOOP_GAIN_CTRL);
+                       snd_soc_write(codec, DA732X_REG_HP_LIN1_GNDSEL,
+                                     DA732X_HP_OUT_GNDSEL);
+
+                       da732x_set_charge_pump(codec, DA732X_ENABLE_CP);
+
+                       snd_soc_write(codec, DA732X_REG_CLK_EN1,
+                             DA732X_SYS3_CLK_EN | DA732X_PC_CLK_EN);
+
+                       /* Enable Zero Crossing */
+                       snd_soc_write(codec, DA732X_REG_INP_ZC_EN,
+                                     DA732X_MIC1_PRE_ZC_EN |
+                                     DA732X_MIC1_ZC_EN |
+                                     DA732X_MIC2_PRE_ZC_EN |
+                                     DA732X_MIC2_ZC_EN |
+                                     DA732X_AUXL_ZC_EN |
+                                     DA732X_AUXR_ZC_EN |
+                                     DA732X_MIC3_PRE_ZC_EN |
+                                     DA732X_MIC3_ZC_EN);
+                       snd_soc_write(codec, DA732X_REG_OUT_ZC_EN,
+                                     DA732X_HPL_ZC_EN | DA732X_HPR_ZC_EN |
+                                     DA732X_LIN2_ZC_EN | DA732X_LIN3_ZC_EN |
+                                     DA732X_LIN4_ZC_EN);
+
+                       da732x_hp_dc_offset_cancellation(codec);
+
+                       regcache_cache_only(codec->control_data, false);
+                       regcache_sync(codec->control_data);
+               } else {
+                       snd_soc_update_bits(codec, DA732X_REG_BIAS_EN,
+                                           DA732X_BIAS_BOOST_MASK,
+                                           DA732X_BIAS_BOOST_50PC);
+                       snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL,
+                                           DA732X_PLL_EN, 0);
+                       da732x->pll_en = false;
+               }
+               break;
+       case SND_SOC_BIAS_OFF:
+               regcache_cache_only(codec->control_data, true);
+               da732x_set_charge_pump(codec, DA732X_DISABLE_CP);
+               snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN,
+                                   DA732X_BIAS_DIS);
+               da732x->pll_en = false;
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int da732x_probe(struct snd_soc_codec *codec)
+{
+       struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int ret = 0;
+
+       da732x->codec = codec;
+
+       dapm->idle_bias_off = false;
+
+       codec->control_data = da732x->regmap;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to register codec.\n");
+               goto err;
+       }
+
+       da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+err:
+       return ret;
+}
+
+static int da732x_remove(struct snd_soc_codec *codec)
+{
+
+       da732x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+struct snd_soc_codec_driver soc_codec_dev_da732x = {
+       .probe                  = da732x_probe,
+       .remove                 = da732x_remove,
+       .set_bias_level         = da732x_set_bias_level,
+       .controls               = da732x_snd_controls,
+       .num_controls           = ARRAY_SIZE(da732x_snd_controls),
+       .dapm_widgets           = da732x_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(da732x_dapm_widgets),
+       .dapm_routes            = da732x_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(da732x_dapm_routes),
+       .set_pll                = da732x_set_dai_pll,
+       .reg_cache_size         = ARRAY_SIZE(da732x_reg_cache),
+};
+
+static __devinit int da732x_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct da732x_priv *da732x;
+       unsigned int reg;
+       int ret;
+
+       da732x = devm_kzalloc(&i2c->dev, sizeof(struct da732x_priv),
+                             GFP_KERNEL);
+       if (!da732x)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, da732x);
+
+       da732x->regmap = devm_regmap_init_i2c(i2c, &da732x_regmap);
+       if (IS_ERR(da732x->regmap)) {
+               ret = PTR_ERR(da732x->regmap);
+               dev_err(&i2c->dev, "Failed to initialize regmap\n");
+               goto err;
+       }
+
+       ret = regmap_read(da732x->regmap, DA732X_REG_ID, &reg);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
+               goto err;
+       }
+
+       dev_info(&i2c->dev, "Revision: %d.%d\n",
+                (reg & DA732X_ID_MAJOR_MASK), (reg & DA732X_ID_MINOR_MASK));
+
+       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da732x,
+                                    da732x_dai, ARRAY_SIZE(da732x_dai));
+       if (ret != 0)
+               dev_err(&i2c->dev, "Failed to register codec.\n");
+
+err:
+       return ret;
+}
+
+static __devexit int da732x_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+
+       return 0;
+}
+
+static const struct i2c_device_id da732x_i2c_id[] = {
+       { "da7320", 0},
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, da732x_i2c_id);
+
+static struct i2c_driver da732x_i2c_driver = {
+       .driver         = {
+               .name   = "da7320",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = da732x_i2c_probe,
+       .remove         = __devexit_p(da732x_i2c_remove),
+       .id_table       = da732x_i2c_id,
+};
+
+module_i2c_driver(da732x_i2c_driver);
+
+
+MODULE_DESCRIPTION("ASoC DA732X driver");
+MODULE_AUTHOR("Michal Hajduk <michal.hajduk@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h
new file mode 100644 (file)
index 0000000..c8ce547
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * da732x.h -- Dialog DA732X ALSA SoC Audio Driver Header File
+ *
+ * Copyright (C) 2012 Dialog Semiconductor GmbH
+ *
+ * Author: Michal Hajduk <Michal.Hajduk@diasemi.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 __DA732X_H_
+#define __DA732X_H
+
+#include <sound/soc.h>
+
+/* General */
+#define        DA732X_U8_MASK                  0xFF
+#define        DA732X_4BYTES                   4
+#define        DA732X_3BYTES                   3
+#define        DA732X_2BYTES                   2
+#define        DA732X_1BYTE                    1
+#define        DA732X_1BYTE_SHIFT              8
+#define        DA732X_2BYTES_SHIFT             16
+#define        DA732X_3BYTES_SHIFT             24
+#define        DA732X_4BYTES_SHIFT             32
+
+#define        DA732X_DACS_DIS                 0x0
+#define        DA732X_HP_DIS                   0x0
+#define        DA732X_CLEAR_REG                0x0
+
+/* Calibration */
+#define        DA732X_DAC_OFFSET_STEP          0x20
+#define        DA732X_OUTPUT_OFFSET_STEP       0x80
+#define        DA732X_HP_OUT_TRIM_VAL          0x0
+#define        DA732X_WAIT_FOR_STABILIZATION   1
+#define        DA732X_HPL_DAC                  0
+#define        DA732X_HPR_DAC                  1
+#define        DA732X_HP_DACS                  2
+#define        DA732X_HPL_AMP                  0
+#define        DA732X_HPR_AMP                  1
+#define        DA732X_HP_AMPS                  2
+
+/* Clock settings */
+#define DA732X_STARTUP_DELAY           100
+#define        DA732X_PLL_OUT_196608           196608000
+#define        DA732X_PLL_OUT_180634           180633600
+#define        DA732X_PLL_OUT_SRM              188620800
+#define        DA732X_MCLK_10MHZ               10000000
+#define        DA732X_MCLK_20MHZ               20000000
+#define        DA732X_MCLK_40MHZ               40000000
+#define        DA732X_MCLK_54MHZ               54000000
+#define        DA732X_MCLK_RET_0_10MHZ         0
+#define        DA732X_MCLK_VAL_0_10MHZ         1
+#define        DA732X_MCLK_RET_10_20MHZ        1
+#define        DA732X_MCLK_VAL_10_20MHZ        2
+#define        DA732X_MCLK_RET_20_40MHZ        2
+#define        DA732X_MCLK_VAL_20_40MHZ        4
+#define        DA732X_MCLK_RET_40_54MHZ        3
+#define        DA732X_MCLK_VAL_40_54MHZ        8
+#define        DA732X_DAI_ID1                  0
+#define        DA732X_DAI_ID2                  1
+#define        DA732X_SRCCLK_PLL               0
+#define        DA732X_SRCCLK_MCLK              1
+
+#define        DA732X_LIN_LP_VOL               0x4F
+#define        DA732X_LP_VOL                   0x40
+
+/* Kcontrols */
+#define        DA732X_DAC_EN_MAX               2
+#define        DA732X_ADCL_MUX_MAX             2
+#define        DA732X_ADCR_MUX_MAX             3
+#define        DA732X_HPF_MODE_MAX             3
+#define        DA732X_HPF_MODE_SHIFT           4
+#define        DA732X_HPF_MUSIC_SHIFT          0
+#define        DA732X_HPF_MUSIC_MAX            4
+#define        DA732X_HPF_VOICE_SHIFT          4
+#define        DA732X_HPF_VOICE_MAX            8
+#define        DA732X_EQ_EN_MAX                1
+#define        DA732X_HPF_VOICE                1
+#define        DA732X_HPF_MUSIC                2
+#define        DA732X_HPF_DISABLED             0
+#define        DA732X_NO_INVERT                0
+#define        DA732X_INVERT                   1
+#define        DA732X_SWITCH_MAX               1
+#define        DA732X_ENABLE_CP                1
+#define        DA732X_DISABLE_CP               0
+#define        DA732X_DISABLE_ALL_CLKS         0
+#define        DA732X_RESET_ADCS               0
+
+/* dB values */
+#define DA732X_MIC_VOL_DB_MIN          0
+#define DA732X_MIC_VOL_DB_INC          50
+#define DA732X_MIC_PRE_VOL_DB_MIN      0
+#define DA732X_MIC_PRE_VOL_DB_INC      600
+#define DA732X_AUX_VOL_DB_MIN          -6000
+#define DA732X_AUX_VOL_DB_INC          150
+#define DA732X_HP_VOL_DB_MIN           -2250
+#define DA732X_HP_VOL_DB_INC           150
+#define        DA732X_LIN2_VOL_DB_MIN          -1650
+#define        DA732X_LIN2_VOL_DB_INC          150
+#define        DA732X_LIN3_VOL_DB_MIN          -1650
+#define DA732X_LIN3_VOL_DB_INC         150
+#define        DA732X_LIN4_VOL_DB_MIN          -2250
+#define DA732X_LIN4_VOL_DB_INC         150
+#define        DA732X_EQ_BAND_VOL_DB_MIN       -1050
+#define        DA732X_EQ_BAND_VOL_DB_INC       150
+#define DA732X_DAC_VOL_DB_MIN          -7725
+#define DA732X_DAC_VOL_DB_INC          75
+#define DA732X_ADC_VOL_DB_MIN          0
+#define DA732X_ADC_VOL_DB_INC          -1
+#define        DA732X_EQ_OVERALL_VOL_DB_MIN    -1800
+#define        DA732X_EQ_OVERALL_VOL_DB_INC    600
+
+#define DA732X_SOC_ENUM_DOUBLE_R(xreg, xrreg, xmax, xtext) \
+       {.reg = xreg, .reg2 = xrreg, .max = xmax, .texts = xtext}
+
+enum da732x_sysctl {
+       DA732X_SR_8KHZ          = 0x1,
+       DA732X_SR_11_025KHZ     = 0x2,
+       DA732X_SR_12KHZ         = 0x3,
+       DA732X_SR_16KHZ         = 0x5,
+       DA732X_SR_22_05KHZ      = 0x6,
+       DA732X_SR_24KHZ         = 0x7,
+       DA732X_SR_32KHZ         = 0x9,
+       DA732X_SR_44_1KHZ       = 0xA,
+       DA732X_SR_48KHZ         = 0xB,
+       DA732X_SR_88_1KHZ       = 0xE,
+       DA732X_SR_96KHZ         = 0xF,
+};
+
+#endif /* __DA732X_H_ */
diff --git a/sound/soc/codecs/da732x_reg.h b/sound/soc/codecs/da732x_reg.h
new file mode 100644 (file)
index 0000000..bdd03ca
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * da732x_reg.h --- Dialog DA732X ALSA SoC Audio Registers Header File
+ *
+ * Copyright (C) 2012 Dialog Semiconductor GmbH
+ *
+ * Author: Michal Hajduk <Michal.Hajduk@diasemi.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 __DA732X_REG_H_
+#define __DA732X_REG_H_
+
+/* DA732X registers */
+#define        DA732X_REG_STATUS_EXT           0x00
+#define DA732X_REG_STATUS              0x01
+#define DA732X_REG_REF1                        0x02
+#define DA732X_REG_BIAS_EN             0x03
+#define DA732X_REG_BIAS1               0x04
+#define DA732X_REG_BIAS2               0x05
+#define DA732X_REG_BIAS3               0x06
+#define DA732X_REG_BIAS4               0x07
+#define DA732X_REG_MICBIAS2            0x0F
+#define DA732X_REG_MICBIAS1            0x10
+#define DA732X_REG_MICDET              0x11
+#define DA732X_REG_MIC1_PRE            0x12
+#define DA732X_REG_MIC1                        0x13
+#define DA732X_REG_MIC2_PRE            0x14
+#define DA732X_REG_MIC2                        0x15
+#define DA732X_REG_AUX1L               0x16
+#define DA732X_REG_AUX1R               0x17
+#define DA732X_REG_MIC3_PRE            0x18
+#define DA732X_REG_MIC3                        0x19
+#define DA732X_REG_INP_PINBIAS         0x1A
+#define DA732X_REG_INP_ZC_EN           0x1B
+#define DA732X_REG_INP_MUX             0x1D
+#define DA732X_REG_HP_DET              0x20
+#define DA732X_REG_HPL_DAC_OFFSET      0x21
+#define DA732X_REG_HPL_DAC_OFF_CNTL    0x22
+#define DA732X_REG_HPL_OUT_OFFSET      0x23
+#define DA732X_REG_HPL                 0x24
+#define DA732X_REG_HPL_VOL             0x25
+#define DA732X_REG_HPR_DAC_OFFSET      0x26
+#define DA732X_REG_HPR_DAC_OFF_CNTL    0x27
+#define DA732X_REG_HPR_OUT_OFFSET      0x28
+#define DA732X_REG_HPR                 0x29
+#define DA732X_REG_HPR_VOL             0x2A
+#define DA732X_REG_LIN2                        0x2B
+#define DA732X_REG_LIN3                        0x2C
+#define DA732X_REG_LIN4                        0x2D
+#define DA732X_REG_OUT_ZC_EN           0x2E
+#define DA732X_REG_HP_LIN1_GNDSEL      0x37
+#define DA732X_REG_CP_HP1              0x3A
+#define DA732X_REG_CP_HP2              0x3B
+#define DA732X_REG_CP_CTRL1            0x40
+#define DA732X_REG_CP_CTRL2            0x41
+#define DA732X_REG_CP_CTRL3            0x42
+#define DA732X_REG_CP_LEVEL_MASK       0x43
+#define DA732X_REG_CP_DET              0x44
+#define DA732X_REG_CP_STATUS           0x45
+#define DA732X_REG_CP_THRESH1          0x46
+#define DA732X_REG_CP_THRESH2          0x47
+#define DA732X_REG_CP_THRESH3          0x48
+#define DA732X_REG_CP_THRESH4          0x49
+#define DA732X_REG_CP_THRESH5          0x4A
+#define DA732X_REG_CP_THRESH6          0x4B
+#define DA732X_REG_CP_THRESH7          0x4C
+#define DA732X_REG_CP_THRESH8          0x4D
+#define DA732X_REG_PLL_DIV_LO          0x50
+#define DA732X_REG_PLL_DIV_MID         0x51
+#define DA732X_REG_PLL_DIV_HI          0x52
+#define DA732X_REG_PLL_CTRL            0x53
+#define DA732X_REG_CLK_CTRL            0x54
+#define DA732X_REG_CLK_DSP             0x5A
+#define DA732X_REG_CLK_EN1             0x5B
+#define DA732X_REG_CLK_EN2             0x5C
+#define DA732X_REG_CLK_EN3             0x5D
+#define DA732X_REG_CLK_EN4             0x5E
+#define DA732X_REG_CLK_EN5             0x5F
+#define DA732X_REG_AIF_MCLK            0x60
+#define DA732X_REG_AIFA1               0x61
+#define DA732X_REG_AIFA2               0x62
+#define DA732X_REG_AIFA3               0x63
+#define DA732X_REG_AIFB1               0x64
+#define DA732X_REG_AIFB2               0x65
+#define DA732X_REG_AIFB3               0x66
+#define DA732X_REG_PC_CTRL             0x6A
+#define DA732X_REG_DATA_ROUTE          0x70
+#define DA732X_REG_DSP_CTRL            0x71
+#define DA732X_REG_CIF_CTRL2           0x74
+#define DA732X_REG_HANDSHAKE           0x75
+#define DA732X_REG_MBOX0               0x76
+#define DA732X_REG_MBOX1               0x77
+#define DA732X_REG_MBOX2               0x78
+#define DA732X_REG_MBOX_STATUS         0x79
+#define DA732X_REG_SPARE1_OUT          0x7D
+#define DA732X_REG_SPARE2_OUT          0x7E
+#define DA732X_REG_SPARE1_IN           0x7F
+#define DA732X_REG_ID                  0x81
+#define DA732X_REG_ADC1_PD             0x90
+#define DA732X_REG_ADC1_HPF            0x93
+#define DA732X_REG_ADC1_SEL            0x94
+#define DA732X_REG_ADC1_EQ12           0x95
+#define DA732X_REG_ADC1_EQ34           0x96
+#define DA732X_REG_ADC1_EQ5            0x97
+#define DA732X_REG_ADC2_PD             0x98
+#define DA732X_REG_ADC2_HPF            0x9B
+#define DA732X_REG_ADC2_SEL            0x9C
+#define DA732X_REG_ADC2_EQ12           0x9D
+#define DA732X_REG_ADC2_EQ34           0x9E
+#define DA732X_REG_ADC2_EQ5            0x9F
+#define DA732X_REG_DAC1_HPF            0xA0
+#define DA732X_REG_DAC1_L_VOL          0xA1
+#define DA732X_REG_DAC1_R_VOL          0xA2
+#define DA732X_REG_DAC1_SEL            0xA3
+#define DA732X_REG_DAC1_SOFTMUTE       0xA4
+#define DA732X_REG_DAC1_EQ12           0xA5
+#define DA732X_REG_DAC1_EQ34           0xA6
+#define DA732X_REG_DAC1_EQ5            0xA7
+#define DA732X_REG_DAC2_HPF            0xB0
+#define DA732X_REG_DAC2_L_VOL          0xB1
+#define DA732X_REG_DAC2_R_VOL          0xB2
+#define DA732X_REG_DAC2_SEL            0xB3
+#define DA732X_REG_DAC2_SOFTMUTE       0xB4
+#define DA732X_REG_DAC2_EQ12           0xB5
+#define DA732X_REG_DAC2_EQ34           0xB6
+#define DA732X_REG_DAC2_EQ5            0xB7
+#define DA732X_REG_DAC3_HPF            0xC0
+#define DA732X_REG_DAC3_VOL            0xC1
+#define DA732X_REG_DAC3_SEL            0xC3
+#define DA732X_REG_DAC3_SOFTMUTE       0xC4
+#define DA732X_REG_DAC3_EQ12           0xC5
+#define DA732X_REG_DAC3_EQ34           0xC6
+#define DA732X_REG_DAC3_EQ5            0xC7
+#define DA732X_REG_BIQ_BYP             0xD2
+#define DA732X_REG_DMA_CMD             0xD3
+#define DA732X_REG_DMA_ADDR0           0xD4
+#define DA732X_REG_DMA_ADDR1           0xD5
+#define DA732X_REG_DMA_DATA0           0xD6
+#define DA732X_REG_DMA_DATA1           0xD7
+#define DA732X_REG_DMA_DATA2           0xD8
+#define DA732X_REG_DMA_DATA3           0xD9
+#define DA732X_REG_DMA_STATUS          0xDA
+#define DA732X_REG_BROWNOUT            0xDF
+#define DA732X_REG_UNLOCK              0xE0
+
+#define        DA732X_MAX_REG                  DA732X_REG_UNLOCK
+/*
+ * Bits
+ */
+
+/* DA732X_REG_STATUS_EXT (addr=0x00) */
+#define        DA732X_STATUS_EXT_DSP                   (1 << 4)
+#define        DA732X_STATUS_EXT_CLEAR                 (0 << 0)
+
+/* DA732X_REG_STATUS   (addr=0x01) */
+#define DA732X_STATUS_PLL_LOCK                 (1 << 0)
+#define DA732X_STATUS_PLL_MCLK_DET             (1 << 1)
+#define DA732X_STATUS_HPDET_OUT                        (1 << 2)
+#define DA732X_STATUS_INP_MIXDET_1             (1 << 3)
+#define DA732X_STATUS_INP_MIXDET_2             (1 << 4)
+#define DA732X_STATUS_BO_STATUS                        (1 << 5)
+
+/* DA732X_REG_REF1     (addr=0x02) */
+#define DA732X_VMID_FASTCHG                    (1 << 1)
+#define DA732X_VMID_FASTDISCHG                 (1 << 2)
+#define DA732X_REFBUFX2_EN                     (1 << 6)
+#define DA732X_REFBUFX2_DIS                    (0 << 6)
+
+/* DA732X_REG_BIAS_EN  (addr=0x03) */
+#define DA732X_BIAS_BOOST_MASK                 (3 << 0)
+#define DA732X_BIAS_BOOST_100PC                        (0 << 0)
+#define DA732X_BIAS_BOOST_133PC                        (1 << 0)
+#define DA732X_BIAS_BOOST_88PC                 (2 << 0)
+#define DA732X_BIAS_BOOST_50PC                 (3 << 0)
+#define DA732X_BIAS_EN                         (1 << 7)
+#define DA732X_BIAS_DIS                                (0 << 7)
+
+/* DA732X_REG_BIAS1    (addr=0x04) */
+#define DA732X_BIAS1_HP_DAC_BIAS_MASK          (3 << 0)
+#define DA732X_BIAS1_HP_DAC_BIAS_100PC         (0 << 0)
+#define DA732X_BIAS1_HP_DAC_BIAS_150PC         (1 << 0)
+#define DA732X_BIAS1_HP_DAC_BIAS_50PC          (2 << 0)
+#define DA732X_BIAS1_HP_DAC_BIAS_75PC          (3 << 0)
+#define DA732X_BIAS1_HP_OUT_BIAS_MASK          (7 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_100PC         (0 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_125PC         (1 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_150PC         (2 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_175PC         (3 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_200PC         (4 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_250PC         (5 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_300PC         (6 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_350PC         (7 << 4)
+
+/* DA732X_REG_BIAS2    (addr=0x05) */
+#define DA732X_BIAS2_LINE2_DAC_BIAS_MASK       (3 << 0)
+#define DA732X_BIAS2_LINE2_DAC_BIAS_100PC      (0 << 0)
+#define DA732X_BIAS2_LINE2_DAC_BIAS_150PC      (1 << 0)
+#define DA732X_BIAS2_LINE2_DAC_BIAS_50PC       (2 << 0)
+#define DA732X_BIAS2_LINE2_DAC_BIAS_75PC       (3 << 0)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_MASK       (7 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_100PC      (0 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_125PC      (1 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_150PC      (2 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_175PC      (3 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_200PC      (4 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_250PC      (5 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_300PC      (6 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_350PC      (7 << 4)
+
+/* DA732X_REG_BIAS3    (addr=0x06) */
+#define DA732X_BIAS3_LINE3_DAC_BIAS_MASK       (3 << 0)
+#define DA732X_BIAS3_LINE3_DAC_BIAS_100PC      (0 << 0)
+#define DA732X_BIAS3_LINE3_DAC_BIAS_150PC      (1 << 0)
+#define DA732X_BIAS3_LINE3_DAC_BIAS_50PC       (2 << 0)
+#define DA732X_BIAS3_LINE3_DAC_BIAS_75PC       (3 << 0)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_MASK       (7 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_100PC      (0 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_125PC      (1 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_150PC      (2 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_175PC      (3 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_200PC      (4 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_250PC      (5 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_300PC      (6 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_350PC      (7 << 4)
+
+/* DA732X_REG_BIAS4    (addr=0x07) */
+#define DA732X_BIAS4_LINE4_DAC_BIAS_MASK       (3 << 0)
+#define DA732X_BIAS4_LINE4_DAC_BIAS_100PC      (0 << 0)
+#define DA732X_BIAS4_LINE4_DAC_BIAS_150PC      (1 << 0)
+#define DA732X_BIAS4_LINE4_DAC_BIAS_50PC       (2 << 0)
+#define DA732X_BIAS4_LINE4_DAC_BIAS_75PC       (3 << 0)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_MASK       (7 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_100PC      (0 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_125PC      (1 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_150PC      (2 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_175PC      (3 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_200PC      (4 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_250PC      (5 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_300PC      (6 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_350PC      (7 << 4)
+
+/* DA732X_REG_SIF_VDD_SEL      (addr=0x08) */
+#define DA732X_SIF_VDD_SEL_AIFA_VDD2           (1 << 0)
+#define DA732X_SIF_VDD_SEL_AIFB_VDD2           (1 << 1)
+#define DA732X_SIF_VDD_SEL_CIFA_VDD2           (1 << 4)
+
+/* DA732X_REG_MICBIAS2/1       (addr=0x0F/0x10) */
+#define DA732X_MICBIAS_VOLTAGE_MASK            (0x0F << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V              (0x00 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V05            (0x01 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V1             (0x02 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V15            (0x03 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V2             (0x04 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V25            (0x05 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V3             (0x06 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V35            (0x07 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V4             (0x08 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V45            (0x09 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V5             (0x0A << 0)
+#define DA732X_MICBIAS_EN                      (1 << 7)
+#define DA732X_MICBIAS_EN_SHIFT                        7
+#define DA732X_MICBIAS_VOLTAGE_SHIFT           0
+#define        DA732X_MICBIAS_VOLTAGE_MAX              0x0B
+
+/* DA732X_REG_MICDET   (addr=0x11) */
+#define DA732X_MICDET_INP_MICRES               (1 << 0)
+#define DA732X_MICDET_INP_MICHOOK              (1 << 1)
+#define DA732X_MICDET_INP_DEBOUNCE_PRD_8MS     (0 << 0)
+#define DA732X_MICDET_INP_DEBOUNCE_PRD_16MS    (1 << 0)
+#define DA732X_MICDET_INP_DEBOUNCE_PRD_32MS    (2 << 0)
+#define DA732X_MICDET_INP_DEBOUNCE_PRD_64MS    (3 << 0)
+#define DA732X_MICDET_INP_MICDET_EN            (1 << 7)
+
+/* DA732X_REG_MIC1/2/3_PRE (addr=0x11/0x14/0x18) */
+#define        DA732X_MICBOOST_MASK                    0x7
+#define        DA732X_MICBOOST_SHIFT                   0
+#define        DA732X_MICBOOST_MIN                     0x1
+#define        DA732X_MICBOOST_MAX                     DA732X_MICBOOST_MASK
+
+/* DA732X_REG_MIC1/2/3 (addr=0x13/0x15/0x19) */
+#define        DA732X_MIC_VOL_SHIFT                    0
+#define        DA732X_MIC_VOL_VAL_MASK                 0x1F
+#define DA732X_MIC_MUTE_SHIFT                  6
+#define DA732X_MIC_EN_SHIFT                    7
+#define DA732X_MIC_VOL_VAL_MIN                 0x7
+#define        DA732X_MIC_VOL_VAL_MAX                  DA732X_MIC_VOL_VAL_MASK
+
+/* DA732X_REG_AUX1L/R  (addr=0x16/0x17) */
+#define        DA732X_AUX_VOL_SHIFT                    0
+#define        DA732X_AUX_VOL_MASK                     0x7
+#define DA732X_AUX_MUTE_SHIFT                  6
+#define DA732X_AUX_EN_SHIFT                    7
+#define        DA732X_AUX_VOL_VAL_MAX                  DA732X_AUX_VOL_MASK
+
+/* DA732X_REG_INP_PINBIAS      (addr=0x1A) */
+#define DA732X_INP_MICL_PINBIAS_EN             (1 << 0)
+#define DA732X_INP_MICR_PINBIAS_EN             (1 << 1)
+#define DA732X_INP_AUX1L_PINBIAS_EN            (1 << 2)
+#define DA732X_INP_AUX1R_PINBIAS_EN            (1 << 3)
+#define DA732X_INP_AUX2_PINBIAS_EN             (1 << 4)
+
+/* DA732X_REG_INP_ZC_EN        (addr=0x1B) */
+#define        DA732X_MIC1_PRE_ZC_EN                   (1 << 0)
+#define        DA732X_MIC1_ZC_EN                       (1 << 1)
+#define        DA732X_MIC2_PRE_ZC_EN                   (1 << 2)
+#define        DA732X_MIC2_ZC_EN                       (1 << 3)
+#define        DA732X_AUXL_ZC_EN                       (1 << 4)
+#define        DA732X_AUXR_ZC_EN                       (1 << 5)
+#define        DA732X_MIC3_PRE_ZC_EN                   (1 << 6)
+#define        DA732X_MIC3_ZC_EN                       (1 << 7)
+
+/* DA732X_REG_INP_MUX  (addr=0x1D) */
+#define DA732X_INP_ADC1L_MUX_SEL_AUX1L         (0 << 0)
+#define DA732X_INP_ADC1L_MUX_SEL_MIC1          (1 << 0)
+#define DA732X_INP_ADC1R_MUX_SEL_MASK          (3 << 2)
+#define DA732X_INP_ADC1R_MUX_SEL_AUX1R         (0 << 2)
+#define DA732X_INP_ADC1R_MUX_SEL_MIC2          (1 << 2)
+#define DA732X_INP_ADC1R_MUX_SEL_MIC3          (2 << 2)
+#define DA732X_INP_ADC2L_MUX_SEL_AUX1L         (0 << 4)
+#define DA732X_INP_ADC2L_MUX_SEL_MICL          (1 << 4)
+#define DA732X_INP_ADC2R_MUX_SEL_MASK          (3 << 6)
+#define DA732X_INP_ADC2R_MUX_SEL_AUX1R         (0 << 6)
+#define DA732X_INP_ADC2R_MUX_SEL_MICR          (1 << 6)
+#define DA732X_INP_ADC2R_MUX_SEL_AUX2          (2 << 6)
+#define        DA732X_ADC1L_MUX_SEL_SHIFT              0
+#define        DA732X_ADC1R_MUX_SEL_SHIFT              2
+#define        DA732X_ADC2L_MUX_SEL_SHIFT              4
+#define        DA732X_ADC2R_MUX_SEL_SHIFT              6
+
+/* DA732X_REG_HP_DET           (addr=0x20) */
+#define DA732X_HP_DET_AZ                       (1 << 0)
+#define DA732X_HP_DET_SEL1                     (1 << 1)
+#define DA732X_HP_DET_IS_MASK                  (3 << 2)
+#define DA732X_HP_DET_IS_0_5UA                 (0 << 2)
+#define DA732X_HP_DET_IS_1UA                   (1 << 2)
+#define DA732X_HP_DET_IS_2UA                   (2 << 2)
+#define DA732X_HP_DET_IS_4UA                   (3 << 2)
+#define DA732X_HP_DET_RS_MASK                  (3 << 4)
+#define DA732X_HP_DET_RS_INFINITE              (0 << 4)
+#define DA732X_HP_DET_RS_100KOHM               (1 << 4)
+#define DA732X_HP_DET_RS_10KOHM                        (2 << 4)
+#define DA732X_HP_DET_RS_1KOHM                 (3 << 4)
+#define DA732X_HP_DET_EN                       (1 << 7)
+
+/* DA732X_REG_HPL_DAC_OFFSET   (addr=0x21/0x26) */
+#define DA732X_HP_DAC_OFFSET_TRIM_MASK         (0x3F << 0)
+#define DA732X_HP_DAC_OFFSET_DAC_SIGN          (1 << 6)
+
+/* DA732X_REG_HPL_DAC_OFF_CNTL (addr=0x22/0x27) */
+#define DA732X_HP_DAC_OFF_CNTL_CONT_MASK       (7 << 0)
+#define DA732X_HP_DAC_OFF_CNTL_COMPO           (1 << 3)
+#define        DA732X_HP_DAC_OFF_CALIBRATION           (1 << 0)
+#define        DA732X_HP_DAC_OFF_SCALE_STEPS           (1 << 1)
+#define        DA732X_HP_DAC_OFF_MASK                  0x7F
+#define DA732X_HP_DAC_COMPO_SHIFT              3
+
+/* DA732X_REG_HPL_OUT_OFFSET   (addr=0x23/0x28) */
+#define DA732X_HP_OUT_OFFSET_MASK              (0xFF << 0)
+#define        DA732X_HP_DAC_OFFSET_TRIM_VAL           0x7F
+
+/* DA732X_REG_HPL/R    (addr=0x24/0x29) */
+#define DA732X_HP_OUT_SIGN                     (1 << 0)
+#define DA732X_HP_OUT_COMP                     (1 << 1)
+#define DA732X_HP_OUT_RESERVED                 (1 << 2)
+#define DA732X_HP_OUT_COMPO                    (1 << 3)
+#define DA732X_HP_OUT_DAC_EN                   (1 << 4)
+#define DA732X_HP_OUT_HIZ_EN                   (1 << 5)
+#define        DA732X_HP_OUT_HIZ_DIS                   (0 << 5)
+#define DA732X_HP_OUT_MUTE                     (1 << 6)
+#define DA732X_HP_OUT_EN                       (1 << 7)
+#define        DA732X_HP_OUT_COMPO_SHIFT               3
+#define        DA732X_HP_OUT_DAC_EN_SHIFT              4
+#define        DA732X_HP_HIZ_SHIFT                     5
+#define        DA732X_HP_MUTE_SHIFT                    6
+#define DA732X_HP_OUT_EN_SHIFT                 7
+
+#define DA732X_OUT_HIZ_EN                      (1 << 5)
+#define        DA732X_OUT_HIZ_DIS                      (0 << 5)
+
+/* DA732X_REG_HPL/R_VOL        (addr=0x25/0x2A) */
+#define        DA732X_HP_VOL_VAL_MASK                  0xF
+#define        DA732X_HP_VOL_SHIFT                     0
+#define        DA732X_HP_VOL_VAL_MAX                   DA732X_HP_VOL_VAL_MASK
+
+/* DA732X_REG_LIN2/3/4 (addr=0x2B/0x2C/0x2D) */
+#define DA732X_LOUT_VOL_SHIFT                  0
+#define DA732X_LOUT_VOL_MASK                   0x0F
+#define DA732X_LOUT_DAC_OFF                    (0 << 4)
+#define DA732X_LOUT_DAC_EN                     (1 << 4)
+#define DA732X_LOUT_HIZ_N_DIS                  (0 << 5)
+#define DA732X_LOUT_HIZ_N_EN                   (1 << 5)
+#define DA732X_LOUT_UNMUTED                    (0 << 6)
+#define DA732X_LOUT_MUTED                      (1 << 6)
+#define DA732X_LOUT_EN                         (0 << 7)
+#define DA732X_LOUT_DIS                                (1 << 7)
+#define DA732X_LOUT_DAC_EN_SHIFT               4
+#define        DA732X_LOUT_MUTE_SHIFT                  6
+#define DA732X_LIN_OUT_EN_SHIFT                        7
+#define DA732X_LOUT_VOL_VAL_MAX                        DA732X_LOUT_VOL_MASK
+
+/* DA732X_REG_OUT_ZC_EN                (addr=0x2E) */
+#define        DA732X_HPL_ZC_EN_SHIFT                  0
+#define DA732X_HPR_ZC_EN_SHIFT                 1
+#define DA732X_HPL_ZC_EN                       (1 << 0)
+#define DA732X_HPL_ZC_DIS                      (0 << 0)
+#define DA732X_HPR_ZC_EN                       (1 << 1)
+#define DA732X_HPR_ZC_DIS                      (0 << 1)
+#define DA732X_LIN2_ZC_EN                      (1 << 2)
+#define DA732X_LIN2_ZC_DIS                     (0 << 2)
+#define DA732X_LIN3_ZC_EN                      (1 << 3)
+#define DA732X_LIN3_ZC_DIS                     (0 << 3)
+#define DA732X_LIN4_ZC_EN                      (1 << 4)
+#define DA732X_LIN4_ZC_DIS                     (0 << 4)
+
+/* DA732X_REG_HP_LIN1_GNDSEL (addr=0x37) */
+#define        DA732X_HP_OUT_GNDSEL                    (1 << 0)
+
+/* DA732X_REG_CP_HP2 (addr=0x3a) */
+#define        DA732X_HP_CP_PULSESKIP                  (1 << 0)
+#define        DA732X_HP_CP_REG                        (1 << 1)
+#define DA732X_HP_CP_EN                                (1 << 3)
+#define DA732X_HP_CP_DIS                       (0 << 3)
+
+/* DA732X_REG_CP_CTRL1 (addr=0x40) */
+#define        DA732X_CP_MODE_MASK                     (7 << 1)
+#define        DA732X_CP_CTRL_STANDBY                  (0 << 1)
+#define        DA732X_CP_CTRL_CPVDD6                   (2 << 1)
+#define        DA732X_CP_CTRL_CPVDD5                   (3 << 1)
+#define        DA732X_CP_CTRL_CPVDD4                   (4 << 1)
+#define        DA732X_CP_CTRL_CPVDD3                   (5 << 1)
+#define        DA732X_CP_CTRL_CPVDD2                   (6 << 1)
+#define        DA732X_CP_CTRL_CPVDD1                   (7 << 1)
+#define        DA723X_CP_DIS                           (0 << 7)
+#define        DA732X_CP_EN                            (1 << 7)
+
+/* DA732X_REG_CP_CTRL2 (addr=0x41) */
+#define        DA732X_CP_BOOST                         (1 << 0)
+#define        DA732X_CP_MANAGE_MAGNITUDE              (2 << 2)
+
+/* DA732X_REG_CP_CTRL3 (addr=0x42) */
+#define        DA732X_CP_1MHZ                          (0 << 0)
+#define        DA732X_CP_500KHZ                        (1 << 0)
+#define        DA732X_CP_250KHZ                        (2 << 0)
+#define        DA732X_CP_125KHZ                        (3 << 0)
+#define        DA732X_CP_63KHZ                         (4 << 0)
+#define        DA732X_CP_0KHZ                          (5 << 0)
+
+/* DA732X_REG_PLL_CTRL (addr=0x53) */
+#define        DA732X_PLL_INDIV_MASK                   (3 << 0)
+#define        DA732X_PLL_SRM_EN                       (1 << 2)
+#define        DA732X_PLL_EN                           (1 << 7)
+#define        DA732X_PLL_BYPASS                       (0 << 0)
+
+/* DA732X_REG_CLK_CTRL (addr=0x54) */
+#define        DA732X_SR1_MASK                         (0xF)
+#define        DA732X_SR2_MASK                         (0xF0)
+
+/* DA732X_REG_CLK_DSP (addr=0x5A) */
+#define        DA732X_DSP_FREQ_MASK                    (7 << 0)
+#define        DA732X_DSP_FREQ_12MHZ                   (0 << 0)
+#define        DA732X_DSP_FREQ_24MHZ                   (1 << 0)
+#define        DA732X_DSP_FREQ_36MHZ                   (2 << 0)
+#define        DA732X_DSP_FREQ_48MHZ                   (3 << 0)
+#define        DA732X_DSP_FREQ_60MHZ                   (4 << 0)
+#define        DA732X_DSP_FREQ_72MHZ                   (5 << 0)
+#define        DA732X_DSP_FREQ_84MHZ                   (6 << 0)
+#define        DA732X_DSP_FREQ_96MHZ                   (7 << 0)
+
+/* DA732X_REG_CLK_EN1 (addr=0x5B) */
+#define        DA732X_DSP_CLK_EN                       (1 << 0)
+#define        DA732X_SYS3_CLK_EN                      (1 << 1)
+#define        DA732X_DSP12_CLK_EN                     (1 << 2)
+#define        DA732X_PC_CLK_EN                        (1 << 3)
+#define        DA732X_MCLK_SQR_EN                      (1 << 7)
+
+/* DA732X_REG_CLK_EN2 (addr=0x5C) */
+#define        DA732X_UART_CLK_EN                      (1 << 1)
+#define        DA732X_CP_CLK_EN                        (1 << 2)
+#define        DA732X_CP_CLK_DIS                       (0 << 2)
+
+/* DA732X_REG_CLK_EN3 (addr=0x5D) */
+#define        DA732X_ADCA_BB_CLK_EN                   (1 << 0)
+#define        DA732X_ADCC_BB_CLK_EN                   (1 << 4)
+
+/* DA732X_REG_CLK_EN4 (addr=0x5E) */
+#define        DA732X_DACA_BB_CLK_EN                   (1 << 0)
+#define        DA732X_DACC_BB_CLK_EN                   (1 << 4)
+#define DA732X_DACA_BB_CLK_SHIFT               0
+#define DA732X_DACC_BB_CLK_SHIFT               4
+
+/* DA732X_REG_CLK_EN5 (addr=0x5F) */
+#define        DA732X_DACE_BB_CLK_EN                   (1 << 0)
+#define DA732X_DACE_BB_CLK_SHIFT               0
+
+/* DA732X_REG_AIF_MCLK (addr=0x60) */
+#define DA732X_AIFM_FRAME_64                   (1 << 2)
+#define        DA732X_AIFM_SRC_SEL_AIFA                (1 << 6)
+#define        DA732X_CLK_GENERATION_AIF_A             (1 << 4)
+#define        DA732X_NO_CLK_GENERATION                0x0
+
+/* DA732X_REG_AIFA1 (addr=0x61) */
+#define        DA732X_AIF_WORD_MASK                    (0x3 << 0)
+#define        DA732X_AIF_WORD_16                      (0 << 0)
+#define        DA732X_AIF_WORD_20                      (1 << 0)
+#define        DA732X_AIF_WORD_24                      (2 << 0)
+#define        DA732X_AIF_WORD_32                      (3 << 0)
+#define        DA732X_AIF_TDM_MONO_SHIFT               (1 << 6)
+#define        DA732X_AIF1_CLK_MASK                    (1 << 7)
+#define        DA732X_AIF_SLAVE                        (0 << 7)
+#define DA732X_AIF_CLK_FROM_SRC                        (1 << 7)
+
+/* DA732X_REG_AIFA3 (addr=0x63) */
+#define        DA732X_AIF_MODE_SHIFT                   0
+#define        DA732X_AIF_MODE_MASK                    0x3
+#define        DA732X_AIF_I2S_MODE                     (0 << 0)
+#define        DA732X_AIF_LEFT_J_MODE                  (1 << 0)
+#define        DA732X_AIF_RIGHT_J_MODE                 (2 << 0)
+#define        DA732X_AIF_DSP_MODE                     (3 << 0)
+#define DA732X_AIF_WCLK_INV                    (1 << 4)
+#define DA732X_AIF_BCLK_INV                    (1 << 5)
+#define        DA732X_AIF_EN                           (1 << 7)
+#define        DA732X_AIF_EN_SHIFT                     7
+
+/* DA732X_REG_PC_CTRL (addr=0x6a) */
+#define        DA732X_PC_PULSE_AIFA                    (0 << 0)
+#define        DA732X_PC_PULSE_AIFB                    (1 << 0)
+#define        DA732X_PC_RESYNC_AUT                    (1 << 6)
+#define        DA732X_PC_RESYNC_NOT_AUT                (0 << 6)
+#define        DA732X_PC_SAME                          (1 << 7)
+
+/* DA732X_REG_DATA_ROUTE (addr=0x70) */
+#define DA732X_ADC1_TO_AIFA                    (0 << 0)
+#define DA732X_DSP_TO_AIFA                     (1 << 0)
+#define DA732X_ADC2_TO_AIFB                    (0 << 1)
+#define DA732X_DSP_TO_AIFB                     (1 << 1)
+#define DA732X_AIFA_TO_DAC1L                   (0 << 2)
+#define DA732X_DSP_TO_DAC1L                    (1 << 2)
+#define DA732X_AIFA_TO_DAC1R                   (0 << 3)
+#define DA732X_DSP_TO_DAC1R                    (1 << 3)
+#define DA732X_AIFB_TO_DAC2L                   (0 << 4)
+#define DA732X_DSP_TO_DAC2L                    (1 << 4)
+#define DA732X_AIFB_TO_DAC2R                   (0 << 5)
+#define DA732X_DSP_TO_DAC2R                    (1 << 5)
+#define DA732X_AIFB_TO_DAC3                    (0 << 6)
+#define DA732X_DSP_TO_DAC3                     (1 << 6)
+#define        DA732X_BYPASS_DSP                       (0 << 0)
+#define        DA732X_ALL_TO_DSP                       (0x7F << 0)
+
+/* DA732X_REG_DSP_CTRL (addr=0x71) */
+#define        DA732X_DIGITAL_EN                       (1 << 0)
+#define        DA732X_DIGITAL_RESET                    (0 << 0)
+#define        DA732X_DSP_CORE_EN                      (1 << 1)
+#define        DA732X_DSP_CORE_RESET                   (0 << 1)
+
+/* DA732X_REG_SPARE1_OUT (addr=0x7D)*/
+#define        DA732X_HP_DRIVER_EN                     (1 << 0)
+#define        DA732X_HP_GATE_LOW                      (1 << 2)
+#define DA732X_HP_LOOP_GAIN_CTRL               (1 << 3)
+
+/* DA732X_REG_ID (addr=0x81)*/
+#define DA732X_ID_MINOR_MASK                   (0xF << 0)
+#define DA732X_ID_MAJOR_MASK                   (0xF << 4)
+
+/* DA732X_REG_ADC1/2_PD (addr=0x90/0x98) */
+#define        DA732X_ADC_RST_MASK                     (0x3 << 0)
+#define        DA732X_ADC_PD_MASK                      (0x3 << 2)
+#define        DA732X_ADC_SET_ACT                      (0x3 << 0)
+#define        DA732X_ADC_SET_RST                      (0x0 << 0)
+#define        DA732X_ADC_ON                           (0x3 << 2)
+#define        DA732X_ADC_OFF                          (0x0 << 2)
+
+/* DA732X_REG_ADC1/2_SEL (addr=0x94/0x9C) */
+#define        DA732X_ADC_VOL_VAL_MASK                 0x7
+#define        DA732X_ADCL_VOL_SHIFT                   0
+#define        DA732X_ADCR_VOL_SHIFT                   4
+#define DA732X_ADCL_EN_SHIFT                   2
+#define DA732X_ADCR_EN_SHIFT                   3
+#define        DA732X_ADCL_EN                          (1 << 2)
+#define        DA732X_ADCR_EN                          (1 << 3)
+#define        DA732X_ADC_VOL_VAL_MAX                  DA732X_ADC_VOL_VAL_MASK
+
+/*
+ * DA732X_REG_ADC1/2_HPF (addr=0x93/0x9b)
+ * DA732x_REG_DAC1/2/3_HPG     (addr=0xA5/0xB5/0xC5)
+ */
+#define        DA732X_HPF_MUSIC_EN                     (1 << 3)
+#define        DA732X_HPF_VOICE_EN                     ((1 << 3) | (1 << 7))
+#define        DA732X_HPF_MASK                         ((1 << 3) | (1 << 7))
+#define DA732X_HPF_DIS                         ((0 << 3) | (0 << 7))
+
+/* DA732X_REG_DAC1/2/3_VOL */
+#define DA732X_DAC_VOL_VAL_MASK                        0x7F
+#define DA732X_DAC_VOL_SHIFT                   0
+#define DA732X_DAC_VOL_VAL_MAX                 DA732X_DAC_VOL_VAL_MASK
+
+/* DA732X_REG_DAC1/2/3_SEL (addr=0xA3/0xB3/0xC3) */
+#define DA732X_DACL_EN_SHIFT                   3
+#define        DA732X_DACR_EN_SHIFT                    7
+#define DA732X_DACL_MUTE_SHIFT                 2
+#define        DA732X_DACR_MUTE_SHIFT                  6
+#define DA732X_DACL_EN                         (1 << 3)
+#define        DA732X_DACR_EN                          (1 << 7)
+#define        DA732X_DACL_SDM                         (1 << 0)
+#define        DA732X_DACR_SDM                         (1 << 4)
+#define        DA732X_DACL_MUTE                        (1 << 2)
+#define        DA732X_DACR_MUTE                        (1 << 6)
+
+/* DA732X_REG_DAC_SOFTMUTE (addr=0xA4/0xB4/0xC4) */
+#define        DA732X_SOFTMUTE_EN                      (1 << 7)
+#define        DA732X_GAIN_RAMPED                      (1 << 6)
+#define        DA732X_16_SAMPLES                       (4 << 0)
+#define        DA732X_SOFTMUTE_MASK                    (1 << 7)
+#define        DA732X_SOFTMUTE_SHIFT                   7
+
+/*
+ * DA732x_REG_ADC1/2_EQ12      (addr=0x95/0x9D)
+ * DA732x_REG_ADC1/2_EQ34      (addr=0x96/0x9E)
+ * DA732x_REG_ADC1/2_EQ5       (addr=0x97/0x9F)
+ * DA732x_REG_DAC1/2/3_EQ12    (addr=0xA5/0xB5/0xC5)
+ * DA732x_REG_DAC1/2/3_EQ34    (addr=0xA6/0xB6/0xC6)
+ * DA732x_REG_DAC1/2/3_EQ5     (addr=0xA7/0xB7/0xB7)
+ */
+#define        DA732X_EQ_VOL_VAL_MASK                  0xF
+#define        DA732X_EQ_BAND1_SHIFT                   0
+#define        DA732X_EQ_BAND2_SHIFT                   4
+#define        DA732X_EQ_BAND3_SHIFT                   0
+#define        DA732X_EQ_BAND4_SHIFT                   4
+#define        DA732X_EQ_BAND5_SHIFT                   0
+#define        DA732X_EQ_OVERALL_SHIFT                 4
+#define        DA732X_EQ_OVERALL_VOL_VAL_MASK          0x3
+#define        DA732X_EQ_DIS                           (0 << 7)
+#define        DA732X_EQ_EN                            (1 << 7)
+#define        DA732X_EQ_EN_SHIFT                      7
+#define        DA732X_EQ_VOL_VAL_MAX                   DA732X_EQ_VOL_VAL_MASK
+#define        DA732X_EQ_OVERALL_VOL_VAL_MAX           DA732X_EQ_OVERALL_VOL_VAL_MASK
+
+/* DA732X_REG_DMA_CMD (addr=0xD3) */
+#define        DA732X_SEL_DSP_DMA_MASK                 (3 << 0)
+#define        DA732X_SEL_DSP_DMA_DIS                  (0 << 0)
+#define        DA732X_SEL_DSP_DMA_PMEM                 (1 << 0)
+#define        DA732X_SEL_DSP_DMA_XMEM                 (2 << 0)
+#define        DA732X_SEL_DSP_DMA_YMEM                 (3 << 0)
+#define        DA732X_DSP_RW_MASK                      (1 << 4)
+#define        DA732X_DSP_DMA_WRITE                    (0 << 4)
+#define        DA732X_DSP_DMA_READ                     (1 << 4)
+
+/* DA732X_REG_DMA_STATUS (addr=0xDA) */
+#define        DA732X_DSP_DMA_FREE                     (0 << 0)
+#define        DA732X_DSP_DMA_BUSY                     (1 << 0)
+
+#endif /* __DA732X_REG_H_ */
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
new file mode 100644 (file)
index 0000000..0d62f3b
--- /dev/null
@@ -0,0 +1,1176 @@
+/*
+ * isabelle.c - Low power high fidelity audio codec driver
+ *
+ * Copyright (c) 2012 Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ *
+ * Initially based on sound/soc/codecs/twl6040.c
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/i2c.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/tlv.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <asm/div64.h>
+#include "isabelle.h"
+
+
+/* Register default values for ISABELLE driver. */
+static struct reg_default isabelle_reg_defs[] = {
+       { 0, 0x00 },
+       { 1, 0x00 },
+       { 2, 0x00 },
+       { 3, 0x00 },
+       { 4, 0x00 },
+       { 5, 0x00 },
+       { 6, 0x00 },
+       { 7, 0x00 },
+       { 8, 0x00 },
+       { 9, 0x00 },
+       { 10, 0x00 },
+       { 11, 0x00 },
+       { 12, 0x00 },
+       { 13, 0x00 },
+       { 14, 0x00 },
+       { 15, 0x00 },
+       { 16, 0x00 },
+       { 17, 0x00 },
+       { 18, 0x00 },
+       { 19, 0x00 },
+       { 20, 0x00 },
+       { 21, 0x02 },
+       { 22, 0x02 },
+       { 23, 0x02 },
+       { 24, 0x02 },
+       { 25, 0x0F },
+       { 26, 0x8F },
+       { 27, 0x0F },
+       { 28, 0x8F },
+       { 29, 0x00 },
+       { 30, 0x00 },
+       { 31, 0x00 },
+       { 32, 0x00 },
+       { 33, 0x00 },
+       { 34, 0x00 },
+       { 35, 0x00 },
+       { 36, 0x00 },
+       { 37, 0x00 },
+       { 38, 0x00 },
+       { 39, 0x00 },
+       { 40, 0x00 },
+       { 41, 0x00 },
+       { 42, 0x00 },
+       { 43, 0x00 },
+       { 44, 0x00 },
+       { 45, 0x00 },
+       { 46, 0x00 },
+       { 47, 0x00 },
+       { 48, 0x00 },
+       { 49, 0x00 },
+       { 50, 0x00 },
+       { 51, 0x00 },
+       { 52, 0x00 },
+       { 53, 0x00 },
+       { 54, 0x00 },
+       { 55, 0x00 },
+       { 56, 0x00 },
+       { 57, 0x00 },
+       { 58, 0x00 },
+       { 59, 0x00 },
+       { 60, 0x00 },
+       { 61, 0x00 },
+       { 62, 0x00 },
+       { 63, 0x00 },
+       { 64, 0x00 },
+       { 65, 0x00 },
+       { 66, 0x00 },
+       { 67, 0x00 },
+       { 68, 0x00 },
+       { 69, 0x90 },
+       { 70, 0x90 },
+       { 71, 0x90 },
+       { 72, 0x00 },
+       { 73, 0x00 },
+       { 74, 0x00 },
+       { 75, 0x00 },
+       { 76, 0x00 },
+       { 77, 0x00 },
+       { 78, 0x00 },
+       { 79, 0x00 },
+       { 80, 0x00 },
+       { 81, 0x00 },
+       { 82, 0x00 },
+       { 83, 0x00 },
+       { 84, 0x00 },
+       { 85, 0x07 },
+       { 86, 0x00 },
+       { 87, 0x00 },
+       { 88, 0x00 },
+       { 89, 0x07 },
+       { 90, 0x80 },
+       { 91, 0x07 },
+       { 92, 0x07 },
+       { 93, 0x00 },
+       { 94, 0x00 },
+       { 95, 0x00 },
+       { 96, 0x00 },
+       { 97, 0x00 },
+       { 98, 0x00 },
+       { 99, 0x00 },
+};
+
+static const char *isabelle_rx1_texts[] = {"VRX1", "ARX1"};
+static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"};
+
+static const struct soc_enum isabelle_rx1_enum[] = {
+       SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, 1, isabelle_rx1_texts),
+       SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, 1, isabelle_rx1_texts),
+};
+
+static const struct soc_enum isabelle_rx2_enum[] = {
+       SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, 1, isabelle_rx2_texts),
+       SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, 1, isabelle_rx2_texts),
+};
+
+/* Headset DAC playback switches */
+static const struct snd_kcontrol_new rx1_mux_controls =
+       SOC_DAPM_ENUM("Route", isabelle_rx1_enum);
+
+static const struct snd_kcontrol_new rx2_mux_controls =
+       SOC_DAPM_ENUM("Route", isabelle_rx2_enum);
+
+/* TX input selection */
+static const char *isabelle_atx_texts[] = {"AMIC1", "DMIC"};
+static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"};
+
+static const struct soc_enum isabelle_atx_enum[] = {
+       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, 1, isabelle_atx_texts),
+       SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_atx_texts),
+};
+
+static const struct soc_enum isabelle_vtx_enum[] = {
+       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, 1, isabelle_vtx_texts),
+       SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_vtx_texts),
+};
+
+static const struct snd_kcontrol_new atx_mux_controls =
+       SOC_DAPM_ENUM("Route", isabelle_atx_enum);
+
+static const struct snd_kcontrol_new vtx_mux_controls =
+       SOC_DAPM_ENUM("Route", isabelle_vtx_enum);
+
+/* Left analog microphone selection */
+static const char *isabelle_amic1_texts[] = {
+       "Main Mic", "Headset Mic", "Aux/FM Left"};
+
+/* Left analog microphone selection */
+static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"};
+
+static const struct soc_enum isabelle_amic1_enum[] = {
+       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 5,
+                       ARRAY_SIZE(isabelle_amic1_texts),
+                       isabelle_amic1_texts),
+};
+
+static const struct soc_enum isabelle_amic2_enum[] = {
+       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 4,
+                       ARRAY_SIZE(isabelle_amic2_texts),
+                       isabelle_amic2_texts),
+};
+
+static const struct snd_kcontrol_new amic1_control =
+       SOC_DAPM_ENUM("Route", isabelle_amic1_enum);
+
+static const struct snd_kcontrol_new amic2_control =
+       SOC_DAPM_ENUM("Route", isabelle_amic2_enum);
+
+static const char *isabelle_st_audio_texts[] = {"ATX1", "ATX2"};
+
+static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"};
+
+static const struct soc_enum isabelle_st_audio_enum[] = {
+       SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, 1,
+                       isabelle_st_audio_texts),
+       SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, 1,
+                       isabelle_st_audio_texts),
+};
+
+static const struct soc_enum isabelle_st_voice_enum[] = {
+       SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, 1,
+                       isabelle_st_voice_texts),
+       SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, 1,
+                       isabelle_st_voice_texts),
+};
+
+static const struct snd_kcontrol_new st_audio_control =
+       SOC_DAPM_ENUM("Route", isabelle_st_audio_enum);
+
+static const struct snd_kcontrol_new st_voice_control =
+       SOC_DAPM_ENUM("Route", isabelle_st_voice_enum);
+
+/* Mixer controls */
+static const struct snd_kcontrol_new isabelle_hs_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC1L Playback Switch", ISABELLE_HSDRV_CFG1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_HSDRV_CFG1_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_hs_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC1R Playback Switch", ISABELLE_HSDRV_CFG1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_HSDRV_CFG1_REG, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_hf_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC2L Playback Switch", ISABELLE_HFLPGA_CFG_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_HFLPGA_CFG_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_hf_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC2R Playback Switch", ISABELLE_HFRPGA_CFG_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_HFRPGA_CFG_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_ep_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC2L Playback Switch", ISABELLE_EARDRV_CFG1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_EARDRV_CFG1_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_aux_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC3L Playback Switch", ISABELLE_LINEAMP_CFG_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_LINEAMP_CFG_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_aux_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC3R Playback Switch", ISABELLE_LINEAMP_CFG_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_LINEAMP_CFG_REG, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga1_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga1_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga2_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga2_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("USNC Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga3_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga3_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx1_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DL1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx2_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("DL2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx3_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("DL3 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx4_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DL4 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx5_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DL5 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx6_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("DL6 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new ep_path_enable_control =
+       SOC_DAPM_SINGLE("Switch", ISABELLE_EARDRV_CFG2_REG, 0, 1, 0);
+
+/* TLV Declarations */
+static const DECLARE_TLV_DB_SCALE(mic_amp_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(afm_amp_tlv, -3300, 300, 0);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -1200, 200, 0);
+static const DECLARE_TLV_DB_SCALE(hf_tlv, -5000, 200, 0);
+
+/* from -63 to 0 dB in 1 dB steps */
+static const DECLARE_TLV_DB_SCALE(dpga_tlv, -6300, 100, 1);
+
+/* from -63 to 9 dB in 1 dB steps */
+static const DECLARE_TLV_DB_SCALE(rx_tlv, -6300, 100, 1);
+
+static const DECLARE_TLV_DB_SCALE(st_tlv, -2700, 300, 1);
+static const DECLARE_TLV_DB_SCALE(tx_tlv, -600, 100, 0);
+
+static const struct snd_kcontrol_new isabelle_snd_controls[] = {
+       SOC_DOUBLE_TLV("Headset Playback Volume", ISABELLE_HSDRV_GAIN_REG,
+                       4, 0, 0xF, 0, dac_tlv),
+       SOC_DOUBLE_R_TLV("Handsfree Playback Volume",
+                       ISABELLE_HFLPGA_CFG_REG, ISABELLE_HFRPGA_CFG_REG,
+                       0, 0x1F, 0, hf_tlv),
+       SOC_DOUBLE_TLV("Aux Playback Volume", ISABELLE_LINEAMP_GAIN_REG,
+                       4, 0, 0xF, 0, dac_tlv),
+       SOC_SINGLE_TLV("Earpiece Playback Volume", ISABELLE_EARDRV_CFG1_REG,
+                       0, 0xF, 0, dac_tlv),
+
+       SOC_DOUBLE_TLV("Aux FM Volume", ISABELLE_APGA_GAIN_REG, 4, 0, 0xF, 0,
+                       afm_amp_tlv),
+       SOC_SINGLE_TLV("Mic1 Capture Volume", ISABELLE_MIC1_GAIN_REG, 3, 0x1F,
+                       0, mic_amp_tlv),
+       SOC_SINGLE_TLV("Mic2 Capture Volume", ISABELLE_MIC2_GAIN_REG, 3, 0x1F,
+                       0, mic_amp_tlv),
+
+       SOC_DOUBLE_R_TLV("DPGA1 Volume", ISABELLE_DPGA1L_GAIN_REG,
+                       ISABELLE_DPGA1R_GAIN_REG, 0, 0x3F, 0, dpga_tlv),
+       SOC_DOUBLE_R_TLV("DPGA2 Volume", ISABELLE_DPGA2L_GAIN_REG,
+                       ISABELLE_DPGA2R_GAIN_REG, 0, 0x3F, 0, dpga_tlv),
+       SOC_DOUBLE_R_TLV("DPGA3 Volume", ISABELLE_DPGA3L_GAIN_REG,
+                       ISABELLE_DPGA3R_GAIN_REG, 0, 0x3F, 0, dpga_tlv),
+
+       SOC_SINGLE_TLV("Sidetone Audio TX1 Volume",
+                       ISABELLE_ATX_STPGA1_CFG_REG, 0, 0xF, 0, st_tlv),
+       SOC_SINGLE_TLV("Sidetone Audio TX2 Volume",
+                       ISABELLE_ATX_STPGA2_CFG_REG, 0, 0xF, 0, st_tlv),
+       SOC_SINGLE_TLV("Sidetone Voice TX1 Volume",
+                       ISABELLE_VTX_STPGA1_CFG_REG, 0, 0xF, 0, st_tlv),
+       SOC_SINGLE_TLV("Sidetone Voice TX2 Volume",
+                       ISABELLE_VTX2_STPGA2_CFG_REG, 0, 0xF, 0, st_tlv),
+
+       SOC_SINGLE_TLV("Audio TX1 Volume", ISABELLE_ATX1_DPGA_REG, 4, 0xF, 0,
+                       tx_tlv),
+       SOC_SINGLE_TLV("Audio TX2 Volume", ISABELLE_ATX2_DPGA_REG, 4, 0xF, 0,
+                       tx_tlv),
+       SOC_SINGLE_TLV("Voice TX1 Volume", ISABELLE_VTX1_DPGA_REG, 4, 0xF, 0,
+                       tx_tlv),
+       SOC_SINGLE_TLV("Voice TX2 Volume", ISABELLE_VTX2_DPGA_REG, 4, 0xF, 0,
+                       tx_tlv),
+
+       SOC_SINGLE_TLV("RX1 DPGA Volume", ISABELLE_RX1_DPGA_REG, 0, 0x3F, 0,
+                       rx_tlv),
+       SOC_SINGLE_TLV("RX2 DPGA Volume", ISABELLE_RX2_DPGA_REG, 0, 0x3F, 0,
+                       rx_tlv),
+       SOC_SINGLE_TLV("RX3 DPGA Volume", ISABELLE_RX3_DPGA_REG, 0, 0x3F, 0,
+                       rx_tlv),
+       SOC_SINGLE_TLV("RX4 DPGA Volume", ISABELLE_RX4_DPGA_REG, 0, 0x3F, 0,
+                       rx_tlv),
+       SOC_SINGLE_TLV("RX5 DPGA Volume", ISABELLE_RX5_DPGA_REG, 0, 0x3F, 0,
+                       rx_tlv),
+       SOC_SINGLE_TLV("RX6 DPGA Volume", ISABELLE_RX6_DPGA_REG, 0, 0x3F, 0,
+                       rx_tlv),
+
+       SOC_SINGLE("Headset Noise Gate", ISABELLE_HS_NG_CFG1_REG, 7, 1, 0),
+       SOC_SINGLE("Handsfree Noise Gate", ISABELLE_HF_NG_CFG1_REG, 7, 1, 0),
+
+       SOC_SINGLE("ATX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+               7, 1, 0),
+       SOC_SINGLE("ATX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+               6, 1, 0),
+       SOC_SINGLE("ARX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+               5, 1, 0),
+       SOC_SINGLE("ARX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+               4, 1, 0),
+       SOC_SINGLE("ARX3 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+               3, 1, 0),
+       SOC_SINGLE("ARX4 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+               2, 1, 0),
+       SOC_SINGLE("ARX5 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+               1, 1, 0),
+       SOC_SINGLE("ARX6 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+               0, 1, 0),
+       SOC_SINGLE("VRX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+               3, 1, 0),
+       SOC_SINGLE("VRX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+               2, 1, 0),
+
+       SOC_SINGLE("ATX1 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG,
+               7, 1, 0),
+       SOC_SINGLE("ATX2 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG,
+               6, 1, 0),
+       SOC_SINGLE("VTX1 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG,
+               5, 1, 0),
+       SOC_SINGLE("VTX2 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG,
+               4, 1, 0),
+       SOC_SINGLE("RX1 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+               5, 1, 0),
+       SOC_SINGLE("RX2 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+               4, 1, 0),
+       SOC_SINGLE("RX3 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+               3, 1, 0),
+       SOC_SINGLE("RX4 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+               2, 1, 0),
+       SOC_SINGLE("RX5 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+               1, 1, 0),
+       SOC_SINGLE("RX6 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+               0, 1, 0),
+
+       SOC_SINGLE("ULATX12 Capture Switch", ISABELLE_ULATX12_INTF_CFG_REG,
+               7, 1, 0),
+
+       SOC_SINGLE("DL12 Playback Switch", ISABELLE_DL12_INTF_CFG_REG,
+               7, 1, 0),
+       SOC_SINGLE("DL34 Playback Switch", ISABELLE_DL34_INTF_CFG_REG,
+               7, 1, 0),
+       SOC_SINGLE("DL56 Playback Switch", ISABELLE_DL56_INTF_CFG_REG,
+               7, 1, 0),
+
+       /* DMIC Switch */
+       SOC_SINGLE("DMIC Switch", ISABELLE_DMIC_CFG_REG, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget isabelle_dapm_widgets[] = {
+       /* Inputs */
+       SND_SOC_DAPM_INPUT("MAINMIC"),
+       SND_SOC_DAPM_INPUT("HSMIC"),
+       SND_SOC_DAPM_INPUT("SUBMIC"),
+       SND_SOC_DAPM_INPUT("LINEIN1"),
+       SND_SOC_DAPM_INPUT("LINEIN2"),
+       SND_SOC_DAPM_INPUT("DMICDAT"),
+
+       /* Outputs */
+       SND_SOC_DAPM_OUTPUT("HSOL"),
+       SND_SOC_DAPM_OUTPUT("HSOR"),
+       SND_SOC_DAPM_OUTPUT("HFL"),
+       SND_SOC_DAPM_OUTPUT("HFR"),
+       SND_SOC_DAPM_OUTPUT("EP"),
+       SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+       SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+
+       SND_SOC_DAPM_PGA("DL1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DL2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DL3", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DL4", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DL5", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DL6", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Analog input muxes for the capture amplifiers */
+       SND_SOC_DAPM_MUX("Analog Left Capture Route",
+                       SND_SOC_NOPM, 0, 0, &amic1_control),
+       SND_SOC_DAPM_MUX("Analog Right Capture Route",
+                       SND_SOC_NOPM, 0, 0, &amic2_control),
+
+       SND_SOC_DAPM_MUX("Sidetone Audio Playback", SND_SOC_NOPM, 0, 0,
+                       &st_audio_control),
+       SND_SOC_DAPM_MUX("Sidetone Voice Playback", SND_SOC_NOPM, 0, 0,
+                       &st_voice_control),
+
+       /* AIF */
+       SND_SOC_DAPM_AIF_IN("INTF1_SDI", NULL, 0, ISABELLE_INTF_EN_REG, 7, 0),
+       SND_SOC_DAPM_AIF_IN("INTF2_SDI", NULL, 0, ISABELLE_INTF_EN_REG, 6, 0),
+
+       SND_SOC_DAPM_AIF_OUT("INTF1_SDO", NULL, 0, ISABELLE_INTF_EN_REG, 5, 0),
+       SND_SOC_DAPM_AIF_OUT("INTF2_SDO", NULL, 0, ISABELLE_INTF_EN_REG, 4, 0),
+
+       SND_SOC_DAPM_OUT_DRV("ULATX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("ULATX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("ULVTX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("ULVTX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Analog Capture PGAs */
+       SND_SOC_DAPM_PGA("MicAmp1", ISABELLE_AMIC_CFG_REG, 5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("MicAmp2", ISABELLE_AMIC_CFG_REG, 4, 0, NULL, 0),
+
+       /* Auxiliary FM PGAs */
+       SND_SOC_DAPM_PGA("APGA1", ISABELLE_APGA_CFG_REG, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("APGA2", ISABELLE_APGA_CFG_REG, 6, 0, NULL, 0),
+
+       /* ADCs */
+       SND_SOC_DAPM_ADC("ADC1", "Left Front Capture",
+                       ISABELLE_AMIC_CFG_REG, 7, 0),
+       SND_SOC_DAPM_ADC("ADC2", "Right Front Capture",
+                       ISABELLE_AMIC_CFG_REG, 6, 0),
+
+       /* Microphone Bias */
+       SND_SOC_DAPM_SUPPLY("Headset Mic Bias", ISABELLE_ABIAS_CFG_REG,
+                       3, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Main Mic Bias", ISABELLE_ABIAS_CFG_REG,
+                       2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Digital Mic1 Bias",
+                       ISABELLE_DBIAS_CFG_REG, 3, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Digital Mic2 Bias",
+                       ISABELLE_DBIAS_CFG_REG, 2, 0, NULL, 0),
+
+       /* Mixers */
+       SND_SOC_DAPM_MIXER("Headset Left Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_hs_left_mixer_controls,
+                       ARRAY_SIZE(isabelle_hs_left_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Headset Right Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_hs_right_mixer_controls,
+                       ARRAY_SIZE(isabelle_hs_right_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Handsfree Left Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_hf_left_mixer_controls,
+                       ARRAY_SIZE(isabelle_hf_left_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Handsfree Right Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_hf_right_mixer_controls,
+                       ARRAY_SIZE(isabelle_hf_right_mixer_controls)),
+       SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_aux_left_mixer_controls,
+                       ARRAY_SIZE(isabelle_aux_left_mixer_controls)),
+       SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_aux_right_mixer_controls,
+                       ARRAY_SIZE(isabelle_aux_right_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Earphone Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_ep_mixer_controls,
+                       ARRAY_SIZE(isabelle_ep_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("DPGA1L Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_dpga1_left_mixer_controls,
+                       ARRAY_SIZE(isabelle_dpga1_left_mixer_controls)),
+       SND_SOC_DAPM_MIXER("DPGA1R Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_dpga1_right_mixer_controls,
+                       ARRAY_SIZE(isabelle_dpga1_right_mixer_controls)),
+       SND_SOC_DAPM_MIXER("DPGA2L Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_dpga2_left_mixer_controls,
+                       ARRAY_SIZE(isabelle_dpga2_left_mixer_controls)),
+       SND_SOC_DAPM_MIXER("DPGA2R Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_dpga2_right_mixer_controls,
+                       ARRAY_SIZE(isabelle_dpga2_right_mixer_controls)),
+       SND_SOC_DAPM_MIXER("DPGA3L Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_dpga3_left_mixer_controls,
+                       ARRAY_SIZE(isabelle_dpga3_left_mixer_controls)),
+       SND_SOC_DAPM_MIXER("DPGA3R Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_dpga3_right_mixer_controls,
+                       ARRAY_SIZE(isabelle_dpga3_right_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("RX1 Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_rx1_mixer_controls,
+                       ARRAY_SIZE(isabelle_rx1_mixer_controls)),
+       SND_SOC_DAPM_MIXER("RX2 Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_rx2_mixer_controls,
+                       ARRAY_SIZE(isabelle_rx2_mixer_controls)),
+       SND_SOC_DAPM_MIXER("RX3 Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_rx3_mixer_controls,
+                       ARRAY_SIZE(isabelle_rx3_mixer_controls)),
+       SND_SOC_DAPM_MIXER("RX4 Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_rx4_mixer_controls,
+                       ARRAY_SIZE(isabelle_rx4_mixer_controls)),
+       SND_SOC_DAPM_MIXER("RX5 Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_rx5_mixer_controls,
+                       ARRAY_SIZE(isabelle_rx5_mixer_controls)),
+       SND_SOC_DAPM_MIXER("RX6 Mixer", SND_SOC_NOPM, 0, 0,
+                       isabelle_rx6_mixer_controls,
+                       ARRAY_SIZE(isabelle_rx6_mixer_controls)),
+
+       /* DACs */
+       SND_SOC_DAPM_DAC("DAC1L", "Headset Playback", ISABELLE_DAC_CFG_REG,
+                       5, 0),
+       SND_SOC_DAPM_DAC("DAC1R", "Headset Playback", ISABELLE_DAC_CFG_REG,
+                       4, 0),
+       SND_SOC_DAPM_DAC("DAC2L", "Handsfree Playback", ISABELLE_DAC_CFG_REG,
+                       3, 0),
+       SND_SOC_DAPM_DAC("DAC2R", "Handsfree Playback", ISABELLE_DAC_CFG_REG,
+                       2, 0),
+       SND_SOC_DAPM_DAC("DAC3L", "Lineout Playback", ISABELLE_DAC_CFG_REG,
+                       1, 0),
+       SND_SOC_DAPM_DAC("DAC3R", "Lineout Playback", ISABELLE_DAC_CFG_REG,
+                       0, 0),
+
+       /* Analog Playback PGAs */
+       SND_SOC_DAPM_PGA("Sidetone Audio PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Sidetone Voice PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HF Left PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HF Right PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DPGA1L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DPGA1R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DPGA2L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DPGA2R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DPGA3L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DPGA3R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Analog Playback Mux */
+       SND_SOC_DAPM_MUX("RX1 Playback", ISABELLE_ALU_RX_EN_REG, 5, 0,
+                       &rx1_mux_controls),
+       SND_SOC_DAPM_MUX("RX2 Playback", ISABELLE_ALU_RX_EN_REG, 4, 0,
+                       &rx2_mux_controls),
+
+       /* TX Select */
+       SND_SOC_DAPM_MUX("ATX Select", ISABELLE_TX_INPUT_CFG_REG,
+                       7, 0, &atx_mux_controls),
+       SND_SOC_DAPM_MUX("VTX Select", ISABELLE_TX_INPUT_CFG_REG,
+                       6, 0, &vtx_mux_controls),
+
+       SND_SOC_DAPM_SWITCH("Earphone Playback", SND_SOC_NOPM, 0, 0,
+                       &ep_path_enable_control),
+
+       /* Output Drivers */
+       SND_SOC_DAPM_OUT_DRV("HS Left Driver", ISABELLE_HSDRV_CFG2_REG,
+                       1, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("HS Right Driver", ISABELLE_HSDRV_CFG2_REG,
+                       0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("LINEOUT1 Left Driver", ISABELLE_LINEAMP_CFG_REG,
+                       1, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("LINEOUT2 Right Driver", ISABELLE_LINEAMP_CFG_REG,
+                       0, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("Earphone Driver", ISABELLE_EARDRV_CFG2_REG,
+                       1, 0, NULL, 0),
+
+       SND_SOC_DAPM_OUT_DRV("HF Left Driver", ISABELLE_HFDRV_CFG_REG,
+                       1, 0, NULL, 0),
+       SND_SOC_DAPM_OUT_DRV("HF Right Driver", ISABELLE_HFDRV_CFG_REG,
+                       0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route isabelle_intercon[] = {
+       /* Interface mapping */
+       { "DL1", "DL12 Playback Switch", "INTF1_SDI" },
+       { "DL2", "DL12 Playback Switch", "INTF1_SDI" },
+       { "DL3", "DL34 Playback Switch", "INTF1_SDI" },
+       { "DL4", "DL34 Playback Switch", "INTF1_SDI" },
+       { "DL5", "DL56 Playback Switch", "INTF1_SDI" },
+       { "DL6", "DL56 Playback Switch", "INTF1_SDI" },
+
+       { "DL1", "DL12 Playback Switch", "INTF2_SDI" },
+       { "DL2", "DL12 Playback Switch", "INTF2_SDI" },
+       { "DL3", "DL34 Playback Switch", "INTF2_SDI" },
+       { "DL4", "DL34 Playback Switch", "INTF2_SDI" },
+       { "DL5", "DL56 Playback Switch", "INTF2_SDI" },
+       { "DL6", "DL56 Playback Switch", "INTF2_SDI" },
+
+       /* Input side mapping */
+       { "Sidetone Audio PGA", NULL, "Sidetone Audio Playback" },
+       { "Sidetone Voice PGA", NULL, "Sidetone Voice Playback" },
+
+       { "RX1 Mixer", "ST1 Playback Switch", "Sidetone Audio PGA" },
+
+       { "RX1 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" },
+       { "RX1 Mixer", "DL1 Playback Switch", "DL1" },
+
+       { "RX2 Mixer", "ST2 Playback Switch", "Sidetone Audio PGA" },
+
+       { "RX2 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" },
+       { "RX2 Mixer", "DL2 Playback Switch", "DL2" },
+
+       { "RX3 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" },
+       { "RX3 Mixer", "DL3 Playback Switch", "DL3" },
+
+       { "RX4 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" },
+       { "RX4 Mixer", "DL4 Playback Switch", "DL4" },
+
+       { "RX5 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" },
+       { "RX5 Mixer", "DL5 Playback Switch", "DL5" },
+
+       { "RX6 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" },
+       { "RX6 Mixer", "DL6 Playback Switch", "DL6" },
+
+       /* Capture path */
+       { "Analog Left Capture Route", "Headset Mic", "HSMIC" },
+       { "Analog Left Capture Route", "Main Mic", "MAINMIC" },
+       { "Analog Left Capture Route", "Aux/FM Left", "LINEIN1" },
+
+       { "Analog Right Capture Route", "Sub Mic", "SUBMIC" },
+       { "Analog Right Capture Route", "Aux/FM Right", "LINEIN2" },
+
+       { "MicAmp1", NULL, "Analog Left Capture Route" },
+       { "MicAmp2", NULL, "Analog Right Capture Route" },
+
+       { "ADC1", NULL, "MicAmp1" },
+       { "ADC2", NULL, "MicAmp2" },
+
+       { "ATX Select", "AMIC1", "ADC1" },
+       { "ATX Select", "DMIC", "DMICDAT" },
+       { "ATX Select", "AMIC2", "ADC2" },
+
+       { "VTX Select", "AMIC1", "ADC1" },
+       { "VTX Select", "DMIC", "DMICDAT" },
+       { "VTX Select", "AMIC2", "ADC2" },
+
+       { "ULATX1", "ATX1 Filter Enable Switch", "ATX Select" },
+       { "ULATX1", "ATX1 Filter Bypass Switch", "ATX Select" },
+       { "ULATX2", "ATX2 Filter Enable Switch", "ATX Select" },
+       { "ULATX2", "ATX2 Filter Bypass Switch", "ATX Select" },
+
+       { "ULVTX1", "VTX1 Filter Enable Switch", "VTX Select" },
+       { "ULVTX1", "VTX1 Filter Bypass Switch", "VTX Select" },
+       { "ULVTX2", "VTX2 Filter Enable Switch", "VTX Select" },
+       { "ULVTX2", "VTX2 Filter Bypass Switch", "VTX Select" },
+
+       { "INTF1_SDO", "ULATX12 Capture Switch", "ULATX1" },
+       { "INTF1_SDO", "ULATX12 Capture Switch", "ULATX2" },
+       { "INTF2_SDO", "ULATX12 Capture Switch", "ULATX1" },
+       { "INTF2_SDO", "ULATX12 Capture Switch", "ULATX2" },
+
+       { "INTF1_SDO", NULL, "ULVTX1" },
+       { "INTF1_SDO", NULL, "ULVTX2" },
+       { "INTF2_SDO", NULL, "ULVTX1" },
+       { "INTF2_SDO", NULL, "ULVTX2" },
+
+       /* AFM Path */
+       { "APGA1", NULL, "LINEIN1" },
+       { "APGA2", NULL, "LINEIN2" },
+
+       { "RX1 Playback", "VRX1 Filter Bypass Switch", "RX1 Mixer" },
+       { "RX1 Playback", "ARX1 Filter Bypass Switch", "RX1 Mixer" },
+       { "RX1 Playback", "RX1 Filter Enable Switch", "RX1 Mixer" },
+
+       { "RX2 Playback", "VRX2 Filter Bypass Switch", "RX2 Mixer" },
+       { "RX2 Playback", "ARX2 Filter Bypass Switch", "RX2 Mixer" },
+       { "RX2 Playback", "RX2 Filter Enable Switch", "RX2 Mixer" },
+
+       { "RX3 Playback", "ARX3 Filter Bypass Switch", "RX3 Mixer" },
+       { "RX3 Playback", "RX3 Filter Enable Switch", "RX3 Mixer" },
+
+       { "RX4 Playback", "ARX4 Filter Bypass Switch", "RX4 Mixer" },
+       { "RX4 Playback", "RX4 Filter Enable Switch", "RX4 Mixer" },
+
+       { "RX5 Playback", "ARX5 Filter Bypass Switch", "RX5 Mixer" },
+       { "RX5 Playback", "RX5 Filter Enable Switch", "RX5 Mixer" },
+
+       { "RX6 Playback", "ARX6 Filter Bypass Switch", "RX6 Mixer" },
+       { "RX6 Playback", "RX6 Filter Enable Switch", "RX6 Mixer" },
+
+       { "DPGA1L Mixer", "RX1 Playback Switch", "RX1 Playback" },
+       { "DPGA1L Mixer", "RX3 Playback Switch", "RX3 Playback" },
+       { "DPGA1L Mixer", "RX5 Playback Switch", "RX5 Playback" },
+
+       { "DPGA1R Mixer", "RX2 Playback Switch", "RX2 Playback" },
+       { "DPGA1R Mixer", "RX4 Playback Switch", "RX4 Playback" },
+       { "DPGA1R Mixer", "RX6 Playback Switch", "RX6 Playback" },
+
+       { "DPGA1L", NULL, "DPGA1L Mixer" },
+       { "DPGA1R", NULL, "DPGA1R Mixer" },
+
+       { "DAC1L", NULL, "DPGA1L" },
+       { "DAC1R", NULL, "DPGA1R" },
+
+       { "DPGA2L Mixer", "RX1 Playback Switch", "RX1 Playback" },
+       { "DPGA2L Mixer", "RX2 Playback Switch", "RX2 Playback" },
+       { "DPGA2L Mixer", "RX3 Playback Switch", "RX3 Playback" },
+       { "DPGA2L Mixer", "RX4 Playback Switch", "RX4 Playback" },
+       { "DPGA2L Mixer", "RX5 Playback Switch", "RX5 Playback" },
+       { "DPGA2L Mixer", "RX6 Playback Switch", "RX6 Playback" },
+
+       { "DPGA2R Mixer", "RX2 Playback Switch", "RX2 Playback" },
+       { "DPGA2R Mixer", "RX4 Playback Switch", "RX4 Playback" },
+       { "DPGA2R Mixer", "RX6 Playback Switch", "RX6 Playback" },
+
+       { "DPGA2L", NULL, "DPGA2L Mixer" },
+       { "DPGA2R", NULL, "DPGA2R Mixer" },
+
+       { "DAC2L", NULL, "DPGA2L" },
+       { "DAC2R", NULL, "DPGA2R" },
+
+       { "DPGA3L Mixer", "RX1 Playback Switch", "RX1 Playback" },
+       { "DPGA3L Mixer", "RX3 Playback Switch", "RX3 Playback" },
+       { "DPGA3L Mixer", "RX5 Playback Switch", "RX5 Playback" },
+
+       { "DPGA3R Mixer", "RX2 Playback Switch", "RX2 Playback" },
+       { "DPGA3R Mixer", "RX4 Playback Switch", "RX4 Playback" },
+       { "DPGA3R Mixer", "RX6 Playback Switch", "RX6 Playback" },
+
+       { "DPGA3L", NULL, "DPGA3L Mixer" },
+       { "DPGA3R", NULL, "DPGA3R Mixer" },
+
+       { "DAC3L", NULL, "DPGA3L" },
+       { "DAC3R", NULL, "DPGA3R" },
+
+       { "Headset Left Mixer", "DAC1L Playback Switch", "DAC1L" },
+       { "Headset Left Mixer", "APGA1 Playback Switch", "APGA1" },
+
+       { "Headset Right Mixer", "DAC1R Playback Switch", "DAC1R" },
+       { "Headset Right Mixer", "APGA2 Playback Switch", "APGA2" },
+
+       { "HS Left Driver", NULL, "Headset Left Mixer" },
+       { "HS Right Driver", NULL, "Headset Right Mixer" },
+
+       { "HSOL", NULL, "HS Left Driver" },
+       { "HSOR", NULL, "HS Right Driver" },
+
+       /* Earphone playback path */
+       { "Earphone Mixer", "DAC2L Playback Switch", "DAC2L" },
+       { "Earphone Mixer", "APGA1 Playback Switch", "APGA1" },
+
+       { "Earphone Playback", "Switch", "Earphone Mixer" },
+       { "Earphone Driver", NULL, "Earphone Playback" },
+       { "EP", NULL, "Earphone Driver" },
+
+       { "Handsfree Left Mixer", "DAC2L Playback Switch", "DAC2L" },
+       { "Handsfree Left Mixer", "APGA1 Playback Switch", "APGA1" },
+
+       { "Handsfree Right Mixer", "DAC2R Playback Switch", "DAC2R" },
+       { "Handsfree Right Mixer", "APGA2 Playback Switch", "APGA2" },
+
+       { "HF Left PGA", NULL, "Handsfree Left Mixer" },
+       { "HF Right PGA", NULL, "Handsfree Right Mixer" },
+
+       { "HF Left Driver", NULL, "HF Left PGA" },
+       { "HF Right Driver", NULL, "HF Right PGA" },
+
+       { "HFL", NULL, "HF Left Driver" },
+       { "HFR", NULL, "HF Right Driver" },
+
+       { "LINEOUT1 Mixer", "DAC3L Playback Switch", "DAC3L" },
+       { "LINEOUT1 Mixer", "APGA1 Playback Switch", "APGA1" },
+
+       { "LINEOUT2 Mixer", "DAC3R Playback Switch", "DAC3R" },
+       { "LINEOUT2 Mixer", "APGA2 Playback Switch", "APGA2" },
+
+       { "LINEOUT1 Driver", NULL, "LINEOUT1 Mixer" },
+       { "LINEOUT2 Driver", NULL, "LINEOUT2 Mixer" },
+
+       { "LINEOUT1", NULL, "LINEOUT1 Driver" },
+       { "LINEOUT2", NULL, "LINEOUT2 Driver" },
+};
+
+static int isabelle_hs_mute(struct snd_soc_dai *dai, int mute)
+{
+       snd_soc_update_bits(dai->codec, ISABELLE_DAC1_SOFTRAMP_REG,
+                       BIT(4), (mute ? BIT(4) : 0));
+
+       return 0;
+}
+
+static int isabelle_hf_mute(struct snd_soc_dai *dai, int mute)
+{
+       snd_soc_update_bits(dai->codec, ISABELLE_DAC2_SOFTRAMP_REG,
+                       BIT(4), (mute ? BIT(4) : 0));
+
+       return 0;
+}
+
+static int isabelle_line_mute(struct snd_soc_dai *dai, int mute)
+{
+       snd_soc_update_bits(dai->codec, ISABELLE_DAC3_SOFTRAMP_REG,
+                       BIT(4), (mute ? BIT(4) : 0));
+
+       return 0;
+}
+
+static int isabelle_set_bias_level(struct snd_soc_codec *codec,
+                               enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               snd_soc_update_bits(codec, ISABELLE_PWR_EN_REG,
+                               ISABELLE_CHIP_EN, BIT(0));
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, ISABELLE_PWR_EN_REG,
+                               ISABELLE_CHIP_EN, 0);
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int isabelle_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;
+       u16 aif = 0;
+       unsigned int fs_val = 0;
+
+       switch (params_rate(params)) {
+       case 8000:
+               fs_val = ISABELLE_FS_RATE_8;
+               break;
+       case 11025:
+               fs_val = ISABELLE_FS_RATE_11;
+               break;
+       case 12000:
+               fs_val = ISABELLE_FS_RATE_12;
+               break;
+       case 16000:
+               fs_val = ISABELLE_FS_RATE_16;
+               break;
+       case 22050:
+               fs_val = ISABELLE_FS_RATE_22;
+               break;
+       case 24000:
+               fs_val = ISABELLE_FS_RATE_24;
+               break;
+       case 32000:
+               fs_val = ISABELLE_FS_RATE_32;
+               break;
+       case 44100:
+               fs_val = ISABELLE_FS_RATE_44;
+               break;
+       case 48000:
+               fs_val = ISABELLE_FS_RATE_48;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, ISABELLE_FS_RATE_CFG_REG,
+                       ISABELLE_FS_RATE_MASK, fs_val);
+
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               aif |= ISABELLE_AIF_LENGTH_20;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               aif |= ISABELLE_AIF_LENGTH_32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, ISABELLE_INTF_CFG_REG,
+                       ISABELLE_AIF_LENGTH_MASK, aif);
+
+       return 0;
+}
+
+static int isabelle_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       unsigned int aif_val = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               aif_val &= ~ISABELLE_AIF_MS;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               aif_val |= ISABELLE_AIF_MS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               aif_val |= ISABELLE_I2S_MODE;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aif_val |= ISABELLE_LEFT_J_MODE;
+               break;
+       case SND_SOC_DAIFMT_PDM:
+               aif_val |= ISABELLE_PDM_MODE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, ISABELLE_INTF_CFG_REG,
+                       (ISABELLE_AIF_MS | ISABELLE_AIF_FMT_MASK), aif_val);
+
+       return 0;
+}
+
+/* Rates supported by Isabelle driver */
+#define ISABELLE_RATES         SNDRV_PCM_RATE_8000_48000
+
+/* Formates supported by Isabelle driver. */
+#define ISABELLE_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops isabelle_hs_dai_ops = {
+       .hw_params      = isabelle_hw_params,
+       .set_fmt        = isabelle_set_dai_fmt,
+       .digital_mute   = isabelle_hs_mute,
+};
+
+static struct snd_soc_dai_ops isabelle_hf_dai_ops = {
+       .hw_params      = isabelle_hw_params,
+       .set_fmt        = isabelle_set_dai_fmt,
+       .digital_mute   = isabelle_hf_mute,
+};
+
+static struct snd_soc_dai_ops isabelle_line_dai_ops = {
+       .hw_params      = isabelle_hw_params,
+       .set_fmt        = isabelle_set_dai_fmt,
+       .digital_mute   = isabelle_line_mute,
+};
+
+static struct snd_soc_dai_ops isabelle_ul_dai_ops = {
+       .hw_params      = isabelle_hw_params,
+       .set_fmt        = isabelle_set_dai_fmt,
+};
+
+/* ISABELLE dai structure */
+struct snd_soc_dai_driver isabelle_dai[] = {
+       {
+               .name = "isabelle-dl1",
+               .playback = {
+                       .stream_name = "Headset Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ISABELLE_RATES,
+                       .formats = ISABELLE_FORMATS,
+               },
+               .ops = &isabelle_hs_dai_ops,
+       },
+       {
+               .name = "isabelle-dl2",
+               .playback = {
+                       .stream_name = "Handsfree Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ISABELLE_RATES,
+                       .formats = ISABELLE_FORMATS,
+               },
+               .ops = &isabelle_hf_dai_ops,
+       },
+       {
+               .name = "isabelle-lineout",
+               .playback = {
+                       .stream_name = "Lineout Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ISABELLE_RATES,
+                       .formats = ISABELLE_FORMATS,
+               },
+               .ops = &isabelle_line_dai_ops,
+       },
+       {
+               .name = "isabelle-ul",
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = ISABELLE_RATES,
+                       .formats = ISABELLE_FORMATS,
+               },
+               .ops = &isabelle_ul_dai_ops,
+       },
+};
+
+static int isabelle_probe(struct snd_soc_codec *codec)
+{
+       int ret = 0;
+
+       codec->control_data = dev_get_regmap(codec->dev, NULL);
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_isabelle = {
+       .probe = isabelle_probe,
+       .set_bias_level = isabelle_set_bias_level,
+       .controls = isabelle_snd_controls,
+       .num_controls = ARRAY_SIZE(isabelle_snd_controls),
+       .dapm_widgets = isabelle_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(isabelle_dapm_widgets),
+       .dapm_routes = isabelle_intercon,
+       .num_dapm_routes = ARRAY_SIZE(isabelle_intercon),
+       .idle_bias_off = true,
+};
+
+static const struct regmap_config isabelle_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = ISABELLE_MAX_REGISTER,
+       .reg_defaults = isabelle_reg_defs,
+       .num_reg_defaults = ARRAY_SIZE(isabelle_reg_defs),
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit isabelle_i2c_probe(struct i2c_client *i2c,
+                                       const struct i2c_device_id *id)
+{
+       struct regmap *isabelle_regmap;
+       int ret = 0;
+
+       isabelle_regmap = devm_regmap_init_i2c(i2c, &isabelle_regmap_config);
+       if (IS_ERR(isabelle_regmap)) {
+               ret = PTR_ERR(isabelle_regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+       i2c_set_clientdata(i2c, isabelle_regmap);
+
+       ret =  snd_soc_register_codec(&i2c->dev,
+                               &soc_codec_dev_isabelle, isabelle_dai,
+                               ARRAY_SIZE(isabelle_dai));
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int __devexit isabelle_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id isabelle_i2c_id[] = {
+       { "isabelle", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, isabelle_i2c_id);
+
+static struct i2c_driver isabelle_i2c_driver = {
+       .driver = {
+               .name = "isabelle",
+               .owner = THIS_MODULE,
+       },
+       .probe = isabelle_i2c_probe,
+       .remove = __devexit_p(isabelle_i2c_remove),
+       .id_table = isabelle_i2c_id,
+};
+
+module_i2c_driver(isabelle_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ISABELLE driver");
+MODULE_AUTHOR("Vishwas A Deshpande <vishwas.a.deshpande@ti.com>");
+MODULE_AUTHOR("M R Swami Reddy <MR.Swami.Reddy@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/isabelle.h b/sound/soc/codecs/isabelle.h
new file mode 100644 (file)
index 0000000..96d839a
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * isabelle.h - Low power high fidelity audio codec driver header file
+ *
+ * Copyright (c) 2012 Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ */
+
+#ifndef _ISABELLE_H
+#define _ISABELLE_H
+
+#include <linux/bitops.h>
+
+/* ISABELLE REGISTERS */
+
+#define ISABELLE_PWR_CFG_REG           0x01
+#define ISABELLE_PWR_EN_REG            0x02
+#define ISABELLE_PS_EN1_REG            0x03
+#define ISABELLE_INT1_STATUS_REG       0x04
+#define ISABELLE_INT1_MASK_REG         0x05
+#define ISABELLE_INT2_STATUS_REG       0x06
+#define ISABELLE_INT2_MASK_REG         0x07
+#define ISABELLE_HKCTL1_REG            0x08
+#define ISABELLE_HKCTL2_REG            0x09
+#define ISABELLE_HKCTL3_REG            0x0A
+#define ISABELLE_ACCDET_STATUS_REG     0x0B
+#define ISABELLE_BUTTON_ID_REG         0x0C
+#define ISABELLE_PLL_CFG_REG           0x10
+#define ISABELLE_PLL_EN_REG            0x11
+#define ISABELLE_FS_RATE_CFG_REG       0x12
+#define ISABELLE_INTF_CFG_REG          0x13
+#define ISABELLE_INTF_EN_REG           0x14
+#define ISABELLE_ULATX12_INTF_CFG_REG  0x15
+#define ISABELLE_DL12_INTF_CFG_REG     0x16
+#define ISABELLE_DL34_INTF_CFG_REG     0x17
+#define ISABELLE_DL56_INTF_CFG_REG     0x18
+#define ISABELLE_ATX_STPGA1_CFG_REG    0x19
+#define ISABELLE_ATX_STPGA2_CFG_REG    0x1A
+#define ISABELLE_VTX_STPGA1_CFG_REG    0x1B
+#define ISABELLE_VTX2_STPGA2_CFG_REG   0x1C
+#define ISABELLE_ATX1_DPGA_REG         0x1D
+#define ISABELLE_ATX2_DPGA_REG         0x1E
+#define ISABELLE_VTX1_DPGA_REG         0x1F
+#define ISABELLE_VTX2_DPGA_REG         0x20
+#define ISABELLE_TX_INPUT_CFG_REG      0x21
+#define ISABELLE_RX_INPUT_CFG_REG      0x22
+#define ISABELLE_RX_INPUT_CFG2_REG     0x23
+#define ISABELLE_VOICE_HPF_CFG_REG     0x24
+#define ISABELLE_AUDIO_HPF_CFG_REG     0x25
+#define ISABELLE_RX1_DPGA_REG          0x26
+#define ISABELLE_RX2_DPGA_REG          0x27
+#define ISABELLE_RX3_DPGA_REG          0x28
+#define ISABELLE_RX4_DPGA_REG          0x29
+#define ISABELLE_RX5_DPGA_REG          0x2A
+#define ISABELLE_RX6_DPGA_REG          0x2B
+#define ISABELLE_ALU_TX_EN_REG         0x2C
+#define ISABELLE_ALU_RX_EN_REG         0x2D
+#define ISABELLE_IIR_RESYNC_REG                0x2E
+#define ISABELLE_ABIAS_CFG_REG         0x30
+#define ISABELLE_DBIAS_CFG_REG         0x31
+#define ISABELLE_MIC1_GAIN_REG         0x32
+#define ISABELLE_MIC2_GAIN_REG         0x33
+#define ISABELLE_AMIC_CFG_REG          0x34
+#define ISABELLE_DMIC_CFG_REG          0x35
+#define ISABELLE_APGA_GAIN_REG         0x36
+#define ISABELLE_APGA_CFG_REG          0x37
+#define ISABELLE_TX_GAIN_DLY_REG       0x38
+#define ISABELLE_RX_GAIN_DLY_REG       0x39
+#define ISABELLE_RX_PWR_CTRL_REG       0x3A
+#define ISABELLE_DPGA1LR_IN_SEL_REG    0x3B
+#define ISABELLE_DPGA1L_GAIN_REG       0x3C
+#define ISABELLE_DPGA1R_GAIN_REG       0x3D
+#define ISABELLE_DPGA2L_IN_SEL_REG     0x3E
+#define ISABELLE_DPGA2R_IN_SEL_REG     0x3F
+#define ISABELLE_DPGA2L_GAIN_REG       0x40
+#define ISABELLE_DPGA2R_GAIN_REG       0x41
+#define ISABELLE_DPGA3LR_IN_SEL_REG    0x42
+#define ISABELLE_DPGA3L_GAIN_REG       0x43
+#define ISABELLE_DPGA3R_GAIN_REG       0x44
+#define ISABELLE_DAC1_SOFTRAMP_REG     0x45
+#define ISABELLE_DAC2_SOFTRAMP_REG     0x46
+#define ISABELLE_DAC3_SOFTRAMP_REG     0x47
+#define ISABELLE_DAC_CFG_REG           0x48
+#define ISABELLE_EARDRV_CFG1_REG       0x49
+#define ISABELLE_EARDRV_CFG2_REG       0x4A
+#define ISABELLE_HSDRV_GAIN_REG                0x4B
+#define ISABELLE_HSDRV_CFG1_REG                0x4C
+#define ISABELLE_HSDRV_CFG2_REG                0x4D
+#define ISABELLE_HS_NG_CFG1_REG                0x4E
+#define ISABELLE_HS_NG_CFG2_REG                0x4F
+#define ISABELLE_LINEAMP_GAIN_REG      0x50
+#define ISABELLE_LINEAMP_CFG_REG       0x51
+#define ISABELLE_HFL_VOL_CTRL_REG      0x52
+#define ISABELLE_HFL_SFTVOL_CTRL_REG   0x53
+#define ISABELLE_HFL_LIM_CTRL_1_REG    0x54
+#define ISABELLE_HFL_LIM_CTRL_2_REG    0x55
+#define ISABELLE_HFR_VOL_CTRL_REG      0x56
+#define ISABELLE_HFR_SFTVOL_CTRL_REG   0x57
+#define ISABELLE_HFR_LIM_CTRL_1_REG    0x58
+#define ISABELLE_HFR_LIM_CTRL_2_REG    0x59
+#define ISABELLE_HF_MODE_REG           0x5A
+#define ISABELLE_HFLPGA_CFG_REG                0x5B
+#define ISABELLE_HFRPGA_CFG_REG                0x5C
+#define ISABELLE_HFDRV_CFG_REG         0x5D
+#define ISABELLE_PDMOUT_CFG1_REG       0x5E
+#define ISABELLE_PDMOUT_CFG2_REG       0x5F
+#define ISABELLE_PDMOUT_L_WM_REG       0x60
+#define ISABELLE_PDMOUT_R_WM_REG       0x61
+#define ISABELLE_HF_NG_CFG1_REG                0x62
+#define ISABELLE_HF_NG_CFG2_REG                0x63
+
+/* ISABELLE_PWR_EN_REG (0x02h) */
+#define ISABELLE_CHIP_EN               BIT(0)
+
+/* ISABELLE DAI FORMATS */
+#define ISABELLE_AIF_FMT_MASK          0x70
+#define ISABELLE_I2S_MODE              0x0
+#define ISABELLE_LEFT_J_MODE           0x1
+#define ISABELLE_PDM_MODE              0x2
+
+#define ISABELLE_AIF_LENGTH_MASK       0x30
+#define ISABELLE_AIF_LENGTH_20         0x00
+#define ISABELLE_AIF_LENGTH_32         0x10
+
+#define ISABELLE_AIF_MS                        0x80
+
+#define ISABELLE_FS_RATE_MASK          0xF
+#define ISABELLE_FS_RATE_8             0x0
+#define ISABELLE_FS_RATE_11            0x1
+#define ISABELLE_FS_RATE_12            0x2
+#define ISABELLE_FS_RATE_16            0x4
+#define ISABELLE_FS_RATE_22            0x5
+#define ISABELLE_FS_RATE_24            0x6
+#define ISABELLE_FS_RATE_32            0x8
+#define ISABELLE_FS_RATE_44            0x9
+#define ISABELLE_FS_RATE_48            0xA
+
+#define ISABELLE_MAX_REGISTER          0xFF
+
+#endif
index 802b9f176b16be32c58a3753ee81e3cf98807f66..99b0a9dcff346ac68b3915ae320b60645cb6a01f 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -1358,7 +1357,7 @@ static struct snd_soc_dai_ops lm49453_lineout_dai_ops = {
 };
 
 /* LM49453 dai structure. */
-static const struct snd_soc_dai_driver lm49453_dai[] = {
+static struct snd_soc_dai_driver lm49453_dai[] = {
        {
                .name = "LM49453 Headset",
                .playback = {
index 35179e2c23c92a31665fef50563c06e295b7a201..7cd508e16a5ca3cd0bfe7dcef88941d7c6ab5c90 100644 (file)
@@ -2216,7 +2216,7 @@ static irqreturn_t max98095_report_jack(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-int max98095_jack_detect_enable(struct snd_soc_codec *codec)
+static int max98095_jack_detect_enable(struct snd_soc_codec *codec)
 {
        struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
@@ -2245,7 +2245,7 @@ int max98095_jack_detect_enable(struct snd_soc_codec *codec)
        return ret;
 }
 
-int max98095_jack_detect_disable(struct snd_soc_codec *codec)
+static int max98095_jack_detect_disable(struct snd_soc_codec *codec)
 {
        int ret = 0;
 
@@ -2286,6 +2286,7 @@ int max98095_jack_detect(struct snd_soc_codec *codec,
        max98095_report_jack(client->irq, codec);
        return 0;
 }
+EXPORT_SYMBOL_GPL(max98095_jack_detect);
 
 #ifdef CONFIG_PM
 static int max98095_suspend(struct snd_soc_codec *codec)
index 64d2a4fa34b27d81ad84d0e64ed625e04e293b7a..58ef59dfbae9913bc796e4021933b845fa68410c 100644 (file)
@@ -368,7 +368,7 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
 static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0);
 
 static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
-       SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
+       SOC_DOUBLE_TLV("Class-D Playback Volume", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
 
 /* Left DAC Mux */
 static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
index a75c3766aedeec9192c0d887ebe9b8ff366e1e5b..78a148f0a8ef22b59ed22d6a514e757335e47e06 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm2000.c  --  WM2000 ALSA Soc Audio driver
  *
- * Copyright 2008-2010 Wolfson Microelectronics PLC.
+ * Copyright 2008-2011 Wolfson Microelectronics PLC.
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
@@ -691,9 +691,39 @@ static int wm2000_resume(struct snd_soc_codec *codec)
 #define wm2000_resume NULL
 #endif
 
+static bool wm2000_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM2000_REG_SYS_START:
+       case WM2000_REG_SPEECH_CLARITY:
+       case WM2000_REG_SYS_WATCHDOG:
+       case WM2000_REG_ANA_VMID_PD_TIME:
+       case WM2000_REG_ANA_VMID_PU_TIME:
+       case WM2000_REG_CAT_FLTR_INDX:
+       case WM2000_REG_CAT_GAIN_0:
+       case WM2000_REG_SYS_STATUS:
+       case WM2000_REG_SYS_MODE_CNTRL:
+       case WM2000_REG_SYS_START0:
+       case WM2000_REG_SYS_START1:
+       case WM2000_REG_ID1:
+       case WM2000_REG_ID2:
+       case WM2000_REG_REVISON:
+       case WM2000_REG_SYS_CTL1:
+       case WM2000_REG_SYS_CTL2:
+       case WM2000_REG_ANC_STAT:
+       case WM2000_REG_IF_CTL:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static const struct regmap_config wm2000_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
+
+       .max_register = WM2000_REG_IF_CTL,
+       .readable_reg = wm2000_readable_reg,
 };
 
 static int wm2000_probe(struct snd_soc_codec *codec)
index e167207a19cc357250fe65c5376b2248e6866d1e..e239f4bf2460dddae415a6da9408d8e25b05fdd9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm5100-tables.c  --  WM5100 ALSA SoC Audio driver data
  *
- * Copyright 2011 Wolfson Microelectronics plc
+ * Copyright 2011-2 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
index cb6d5372103a56290fafc84f3c917cdb8362cb0f..3823af3629120ba16fcbc25e6f154ea219f437b2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm5100.c  --  WM5100 ALSA SoC Audio driver
  *
- * Copyright 2011 Wolfson Microelectronics plc
+ * Copyright 2011-2 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
index 555ee146ae0d00bc4c36a8a006580c1d01fc75d3..d26c8ae4e6d937f8ccd856e6e7b9dbb2e0adcaab 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8350.c -- WM8350 ALSA SoC audio driver
  *
- * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
+ * Copyright (C) 2007-12 Wolfson Microelectronics PLC.
  *
  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
@@ -71,20 +71,6 @@ struct wm8350_data {
        int fll_freq_in;
 };
 
-static unsigned int wm8350_codec_read(struct snd_soc_codec *codec,
-                                     unsigned int reg)
-{
-       struct wm8350 *wm8350 = codec->control_data;
-       return wm8350_reg_read(wm8350, reg);
-}
-
-static int wm8350_codec_write(struct snd_soc_codec *codec, unsigned int reg,
-                             unsigned int value)
-{
-       struct wm8350 *wm8350 = codec->control_data;
-       return wm8350_reg_write(wm8350, reg, value);
-}
-
 /*
  * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown.
  */
@@ -1519,7 +1505,9 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
        if (ret != 0)
                return ret;
 
-       codec->control_data = wm8350;
+       codec->control_data = wm8350->regmap;
+
+       snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
 
        /* Put the codec into reset if it wasn't already */
        wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
@@ -1629,8 +1617,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
        .remove =       wm8350_codec_remove,
        .suspend =      wm8350_suspend,
        .resume =       wm8350_resume,
-       .read = wm8350_codec_read,
-       .write = wm8350_codec_write,
        .set_bias_level = wm8350_set_bias_level,
 
        .controls = wm8350_snd_controls,
index 5dc31ebcd0e7ca5ffe2f1b545788f894c11a2080..5d277a915f8180a4a5b4bc301ecad54d7b7c6b9f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8400.c  --  WM8400 ALSA Soc Audio driver
  *
- * Copyright 2008, 2009 Wolfson Microelectronics PLC.
+ * Copyright 2008-11 Wolfson Microelectronics PLC.
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
index 211285164d70eb1ddf6dc4f86e084a124e136729..7c68226376e415a5e058bb10153531b68d49c990 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8580.c  --  WM8580 ALSA Soc Audio driver
  *
- * Copyright 2008, 2009 Wolfson Microelectronics PLC.
+ * Copyright 2008-11 Wolfson Microelectronics PLC.
  *
  *  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
index 9d1b9b0271f18671bf50cdfb77c448b40d46db8b..bb1d26919b10c1ce05553317ede7a25c05c4e006 100644 (file)
@@ -2,6 +2,7 @@
  * wm8731.c  --  WM8731 ALSA SoC Audio driver
  *
  * Copyright 2005 Openedhand Ltd.
+ * Copyright 2006-12 Wolfson Microelectronics, plc
  *
  * Author: Richard Purdie <richard@openedhand.com>
  *
index 6e849cb042430dc5ca22df08c1bb1708a36ec238..35f3d23200e048ed8a358861b28888d3cf20678c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8741.c  --  WM8741 ALSA SoC Audio driver
  *
- * Copyright 2010 Wolfson Microelectronics plc
+ * Copyright 2010-1 Wolfson Microelectronics plc
  *
  * Author: Ian Lartey <ian@opensource.wolfsonmicro.com>
  *
index a26482cd7654fbfcbccd64ef7a86bbb7faaaa619..13bff87ddcf57853c1163f6307b603d7d25a1ad1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8753.c  --  WM8753 ALSA Soc Audio driver
  *
- * Copyright 2003 Wolfson Microelectronics PLC.
+ * Copyright 2003-11 Wolfson Microelectronics PLC.
  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
index a19db5a0a17ab05fc7503d7b8722ec2a6c0cf13c..879c356a9045941408932557db6bb5f42608fd91 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8776.c  --  WM8776 ALSA SoC Audio driver
  *
- * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2009-12 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
index 6bd1b767b138881eecb66451d9b468309b650d29..c088020172ab66e25bbc8e0f30f554b77debb202 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8804.c  --  WM8804 S/PDIF transceiver driver
  *
- * Copyright 2010 Wolfson Microelectronics plc
+ * Copyright 2010-11 Wolfson Microelectronics plc
  *
  * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
  *
index 86b8a2926591e15bf487ec96cb1c3e5125c45770..73f1c8d7bafbdc591e990f2dc2fd678a61ff1f8a 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * wm8903.c  --  WM8903 ALSA SoC Audio driver
  *
- * Copyright 2008 Wolfson Microelectronics
- * Copyright 2011 NVIDIA, Inc.
+ * Copyright 2008-12 Wolfson Microelectronics
+ * Copyright 2011-2012 NVIDIA, Inc.
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
@@ -116,6 +116,7 @@ static const struct reg_default wm8903_reg_defaults[] = {
 
 struct wm8903_priv {
        struct wm8903_platform_data *pdata;
+       struct device *dev;
        struct snd_soc_codec *codec;
        struct regmap *regmap;
 
@@ -1635,17 +1636,27 @@ EXPORT_SYMBOL_GPL(wm8903_mic_detect);
 
 static irqreturn_t wm8903_irq(int irq, void *data)
 {
-       struct snd_soc_codec *codec = data;
-       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       int mic_report;
-       int int_pol;
-       int int_val = 0;
-       int mask = ~snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1_MASK);
+       struct wm8903_priv *wm8903 = data;
+       int mic_report, ret;
+       unsigned int int_val, mask, int_pol;
 
-       int_val = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1) & mask;
+       ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1_MASK,
+                         &mask);
+       if (ret != 0) {
+               dev_err(wm8903->dev, "Failed to read IRQ mask: %d\n", ret);
+               return IRQ_NONE;
+       }
+
+       ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1, &int_val);
+       if (ret != 0) {
+               dev_err(wm8903->dev, "Failed to read IRQ status: %d\n", ret);
+               return IRQ_NONE;
+       }
+
+       int_val &= ~mask;
 
        if (int_val & WM8903_WSEQ_BUSY_EINT) {
-               dev_warn(codec->dev, "Write sequencer done\n");
+               dev_warn(wm8903->dev, "Write sequencer done\n");
        }
 
        /*
@@ -1656,22 +1667,28 @@ static irqreturn_t wm8903_irq(int irq, void *data)
         * the polarity register.
         */
        mic_report = wm8903->mic_last_report;
-       int_pol = snd_soc_read(codec, WM8903_INTERRUPT_POLARITY_1);
+       ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
+                         &int_pol);
+       if (ret != 0) {
+               dev_err(wm8903->dev, "Failed to read interrupt polarity: %d\n",
+                       ret);
+               return IRQ_HANDLED;
+       }
 
 #ifndef CONFIG_SND_SOC_WM8903_MODULE
        if (int_val & (WM8903_MICSHRT_EINT | WM8903_MICDET_EINT))
-               trace_snd_soc_jack_irq(dev_name(codec->dev));
+               trace_snd_soc_jack_irq(dev_name(wm8903->dev));
 #endif
 
        if (int_val & WM8903_MICSHRT_EINT) {
-               dev_dbg(codec->dev, "Microphone short (pol=%x)\n", int_pol);
+               dev_dbg(wm8903->dev, "Microphone short (pol=%x)\n", int_pol);
 
                mic_report ^= wm8903->mic_short;
                int_pol ^= WM8903_MICSHRT_INV;
        }
 
        if (int_val & WM8903_MICDET_EINT) {
-               dev_dbg(codec->dev, "Microphone detect (pol=%x)\n", int_pol);
+               dev_dbg(wm8903->dev, "Microphone detect (pol=%x)\n", int_pol);
 
                mic_report ^= wm8903->mic_det;
                int_pol ^= WM8903_MICDET_INV;
@@ -1679,8 +1696,8 @@ static irqreturn_t wm8903_irq(int irq, void *data)
                msleep(wm8903->mic_delay);
        }
 
-       snd_soc_update_bits(codec, WM8903_INTERRUPT_POLARITY_1,
-                           WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
+       regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
+                          WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
 
        snd_soc_jack_report(wm8903->mic_jack, mic_report,
                            wm8903->mic_short | wm8903->mic_det);
@@ -1774,7 +1791,6 @@ static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset)
 static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
        struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
-       struct snd_soc_codec *codec = wm8903->codec;
        unsigned int mask, val;
        int ret;
 
@@ -1782,8 +1798,8 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
        val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) |
                WM8903_GP1_DIR;
 
-       ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
-                                 mask, val);
+       ret = regmap_update_bits(wm8903->regmap,
+                                WM8903_GPIO_CONTROL_1 + offset, mask, val);
        if (ret < 0)
                return ret;
 
@@ -1793,10 +1809,9 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
-       struct snd_soc_codec *codec = wm8903->codec;
-       int reg;
+       unsigned int reg;
 
-       reg = snd_soc_read(codec, WM8903_GPIO_CONTROL_1 + offset);
+       regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, &reg);
 
        return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT;
 }
@@ -1805,7 +1820,6 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
                                     unsigned offset, int value)
 {
        struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
-       struct snd_soc_codec *codec = wm8903->codec;
        unsigned int mask, val;
        int ret;
 
@@ -1813,8 +1827,8 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
        val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) |
                (value << WM8903_GP2_LVL_SHIFT);
 
-       ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
-                                 mask, val);
+       ret = regmap_update_bits(wm8903->regmap,
+                                WM8903_GPIO_CONTROL_1 + offset, mask, val);
        if (ret < 0)
                return ret;
 
@@ -1824,11 +1838,10 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
 static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
-       struct snd_soc_codec *codec = wm8903->codec;
 
-       snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
-                           WM8903_GP1_LVL_MASK,
-                           !!value << WM8903_GP1_LVL_SHIFT);
+       regmap_update_bits(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset,
+                          WM8903_GP1_LVL_MASK,
+                          !!value << WM8903_GP1_LVL_SHIFT);
 }
 
 static struct gpio_chip wm8903_template_chip = {
@@ -1842,15 +1855,14 @@ static struct gpio_chip wm8903_template_chip = {
        .can_sleep              = 1,
 };
 
-static void wm8903_init_gpio(struct snd_soc_codec *codec)
+static void wm8903_init_gpio(struct wm8903_priv *wm8903)
 {
-       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        struct wm8903_platform_data *pdata = wm8903->pdata;
        int ret;
 
        wm8903->gpio_chip = wm8903_template_chip;
        wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO;
-       wm8903->gpio_chip.dev = codec->dev;
+       wm8903->gpio_chip.dev = wm8903->dev;
 
        if (pdata->gpio_base)
                wm8903->gpio_chip.base = pdata->gpio_base;
@@ -1859,24 +1871,23 @@ static void wm8903_init_gpio(struct snd_soc_codec *codec)
 
        ret = gpiochip_add(&wm8903->gpio_chip);
        if (ret != 0)
-               dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+               dev_err(wm8903->dev, "Failed to add GPIOs: %d\n", ret);
 }
 
-static void wm8903_free_gpio(struct snd_soc_codec *codec)
+static void wm8903_free_gpio(struct wm8903_priv *wm8903)
 {
-       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
        ret = gpiochip_remove(&wm8903->gpio_chip);
        if (ret != 0)
-               dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+               dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret);
 }
 #else
-static void wm8903_init_gpio(struct snd_soc_codec *codec)
+static void wm8903_init_gpio(struct wm8903_priv *wm8903)
 {
 }
 
-static void wm8903_free_gpio(struct snd_soc_codec *codec)
+static void wm8903_free_gpio(struct wm8903_priv *wm8903)
 {
 }
 #endif
@@ -1884,11 +1895,7 @@ static void wm8903_free_gpio(struct snd_soc_codec *codec)
 static int wm8903_probe(struct snd_soc_codec *codec)
 {
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       struct wm8903_platform_data *pdata = wm8903->pdata;
-       int ret, i;
-       int trigger, irq_pol;
-       u16 val;
-       bool mic_gpio = false;
+       int ret;
 
        wm8903->codec = codec;
        codec->control_data = wm8903->regmap;
@@ -1899,121 +1906,16 @@ static int wm8903_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       /* Set up GPIOs, detect if any are MIC detect outputs */
-       for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
-               if ((!pdata->gpio_cfg[i]) ||
-                   (pdata->gpio_cfg[i] > WM8903_GPIO_CONFIG_ZERO))
-                       continue;
-
-               snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i,
-                               pdata->gpio_cfg[i] & 0x7fff);
-
-               val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK)
-                       >> WM8903_GP1_FN_SHIFT;
-
-               switch (val) {
-               case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
-               case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
-                       mic_gpio = true;
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       /* Set up microphone detection */
-       snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0,
-                       pdata->micdet_cfg);
-
-       /* Microphone detection needs the WSEQ clock */
-       if (pdata->micdet_cfg)
-               snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,
-                                   WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
-
-       /* If microphone detection is enabled by pdata but
-           * detected via IRQ then interrupts can be lost before
-           * the machine driver has set up microphone detection
-           * IRQs as the IRQs are clear on read.  The detection
-           * will be enabled when the machine driver configures.
-           */
-       WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA));
-
-       wm8903->mic_delay = pdata->micdet_delay;
-
-       if (wm8903->irq) {
-               if (pdata->irq_active_low) {
-                       trigger = IRQF_TRIGGER_LOW;
-                       irq_pol = WM8903_IRQ_POL;
-               } else {
-                       trigger = IRQF_TRIGGER_HIGH;
-                       irq_pol = 0;
-               }
-
-               snd_soc_update_bits(codec, WM8903_INTERRUPT_CONTROL,
-                                   WM8903_IRQ_POL, irq_pol);
-               
-               ret = request_threaded_irq(wm8903->irq, NULL, wm8903_irq,
-                                          trigger | IRQF_ONESHOT,
-                                          "wm8903", codec);
-               if (ret != 0) {
-                       dev_err(codec->dev, "Failed to request IRQ: %d\n",
-                               ret);
-                       return ret;
-               }
-
-               /* Enable write sequencer interrupts */
-               snd_soc_update_bits(codec, WM8903_INTERRUPT_STATUS_1_MASK,
-                                   WM8903_IM_WSEQ_BUSY_EINT, 0);
-       }
-
        /* power on device */
        wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       /* Latch volume update bits */
-       val = snd_soc_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT);
-       val |= WM8903_ADCVU;
-       snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val);
-       snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val);
-
-       val = snd_soc_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT);
-       val |= WM8903_DACVU;
-       snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val);
-       snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val);
-
-       val = snd_soc_read(codec, WM8903_ANALOGUE_OUT1_LEFT);
-       val |= WM8903_HPOUTVU;
-       snd_soc_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val);
-       snd_soc_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val);
-
-       val = snd_soc_read(codec, WM8903_ANALOGUE_OUT2_LEFT);
-       val |= WM8903_LINEOUTVU;
-       snd_soc_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val);
-       snd_soc_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val);
-
-       val = snd_soc_read(codec, WM8903_ANALOGUE_OUT3_LEFT);
-       val |= WM8903_SPKVU;
-       snd_soc_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val);
-       snd_soc_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val);
-
-       /* Enable DAC soft mute by default */
-       snd_soc_update_bits(codec, WM8903_DAC_DIGITAL_1,
-                           WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE,
-                           WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE);
-
-       wm8903_init_gpio(codec);
-
        return ret;
 }
 
 /* power down chip */
 static int wm8903_remove(struct snd_soc_codec *codec)
 {
-       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-
-       wm8903_free_gpio(codec);
        wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       if (wm8903->irq)
-               free_irq(wm8903->irq, codec);
 
        return 0;
 }
@@ -2123,15 +2025,18 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
 {
        struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
        struct wm8903_priv *wm8903;
-       unsigned int val;
-       int ret;
+       int trigger;
+       bool mic_gpio = false;
+       unsigned int val, irq_pol;
+       int ret, i;
 
        wm8903 = devm_kzalloc(&i2c->dev,  sizeof(struct wm8903_priv),
                              GFP_KERNEL);
        if (wm8903 == NULL)
                return -ENOMEM;
+       wm8903->dev = &i2c->dev;
 
-       wm8903->regmap = regmap_init_i2c(i2c, &wm8903_regmap);
+       wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap);
        if (IS_ERR(wm8903->regmap)) {
                ret = PTR_ERR(wm8903->regmap);
                dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -2140,7 +2045,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
        }
 
        i2c_set_clientdata(i2c, wm8903);
-       wm8903->irq = i2c->irq;
 
        /* If no platform data was supplied, create storage for defaults */
        if (pdata) {
@@ -2167,6 +2071,8 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
                }
        }
 
+       pdata = wm8903->pdata;
+
        ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val);
        if (ret != 0) {
                dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
@@ -2189,6 +2095,107 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
        /* Reset the device */
        regmap_write(wm8903->regmap, WM8903_SW_RESET_AND_ID, 0x8903);
 
+       wm8903_init_gpio(wm8903);
+
+       /* Set up GPIO pin state, detect if any are MIC detect outputs */
+       for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
+               if ((!pdata->gpio_cfg[i]) ||
+                   (pdata->gpio_cfg[i] > WM8903_GPIO_CONFIG_ZERO))
+                       continue;
+
+               regmap_write(wm8903->regmap, WM8903_GPIO_CONTROL_1 + i,
+                               pdata->gpio_cfg[i] & 0x7fff);
+
+               val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK)
+                       >> WM8903_GP1_FN_SHIFT;
+
+               switch (val) {
+               case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
+               case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
+                       mic_gpio = true;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       /* Set up microphone detection */
+       regmap_write(wm8903->regmap, WM8903_MIC_BIAS_CONTROL_0,
+                    pdata->micdet_cfg);
+
+       /* Microphone detection needs the WSEQ clock */
+       if (pdata->micdet_cfg)
+               regmap_update_bits(wm8903->regmap, WM8903_WRITE_SEQUENCER_0,
+                                  WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
+
+       /* If microphone detection is enabled by pdata but
+        * detected via IRQ then interrupts can be lost before
+        * the machine driver has set up microphone detection
+        * IRQs as the IRQs are clear on read.  The detection
+        * will be enabled when the machine driver configures.
+        */
+       WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA));
+
+       wm8903->mic_delay = pdata->micdet_delay;
+
+       if (i2c->irq) {
+               if (pdata->irq_active_low) {
+                       trigger = IRQF_TRIGGER_LOW;
+                       irq_pol = WM8903_IRQ_POL;
+               } else {
+                       trigger = IRQF_TRIGGER_HIGH;
+                       irq_pol = 0;
+               }
+
+               regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_CONTROL,
+                                  WM8903_IRQ_POL, irq_pol);
+
+               ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq,
+                                          trigger | IRQF_ONESHOT,
+                                          "wm8903", wm8903);
+               if (ret != 0) {
+                       dev_err(wm8903->dev, "Failed to request IRQ: %d\n",
+                               ret);
+                       return ret;
+               }
+
+               /* Enable write sequencer interrupts */
+               regmap_update_bits(wm8903->regmap,
+                                  WM8903_INTERRUPT_STATUS_1_MASK,
+                                  WM8903_IM_WSEQ_BUSY_EINT, 0);
+       }
+
+       /* Latch volume update bits */
+       regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_LEFT,
+                          WM8903_ADCVU, WM8903_ADCVU);
+       regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_RIGHT,
+                          WM8903_ADCVU, WM8903_ADCVU);
+
+       regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_LEFT,
+                          WM8903_DACVU, WM8903_DACVU);
+       regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_RIGHT,
+                          WM8903_DACVU, WM8903_DACVU);
+
+       regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_LEFT,
+                          WM8903_HPOUTVU, WM8903_HPOUTVU);
+       regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_RIGHT,
+                          WM8903_HPOUTVU, WM8903_HPOUTVU);
+
+       regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_LEFT,
+                          WM8903_LINEOUTVU, WM8903_LINEOUTVU);
+       regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_RIGHT,
+                          WM8903_LINEOUTVU, WM8903_LINEOUTVU);
+
+       regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_LEFT,
+                          WM8903_SPKVU, WM8903_SPKVU);
+       regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_RIGHT,
+                          WM8903_SPKVU, WM8903_SPKVU);
+
+       /* Enable DAC soft mute by default */
+       regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_1,
+                          WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE,
+                          WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE);
+
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8903, &wm8903_dai, 1);
        if (ret != 0)
@@ -2196,7 +2203,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
 
        return 0;
 err:
-       regmap_exit(wm8903->regmap);
        return ret;
 }
 
@@ -2204,7 +2210,9 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client)
 {
        struct wm8903_priv *wm8903 = i2c_get_clientdata(client);
 
-       regmap_exit(wm8903->regmap);
+       if (client->irq)
+               free_irq(client->irq, wm8903);
+       wm8903_free_gpio(wm8903);
        snd_soc_unregister_codec(&client->dev);
 
        return 0;
index 65d525d74c549ee9d83bbb1f1ca0a982a103a567..560a9a47596bb48c2fbd7ad9a4cd510b6124df7f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8904.c  --  WM8904 ALSA SoC Audio driver
  *
- * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2009-12 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
@@ -2263,7 +2263,7 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
        if (wm8904 == NULL)
                return -ENOMEM;
 
-       wm8904->regmap = regmap_init_i2c(i2c, &wm8904_regmap);
+       wm8904->regmap = devm_regmap_init_i2c(i2c, &wm8904_regmap);
        if (IS_ERR(wm8904->regmap)) {
                ret = PTR_ERR(wm8904->regmap);
                dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -2283,15 +2283,12 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
        return 0;
 
 err:
-       regmap_exit(wm8904->regmap);
        return ret;
 }
 
 static __devexit int wm8904_i2c_remove(struct i2c_client *client)
 {
-       struct wm8904_priv *wm8904 = i2c_get_clientdata(client);
        snd_soc_unregister_codec(&client->dev);
-       regmap_exit(wm8904->regmap);
        return 0;
 }
 
@@ -2313,23 +2310,7 @@ static struct i2c_driver wm8904_i2c_driver = {
        .id_table = wm8904_i2c_id,
 };
 
-static int __init wm8904_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8904_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register wm8904 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8904_modinit);
-
-static void __exit wm8904_exit(void)
-{
-       i2c_del_driver(&wm8904_i2c_driver);
-}
-module_exit(wm8904_exit);
+module_i2c_driver(wm8904_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8904 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index 8bc659d8dd2e2d5bda0936a37bd694ee33ed10c4..96518ac8e24ce9660f6fde240cc951570af6a61c 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * wm8960.c  --  WM8960 ALSA SoC Audio driver
  *
+ * Copyright 2007-11 Wolfson Microelectronics, plc
+ *
  * Author: Liam Girdwood
  *
  * This program is free software; you can redistribute it and/or modify
index 05ea7c2740933b0ff4b2cbfedc3be54515670fa8..01edbcc754d2cb7ef10124963a701583cf75f762 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * wm8961.c  --  WM8961 ALSA SoC Audio driver
  *
+ * Copyright 2009-10 Wolfson Microelectronics, plc
+ *
  * Author: Mark Brown
  *
  * This program is free software; you can redistribute it and/or modify
index 0cfce9999c894b83bef22d09ae6320c7ce88e8b8..27da4d722edc82dc4ec5dee9d9cce7fcce6dc375 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8962.c  --  WM8962 ALSA SoC Audio driver
  *
- * Copyright 2010 Wolfson Microelectronics plc
+ * Copyright 2010-2 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
index 36acfccab99986fa7ee5e3bd3f770d4212c2d29a..9fd80d688979c2043326b03a40f3da1c4e220189 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8993.c -- WM8993 ALSA SoC audio driver
  *
- * Copyright 2009, 2010 Wolfson Microelectronics plc
+ * Copyright 2009-12 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
index 993639d694ce308aed067cea3003fcbf6ad2ee2b..5d4d7df8d339d94e1bb59b8b293afd9fbbb6dfd0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8994.c  --  WM8994 ALSA SoC Audio driver
  *
- * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2009-12 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
index 8af422e38fd060118968eb6f3bf62d707b32584e..a6b5cffa498aef920a1c29a112f7c66b88412870 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8996.c - WM8996 audio codec interface
  *
- * Copyright 2011 Wolfson Microelectronics PLC.
+ * Copyright 2011-2 Wolfson Microelectronics PLC.
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -296,184 +296,6 @@ static struct reg_default wm8996_reg[] = {
        { WM8996_RIGHT_PDM_SPEAKER, 0x1 },
        { WM8996_PDM_SPEAKER_MUTE_SEQUENCE, 0x69 },
        { WM8996_PDM_SPEAKER_VOLUME, 0x66 },
-       { WM8996_WRITE_SEQUENCER_0, 0x1 },
-       { WM8996_WRITE_SEQUENCER_1, 0x1 },
-       { WM8996_WRITE_SEQUENCER_3, 0x6 },
-       { WM8996_WRITE_SEQUENCER_4, 0x40 },
-       { WM8996_WRITE_SEQUENCER_5, 0x1 },
-       { WM8996_WRITE_SEQUENCER_6, 0xf },
-       { WM8996_WRITE_SEQUENCER_7, 0x6 },
-       { WM8996_WRITE_SEQUENCER_8, 0x1 },
-       { WM8996_WRITE_SEQUENCER_9, 0x3 },
-       { WM8996_WRITE_SEQUENCER_10, 0x104 },
-       { WM8996_WRITE_SEQUENCER_12, 0x60 },
-       { WM8996_WRITE_SEQUENCER_13, 0x11 },
-       { WM8996_WRITE_SEQUENCER_14, 0x401 },
-       { WM8996_WRITE_SEQUENCER_16, 0x50 },
-       { WM8996_WRITE_SEQUENCER_17, 0x3 },
-       { WM8996_WRITE_SEQUENCER_18, 0x100 },
-       { WM8996_WRITE_SEQUENCER_20, 0x51 },
-       { WM8996_WRITE_SEQUENCER_21, 0x3 },
-       { WM8996_WRITE_SEQUENCER_22, 0x104 },
-       { WM8996_WRITE_SEQUENCER_23, 0xa },
-       { WM8996_WRITE_SEQUENCER_24, 0x60 },
-       { WM8996_WRITE_SEQUENCER_25, 0x3b },
-       { WM8996_WRITE_SEQUENCER_26, 0x502 },
-       { WM8996_WRITE_SEQUENCER_27, 0x100 },
-       { WM8996_WRITE_SEQUENCER_28, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_32, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_36, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_40, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_44, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_48, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_52, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_56, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_60, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_64, 0x1 },
-       { WM8996_WRITE_SEQUENCER_65, 0x1 },
-       { WM8996_WRITE_SEQUENCER_67, 0x6 },
-       { WM8996_WRITE_SEQUENCER_68, 0x40 },
-       { WM8996_WRITE_SEQUENCER_69, 0x1 },
-       { WM8996_WRITE_SEQUENCER_70, 0xf },
-       { WM8996_WRITE_SEQUENCER_71, 0x6 },
-       { WM8996_WRITE_SEQUENCER_72, 0x1 },
-       { WM8996_WRITE_SEQUENCER_73, 0x3 },
-       { WM8996_WRITE_SEQUENCER_74, 0x104 },
-       { WM8996_WRITE_SEQUENCER_76, 0x60 },
-       { WM8996_WRITE_SEQUENCER_77, 0x11 },
-       { WM8996_WRITE_SEQUENCER_78, 0x401 },
-       { WM8996_WRITE_SEQUENCER_80, 0x50 },
-       { WM8996_WRITE_SEQUENCER_81, 0x3 },
-       { WM8996_WRITE_SEQUENCER_82, 0x100 },
-       { WM8996_WRITE_SEQUENCER_84, 0x60 },
-       { WM8996_WRITE_SEQUENCER_85, 0x3b },
-       { WM8996_WRITE_SEQUENCER_86, 0x502 },
-       { WM8996_WRITE_SEQUENCER_87, 0x100 },
-       { WM8996_WRITE_SEQUENCER_88, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_92, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_96, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_100, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_104, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_108, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_112, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_116, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_120, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_124, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_128, 0x1 },
-       { WM8996_WRITE_SEQUENCER_129, 0x1 },
-       { WM8996_WRITE_SEQUENCER_131, 0x6 },
-       { WM8996_WRITE_SEQUENCER_132, 0x40 },
-       { WM8996_WRITE_SEQUENCER_133, 0x1 },
-       { WM8996_WRITE_SEQUENCER_134, 0xf },
-       { WM8996_WRITE_SEQUENCER_135, 0x6 },
-       { WM8996_WRITE_SEQUENCER_136, 0x1 },
-       { WM8996_WRITE_SEQUENCER_137, 0x3 },
-       { WM8996_WRITE_SEQUENCER_138, 0x106 },
-       { WM8996_WRITE_SEQUENCER_140, 0x61 },
-       { WM8996_WRITE_SEQUENCER_141, 0x11 },
-       { WM8996_WRITE_SEQUENCER_142, 0x401 },
-       { WM8996_WRITE_SEQUENCER_144, 0x50 },
-       { WM8996_WRITE_SEQUENCER_145, 0x3 },
-       { WM8996_WRITE_SEQUENCER_146, 0x102 },
-       { WM8996_WRITE_SEQUENCER_148, 0x51 },
-       { WM8996_WRITE_SEQUENCER_149, 0x3 },
-       { WM8996_WRITE_SEQUENCER_150, 0x106 },
-       { WM8996_WRITE_SEQUENCER_151, 0xa },
-       { WM8996_WRITE_SEQUENCER_152, 0x61 },
-       { WM8996_WRITE_SEQUENCER_153, 0x3b },
-       { WM8996_WRITE_SEQUENCER_154, 0x502 },
-       { WM8996_WRITE_SEQUENCER_155, 0x100 },
-       { WM8996_WRITE_SEQUENCER_156, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_160, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_164, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_168, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_172, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_176, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_180, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_184, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_188, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_192, 0x1 },
-       { WM8996_WRITE_SEQUENCER_193, 0x1 },
-       { WM8996_WRITE_SEQUENCER_195, 0x6 },
-       { WM8996_WRITE_SEQUENCER_196, 0x40 },
-       { WM8996_WRITE_SEQUENCER_197, 0x1 },
-       { WM8996_WRITE_SEQUENCER_198, 0xf },
-       { WM8996_WRITE_SEQUENCER_199, 0x6 },
-       { WM8996_WRITE_SEQUENCER_200, 0x1 },
-       { WM8996_WRITE_SEQUENCER_201, 0x3 },
-       { WM8996_WRITE_SEQUENCER_202, 0x106 },
-       { WM8996_WRITE_SEQUENCER_204, 0x61 },
-       { WM8996_WRITE_SEQUENCER_205, 0x11 },
-       { WM8996_WRITE_SEQUENCER_206, 0x401 },
-       { WM8996_WRITE_SEQUENCER_208, 0x50 },
-       { WM8996_WRITE_SEQUENCER_209, 0x3 },
-       { WM8996_WRITE_SEQUENCER_210, 0x102 },
-       { WM8996_WRITE_SEQUENCER_212, 0x61 },
-       { WM8996_WRITE_SEQUENCER_213, 0x3b },
-       { WM8996_WRITE_SEQUENCER_214, 0x502 },
-       { WM8996_WRITE_SEQUENCER_215, 0x100 },
-       { WM8996_WRITE_SEQUENCER_216, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_220, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_224, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_228, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_232, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_236, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_240, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_244, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_248, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_252, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_256, 0x60 },
-       { WM8996_WRITE_SEQUENCER_258, 0x601 },
-       { WM8996_WRITE_SEQUENCER_260, 0x50 },
-       { WM8996_WRITE_SEQUENCER_262, 0x100 },
-       { WM8996_WRITE_SEQUENCER_264, 0x1 },
-       { WM8996_WRITE_SEQUENCER_266, 0x104 },
-       { WM8996_WRITE_SEQUENCER_267, 0x100 },
-       { WM8996_WRITE_SEQUENCER_268, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_272, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_276, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_280, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_284, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_288, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_292, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_296, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_300, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_304, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_308, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_312, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_316, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_320, 0x61 },
-       { WM8996_WRITE_SEQUENCER_322, 0x601 },
-       { WM8996_WRITE_SEQUENCER_324, 0x50 },
-       { WM8996_WRITE_SEQUENCER_326, 0x102 },
-       { WM8996_WRITE_SEQUENCER_328, 0x1 },
-       { WM8996_WRITE_SEQUENCER_330, 0x106 },
-       { WM8996_WRITE_SEQUENCER_331, 0x100 },
-       { WM8996_WRITE_SEQUENCER_332, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_336, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_340, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_344, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_348, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_352, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_356, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_360, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_364, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_368, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_372, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_376, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_380, 0x2fff },
-       { WM8996_WRITE_SEQUENCER_384, 0x60 },
-       { WM8996_WRITE_SEQUENCER_386, 0x601 },
-       { WM8996_WRITE_SEQUENCER_388, 0x61 },
-       { WM8996_WRITE_SEQUENCER_390, 0x601 },
-       { WM8996_WRITE_SEQUENCER_392, 0x50 },
-       { WM8996_WRITE_SEQUENCER_394, 0x300 },
-       { WM8996_WRITE_SEQUENCER_396, 0x1 },
-       { WM8996_WRITE_SEQUENCER_398, 0x304 },
-       { WM8996_WRITE_SEQUENCER_400, 0x40 },
-       { WM8996_WRITE_SEQUENCER_402, 0xf },
-       { WM8996_WRITE_SEQUENCER_404, 0x1 },
-       { WM8996_WRITE_SEQUENCER_407, 0x100 },
 };
 
 static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0);
@@ -3178,7 +3000,7 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
                msleep(5);
        }
 
-       wm8996->regmap = regmap_init_i2c(i2c, &wm8996_regmap);
+       wm8996->regmap = devm_regmap_init_i2c(i2c, &wm8996_regmap);
        if (IS_ERR(wm8996->regmap)) {
                ret = PTR_ERR(wm8996->regmap);
                dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
@@ -3227,7 +3049,6 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
 err_gpiolib:
        wm8996_free_gpio(wm8996);
 err_regmap:
-       regmap_exit(wm8996->regmap);
 err_enable:
        if (wm8996->pdata.ldo_ena > 0)
                gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
@@ -3246,7 +3067,6 @@ static __devexit int wm8996_i2c_remove(struct i2c_client *client)
 
        snd_soc_unregister_codec(&client->dev);
        wm8996_free_gpio(wm8996);
-       regmap_exit(wm8996->regmap);
        if (wm8996->pdata.ldo_ena > 0) {
                gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
                gpio_free(wm8996->pdata.ldo_ena);
index 9328270df16cfcc91cb758b65effa6c9607ea9c3..2de74e1ea2259ae0750d90d0f3e769698b43469a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Author: Mark Brown
  *
- * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2009-12 Wolfson Microelectronics plc
  *
  * 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
index 4b263b6edf13793908d3d1ab11c2630e5bee9054..2c2346fdd6370a3e307bd75a2815c6fcb89379eb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC WM9090 driver
  *
- * Copyright 2009, 2010 Wolfson Microelectronics
+ * Copyright 2009-12 Wolfson Microelectronics
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
index a1541414d904d0ac96dd5d9715d6205b941ad614..099e6ec321256009a99ba90c73fc66283cece2d4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm9712.c  --  ALSA Soc WM9712 codec support
  *
- * Copyright 2006 Wolfson Microelectronics PLC.
+ * Copyright 2006-12 Wolfson Microelectronics PLC.
  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
index 2d22cc70d5362d72c2372710597318e1cae61e6b..3eb19fb71d17209e0bccc071ed3f481471201276 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm9713.c  --  ALSA Soc WM9713 codec support
  *
- * Copyright 2006 Wolfson Microelectronics PLC.
+ * Copyright 2006-10 Wolfson Microelectronics PLC.
  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
index dfe957a47f29b02073de0de666de9cfab51c96e4..61baa48823cba20a7b8696824f333cb82bad2a1e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm_hubs.c  --  WM8993/4 common code
  *
- * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2009-12 Wolfson Microelectronics plc
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
index 3e6e8764b2e67674ad9ba3f571cd162a13cad509..215113b05f7d07c6ec46ecb591ec69bd04c5c610 100644 (file)
@@ -133,7 +133,7 @@ static int __devinit mxs_sgtl5000_probe_dt(struct platform_device *pdev)
                mxs_sgtl5000_dai[i].codec_name = NULL;
                mxs_sgtl5000_dai[i].codec_of_node = codec_np;
                mxs_sgtl5000_dai[i].cpu_dai_name = NULL;
-               mxs_sgtl5000_dai[i].cpu_dai_of_node = saif_np[i];
+               mxs_sgtl5000_dai[i].cpu_of_node = saif_np[i];
                mxs_sgtl5000_dai[i].platform_name = NULL;
                mxs_sgtl5000_dai[i].platform_of_node = saif_np[i];
        }
index 2ef98536f1da9ecff07ebd3d6903a8bf78345029..53486ff9c2afab75064de91599a2e1297a744359 100644 (file)
@@ -247,7 +247,7 @@ struct fsi_priv {
 struct fsi_stream_handler {
        int (*init)(struct fsi_priv *fsi, struct fsi_stream *io);
        int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io);
-       int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io);
+       int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev);
        int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io);
        int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io);
        void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io,
@@ -571,16 +571,16 @@ static int fsi_stream_transfer(struct fsi_stream *io)
 #define fsi_stream_stop(fsi, io)\
        fsi_stream_handler_call(io, start_stop, fsi, io, 0)
 
-static int fsi_stream_probe(struct fsi_priv *fsi)
+static int fsi_stream_probe(struct fsi_priv *fsi, struct device *dev)
 {
        struct fsi_stream *io;
        int ret1, ret2;
 
        io = &fsi->playback;
-       ret1 = fsi_stream_handler_call(io, probe, fsi, io);
+       ret1 = fsi_stream_handler_call(io, probe, fsi, io, dev);
 
        io = &fsi->capture;
-       ret2 = fsi_stream_handler_call(io, probe, fsi, io);
+       ret2 = fsi_stream_handler_call(io, probe, fsi, io, dev);
 
        if (ret1 < 0)
                return ret1;
@@ -1089,13 +1089,10 @@ static void fsi_dma_do_tasklet(unsigned long data)
 {
        struct fsi_stream *io = (struct fsi_stream *)data;
        struct fsi_priv *fsi = fsi_stream_to_priv(io);
-       struct dma_chan *chan;
        struct snd_soc_dai *dai;
        struct dma_async_tx_descriptor *desc;
-       struct scatterlist sg;
        struct snd_pcm_runtime *runtime;
        enum dma_data_direction dir;
-       dma_cookie_t cookie;
        int is_play = fsi_stream_is_play(fsi, io);
        int len;
        dma_addr_t buf;
@@ -1104,7 +1101,6 @@ static void fsi_dma_do_tasklet(unsigned long data)
                return;
 
        dai     = fsi_get_dai(io->substream);
-       chan    = io->chan;
        runtime = io->substream->runtime;
        dir     = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
        len     = samples_to_bytes(runtime, io->period_samples);
@@ -1112,14 +1108,8 @@ static void fsi_dma_do_tasklet(unsigned long data)
 
        dma_sync_single_for_device(dai->dev, buf, len, dir);
 
-       sg_init_table(&sg, 1);
-       sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)),
-                   len , offset_in_page(buf));
-       sg_dma_address(&sg) = buf;
-       sg_dma_len(&sg) = len;
-
-       desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir,
-                                      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       desc = dmaengine_prep_slave_single(io->chan, buf, len, dir,
+                                          DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc) {
                dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n");
                return;
@@ -1128,13 +1118,12 @@ static void fsi_dma_do_tasklet(unsigned long data)
        desc->callback          = fsi_dma_complete;
        desc->callback_param    = io;
 
-       cookie = desc->tx_submit(desc);
-       if (cookie < 0) {
+       if (dmaengine_submit(desc) < 0) {
                dev_err(dai->dev, "tx_submit() fail\n");
                return;
        }
 
-       dma_async_issue_pending(chan);
+       dma_async_issue_pending(io->chan);
 
        /*
         * FIXME
@@ -1184,7 +1173,7 @@ static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
                fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
 }
 
-static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
+static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
 {
        dma_cap_mask_t mask;
 
@@ -1192,8 +1181,19 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
        dma_cap_set(DMA_SLAVE, mask);
 
        io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave);
-       if (!io->chan)
-               return -EIO;
+       if (!io->chan) {
+
+               /* switch to PIO handler */
+               if (fsi_stream_is_play(fsi, io))
+                       fsi->playback.handler   = &fsi_pio_push_handler;
+               else
+                       fsi->capture.handler    = &fsi_pio_pop_handler;
+
+               dev_info(dev, "switch handler (dma => pio)\n");
+
+               /* probe again */
+               return fsi_stream_probe(fsi, dev);
+       }
 
        tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io);
 
@@ -1683,7 +1683,7 @@ static int fsi_probe(struct platform_device *pdev)
        master->fsia.master     = master;
        master->fsia.info       = &info->port_a;
        fsi_handler_init(&master->fsia);
-       ret = fsi_stream_probe(&master->fsia);
+       ret = fsi_stream_probe(&master->fsia, &pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "FSIA stream probe failed\n");
                goto exit_iounmap;
@@ -1694,7 +1694,7 @@ static int fsi_probe(struct platform_device *pdev)
        master->fsib.master     = master;
        master->fsib.info       = &info->port_b;
        fsi_handler_init(&master->fsib);
-       ret = fsi_stream_probe(&master->fsib);
+       ret = fsi_stream_probe(&master->fsib, &pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "FSIB stream probe failed\n");
                goto exit_fsia;
index b37ee8077ed148613419ae37a4427ddb227ec095..3d803f3cd27292e0f98f2c50672a376cb6dae4f7 100644 (file)
@@ -812,13 +812,15 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 
        /* Find CPU DAI from registered DAIs*/
        list_for_each_entry(cpu_dai, &dai_list, list) {
-               if (dai_link->cpu_dai_of_node) {
-                       if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
-                               continue;
-               } else {
-                       if (strcmp(cpu_dai->name, dai_link->cpu_dai_name))
-                               continue;
-               }
+               if (dai_link->cpu_of_node &&
+                   (cpu_dai->dev->of_node != dai_link->cpu_of_node))
+                       continue;
+               if (dai_link->cpu_name &&
+                   strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name))
+                       continue;
+               if (dai_link->cpu_dai_name &&
+                   strcmp(cpu_dai->name, dai_link->cpu_dai_name))
+                       continue;
 
                rtd->cpu_dai = cpu_dai;
        }
@@ -2789,6 +2791,104 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
 
+/**
+ * snd_soc_info_volsw_range - single mixer info callback with range.
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information, within a range, about a single
+ * mixer control.
+ *
+ * returns 0 for success.
+ */
+int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int platform_max;
+       int min = mc->min;
+
+       if (!mc->platform_max)
+               mc->platform_max = mc->max;
+       platform_max = mc->platform_max;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = platform_max - min;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range);
+
+/**
+ * snd_soc_put_volsw_range - single mixer put value callback with range.
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to set the value, within a range, for a single mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int shift = mc->shift;
+       int min = mc->min;
+       int max = mc->max;
+       unsigned int mask = (1 << fls(max)) - 1;
+       unsigned int invert = mc->invert;
+       unsigned int val, val_mask;
+
+       val = ((ucontrol->value.integer.value[0] + min) & mask);
+       if (invert)
+               val = max - val;
+       val_mask = mask << shift;
+       val = val << shift;
+
+       return snd_soc_update_bits_locked(codec, reg, val_mask, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range);
+
+/**
+ * snd_soc_get_volsw_range - single mixer get callback with range
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value, within a range, of a single mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int shift = mc->shift;
+       int min = mc->min;
+       int max = mc->max;
+       unsigned int mask = (1 << fls(max)) - 1;
+       unsigned int invert = mc->invert;
+
+       ucontrol->value.integer.value[0] =
+               (snd_soc_read(codec, reg) >> shift) & mask;
+       if (invert)
+               ucontrol->value.integer.value[0] =
+                       max - ucontrol->value.integer.value[0];
+       ucontrol->value.integer.value[0] =
+               ucontrol->value.integer.value[0] - min;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
+
 /**
  * snd_soc_limit_volume - Set new limit to an existing volume control.
  *
@@ -3346,6 +3446,12 @@ int snd_soc_register_card(struct snd_soc_card *card)
                                link->name);
                        return -EINVAL;
                }
+               /* Codec DAI name must be specified */
+               if (!link->codec_dai_name) {
+                       dev_err(card->dev, "codec_dai_name not set for %s\n",
+                               link->name);
+                       return -EINVAL;
+               }
 
                /*
                 * Platform may be specified by either name or OF node, but
@@ -3358,12 +3464,24 @@ int snd_soc_register_card(struct snd_soc_card *card)
                }
 
                /*
-                * CPU DAI must be specified by 1 of name or OF node,
-                * not both or neither.
+                * CPU device may be specified by either name or OF node, but
+                * can be left unspecified, and will be matched based on DAI
+                * name alone..
+                */
+               if (link->cpu_name && link->cpu_of_node) {
+                       dev_err(card->dev,
+                               "Neither/both cpu name/of_node are set for %s\n",
+                               link->name);
+                       return -EINVAL;
+               }
+               /*
+                * At least one of CPU DAI name or CPU device name/node must be
+                * specified
                 */
-               if (!!link->cpu_dai_name == !!link->cpu_dai_of_node) {
+               if (!link->cpu_dai_name &&
+                   !(link->cpu_name || link->cpu_of_node)) {
                        dev_err(card->dev,
-                               "Neither/both cpu_dai name/of_node are set for %s\n",
+                               "Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
                                link->name);
                        return -EINVAL;
                }
index 90ee77d2409da8402ea58026b788a624f850a25a..7365fed1ba74802edff6884d7aaef524727919e3 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/debugfs.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/clk.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -51,6 +52,7 @@ static int dapm_up_seq[] = {
        [snd_soc_dapm_pre] = 0,
        [snd_soc_dapm_supply] = 1,
        [snd_soc_dapm_regulator_supply] = 1,
+       [snd_soc_dapm_clock_supply] = 1,
        [snd_soc_dapm_micbias] = 2,
        [snd_soc_dapm_dai_link] = 2,
        [snd_soc_dapm_dai] = 3,
@@ -92,6 +94,7 @@ static int dapm_down_seq[] = {
        [snd_soc_dapm_aif_out] = 10,
        [snd_soc_dapm_dai] = 10,
        [snd_soc_dapm_dai_link] = 11,
+       [snd_soc_dapm_clock_supply] = 12,
        [snd_soc_dapm_regulator_supply] = 12,
        [snd_soc_dapm_supply] = 12,
        [snd_soc_dapm_post] = 13,
@@ -391,6 +394,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        case snd_soc_dapm_vmid:
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
+       case snd_soc_dapm_clock_supply:
        case snd_soc_dapm_aif_in:
        case snd_soc_dapm_aif_out:
        case snd_soc_dapm_dai:
@@ -764,6 +768,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
        switch (widget->id) {
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
+       case snd_soc_dapm_clock_supply:
                return 0;
        default:
                break;
@@ -850,6 +855,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
        switch (widget->id) {
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
+       case snd_soc_dapm_clock_supply:
                return 0;
        default:
                break;
@@ -996,6 +1002,26 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(dapm_regulator_event);
 
+/*
+ * Handler for clock supply widget.
+ */
+int dapm_clock_event(struct snd_soc_dapm_widget *w,
+                  struct snd_kcontrol *kcontrol, int event)
+{
+       if (!w->clk)
+               return -EIO;
+
+#ifdef CONFIG_HAVE_CLK
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               return clk_enable(w->clk);
+       } else {
+               clk_disable(w->clk);
+               return 0;
+       }
+#endif
+}
+EXPORT_SYMBOL_GPL(dapm_clock_event);
+
 static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
 {
        if (w->power_checked)
@@ -1487,6 +1513,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
        switch (w->id) {
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
+       case snd_soc_dapm_clock_supply:
                /* Supplies can't affect their outputs, only their inputs */
                break;
        default:
@@ -1587,6 +1614,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                                break;
                        case snd_soc_dapm_supply:
                        case snd_soc_dapm_regulator_supply:
+                       case snd_soc_dapm_clock_supply:
                        case snd_soc_dapm_micbias:
                                if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
                                        d->target_bias_level = SND_SOC_BIAS_STANDBY;
@@ -1941,6 +1969,7 @@ static ssize_t dapm_widget_show(struct device *dev,
                case snd_soc_dapm_mixer_named_ctl:
                case snd_soc_dapm_supply:
                case snd_soc_dapm_regulator_supply:
+               case snd_soc_dapm_clock_supply:
                        if (w->name)
                                count += sprintf(buf + count, "%s: %s\n",
                                        w->name, w->power ? "On":"Off");
@@ -2187,6 +2216,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
        case snd_soc_dapm_post:
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
+       case snd_soc_dapm_clock_supply:
        case snd_soc_dapm_aif_in:
        case snd_soc_dapm_aif_out:
        case snd_soc_dapm_dai:
@@ -2873,6 +2903,19 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                        return NULL;
                }
                break;
+       case snd_soc_dapm_clock_supply:
+#ifdef CONFIG_CLKDEV_LOOKUP
+               w->clk = devm_clk_get(dapm->dev, w->name);
+               if (IS_ERR(w->clk)) {
+                       ret = PTR_ERR(w->clk);
+                       dev_err(dapm->dev, "Failed to request %s: %d\n",
+                               w->name, ret);
+                       return NULL;
+               }
+#else
+               return NULL;
+#endif
+               break;
        default:
                break;
        }
@@ -2924,6 +2967,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                break;
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
+       case snd_soc_dapm_clock_supply:
                w->power_check = dapm_supply_check_power;
                break;
        case snd_soc_dapm_dai:
index 4d8dc6a27d4d170f1586999a88a531fa30ea6807..44d0174b4d97d1a0e727fb3d606ea68be4e59740 100644 (file)
@@ -142,6 +142,8 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
        case SND_SOC_REGMAP:
                /* Device has made its own regmap arrangements */
                codec->using_regmap = true;
+               if (!codec->control_data)
+                       codec->control_data = dev_get_regmap(codec->dev, NULL);
 
                ret = regmap_get_val_bytes(codec->control_data);
                /* Errors are legitimate for non-integer byte multiples */
index 0c7af63d444b4ba42f8305a8d12392668718e624..c5fc6b1404f62ad3ba4529daa050fd884dd91bdd 100644 (file)
 
 #define DRV_NAME "tegra20-i2s"
 
-static inline void tegra20_i2s_write(struct tegra20_i2s *i2s, u32 reg, u32 val)
-{
-       regmap_write(i2s->regmap, reg, val);
-}
-
-static inline u32 tegra20_i2s_read(struct tegra20_i2s *i2s, u32 reg)
-{
-       u32 val;
-       regmap_read(i2s->regmap, reg, &val);
-       return val;
-}
-
 static int tegra20_i2s_runtime_suspend(struct device *dev)
 {
        struct tegra20_i2s *i2s = dev_get_drvdata(dev);
@@ -85,6 +73,7 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
                                unsigned int fmt)
 {
        struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+       unsigned int mask, val;
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
        case SND_SOC_DAIFMT_NB_NF:
@@ -93,10 +82,10 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
-       i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_MASTER_ENABLE;
+       mask = TEGRA20_I2S_CTRL_MASTER_ENABLE;
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBS_CFS:
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
+               val = TEGRA20_I2S_CTRL_MASTER_ENABLE;
                break;
        case SND_SOC_DAIFMT_CBM_CFM:
                break;
@@ -104,33 +93,35 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
-       i2s->reg_ctrl &= ~(TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
-                          TEGRA20_I2S_CTRL_LRCK_MASK);
+       mask |= TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
+               TEGRA20_I2S_CTRL_LRCK_MASK;
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_A:
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+               val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+               val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
                break;
        case SND_SOC_DAIFMT_DSP_B:
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
+               val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+               val |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
                break;
        case SND_SOC_DAIFMT_I2S:
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+               val |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
+               val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
                break;
        case SND_SOC_DAIFMT_RIGHT_J:
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+               val |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
+               val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+               val |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
+               val |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
                break;
        default:
                return -EINVAL;
        }
 
+       regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val);
+
        return 0;
 }
 
@@ -138,29 +129,34 @@ static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
 {
-       struct device *dev = substream->pcm->card->dev;
+       struct device *dev = dai->dev;
        struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-       u32 reg;
+       unsigned int mask, val;
        int ret, sample_size, srate, i2sclock, bitcnt;
 
-       i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
+       mask = TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_16;
+               val = TEGRA20_I2S_CTRL_BIT_SIZE_16;
                sample_size = 16;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_24;
+               val = TEGRA20_I2S_CTRL_BIT_SIZE_24;
                sample_size = 24;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
-               i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_32;
+               val = TEGRA20_I2S_CTRL_BIT_SIZE_32;
                sample_size = 32;
                break;
        default:
                return -EINVAL;
        }
 
+       mask |= TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK;
+       val |= TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
+
+       regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val);
+
        srate = params_rate(params);
 
        /* Final "* 2" required by Tegra hardware */
@@ -175,42 +171,44 @@ static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
        bitcnt = (i2sclock / (2 * srate)) - 1;
        if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
                return -EINVAL;
-       reg = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
+       val = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
 
        if (i2sclock % (2 * srate))
-               reg |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
+               val |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
 
-       tegra20_i2s_write(i2s, TEGRA20_I2S_TIMING, reg);
+       regmap_write(i2s->regmap, TEGRA20_I2S_TIMING, val);
 
-       tegra20_i2s_write(i2s, TEGRA20_I2S_FIFO_SCR,
-               TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
-               TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
+       regmap_write(i2s->regmap, TEGRA20_I2S_FIFO_SCR,
+                    TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
+                    TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
 
        return 0;
 }
 
 static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s)
 {
-       i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO1_ENABLE;
-       tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+       regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
+                          TEGRA20_I2S_CTRL_FIFO1_ENABLE,
+                          TEGRA20_I2S_CTRL_FIFO1_ENABLE);
 }
 
 static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s)
 {
-       i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO1_ENABLE;
-       tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+       regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
+                          TEGRA20_I2S_CTRL_FIFO1_ENABLE, 0);
 }
 
 static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s)
 {
-       i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO2_ENABLE;
-       tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+       regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
+                          TEGRA20_I2S_CTRL_FIFO2_ENABLE,
+                          TEGRA20_I2S_CTRL_FIFO2_ENABLE);
 }
 
 static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s)
 {
-       i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO2_ENABLE;
-       tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+       regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL,
+                          TEGRA20_I2S_CTRL_FIFO2_ENABLE, 0);
 }
 
 static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -261,12 +259,14 @@ static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
 static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
        .probe = tegra20_i2s_probe,
        .playback = {
+               .stream_name = "Playback",
                .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .capture = {
+               .stream_name = "Capture",
                .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
@@ -412,8 +412,6 @@ static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
        i2s->playback_dma_data.width = 32;
        i2s->playback_dma_data.req_sel = dma_ch;
 
-       i2s->reg_ctrl = TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
-
        pm_runtime_enable(&pdev->dev);
        if (!pm_runtime_enabled(&pdev->dev)) {
                ret = tegra20_i2s_runtime_resume(&pdev->dev);
index a57efc6a597e4baf3574f8f3c51b8aee061786ae..c27069d24d77257d41039e1632f04ae2c33a57bd 100644 (file)
@@ -158,7 +158,6 @@ struct tegra20_i2s {
        struct tegra_pcm_dma_params capture_dma_data;
        struct tegra_pcm_dma_params playback_dma_data;
        struct regmap *regmap;
-       u32 reg_ctrl;
 };
 
 #endif
index f9b57418bd088c42f83f7e4bfde699dd7407298d..5c33c618929d79b5fe68da08163e6494ead8a455 100644 (file)
 
 #define DRV_NAME "tegra20-spdif"
 
-static inline void tegra20_spdif_write(struct tegra20_spdif *spdif, u32 reg,
-                                       u32 val)
-{
-       regmap_write(spdif->regmap, reg, val);
-}
-
-static inline u32 tegra20_spdif_read(struct tegra20_spdif *spdif, u32 reg)
-{
-       u32 val;
-       regmap_read(spdif->regmap, reg, &val);
-       return val;
-}
-
 static int tegra20_spdif_runtime_suspend(struct device *dev)
 {
        struct tegra20_spdif *spdif = dev_get_drvdata(dev);
@@ -77,21 +64,24 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
-       struct device *dev = substream->pcm->card->dev;
+       struct device *dev = dai->dev;
        struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+       unsigned int mask, val;
        int ret, spdifclock;
 
-       spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_PACK;
-       spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
+       mask = TEGRA20_SPDIF_CTRL_PACK |
+              TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
-               spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_PACK;
-               spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT;
+               val = TEGRA20_SPDIF_CTRL_PACK |
+                     TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT;
                break;
        default:
                return -EINVAL;
        }
 
+       regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, mask, val);
+
        switch (params_rate(params)) {
        case 32000:
                spdifclock = 4096000;
@@ -129,14 +119,15 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
 
 static void tegra20_spdif_start_playback(struct tegra20_spdif *spdif)
 {
-       spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_TX_EN;
-       tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl);
+       regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL,
+                          TEGRA20_SPDIF_CTRL_TX_EN,
+                          TEGRA20_SPDIF_CTRL_TX_EN);
 }
 
 static void tegra20_spdif_stop_playback(struct tegra20_spdif *spdif)
 {
-       spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_TX_EN;
-       tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl);
+       regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL,
+                          TEGRA20_SPDIF_CTRL_TX_EN, 0);
 }
 
 static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -181,6 +172,7 @@ static struct snd_soc_dai_driver tegra20_spdif_dai = {
        .name = DRV_NAME,
        .probe = tegra20_spdif_probe,
        .playback = {
+               .stream_name = "Playback",
                .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
index ed756527efeaadccc90e57107b93c7e2adee39c9..b48d699fd583dada33fc3a2631ff82d16b1bec37 100644 (file)
@@ -465,7 +465,6 @@ struct tegra20_spdif {
        struct tegra_pcm_dma_params capture_dma_data;
        struct tegra_pcm_dma_params playback_dma_data;
        struct regmap *regmap;
-       u32 reg_ctrl;
 };
 
 #endif
index 8596032985dc790e7ca07fc637fd11c36f210cf8..b68e27a14608b8b638314d8e8f51632652443d0d 100644 (file)
 
 #define DRV_NAME "tegra30-i2s"
 
-static inline void tegra30_i2s_write(struct tegra30_i2s *i2s, u32 reg, u32 val)
-{
-       regmap_write(i2s->regmap, reg, val);
-}
-
-static inline u32 tegra30_i2s_read(struct tegra30_i2s *i2s, u32 reg)
-{
-       u32 val;
-       regmap_read(i2s->regmap, reg, &val);
-       return val;
-}
-
 static int tegra30_i2s_runtime_suspend(struct device *dev)
 {
        struct tegra30_i2s *i2s = dev_get_drvdata(dev);
@@ -128,6 +116,7 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
                                unsigned int fmt)
 {
        struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+       unsigned int mask, val;
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
        case SND_SOC_DAIFMT_NB_NF:
@@ -136,10 +125,10 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
-       i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_MASTER_ENABLE;
+       mask = TEGRA30_I2S_CTRL_MASTER_ENABLE;
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBS_CFS:
-               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
+               val = TEGRA30_I2S_CTRL_MASTER_ENABLE;
                break;
        case SND_SOC_DAIFMT_CBM_CFM:
                break;
@@ -147,33 +136,37 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
-       i2s->reg_ctrl &= ~(TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK |
-                          TEGRA30_I2S_CTRL_LRCK_MASK);
+       mask |= TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK |
+               TEGRA30_I2S_CTRL_LRCK_MASK;
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_A:
-               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
-               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+               val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
+               val |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
                break;
        case SND_SOC_DAIFMT_DSP_B:
-               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
-               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW;
+               val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
+               val |= TEGRA30_I2S_CTRL_LRCK_R_LOW;
                break;
        case SND_SOC_DAIFMT_I2S:
-               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
-               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+               val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+               val |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
                break;
        case SND_SOC_DAIFMT_RIGHT_J:
-               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
-               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+               val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+               val |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
-               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
-               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+               val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+               val |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
                break;
        default:
                return -EINVAL;
        }
 
+       pm_runtime_get_sync(dai->dev);
+       regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, mask, val);
+       pm_runtime_put(dai->dev);
+
        return 0;
 }
 
@@ -181,24 +174,26 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
 {
-       struct device *dev = substream->pcm->card->dev;
+       struct device *dev = dai->dev;
        struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-       u32 val;
+       unsigned int mask, val, reg;
        int ret, sample_size, srate, i2sclock, bitcnt;
 
        if (params_channels(params) != 2)
                return -EINVAL;
 
-       i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK;
+       mask = TEGRA30_I2S_CTRL_BIT_SIZE_MASK;
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
-               i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16;
+               val = TEGRA30_I2S_CTRL_BIT_SIZE_16;
                sample_size = 16;
                break;
        default:
                return -EINVAL;
        }
 
+       regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, mask, val);
+
        srate = params_rate(params);
 
        /* Final "* 2" required by Tegra hardware */
@@ -219,7 +214,7 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
        if (i2sclock % (2 * srate))
                val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE;
 
-       tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val);
+       regmap_write(i2s->regmap, TEGRA30_I2S_TIMING, val);
 
        val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
              (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
@@ -229,15 +224,17 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
-               tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val);
+               reg = TEGRA30_I2S_CIF_RX_CTRL;
        } else {
                val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
-               tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val);
+               reg = TEGRA30_I2S_CIF_RX_CTRL;
        }
 
+       regmap_write(i2s->regmap, reg, val);
+
        val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) |
              (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT);
-       tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val);
+       regmap_write(i2s->regmap, TEGRA30_I2S_OFFSET, val);
 
        return 0;
 }
@@ -245,29 +242,31 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
 static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s)
 {
        tegra30_ahub_enable_tx_fifo(i2s->playback_fifo_cif);
-       i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX;
-       tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+       regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL,
+                          TEGRA30_I2S_CTRL_XFER_EN_TX,
+                          TEGRA30_I2S_CTRL_XFER_EN_TX);
 }
 
 static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s)
 {
        tegra30_ahub_disable_tx_fifo(i2s->playback_fifo_cif);
-       i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX;
-       tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+       regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL,
+                          TEGRA30_I2S_CTRL_XFER_EN_TX, 0);
 }
 
 static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s)
 {
        tegra30_ahub_enable_rx_fifo(i2s->capture_fifo_cif);
-       i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX;
-       tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+       regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL,
+                          TEGRA30_I2S_CTRL_XFER_EN_RX,
+                          TEGRA30_I2S_CTRL_XFER_EN_RX);
 }
 
 static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s)
 {
        tegra30_ahub_disable_rx_fifo(i2s->capture_fifo_cif);
-       i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX;
-       tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+       regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL,
+                          TEGRA30_I2S_CTRL_XFER_EN_RX, 0);
 }
 
 static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -320,12 +319,14 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
 static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
        .probe = tegra30_i2s_probe,
        .playback = {
+               .stream_name = "Playback",
                .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .capture = {
+               .stream_name = "Capture",
                .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
index 91adf29c7a8768a898584020262a487dcac4fc13..34dc47b9581c21e8700eab513265d5c4096ca794 100644 (file)
@@ -236,7 +236,6 @@ struct tegra30_i2s {
        enum tegra30_ahub_txcif playback_fifo_cif;
        struct tegra_pcm_dma_params playback_dma_data;
        struct regmap *regmap;
-       u32 reg_ctrl;
 };
 
 #endif
index 32de7006daf08975e5a3edb4e4e8b9bfe029b572..d684df294c0c5c80458b6de591c16965027db14b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * tegra_alc5632.c  --  Toshiba AC100(PAZ00) machine ASoC driver
+* tegra_alc5632.c  --  Toshiba AC100(PAZ00) machine ASoC driver
  *
  * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
  * Copyright (C) 2012 - NVIDIA, Inc.
 
 #define DRV_NAME "tegra-alc5632"
 
-#define GPIO_HP_DET     BIT(0)
-
 struct tegra_alc5632 {
        struct tegra_asoc_utils_data util_data;
-       int gpio_requested;
        int gpio_hp_det;
 };
 
@@ -46,7 +43,7 @@ static int tegra_alc5632_asoc_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_codec *codec = codec_dai->codec;
        struct snd_soc_card *card = codec->card;
        struct tegra_alc5632 *alc5632 = snd_soc_card_get_drvdata(card);
        int srate, mclk;
@@ -108,9 +105,9 @@ static const struct snd_kcontrol_new tegra_alc5632_controls[] = {
 
 static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       struct device_node *np = codec->card->dev->of_node;
        struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(codec->card);
 
        snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
@@ -119,14 +116,11 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
                        ARRAY_SIZE(tegra_alc5632_hs_jack_pins),
                        tegra_alc5632_hs_jack_pins);
 
-       machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
-
        if (gpio_is_valid(machine->gpio_hp_det)) {
                tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det;
                snd_soc_jack_add_gpios(&tegra_alc5632_hs_jack,
                                                1,
                                                &tegra_alc5632_hp_jack_gpio);
-               machine->gpio_requested |= GPIO_HP_DET;
        }
 
        snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
@@ -159,6 +153,7 @@ static struct snd_soc_card snd_soc_tegra_alc5632 = {
 
 static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        struct snd_soc_card *card = &snd_soc_tegra_alc5632;
        struct tegra_alc5632 *alc5632;
        int ret;
@@ -181,6 +176,10 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
                goto err;
        }
 
+       alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+       if (alc5632->gpio_hp_det == -ENODEV)
+               return -EPROBE_DEFER;
+
        ret = snd_soc_of_parse_card_name(card, "nvidia,model");
        if (ret)
                goto err;
@@ -199,16 +198,16 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
                goto err;
        }
 
-       tegra_alc5632_dai.cpu_dai_of_node = of_parse_phandle(
+       tegra_alc5632_dai.cpu_of_node = of_parse_phandle(
                        pdev->dev.of_node, "nvidia,i2s-controller", 0);
-       if (!tegra_alc5632_dai.cpu_dai_of_node) {
+       if (!tegra_alc5632_dai.cpu_of_node) {
                dev_err(&pdev->dev,
                "Property 'nvidia,i2s-controller' missing or invalid\n");
                ret = -EINVAL;
                goto err;
        }
 
-       tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_dai_of_node;
+       tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_of_node;
 
        ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev);
        if (ret)
@@ -234,11 +233,8 @@ static int __devexit tegra_alc5632_remove(struct platform_device *pdev)
        struct snd_soc_card *card = platform_get_drvdata(pdev);
        struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card);
 
-       if (machine->gpio_requested & GPIO_HP_DET)
-               snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack,
-                                       1,
-                                       &tegra_alc5632_hp_jack_gpio);
-       machine->gpio_requested = 0;
+       snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, 1,
+                               &tegra_alc5632_hp_jack_gpio);
 
        snd_soc_unregister_card(card);
 
index 4e77026807a261ccf6fe3a147c0098da33df571b..ea9166d5c4ebeba6c649e6fcb8551c290acc2849 100644 (file)
@@ -57,7 +57,7 @@ static int tegra_wm8753_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_codec *codec = codec_dai->codec;
        struct snd_soc_card *card = codec->card;
        struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
        int srate, mclk;
@@ -157,9 +157,9 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev)
                goto err;
        }
 
-       tegra_wm8753_dai.cpu_dai_of_node = of_parse_phandle(
+       tegra_wm8753_dai.cpu_of_node = of_parse_phandle(
                        pdev->dev.of_node, "nvidia,i2s-controller", 0);
-       if (!tegra_wm8753_dai.cpu_dai_of_node) {
+       if (!tegra_wm8753_dai.cpu_of_node) {
                dev_err(&pdev->dev,
                        "Property 'nvidia,i2s-controller' missing or invalid\n");
                ret = -EINVAL;
@@ -167,7 +167,7 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev)
        }
 
        tegra_wm8753_dai.platform_of_node =
-                               tegra_wm8753_dai.cpu_dai_of_node;
+                               tegra_wm8753_dai.cpu_of_node;
 
        ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
        if (ret)
index 0b0df49d9d33b071118576c340b69366f212663f..08b5fef67b3193fa99f29d308610f4b8ccea76a8 100644 (file)
@@ -28,8 +28,6 @@
  *
  */
 
-#include <asm/mach-types.h>
-
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
 #define DRV_NAME "tegra-snd-wm8903"
 
-#define GPIO_SPKR_EN    BIT(0)
-#define GPIO_HP_MUTE    BIT(1)
-#define GPIO_INT_MIC_EN BIT(2)
-#define GPIO_EXT_MIC_EN BIT(3)
-#define GPIO_HP_DET     BIT(4)
-
 struct tegra_wm8903 {
        struct tegra_wm8903_platform_data pdata;
        struct tegra_asoc_utils_data util_data;
-       int gpio_requested;
 };
 
 static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
@@ -67,8 +58,7 @@ static int tegra_wm8903_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_codec *codec = codec_dai->codec;
        struct snd_soc_card *card = codec->card;
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
        int srate, mclk;
@@ -95,24 +85,6 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
                return err;
        }
 
-       err = snd_soc_dai_set_fmt(codec_dai,
-                                       SND_SOC_DAIFMT_I2S |
-                                       SND_SOC_DAIFMT_NB_NF |
-                                       SND_SOC_DAIFMT_CBS_CFS);
-       if (err < 0) {
-               dev_err(card->dev, "codec_dai fmt not set\n");
-               return err;
-       }
-
-       err = snd_soc_dai_set_fmt(cpu_dai,
-                                       SND_SOC_DAIFMT_I2S |
-                                       SND_SOC_DAIFMT_NB_NF |
-                                       SND_SOC_DAIFMT_CBS_CFS);
-       if (err < 0) {
-               dev_err(card->dev, "cpu_dai fmt not set\n");
-               return err;
-       }
-
        err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
                                        SND_SOC_CLOCK_IN);
        if (err < 0) {
@@ -160,7 +132,7 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
        struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
-       if (!(machine->gpio_requested & GPIO_SPKR_EN))
+       if (!gpio_is_valid(pdata->gpio_spkr_en))
                return 0;
 
        gpio_set_value_cansleep(pdata->gpio_spkr_en,
@@ -177,7 +149,7 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w,
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
        struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
-       if (!(machine->gpio_requested & GPIO_HP_MUTE))
+       if (!gpio_is_valid(pdata->gpio_hp_mute))
                return 0;
 
        gpio_set_value_cansleep(pdata->gpio_hp_mute,
@@ -203,122 +175,18 @@ static const struct snd_soc_dapm_route harmony_audio_map[] = {
        {"IN1L", NULL, "Mic Jack"},
 };
 
-static const struct snd_soc_dapm_route seaboard_audio_map[] = {
-       {"Headphone Jack", NULL, "HPOUTR"},
-       {"Headphone Jack", NULL, "HPOUTL"},
-       {"Int Spk", NULL, "ROP"},
-       {"Int Spk", NULL, "RON"},
-       {"Int Spk", NULL, "LOP"},
-       {"Int Spk", NULL, "LON"},
-       {"Mic Jack", NULL, "MICBIAS"},
-       {"IN1R", NULL, "Mic Jack"},
-};
-
-static const struct snd_soc_dapm_route kaen_audio_map[] = {
-       {"Headphone Jack", NULL, "HPOUTR"},
-       {"Headphone Jack", NULL, "HPOUTL"},
-       {"Int Spk", NULL, "ROP"},
-       {"Int Spk", NULL, "RON"},
-       {"Int Spk", NULL, "LOP"},
-       {"Int Spk", NULL, "LON"},
-       {"Mic Jack", NULL, "MICBIAS"},
-       {"IN2R", NULL, "Mic Jack"},
-};
-
-static const struct snd_soc_dapm_route aebl_audio_map[] = {
-       {"Headphone Jack", NULL, "HPOUTR"},
-       {"Headphone Jack", NULL, "HPOUTL"},
-       {"Int Spk", NULL, "LINEOUTR"},
-       {"Int Spk", NULL, "LINEOUTL"},
-       {"Mic Jack", NULL, "MICBIAS"},
-       {"IN1R", NULL, "Mic Jack"},
-};
-
 static const struct snd_kcontrol_new tegra_wm8903_controls[] = {
        SOC_DAPM_PIN_SWITCH("Int Spk"),
 };
 
 static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct snd_soc_card *card = codec->card;
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
        struct tegra_wm8903_platform_data *pdata = &machine->pdata;
-       struct device_node *np = card->dev->of_node;
-       int ret;
-
-       if (card->dev->platform_data) {
-               memcpy(pdata, card->dev->platform_data, sizeof(*pdata));
-       } else if (np) {
-               /*
-                * This part must be in init() rather than probe() in order to
-                * guarantee that the WM8903 has been probed, and hence its
-                * GPIO controller registered, which is a pre-condition for
-                * of_get_named_gpio() to be able to map the phandles in the
-                * properties to the controller node. Given this, all
-                * pdata handling is in init() for consistency.
-                */
-               pdata->gpio_spkr_en = of_get_named_gpio(np,
-                                               "nvidia,spkr-en-gpios", 0);
-               pdata->gpio_hp_mute = of_get_named_gpio(np,
-                                               "nvidia,hp-mute-gpios", 0);
-               pdata->gpio_hp_det = of_get_named_gpio(np,
-                                               "nvidia,hp-det-gpios", 0);
-               pdata->gpio_int_mic_en = of_get_named_gpio(np,
-                                               "nvidia,int-mic-en-gpios", 0);
-               pdata->gpio_ext_mic_en = of_get_named_gpio(np,
-                                               "nvidia,ext-mic-en-gpios", 0);
-       } else {
-               dev_err(card->dev, "No platform data supplied\n");
-               return -EINVAL;
-       }
-
-       if (gpio_is_valid(pdata->gpio_spkr_en)) {
-               ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
-               if (ret) {
-                       dev_err(card->dev, "cannot get spkr_en gpio\n");
-                       return ret;
-               }
-               machine->gpio_requested |= GPIO_SPKR_EN;
-
-               gpio_direction_output(pdata->gpio_spkr_en, 0);
-       }
-
-       if (gpio_is_valid(pdata->gpio_hp_mute)) {
-               ret = gpio_request(pdata->gpio_hp_mute, "hp_mute");
-               if (ret) {
-                       dev_err(card->dev, "cannot get hp_mute gpio\n");
-                       return ret;
-               }
-               machine->gpio_requested |= GPIO_HP_MUTE;
-
-               gpio_direction_output(pdata->gpio_hp_mute, 1);
-       }
-
-       if (gpio_is_valid(pdata->gpio_int_mic_en)) {
-               ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en");
-               if (ret) {
-                       dev_err(card->dev, "cannot get int_mic_en gpio\n");
-                       return ret;
-               }
-               machine->gpio_requested |= GPIO_INT_MIC_EN;
-
-               /* Disable int mic; enable signal is active-high */
-               gpio_direction_output(pdata->gpio_int_mic_en, 0);
-       }
-
-       if (gpio_is_valid(pdata->gpio_ext_mic_en)) {
-               ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en");
-               if (ret) {
-                       dev_err(card->dev, "cannot get ext_mic_en gpio\n");
-                       return ret;
-               }
-               machine->gpio_requested |= GPIO_EXT_MIC_EN;
-
-               /* Enable ext mic; enable signal is active-low */
-               gpio_direction_output(pdata->gpio_ext_mic_en, 0);
-       }
 
        if (gpio_is_valid(pdata->gpio_hp_det)) {
                tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det;
@@ -330,7 +198,6 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
                snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack,
                                        1,
                                        &tegra_wm8903_hp_jack_gpio);
-               machine->gpio_requested |= GPIO_HP_DET;
        }
 
        snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
@@ -355,6 +222,9 @@ static struct snd_soc_dai_link tegra_wm8903_dai = {
        .codec_dai_name = "wm8903-hifi",
        .init = tegra_wm8903_init,
        .ops = &tegra_wm8903_ops,
+       .dai_fmt = SND_SOC_DAIFMT_I2S |
+                  SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
 };
 
 static struct snd_soc_card snd_soc_tegra_wm8903 = {
@@ -372,8 +242,10 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = {
 
 static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        struct snd_soc_card *card = &snd_soc_tegra_wm8903;
        struct tegra_wm8903 *machine;
+       struct tegra_wm8903_platform_data *pdata;
        int ret;
 
        if (!pdev->dev.platform_data && !pdev->dev.of_node) {
@@ -388,12 +260,42 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto err;
        }
+       pdata = &machine->pdata;
 
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
        snd_soc_card_set_drvdata(card, machine);
 
-       if (pdev->dev.of_node) {
+       if (pdev->dev.platform_data) {
+               memcpy(pdata, card->dev->platform_data, sizeof(*pdata));
+       } else if (np) {
+               pdata->gpio_spkr_en = of_get_named_gpio(np,
+                                               "nvidia,spkr-en-gpios", 0);
+               if (pdata->gpio_spkr_en == -ENODEV)
+                       return -EPROBE_DEFER;
+
+               pdata->gpio_hp_mute = of_get_named_gpio(np,
+                                               "nvidia,hp-mute-gpios", 0);
+               if (pdata->gpio_hp_mute == -ENODEV)
+                       return -EPROBE_DEFER;
+
+               pdata->gpio_hp_det = of_get_named_gpio(np,
+                                               "nvidia,hp-det-gpios", 0);
+               if (pdata->gpio_hp_det == -ENODEV)
+                       return -EPROBE_DEFER;
+
+               pdata->gpio_int_mic_en = of_get_named_gpio(np,
+                                               "nvidia,int-mic-en-gpios", 0);
+               if (pdata->gpio_int_mic_en == -ENODEV)
+                       return -EPROBE_DEFER;
+
+               pdata->gpio_ext_mic_en = of_get_named_gpio(np,
+                                               "nvidia,ext-mic-en-gpios", 0);
+               if (pdata->gpio_ext_mic_en == -ENODEV)
+                       return -EPROBE_DEFER;
+       }
+
+       if (np) {
                ret = snd_soc_of_parse_card_name(card, "nvidia,model");
                if (ret)
                        goto err;
@@ -404,8 +306,8 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
                        goto err;
 
                tegra_wm8903_dai.codec_name = NULL;
-               tegra_wm8903_dai.codec_of_node = of_parse_phandle(
-                               pdev->dev.of_node, "nvidia,audio-codec", 0);
+               tegra_wm8903_dai.codec_of_node = of_parse_phandle(np,
+                               "nvidia,audio-codec", 0);
                if (!tegra_wm8903_dai.codec_of_node) {
                        dev_err(&pdev->dev,
                                "Property 'nvidia,audio-codec' missing or invalid\n");
@@ -414,9 +316,9 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
                }
 
                tegra_wm8903_dai.cpu_dai_name = NULL;
-               tegra_wm8903_dai.cpu_dai_of_node = of_parse_phandle(
-                               pdev->dev.of_node, "nvidia,i2s-controller", 0);
-               if (!tegra_wm8903_dai.cpu_dai_of_node) {
+               tegra_wm8903_dai.cpu_of_node = of_parse_phandle(np,
+                               "nvidia,i2s-controller", 0);
+               if (!tegra_wm8903_dai.cpu_of_node) {
                        dev_err(&pdev->dev,
                                "Property 'nvidia,i2s-controller' missing or invalid\n");
                        ret = -EINVAL;
@@ -425,20 +327,47 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
 
                tegra_wm8903_dai.platform_name = NULL;
                tegra_wm8903_dai.platform_of_node =
-                                       tegra_wm8903_dai.cpu_dai_of_node;
+                                       tegra_wm8903_dai.cpu_of_node;
        } else {
-               if (machine_is_harmony()) {
-                       card->dapm_routes = harmony_audio_map;
-                       card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
-               } else if (machine_is_seaboard()) {
-                       card->dapm_routes = seaboard_audio_map;
-                       card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map);
-               } else if (machine_is_kaen()) {
-                       card->dapm_routes = kaen_audio_map;
-                       card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map);
-               } else {
-                       card->dapm_routes = aebl_audio_map;
-                       card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map);
+               card->dapm_routes = harmony_audio_map;
+               card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
+       }
+
+       if (gpio_is_valid(pdata->gpio_spkr_en)) {
+               ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_spkr_en,
+                                           GPIOF_OUT_INIT_LOW, "spkr_en");
+               if (ret) {
+                       dev_err(card->dev, "cannot get spkr_en gpio\n");
+                       return ret;
+               }
+       }
+
+       if (gpio_is_valid(pdata->gpio_hp_mute)) {
+               ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_hp_mute,
+                                           GPIOF_OUT_INIT_HIGH, "hp_mute");
+               if (ret) {
+                       dev_err(card->dev, "cannot get hp_mute gpio\n");
+                       return ret;
+               }
+       }
+
+       if (gpio_is_valid(pdata->gpio_int_mic_en)) {
+               /* Disable int mic; enable signal is active-high */
+               ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_int_mic_en,
+                                           GPIOF_OUT_INIT_LOW, "int_mic_en");
+               if (ret) {
+                       dev_err(card->dev, "cannot get int_mic_en gpio\n");
+                       return ret;
+               }
+       }
+
+       if (gpio_is_valid(pdata->gpio_ext_mic_en)) {
+               /* Enable ext mic; enable signal is active-low */
+               ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_ext_mic_en,
+                                           GPIOF_OUT_INIT_LOW, "ext_mic_en");
+               if (ret) {
+                       dev_err(card->dev, "cannot get ext_mic_en gpio\n");
+                       return ret;
                }
        }
 
@@ -465,21 +394,9 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-       struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
-       if (machine->gpio_requested & GPIO_HP_DET)
-               snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack,
-                                       1,
-                                       &tegra_wm8903_hp_jack_gpio);
-       if (machine->gpio_requested & GPIO_EXT_MIC_EN)
-               gpio_free(pdata->gpio_ext_mic_en);
-       if (machine->gpio_requested & GPIO_INT_MIC_EN)
-               gpio_free(pdata->gpio_int_mic_en);
-       if (machine->gpio_requested & GPIO_HP_MUTE)
-               gpio_free(pdata->gpio_hp_mute);
-       if (machine->gpio_requested & GPIO_SPKR_EN)
-               gpio_free(pdata->gpio_spkr_en);
-       machine->gpio_requested = 0;
+       snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 1,
+                               &tegra_wm8903_hp_jack_gpio);
 
        snd_soc_unregister_card(card);
 
index 4a8d5b672c9ff5a018bd81c88a94167ea928e0b1..e69a4f7000d6166e0a0065365827486fb4c5fc99 100644 (file)
@@ -52,8 +52,7 @@ static int trimslice_asoc_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_codec *codec = codec_dai->codec;
        struct snd_soc_card *card = codec->card;
        struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card);
        int srate, mclk;
@@ -68,24 +67,6 @@ static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream,
                return err;
        }
 
-       err = snd_soc_dai_set_fmt(codec_dai,
-                                       SND_SOC_DAIFMT_I2S |
-                                       SND_SOC_DAIFMT_NB_NF |
-                                       SND_SOC_DAIFMT_CBS_CFS);
-       if (err < 0) {
-               dev_err(card->dev, "codec_dai fmt not set\n");
-               return err;
-       }
-
-       err = snd_soc_dai_set_fmt(cpu_dai,
-                                       SND_SOC_DAIFMT_I2S |
-                                       SND_SOC_DAIFMT_NB_NF |
-                                       SND_SOC_DAIFMT_CBS_CFS);
-       if (err < 0) {
-               dev_err(card->dev, "cpu_dai fmt not set\n");
-               return err;
-       }
-
        err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
                                        SND_SOC_CLOCK_IN);
        if (err < 0) {
@@ -121,6 +102,9 @@ static struct snd_soc_dai_link trimslice_tlv320aic23_dai = {
        .cpu_dai_name = "tegra20-i2s.0",
        .codec_dai_name = "tlv320aic23-hifi",
        .ops = &trimslice_asoc_ops,
+       .dai_fmt = SND_SOC_DAIFMT_I2S |
+                  SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
 };
 
 static struct snd_soc_card snd_soc_trimslice = {
@@ -162,9 +146,9 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
                }
 
                trimslice_tlv320aic23_dai.cpu_dai_name = NULL;
-               trimslice_tlv320aic23_dai.cpu_dai_of_node = of_parse_phandle(
+               trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle(
                                pdev->dev.of_node, "nvidia,i2s-controller", 0);
-               if (!trimslice_tlv320aic23_dai.cpu_dai_of_node) {
+               if (!trimslice_tlv320aic23_dai.cpu_of_node) {
                        dev_err(&pdev->dev,
                                "Property 'nvidia,i2s-controller' missing or invalid\n");
                        ret = -EINVAL;
@@ -173,7 +157,7 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
 
                trimslice_tlv320aic23_dai.platform_name = NULL;
                trimslice_tlv320aic23_dai.platform_of_node =
-                               trimslice_tlv320aic23_dai.cpu_dai_of_node;
+                               trimslice_tlv320aic23_dai.cpu_of_node;
        }
 
        ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
index 44cf43404cd9381a7a519616e146a284f023b6c1..1d385150064f15f3b3a4889634a702f4e888d952 100644 (file)
@@ -12,3 +12,10 @@ menuconfig SND_SOC_UX500
 config SND_SOC_UX500_PLAT_MSP_I2S
        tristate
        depends on SND_SOC_UX500
+
+config SND_SOC_UX500_PLAT_DMA
+       tristate "Platform - DB8500 (DMA)"
+       depends on SND_SOC_UX500
+       select SND_SOC_DMAENGINE_PCM
+       help
+               Say Y if you want to enable the Ux500 platform-driver.
index 19974c5a2ea13ea13835bd679fef6986081e0970..4634bf015f623517d4cfa567827c1fa48073af13 100644 (file)
@@ -2,3 +2,6 @@
 
 snd-soc-ux500-plat-msp-i2s-objs := ux500_msp_dai.o ux500_msp_i2s.o
 obj-$(CONFIG_SND_SOC_UX500_PLAT_MSP_I2S) += snd-soc-ux500-plat-msp-i2s.o
+
+snd-soc-ux500-plat-dma-objs := ux500_pcm.o
+obj-$(CONFIG_SND_SOC_UX500_PLAT_DMA) += snd-soc-ux500-plat-dma.o
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c
new file mode 100644 (file)
index 0000000..66b080e
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 <asm/page.h>
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/slab.h>
+
+#include <plat/ste_dma40.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "ux500_msp_i2s.h"
+#include "ux500_pcm.h"
+
+static struct snd_pcm_hardware ux500_pcm_hw_playback = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_RESUME |
+               SNDRV_PCM_INFO_PAUSE,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+               SNDRV_PCM_FMTBIT_U16_LE |
+               SNDRV_PCM_FMTBIT_S16_BE |
+               SNDRV_PCM_FMTBIT_U16_BE,
+       .rates = SNDRV_PCM_RATE_KNOT,
+       .rate_min = UX500_PLATFORM_MIN_RATE_PLAYBACK,
+       .rate_max = UX500_PLATFORM_MAX_RATE_PLAYBACK,
+       .channels_min = UX500_PLATFORM_MIN_CHANNELS,
+       .channels_max = UX500_PLATFORM_MAX_CHANNELS,
+       .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
+       .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
+       .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
+       .periods_min = UX500_PLATFORM_PERIODS_MIN,
+       .periods_max = UX500_PLATFORM_PERIODS_MAX,
+};
+
+static struct snd_pcm_hardware ux500_pcm_hw_capture = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_RESUME |
+               SNDRV_PCM_INFO_PAUSE,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+               SNDRV_PCM_FMTBIT_U16_LE |
+               SNDRV_PCM_FMTBIT_S16_BE |
+               SNDRV_PCM_FMTBIT_U16_BE,
+       .rates = SNDRV_PCM_RATE_KNOT,
+       .rate_min = UX500_PLATFORM_MIN_RATE_CAPTURE,
+       .rate_max = UX500_PLATFORM_MAX_RATE_CAPTURE,
+       .channels_min = UX500_PLATFORM_MIN_CHANNELS,
+       .channels_max = UX500_PLATFORM_MAX_CHANNELS,
+       .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
+       .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
+       .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
+       .periods_min = UX500_PLATFORM_PERIODS_MIN,
+       .periods_max = UX500_PLATFORM_PERIODS_MAX,
+};
+
+static void ux500_pcm_dma_hw_free(struct device *dev,
+                               struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_dma_buffer *buf = runtime->dma_buffer_p;
+
+       if (runtime->dma_area == NULL)
+               return;
+
+       if (buf != &substream->dma_buffer) {
+               dma_free_coherent(buf->dev.dev, buf->bytes, buf->area,
+                               buf->addr);
+               kfree(runtime->dma_buffer_p);
+       }
+
+       snd_pcm_set_runtime_buffer(substream, NULL);
+}
+
+static int ux500_pcm_open(struct snd_pcm_substream *substream)
+{
+       int stream_id = substream->pstr->stream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct device *dev = dai->dev;
+       int ret;
+       struct ux500_msp_dma_params *dma_params;
+       u16 per_data_width, mem_data_width;
+       struct stedma40_chan_cfg *dma_cfg;
+
+       dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
+               snd_pcm_stream_str(substream));
+
+       dev_dbg(dev, "%s: Set runtime hwparams.\n", __func__);
+       if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+               snd_soc_set_runtime_hwparams(substream,
+                                       &ux500_pcm_hw_playback);
+       else
+               snd_soc_set_runtime_hwparams(substream,
+                                       &ux500_pcm_hw_capture);
+
+       /* ensure that buffer size is a multiple of period size */
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                       SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0) {
+               dev_err(dev, "%s: Error: snd_pcm_hw_constraints failed (%d)\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       dev_dbg(dev, "%s: Set hw-struct for %s.\n", __func__,
+               snd_pcm_stream_str(substream));
+       runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ?
+               ux500_pcm_hw_playback : ux500_pcm_hw_capture;
+
+       mem_data_width = STEDMA40_HALFWORD_WIDTH;
+
+       dma_params = snd_soc_dai_get_dma_data(dai, substream);
+       switch (dma_params->data_size) {
+       case 32:
+               per_data_width = STEDMA40_WORD_WIDTH;
+               break;
+       case 16:
+               per_data_width = STEDMA40_HALFWORD_WIDTH;
+               break;
+       case 8:
+               per_data_width = STEDMA40_BYTE_WIDTH;
+               break;
+       default:
+               per_data_width = STEDMA40_WORD_WIDTH;
+               dev_warn(rtd->platform->dev,
+                       "%s: Unknown data-size (%d)! Assuming 32 bits.\n",
+                       __func__, dma_params->data_size);
+       }
+
+       dma_cfg = dma_params->dma_cfg;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               dma_cfg->src_info.data_width = mem_data_width;
+               dma_cfg->dst_info.data_width = per_data_width;
+       } else {
+               dma_cfg->src_info.data_width = per_data_width;
+               dma_cfg->dst_info.data_width = mem_data_width;
+       }
+
+
+       ret = snd_dmaengine_pcm_open(substream, stedma40_filter, dma_cfg);
+       if (ret) {
+               dev_dbg(dai->dev,
+                       "%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       snd_dmaengine_pcm_set_data(substream, dma_cfg);
+
+       return 0;
+}
+
+static int ux500_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+
+       dev_dbg(dai->dev, "%s: Enter\n", __func__);
+
+       snd_dmaengine_pcm_close(substream);
+
+       return 0;
+}
+
+static int ux500_pcm_hw_params(struct snd_pcm_substream *substream,
+                       struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_dma_buffer *buf = runtime->dma_buffer_p;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       int ret = 0;
+       int size;
+
+       dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
+
+       size = params_buffer_bytes(hw_params);
+
+       if (buf) {
+               if (buf->bytes >= size)
+                       goto out;
+               ux500_pcm_dma_hw_free(NULL, substream);
+       }
+
+       if (substream->dma_buffer.area != NULL &&
+               substream->dma_buffer.bytes >= size) {
+               buf = &substream->dma_buffer;
+       } else {
+               buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
+               if (!buf)
+                       goto nomem;
+
+               buf->dev.type = SNDRV_DMA_TYPE_DEV;
+               buf->dev.dev = NULL;
+               buf->area = dma_alloc_coherent(NULL, size, &buf->addr,
+                                       GFP_KERNEL);
+               buf->bytes = size;
+               buf->private_data = NULL;
+
+               if (!buf->area)
+                       goto free;
+       }
+       snd_pcm_set_runtime_buffer(substream, buf);
+       ret = 1;
+ out:
+       runtime->dma_bytes = size;
+       return ret;
+
+ free:
+       kfree(buf);
+ nomem:
+       return -ENOMEM;
+}
+
+static int ux500_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
+
+       ux500_pcm_dma_hw_free(NULL, substream);
+
+       return 0;
+}
+
+static int ux500_pcm_mmap(struct snd_pcm_substream *substream,
+                       struct vm_area_struct *vma)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       dev_dbg(rtd->platform->dev, "%s: Enter.\n", __func__);
+
+       return dma_mmap_coherent(NULL, vma, runtime->dma_area,
+                               runtime->dma_addr, runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops ux500_pcm_ops = {
+       .open           = ux500_pcm_open,
+       .close          = ux500_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = ux500_pcm_hw_params,
+       .hw_free        = ux500_pcm_hw_free,
+       .trigger        = snd_dmaengine_pcm_trigger,
+       .pointer        = snd_dmaengine_pcm_pointer,
+       .mmap           = ux500_pcm_mmap
+};
+
+int ux500_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+
+       dev_dbg(rtd->platform->dev, "%s: Enter (id = '%s').\n", __func__,
+               pcm->id);
+
+       pcm->info_flags = 0;
+
+       return 0;
+}
+
+static struct snd_soc_platform_driver ux500_pcm_soc_drv = {
+       .ops            = &ux500_pcm_ops,
+       .pcm_new        = ux500_pcm_new,
+};
+
+static int __devexit ux500_pcm_drv_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       ret = snd_soc_register_platform(&pdev->dev, &ux500_pcm_soc_drv);
+       if (ret < 0) {
+               dev_err(&pdev->dev,
+                       "%s: ERROR: Failed to register platform '%s' (%d)!\n",
+                       __func__, pdev->name, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devinit ux500_pcm_drv_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+
+       return 0;
+}
+
+static struct platform_driver ux500_pcm_driver = {
+       .driver = {
+               .name = "ux500-pcm",
+               .owner = THIS_MODULE,
+       },
+
+       .probe = ux500_pcm_drv_probe,
+       .remove = __devexit_p(ux500_pcm_drv_remove),
+};
+module_platform_driver(ux500_pcm_driver);
+
+MODULE_LICENSE("GPLv2");
diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h
new file mode 100644 (file)
index 0000000..77ed44d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 UX500_PCM_H
+#define UX500_PCM_H
+
+#include <asm/page.h>
+
+#include <linux/workqueue.h>
+
+#define UX500_PLATFORM_MIN_RATE_PLAYBACK 8000
+#define UX500_PLATFORM_MAX_RATE_PLAYBACK 48000
+#define UX500_PLATFORM_MIN_RATE_CAPTURE        8000
+#define UX500_PLATFORM_MAX_RATE_CAPTURE        48000
+
+#define UX500_PLATFORM_MIN_CHANNELS 1
+#define UX500_PLATFORM_MAX_CHANNELS 8
+
+#define UX500_PLATFORM_PERIODS_BYTES_MIN       128
+#define UX500_PLATFORM_PERIODS_BYTES_MAX       (64 * PAGE_SIZE)
+#define UX500_PLATFORM_PERIODS_MIN             2
+#define UX500_PLATFORM_PERIODS_MAX             48
+#define UX500_PLATFORM_BUFFER_BYTES_MAX                (2048 * PAGE_SIZE)
+
+#endif