Merge branch 'for-2.6.39' into for-2.6.40
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Sun, 3 Apr 2011 10:29:43 +0000 (19:29 +0900)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Sun, 3 Apr 2011 10:29:43 +0000 (19:29 +0900)
44 files changed:
include/linux/mfd/wm8994/pdata.h
include/sound/soc.h
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/au1x/db1200.c
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/blackfin/bf5xx-ad193x.c
sound/soc/blackfin/bf5xx-ad1980.c
sound/soc/blackfin/bf5xx-ad73311.c
sound/soc/blackfin/bf5xx-i2s-pcm.c
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-sport.c
sound/soc/blackfin/bf5xx-sport.h
sound/soc/blackfin/bf5xx-ssm2602.c
sound/soc/blackfin/bf5xx-tdm-pcm.c
sound/soc/blackfin/bf5xx-tdm.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ad193x.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/ad73311.c
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/cx20442.c
sound/soc/codecs/max98088.c
sound/soc/codecs/sn95031.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/wm8711.c
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8958-dsp2.c [new file with mode: 0644]
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/imx/imx-ssi.c
sound/soc/pxa/corgi.c
sound/soc/pxa/poodle.c
sound/soc/soc-cache.c
sound/soc/soc-core.c

index 466b1c7..d12f8d6 100644 (file)
@@ -32,6 +32,10 @@ struct wm8994_ldo_pdata {
 #define WM8994_EQ_REGS  20
 #define WM8958_MBC_CUTOFF_REGS 20
 #define WM8958_MBC_COEFF_REGS  48
+#define WM8958_MBC_COMBINED_REGS 56
+#define WM8958_VSS_HPF_REGS 2
+#define WM8958_VSS_REGS 148
+#define WM8958_ENH_EQ_REGS 32
 
 /**
  * DRC configurations are specified with a label and a set of register
@@ -71,6 +75,42 @@ struct wm8958_mbc_cfg {
        const char *name;
        u16 cutoff_regs[WM8958_MBC_CUTOFF_REGS];
        u16 coeff_regs[WM8958_MBC_COEFF_REGS];
+
+       /* Coefficient layout when using MBC+VSS firmware */
+       u16 combined_regs[WM8958_MBC_COMBINED_REGS];
+};
+
+/**
+ * VSS HPF configurations are specified with a label and two values to
+ * write.  Configurations are expected to be generated using the
+ * multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_vss_hpf_cfg {
+       const char *name;
+       u16 regs[WM8958_VSS_HPF_REGS];
+};
+
+/**
+ * VSS configurations are specified with a label and array of values
+ * to write.  Configurations are expected to be generated using the
+ * multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_vss_cfg {
+       const char *name;
+       u16 regs[WM8958_VSS_REGS];
+};
+
+/**
+ * Enhanced EQ configurations are specified with a label and array of
+ * values to write.  Configurations are expected to be generated using
+ * the multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_enh_eq_cfg {
+       const char *name;
+       u16 regs[WM8958_ENH_EQ_REGS];
 };
 
 struct wm8994_pdata {
@@ -95,6 +135,15 @@ struct wm8994_pdata {
        int num_mbc_cfgs;
        struct wm8958_mbc_cfg *mbc_cfgs;
 
+       int num_vss_cfgs;
+       struct wm8958_vss_cfg *vss_cfgs;
+
+       int num_vss_hpf_cfgs;
+       struct wm8958_vss_hpf_cfg *vss_hpf_cfgs;
+
+       int num_enh_eq_cfgs;
+       struct wm8958_enh_eq_cfg *enh_eq_cfgs;
+
         /* LINEOUT can be differential or single ended */
         unsigned int lineout1_diff:1;
         unsigned int lineout2_diff:1;
index bfa4836..2720a9f 100644 (file)
@@ -248,7 +248,7 @@ typedef int (*hw_write_t)(void *,const char* ,int);
 extern struct snd_ac97_bus_ops soc_ac97_ops;
 
 enum snd_soc_control_type {
-       SND_SOC_CUSTOM,
+       SND_SOC_CUSTOM = 1,
        SND_SOC_I2C,
        SND_SOC_SPI,
 };
@@ -278,6 +278,10 @@ int snd_soc_register_codec(struct device *dev,
 void snd_soc_unregister_codec(struct device *dev);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
                                    unsigned int reg);
+int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
+                                   unsigned int reg);
+int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
+                                   unsigned int reg);
 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
                               int addr_bits, int data_bits,
                               enum snd_soc_control_type control);
@@ -292,6 +296,8 @@ int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
                                      unsigned int reg);
 int snd_soc_default_readable_register(struct snd_soc_codec *codec,
                                      unsigned int reg);
+int snd_soc_default_writable_register(struct snd_soc_codec *codec,
+                                     unsigned int reg);
 
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
@@ -523,6 +529,7 @@ struct snd_soc_codec {
        size_t reg_size;        /* reg_cache_size * reg_word_size */
        int (*volatile_register)(struct snd_soc_codec *, unsigned int);
        int (*readable_register)(struct snd_soc_codec *, unsigned int);
+       int (*writable_register)(struct snd_soc_codec *, unsigned int);
 
        /* runtime */
        struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
@@ -539,10 +546,12 @@ struct snd_soc_codec {
 
        /* codec IO */
        void *control_data; /* codec control (i2c/3wire) data */
+       enum snd_soc_control_type control_type;
        hw_write_t hw_write;
        unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
        unsigned int (*read)(struct snd_soc_codec *, unsigned int);
        int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+       int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t);
        void *reg_cache;
        const void *reg_def_copy;
        const struct snd_soc_cache_ops *cache_ops;
@@ -587,6 +596,7 @@ struct snd_soc_codec_driver {
                                size_t, unsigned int);
        int (*volatile_register)(struct snd_soc_codec *, unsigned int);
        int (*readable_register)(struct snd_soc_codec *, unsigned int);
+       int (*writable_register)(struct snd_soc_codec *, unsigned int);
        short reg_cache_size;
        short reg_cache_step;
        short reg_word_size;
@@ -814,6 +824,8 @@ struct soc_enum {
 unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
 unsigned int snd_soc_write(struct snd_soc_codec *codec,
                           unsigned int reg, unsigned int val);
+unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec,
+                                   unsigned int reg, const void *data, size_t len);
 
 /* device driver data */
 
index af3c730..28afbbf 100644 (file)
@@ -184,7 +184,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
        .codec_dai_name = "wm8731-hifi",
        .init = at91sam9g20ek_wm8731_init,
        .platform_name = "atmel-pcm-audio",
-       .codec_name = "wm8731-codec.0-001b",
+       .codec_name = "wm8731.0-001b",
        .ops = &at91sam9g20ek_ops,
 };
 
index cb99f04..1d3e258 100644 (file)
@@ -77,7 +77,7 @@ static struct snd_soc_dai_link db1200_i2s_dai = {
        .codec_dai_name = "wm8731-hifi",
        .cpu_dai_name   = "au1xpsc_i2s.1",
        .platform_name  = "au1xpsc-pcm.1",
-       .codec_name     = "wm8731-codec.0-001b",
+       .codec_name     = "wm8731.0-001b",
        .ops            = &db1200_i2s_wm8731_ops,
 };
 
index 5a2fd8a..98b44b3 100644 (file)
@@ -243,6 +243,9 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
        struct snd_pcm_runtime *runtime = substream->runtime;
        int ret;
 
@@ -314,6 +317,9 @@ static struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
 
 static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 {
+       struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
        struct snd_pcm_substream *substream = pcm->streams[stream].substream;
        struct snd_dma_buffer *buf = &substream->dma_buffer;
        size_t size = bf5xx_pcm_hardware.buffer_bytes_max
@@ -377,6 +383,9 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
        struct snd_dma_buffer *buf;
        int stream;
 #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
+       struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
        size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
                sizeof(struct ac97_frame) / 4;
 #endif
@@ -405,8 +414,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
        }
 #endif
        }
-       if (sport_handle)
-               sport_done(sport_handle);
 }
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -458,7 +465,7 @@ static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 
 static struct platform_driver bf5xx_pcm_driver = {
        .driver = {
-                       .name = "bf5xx-pcm-audio",
+                       .name = "bfin-ac97-pcm-audio",
                        .owner = THIS_MODULE,
        },
 
index ffbac26..6d21625 100644 (file)
  *             anomaly does not affect blackfin sound drivers.
 */
 
-static int *cmd_count;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-#define SPORT_REQ(x) \
-       [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
-              P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
-static u16 sport_req[][7] = {
-#ifdef SPORT0_TCR1
-       SPORT_REQ(0),
-#endif
-#ifdef SPORT1_TCR1
-       SPORT_REQ(1),
-#endif
-#ifdef SPORT2_TCR1
-       SPORT_REQ(2),
-#endif
-#ifdef SPORT3_TCR1
-       SPORT_REQ(3),
-#endif
-};
-
-#define SPORT_PARAMS(x) \
-       [x] = { \
-               .dma_rx_chan = CH_SPORT##x##_RX, \
-               .dma_tx_chan = CH_SPORT##x##_TX, \
-               .err_irq     = IRQ_SPORT##x##_ERROR, \
-               .regs        = (struct sport_register *)SPORT##x##_TCR1, \
-       }
-static struct sport_param sport_params[4] = {
-#ifdef SPORT0_TCR1
-       SPORT_PARAMS(0),
-#endif
-#ifdef SPORT1_TCR1
-       SPORT_PARAMS(1),
-#endif
-#ifdef SPORT2_TCR1
-       SPORT_PARAMS(2),
-#endif
-#ifdef SPORT3_TCR1
-       SPORT_PARAMS(3),
-#endif
-};
+static struct sport_device *ac97_sport_handle;
 
 void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
                size_t count, unsigned int chan_mask)
@@ -140,7 +99,8 @@ static unsigned int sport_tx_curr_frag(struct sport_device *sport)
 
 static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 {
-       struct sport_device *sport = sport_handle;
+       struct sport_device *sport = ac97_sport_handle;
+       int *cmd_count = sport->private_data;
        int nextfrag = sport_tx_curr_frag(sport);
        struct ac97_frame *nextwrite;
 
@@ -161,6 +121,7 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
        unsigned short reg)
 {
+       struct sport_device *sport_handle = ac97_sport_handle;
        struct ac97_frame out_frame[2], in_frame[2];
 
        pr_debug("%s enter 0x%x\n", __func__, reg);
@@ -185,6 +146,8 @@ static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
 void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
        unsigned short val)
 {
+       struct sport_device *sport_handle = ac97_sport_handle;
+
        pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val);
 
        if (sport_handle->tx_run) {
@@ -203,28 +166,19 @@ void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 
 static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97)
 {
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF561) || \
- (defined(BF537_FAMILY) && (CONFIG_SND_BF5XX_SPORT_NUM == 1))
-
-#define CONCAT(a, b, c) a ## b ## c
-#define BFIN_SPORT_RFS(x) CONCAT(P_SPORT, x, _RFS)
-
-       u16 per = BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM);
-       u16 gpio = P_IDENT(BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM));
+       struct sport_device *sport_handle = ac97_sport_handle;
+       u16 gpio = P_IDENT(sport_handle->pin_req[3]);
 
        pr_debug("%s enter\n", __func__);
 
-       peripheral_free(per);
+       peripheral_free_list(sport_handle->pin_req);
        gpio_request(gpio, "bf5xx-ac97");
        gpio_direction_output(gpio, 1);
        udelay(2);
        gpio_set_value(gpio, 0);
        udelay(1);
        gpio_free(gpio);
-       peripheral_request(per, "soc-audio");
-#else
-       pr_info("%s: Not implemented\n", __func__);
-#endif
+       peripheral_request_list(sport_handle->pin_req, "soc-audio");
 }
 
 static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
@@ -306,18 +260,32 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 #define bf5xx_ac97_resume      NULL
 #endif
 
-static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
+static struct snd_soc_dai_driver bfin_ac97_dai = {
+       .ac97_control = 1,
+       .suspend = bf5xx_ac97_suspend,
+       .resume = bf5xx_ac97_resume,
+       .playback = {
+               .stream_name = "AC97 Playback",
+               .channels_min = 2,
+#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
+               .channels_max = 6,
+#else
+               .channels_max = 2,
+#endif
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+       .capture = {
+               .stream_name = "AC97 Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+
+static int __devinit asoc_bfin_ac97_probe(struct platform_device *pdev)
 {
-       int ret = 0;
-       cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
-       if (cmd_count == NULL)
-               return -ENOMEM;
-
-       if (peripheral_request_list(sport_req[sport_num], "soc-audio")) {
-               pr_err("Requesting Peripherals failed\n");
-               ret =  -EFAULT;
-               goto peripheral_err;
-       }
+       struct sport_device *sport_handle;
+       int ret;
 
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        /* Request PB3 as reset pin */
@@ -329,12 +297,14 @@ static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
        }
        gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
 #endif
-       sport_handle = sport_init(&sport_params[sport_num], 2, \
-                       sizeof(struct ac97_frame), NULL);
+
+       sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame),
+               PAGE_SIZE);
        if (!sport_handle) {
                ret = -ENODEV;
                goto sport_err;
        }
+
        /*SPORT works in TDM mode to simulate AC97 transfers*/
 #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
        ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1);
@@ -361,67 +331,37 @@ static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
                goto sport_config_err;
        }
 
+       ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+       if (ret) {
+               pr_err("Failed to register DAI: %d\n", ret);
+               goto sport_config_err;
+       }
+
+       ac97_sport_handle = sport_handle;
+
        return 0;
 
 sport_config_err:
-       kfree(sport_handle);
+       sport_done(sport_handle);
 sport_err:
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 gpio_err:
 #endif
-       peripheral_free_list(sport_req[sport_num]);
-peripheral_err:
-       free_page((unsigned long)cmd_count);
-       cmd_count = NULL;
 
        return ret;
 }
 
-static int bf5xx_ac97_remove(struct snd_soc_dai *dai)
+static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
 {
-       free_page((unsigned long)cmd_count);
-       cmd_count = NULL;
-       peripheral_free_list(sport_req[sport_num]);
+       struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_dai(&pdev->dev);
+       sport_done(sport_handle);
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 #endif
-       return 0;
-}
-
-struct snd_soc_dai_driver bfin_ac97_dai = {
-       .ac97_control = 1,
-       .probe = bf5xx_ac97_probe,
-       .remove = bf5xx_ac97_remove,
-       .suspend = bf5xx_ac97_suspend,
-       .resume = bf5xx_ac97_resume,
-       .playback = {
-               .stream_name = "AC97 Playback",
-               .channels_min = 2,
-#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
-               .channels_max = 6,
-#else
-               .channels_max = 2,
-#endif
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
-       .capture = {
-               .stream_name = "AC97 Capture",
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
-};
-EXPORT_SYMBOL_GPL(bfin_ac97_dai);
-
-static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev)
-{
-       return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
-}
 
-static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_dai(&pdev->dev);
        return 0;
 }
 
index 83012da..ea4951c 100644 (file)
 #include <asm/portmux.h>
 
 #include "../codecs/ad1836.h"
-#include "bf5xx-sport.h"
 
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm.h"
 
 static struct snd_soc_card bf5xx_ad1836;
 
-static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-       return 0;
-}
-
 static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
@@ -75,23 +65,33 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_ops bf5xx_ad1836_ops = {
-       .startup = bf5xx_ad1836_startup,
        .hw_params = bf5xx_ad1836_hw_params,
 };
 
-static struct snd_soc_dai_link bf5xx_ad1836_dai = {
-       .name = "ad1836",
-       .stream_name = "AD1836",
-       .cpu_dai_name = "bf5xx-tdm",
-       .codec_dai_name = "ad1836-hifi",
-       .platform_name = "bf5xx-tdm-pcm-audio",
-       .codec_name = "ad1836-codec.0",
-       .ops = &bf5xx_ad1836_ops,
+static struct snd_soc_dai_link bf5xx_ad1836_dai[] = {
+       {
+               .name = "ad1836",
+               .stream_name = "AD1836",
+               .cpu_dai_name = "bfin-tdm.0",
+               .codec_dai_name = "ad1836-hifi",
+               .platform_name = "bfin-tdm-pcm-audio",
+               .codec_name = "ad1836.0",
+               .ops = &bf5xx_ad1836_ops,
+       },
+       {
+               .name = "ad1836",
+               .stream_name = "AD1836",
+               .cpu_dai_name = "bfin-tdm.1",
+               .codec_dai_name = "ad1836-hifi",
+               .platform_name = "bfin-tdm-pcm-audio",
+               .codec_name = "ad1836.0",
+               .ops = &bf5xx_ad1836_ops,
+       },
 };
 
 static struct snd_soc_card bf5xx_ad1836 = {
-       .name = "bf5xx_ad1836",
-       .dai_link = &bf5xx_ad1836_dai,
+       .name = "bfin-ad1836",
+       .dai_link = &bf5xx_ad1836_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
 
index d3ccb92..d6651c0 100644 (file)
 #include <asm/portmux.h>
 
 #include "../codecs/ad193x.h"
-#include "bf5xx-sport.h"
 
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm.h"
 
 static struct snd_soc_card bf5xx_ad193x;
 
-static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-       return 0;
-}
-
 static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       unsigned int clk = 0;
        unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
        int ret = 0;
+
+       switch (params_rate(params)) {
+       case 48000:
+               clk = 12288000;
+               break;
+       }
+
        /* set cpu DAI configuration */
        ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
                SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
@@ -74,6 +72,12 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
+       /* set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
+               SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
        /* set codec DAI slots, 8 channels, all channels are enabled */
        ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32);
        if (ret < 0)
@@ -89,23 +93,33 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_ops bf5xx_ad193x_ops = {
-       .startup = bf5xx_ad193x_startup,
        .hw_params = bf5xx_ad193x_hw_params,
 };
 
-static struct snd_soc_dai_link bf5xx_ad193x_dai = {
-       .name = "ad193x",
-       .stream_name = "AD193X",
-       .cpu_dai_name = "bf5xx-tdm",
-       .codec_dai_name ="ad193x-hifi",
-       .platform_name = "bf5xx-tdm-pcm-audio",
-       .codec_name = "ad193x-codec.5",
-       .ops = &bf5xx_ad193x_ops,
+static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
+       {
+               .name = "ad193x",
+               .stream_name = "AD193X",
+               .cpu_dai_name = "bfin-tdm.0",
+               .codec_dai_name ="ad193x-hifi",
+               .platform_name = "bfin-tdm-pcm-audio",
+               .codec_name = "ad193x.5",
+               .ops = &bf5xx_ad193x_ops,
+       },
+       {
+               .name = "ad193x",
+               .stream_name = "AD193X",
+               .cpu_dai_name = "bfin-tdm.1",
+               .codec_dai_name ="ad193x-hifi",
+               .platform_name = "bfin-tdm-pcm-audio",
+               .codec_name = "ad193x.5",
+               .ops = &bf5xx_ad193x_ops,
+       },
 };
 
 static struct snd_soc_card bf5xx_ad193x = {
-       .name = "bf5xx_ad193x",
-       .dai_link = &bf5xx_ad193x_dai,
+       .name = "bfin-ad193x",
+       .dai_link = &bf5xx_ad193x_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
 
index d57c9c9..06a84b2 100644 (file)
 #include <asm/portmux.h>
 
 #include "../codecs/ad1980.h"
-#include "bf5xx-sport.h"
+
 #include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97.h"
 
 static struct snd_soc_card bf5xx_board;
 
-static int bf5xx_board_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       pr_debug("%s enter\n", __func__);
-       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-       return 0;
-}
-
-static struct snd_soc_ops bf5xx_board_ops = {
-       .startup = bf5xx_board_startup,
-};
-
-static struct snd_soc_dai_link bf5xx_board_dai = {
-       .name = "AC97",
-       .stream_name = "AC97 HiFi",
-       .cpu_dai_name = "bfin-ac97",
-       .codec_dai_name = "ad1980-hifi",
-       .platform_name = "bfin-pcm-audio",
-       .codec_name = "ad1980-codec",
-       .ops = &bf5xx_board_ops,
+static struct snd_soc_dai_link bf5xx_board_dai[] = {
+       {
+               .name = "AC97",
+               .stream_name = "AC97 HiFi",
+               .cpu_dai_name = "bfin-ac97.0",
+               .codec_dai_name = "ad1980-hifi",
+               .platform_name = "bfin-ac97-pcm-audio",
+               .codec_name = "ad1980",
+       },
+       {
+               .name = "AC97",
+               .stream_name = "AC97 HiFi",
+               .cpu_dai_name = "bfin-ac97.1",
+               .codec_dai_name = "ad1980-hifi",
+               .platform_name = "bfin-ac97-pcm-audio",
+               .codec_name = "ad1980",
+       },
 };
 
 static struct snd_soc_card bf5xx_board = {
-       .name = "bf5xx-board",
-       .dai_link = &bf5xx_board_dai,
+       .name = "bfin-ad1980",
+       .dai_link = &bf5xx_board_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
 
index 732fb8b..732a247 100644 (file)
@@ -145,16 +145,6 @@ static int bf5xx_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       pr_debug("%s enter\n", __func__);
-       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-       return 0;
-}
-
 static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
@@ -176,24 +166,34 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
 
 
 static struct snd_soc_ops bf5xx_ad73311_ops = {
-       .startup = bf5xx_ad73311_startup,
        .hw_params = bf5xx_ad73311_hw_params,
 };
 
-static struct snd_soc_dai_link bf5xx_ad73311_dai = {
-       .name = "ad73311",
-       .stream_name = "AD73311",
-       .cpu_dai_name = "bf5xx-i2s",
-       .codec_dai_name = "ad73311-hifi",
-       .platform_name = "bfin-pcm-audio",
-       .codec_name = "ad73311-codec",
-       .ops = &bf5xx_ad73311_ops,
+static struct snd_soc_dai_link bf5xx_ad73311_dai[] = {
+       {
+               .name = "ad73311",
+               .stream_name = "AD73311",
+               .cpu_dai_name = "bfin-i2s.0",
+               .codec_dai_name = "ad73311-hifi",
+               .platform_name = "bfin-i2s-pcm-audio",
+               .codec_name = "ad73311",
+               .ops = &bf5xx_ad73311_ops,
+       },
+       {
+               .name = "ad73311",
+               .stream_name = "AD73311",
+               .cpu_dai_name = "bfin-i2s.1",
+               .codec_dai_name = "ad73311-hifi",
+               .platform_name = "bfin-i2s-pcm-audio",
+               .codec_name = "ad73311",
+               .ops = &bf5xx_ad73311_ops,
+       },
 };
 
 static struct snd_soc_card bf5xx_ad73311 = {
-       .name = "bf5xx_ad73311",
+       .name = "bfin-ad73311",
        .probe = bf5xx_probe,
-       .dai_link = &bf5xx_ad73311_dai,
+       .dai_link = &bf5xx_ad73311_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
 
index 890a0dc..b5101ef 100644 (file)
@@ -148,10 +148,15 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
        int ret;
 
        pr_debug("%s enter\n", __func__);
+
        snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
 
        ret = snd_pcm_hw_constraint_integer(runtime, \
@@ -159,9 +164,14 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
        if (ret < 0)
                goto out;
 
-       if (sport_handle != NULL)
+       if (sport_handle != NULL) {
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       sport_handle->tx_buf = buf->area;
+               else
+                       sport_handle->rx_buf = buf->area;
+
                runtime->private_data = sport_handle;
-       else {
+       else {
                pr_err("sport_handle is NULL\n");
                return -1;
        }
@@ -214,11 +224,6 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
        pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
                buf->area, buf->bytes);
 
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-               sport_handle->tx_buf = buf->area;
-       else
-               sport_handle->rx_buf = buf->area;
-
        return 0;
 }
 
@@ -239,8 +244,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
                dma_free_coherent(NULL, buf->bytes, buf->area, 0);
                buf->area = NULL;
        }
-       if (sport_handle)
-               sport_done(sport_handle);
 }
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -292,7 +295,7 @@ static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
 
 static struct platform_driver bfin_i2s_pcm_driver = {
        .driver = {
-                       .name = "bfin-pcm-audio",
+                       .name = "bfin-i2s-pcm-audio",
                        .owner = THIS_MODULE,
        },
 
index d453b1e..00cc3e0 100644 (file)
@@ -51,59 +51,24 @@ struct bf5xx_i2s_port {
        int configured;
 };
 
-static struct bf5xx_i2s_port bf5xx_i2s;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-static struct sport_param sport_params[2] = {
-       {
-               .dma_rx_chan    = CH_SPORT0_RX,
-               .dma_tx_chan    = CH_SPORT0_TX,
-               .err_irq        = IRQ_SPORT0_ERROR,
-               .regs           = (struct sport_register *)SPORT0_TCR1,
-       },
-       {
-               .dma_rx_chan    = CH_SPORT1_RX,
-               .dma_tx_chan    = CH_SPORT1_TX,
-               .err_irq        = IRQ_SPORT1_ERROR,
-               .regs           = (struct sport_register *)SPORT1_TCR1,
-       }
-};
-
-/*
- * Setting the TFS pin selector for SPORT 0 based on whether the selected
- * port id F or G. If the port is F then no conflict should exist for the
- * TFS. When Port G is selected and EMAC then there is a conflict between
- * the PHY interrupt line and TFS.  Current settings prevent the conflict
- * by ignoring the TFS pin when Port G is selected. This allows both
- * codecs and EMAC using Port G concurrently.
- */
-#ifdef CONFIG_BF527_SPORT0_PORTG
-#define LOCAL_SPORT0_TFS (0)
-#else
-#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
-#endif
-
-static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-               P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
-               {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
-               P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
-
 static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
        int ret = 0;
 
        /* interface format:support I2S,slave mode */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
-               bf5xx_i2s.tcr1 |= TFSR | TCKFE;
-               bf5xx_i2s.rcr1 |= RFSR | RCKFE;
-               bf5xx_i2s.tcr2 |= TSFSE;
-               bf5xx_i2s.rcr2 |= RSFSE;
+               bf5xx_i2s->tcr1 |= TFSR | TCKFE;
+               bf5xx_i2s->rcr1 |= RFSR | RCKFE;
+               bf5xx_i2s->tcr2 |= TSFSE;
+               bf5xx_i2s->rcr2 |= RSFSE;
                break;
        case SND_SOC_DAIFMT_DSP_A:
-               bf5xx_i2s.tcr1 |= TFSR;
-               bf5xx_i2s.rcr1 |= RFSR;
+               bf5xx_i2s->tcr1 |= TFSR;
+               bf5xx_i2s->rcr1 |= RFSR;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
                ret = -EINVAL;
@@ -135,29 +100,35 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
        int ret = 0;
 
-       bf5xx_i2s.tcr2 &= ~0x1f;
-       bf5xx_i2s.rcr2 &= ~0x1f;
+       bf5xx_i2s->tcr2 &= ~0x1f;
+       bf5xx_i2s->rcr2 &= ~0x1f;
        switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               bf5xx_i2s->tcr2 |= 7;
+               bf5xx_i2s->rcr2 |= 7;
+               sport_handle->wdsize = 1;
        case SNDRV_PCM_FORMAT_S16_LE:
-               bf5xx_i2s.tcr2 |= 15;
-               bf5xx_i2s.rcr2 |= 15;
+               bf5xx_i2s->tcr2 |= 15;
+               bf5xx_i2s->rcr2 |= 15;
                sport_handle->wdsize = 2;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
-               bf5xx_i2s.tcr2 |= 23;
-               bf5xx_i2s.rcr2 |= 23;
+               bf5xx_i2s->tcr2 |= 23;
+               bf5xx_i2s->rcr2 |= 23;
                sport_handle->wdsize = 3;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
-               bf5xx_i2s.tcr2 |= 31;
-               bf5xx_i2s.rcr2 |= 31;
+               bf5xx_i2s->tcr2 |= 31;
+               bf5xx_i2s->rcr2 |= 31;
                sport_handle->wdsize = 4;
                break;
        }
 
-       if (!bf5xx_i2s.configured) {
+       if (!bf5xx_i2s->configured) {
                /*
                 * TX and RX are not independent,they are enabled at the
                 * same time, even if only one side is running. So, we
@@ -166,16 +137,16 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
                 *
                 * CPU DAI:slave mode.
                 */
-               bf5xx_i2s.configured = 1;
-               ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
-                                     bf5xx_i2s.rcr2, 0, 0);
+               bf5xx_i2s->configured = 1;
+               ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
+                                     bf5xx_i2s->rcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
                }
 
-               ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
-                                     bf5xx_i2s.tcr2, 0, 0);
+               ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
+                                     bf5xx_i2s->tcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
@@ -188,41 +159,19 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
                               struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+
        pr_debug("%s enter\n", __func__);
        /* No active stream, SPORT is allowed to be configured again. */
        if (!dai->active)
-               bf5xx_i2s.configured = 0;
-}
-
-static int bf5xx_i2s_probe(struct snd_soc_dai *dai)
-{
-       pr_debug("%s enter\n", __func__);
-       if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
-               pr_err("Requesting Peripherals failed\n");
-               return -EFAULT;
-       }
-
-       /* request DMA for SPORT */
-       sport_handle = sport_init(&sport_params[sport_num], 4, \
-                       2 * sizeof(u32), NULL);
-       if (!sport_handle) {
-               peripheral_free_list(&sport_req[sport_num][0]);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static int bf5xx_i2s_remove(struct snd_soc_dai *dai)
-{
-       pr_debug("%s enter\n", __func__);
-       peripheral_free_list(&sport_req[sport_num][0]);
-       return 0;
+               bf5xx_i2s->configured = 0;
 }
 
 #ifdef CONFIG_PM
 static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
 
        pr_debug("%s : sport %d\n", __func__, dai->id);
 
@@ -235,19 +184,21 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 
 static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
        int ret;
 
        pr_debug("%s : sport %d\n", __func__, dai->id);
 
-       ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
-                                     bf5xx_i2s.rcr2, 0, 0);
+       ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
+                                     bf5xx_i2s->rcr2, 0, 0);
        if (ret) {
                pr_err("SPORT is busy!\n");
                return -EBUSY;
        }
 
-       ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
-                                     bf5xx_i2s.tcr2, 0, 0);
+       ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
+                                     bf5xx_i2s->tcr2, 0, 0);
        if (ret) {
                pr_err("SPORT is busy!\n");
                return -EBUSY;
@@ -266,8 +217,11 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
                SNDRV_PCM_RATE_96000)
 
-#define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
-       SNDRV_PCM_FMTBIT_S32_LE)
+#define BF5XX_I2S_FORMATS \
+       (SNDRV_PCM_FMTBIT_S8 | \
+        SNDRV_PCM_FMTBIT_S16_LE | \
+        SNDRV_PCM_FMTBIT_S24_LE | \
+        SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
        .shutdown       = bf5xx_i2s_shutdown,
@@ -276,8 +230,6 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
 };
 
 static struct snd_soc_dai_driver bf5xx_i2s_dai = {
-       .probe = bf5xx_i2s_probe,
-       .remove = bf5xx_i2s_remove,
        .suspend = bf5xx_i2s_suspend,
        .resume = bf5xx_i2s_resume,
        .playback = {
@@ -293,23 +245,45 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = {
        .ops = &bf5xx_i2s_dai_ops,
 };
 
-static int bfin_i2s_drv_probe(struct platform_device *pdev)
+static int __devinit bf5xx_i2s_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+       struct sport_device *sport_handle;
+       int ret;
+
+       /* configure SPORT for I2S */
+       sport_handle = sport_init(pdev, 4, 2 * sizeof(u32),
+               sizeof(struct bf5xx_i2s_port));
+       if (!sport_handle)
+               return -ENODEV;
+
+       /* register with the ASoC layers */
+       ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+       if (ret) {
+               pr_err("Failed to register DAI: %d\n", ret);
+               sport_done(sport_handle);
+               return ret;
+       }
+
+       return 0;
 }
 
-static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev)
+static int __devexit bf5xx_i2s_remove(struct platform_device *pdev)
 {
+       struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
+       pr_debug("%s enter\n", __func__);
+
        snd_soc_unregister_dai(&pdev->dev);
+       sport_done(sport_handle);
+
        return 0;
 }
 
 static struct platform_driver bfin_i2s_driver = {
-       .probe = bfin_i2s_drv_probe,
-       .remove = __devexit_p(bfin_i2s_drv_remove),
-
+       .probe  = bf5xx_i2s_probe,
+       .remove = __devexit_p(bf5xx_i2s_remove),
        .driver = {
-               .name = "bf5xx-i2s",
+               .name = "bfin-i2s",
                .owner = THIS_MODULE,
        },
 };
index 99051ff..a2d4034 100644 (file)
@@ -42,8 +42,6 @@
 /* delay between frame sync pulse and first data bit in multichannel mode */
 #define FRAME_DELAY (1<<12)
 
-struct sport_device *sport_handle;
-EXPORT_SYMBOL(sport_handle);
 /* note: multichannel is in units of 8 channels,
  * tdm_count is # channels NOT / 8 ! */
 int sport_set_multichannel(struct sport_device *sport,
@@ -798,86 +796,164 @@ int sport_set_err_callback(struct sport_device *sport,
 }
 EXPORT_SYMBOL(sport_set_err_callback);
 
-struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
-               unsigned dummy_count, void *private_data)
+static int sport_config_pdev(struct platform_device *pdev, struct sport_param *param)
 {
-       int ret;
+       /* Extract settings from platform data */
+       struct device *dev = &pdev->dev;
+       struct bfin_snd_platform_data *pdata = dev->platform_data;
+       struct resource *res;
+
+       param->num = pdev->id;
+
+       if (!pdata) {
+               dev_err(dev, "no platform_data\n");
+               return -ENODEV;
+       }
+       param->pin_req = pdata->pin_req;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "no MEM resource\n");
+               return -ENODEV;
+       }
+       param->regs = (struct sport_register *)res->start;
+
+       /* first RX, then TX */
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!res) {
+               dev_err(dev, "no rx DMA resource\n");
+               return -ENODEV;
+       }
+       param->dma_rx_chan = res->start;
+
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!res) {
+               dev_err(dev, "no tx DMA resource\n");
+               return -ENODEV;
+       }
+       param->dma_tx_chan = res->start;
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dev_err(dev, "no irq resource\n");
+               return -ENODEV;
+       }
+       param->err_irq = res->start;
+
+       return 0;
+}
+
+struct sport_device *sport_init(struct platform_device *pdev,
+       unsigned int wdsize, unsigned int dummy_count, size_t priv_size)
+{
+       struct device *dev = &pdev->dev;
+       struct sport_param param;
        struct sport_device *sport;
-       pr_debug("%s enter\n", __func__);
-       BUG_ON(param == NULL);
-       BUG_ON(wdsize == 0 || dummy_count == 0);
-       sport = kmalloc(sizeof(struct sport_device), GFP_KERNEL);
-       if (!sport) {
-               pr_err("Failed to allocate for sport device\n");
+       int ret;
+
+       dev_dbg(dev, "%s enter\n", __func__);
+
+       param.wdsize = wdsize;
+       param.dummy_count = dummy_count;
+       BUG_ON(param.wdsize == 0 || param.dummy_count == 0);
+
+       ret = sport_config_pdev(pdev, &param);
+       if (ret)
+               return NULL;
+
+       if (peripheral_request_list(param.pin_req, "soc-audio")) {
+               dev_err(dev, "requesting Peripherals failed\n");
                return NULL;
        }
 
-       memset(sport, 0, sizeof(struct sport_device));
-       sport->dma_rx_chan = param->dma_rx_chan;
-       sport->dma_tx_chan = param->dma_tx_chan;
-       sport->err_irq = param->err_irq;
-       sport->regs = param->regs;
-       sport->private_data = private_data;
+       sport = kzalloc(sizeof(*sport), GFP_KERNEL);
+       if (!sport) {
+               dev_err(dev, "failed to allocate for sport device\n");
+               goto __init_err0;
+       }
+
+       sport->num = param.num;
+       sport->dma_rx_chan = param.dma_rx_chan;
+       sport->dma_tx_chan = param.dma_tx_chan;
+       sport->err_irq = param.err_irq;
+       sport->regs = param.regs;
+       sport->pin_req = param.pin_req;
 
        if (request_dma(sport->dma_rx_chan, "SPORT RX Data") == -EBUSY) {
-               pr_err("Failed to request RX dma %d\n", \
-                               sport->dma_rx_chan);
+               dev_err(dev, "failed to request RX dma %d\n", sport->dma_rx_chan);
                goto __init_err1;
        }
        if (set_dma_callback(sport->dma_rx_chan, rx_handler, sport) != 0) {
-               pr_err("Failed to request RX irq %d\n", \
-                               sport->dma_rx_chan);
+               dev_err(dev, "failed to request RX irq %d\n", sport->dma_rx_chan);
                goto __init_err2;
        }
 
        if (request_dma(sport->dma_tx_chan, "SPORT TX Data") == -EBUSY) {
-               pr_err("Failed to request TX dma %d\n", \
-                               sport->dma_tx_chan);
+               dev_err(dev, "failed to request TX dma %d\n", sport->dma_tx_chan);
                goto __init_err2;
        }
 
        if (set_dma_callback(sport->dma_tx_chan, tx_handler, sport) != 0) {
-               pr_err("Failed to request TX irq %d\n", \
-                               sport->dma_tx_chan);
+               dev_err(dev, "failed to request TX irq %d\n", sport->dma_tx_chan);
                goto __init_err3;
        }
 
        if (request_irq(sport->err_irq, err_handler, IRQF_SHARED, "SPORT err",
                        sport) < 0) {
-               pr_err("Failed to request err irq:%d\n", \
-                               sport->err_irq);
+               dev_err(dev, "failed to request err irq %d\n", sport->err_irq);
                goto __init_err3;
        }
 
-       pr_err("dma rx:%d tx:%d, err irq:%d, regs:%p\n",
+       dev_info(dev, "dma rx:%d tx:%d, err irq:%d, regs:%p\n",
                        sport->dma_rx_chan, sport->dma_tx_chan,
                        sport->err_irq, sport->regs);
 
-       sport->wdsize = wdsize;
-       sport->dummy_count = dummy_count;
+       sport->wdsize = param.wdsize;
+       sport->dummy_count = param.dummy_count;
+
+       sport->private_data = kzalloc(priv_size, GFP_KERNEL);
+       if (!sport->private_data) {
+               dev_err(dev, "could not alloc priv data %zu bytes\n", priv_size);
+               goto __init_err4;
+       }
 
        if (L1_DATA_A_LENGTH)
-               sport->dummy_buf = l1_data_sram_zalloc(dummy_count * 2);
+               sport->dummy_buf = l1_data_sram_zalloc(param.dummy_count * 2);
        else
-               sport->dummy_buf = kzalloc(dummy_count * 2, GFP_KERNEL);
+               sport->dummy_buf = kzalloc(param.dummy_count * 2, GFP_KERNEL);
        if (sport->dummy_buf == NULL) {
-               pr_err("Failed to allocate dummy buffer\n");
-               goto __error;
+               dev_err(dev, "failed to allocate dummy buffer\n");
+               goto __error1;
        }
 
        ret = sport_config_rx_dummy(sport);
        if (ret) {
-               pr_err("Failed to config rx dummy ring\n");
-               goto __error;
+               dev_err(dev, "failed to config rx dummy ring\n");
+               goto __error2;
        }
        ret = sport_config_tx_dummy(sport);
        if (ret) {
-               pr_err("Failed to config tx dummy ring\n");
-               goto __error;
+               dev_err(dev, "failed to config tx dummy ring\n");
+               goto __error3;
        }
 
+       platform_set_drvdata(pdev, sport);
+
        return sport;
-__error:
+__error3:
+       if (L1_DATA_A_LENGTH)
+               l1_data_sram_free(sport->dummy_rx_desc);
+       else
+               dma_free_coherent(NULL, 2*sizeof(struct dmasg),
+                               sport->dummy_rx_desc, 0);
+__error2:
+       if (L1_DATA_A_LENGTH)
+               l1_data_sram_free(sport->dummy_buf);
+       else
+               kfree(sport->dummy_buf);
+__error1:
+       kfree(sport->private_data);
+__init_err4:
        free_irq(sport->err_irq, sport);
 __init_err3:
        free_dma(sport->dma_tx_chan);
@@ -885,6 +961,8 @@ __init_err2:
        free_dma(sport->dma_rx_chan);
 __init_err1:
        kfree(sport);
+__init_err0:
+       peripheral_free_list(param.pin_req);
        return NULL;
 }
 EXPORT_SYMBOL(sport_init);
@@ -917,8 +995,9 @@ void sport_done(struct sport_device *sport)
        free_dma(sport->dma_tx_chan);
        free_irq(sport->err_irq, sport);
 
+       kfree(sport->private_data);
+       peripheral_free_list(sport->pin_req);
        kfree(sport);
-               sport = NULL;
 }
 EXPORT_SYMBOL(sport_done);
 
index a86e8cc..5ab60bd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * File:         bf5xx_ac97_sport.h
+ * File:         bf5xx_sport.h
  * Based on:
  * Author:       Roy Huang <roy.huang@analog.com>
  *
 #include <linux/types.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
+#include <linux/platform_device.h>
 #include <asm/dma.h>
 #include <asm/bfin_sport.h>
 
 #define DESC_ELEMENT_COUNT 9
 
 struct sport_device {
+       int num;
        int dma_rx_chan;
        int dma_tx_chan;
        int err_irq;
+       const unsigned short *pin_req;
        struct sport_register *regs;
 
        unsigned char *rx_buf;
@@ -103,17 +106,20 @@ struct sport_device {
        void *private_data;
 };
 
-extern struct sport_device *sport_handle;
-
 struct sport_param {
+       int num;
        int dma_rx_chan;
        int dma_tx_chan;
        int err_irq;
+       const unsigned short *pin_req;
        struct sport_register *regs;
+       unsigned int wdsize;
+       unsigned int dummy_count;
+       void *private_data;
 };
 
-struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
-               unsigned dummy_count, void *private_data);
+struct sport_device *sport_init(struct platform_device *pdev,
+       unsigned int wdsize, unsigned int dummy_count, size_t priv_size);
 
 void sport_done(struct sport_device *sport);
 
index ad28663..767e772 100644 (file)
 
 static struct snd_soc_card bf5xx_ssm2602;
 
-static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       pr_debug("%s enter\n", __func__);
-       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-       return 0;
-}
-
 static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
@@ -109,23 +99,33 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_ops bf5xx_ssm2602_ops = {
-       .startup = bf5xx_ssm2602_startup,
        .hw_params = bf5xx_ssm2602_hw_params,
 };
 
-static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
-       .name = "ssm2602",
-       .stream_name = "SSM2602",
-       .cpu_dai_name = "bf5xx-i2s",
-       .codec_dai_name = "ssm2602-hifi",
-       .platform_name = "bf5xx-pcm-audio",
-       .codec_name = "ssm2602-codec.0-001b",
-       .ops = &bf5xx_ssm2602_ops,
+static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
+       {
+               .name = "ssm2602",
+               .stream_name = "SSM2602",
+               .cpu_dai_name = "bfin-i2s.0",
+               .codec_dai_name = "ssm2602-hifi",
+               .platform_name = "bfin-i2s-pcm-audio",
+               .codec_name = "ssm2602.0-001b",
+               .ops = &bf5xx_ssm2602_ops,
+       },
+       {
+               .name = "ssm2602",
+               .stream_name = "SSM2602",
+               .cpu_dai_name = "bfin-i2s.1",
+               .codec_dai_name = "ssm2602-hifi",
+               .platform_name = "bfin-i2s-pcm-audio",
+               .codec_name = "ssm2602.0-001b",
+               .ops = &bf5xx_ssm2602_ops,
+       },
 };
 
 static struct snd_soc_card bf5xx_ssm2602 = {
-       .name = "bf5xx_ssm2602",
-       .dai_link = &bf5xx_ssm2602_dai,
+       .name = "bfin-ssm2602",
+       .dai_link = &bf5xx_ssm2602_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
 
index 74cf759..07cfc7a 100644 (file)
@@ -154,7 +154,12 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
+
        int ret = 0;
 
        snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
@@ -164,9 +169,14 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
        if (ret < 0)
                goto out;
 
-       if (sport_handle != NULL)
+       if (sport_handle != NULL) {
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       sport_handle->tx_buf = buf->area;
+               else
+                       sport_handle->rx_buf = buf->area;
+
                runtime->private_data = sport_handle;
-       else {
+       else {
                pr_err("sport_handle is NULL\n");
                ret = -ENODEV;
        }
@@ -249,11 +259,6 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
        }
        buf->bytes = size;
 
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-               sport_handle->tx_buf = buf->area;
-       else
-               sport_handle->rx_buf = buf->area;
-
        return 0;
 }
 
@@ -274,8 +279,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
                dma_free_coherent(NULL, buf->bytes, buf->area, 0);
                buf->area = NULL;
        }
-       if (sport_handle)
-               sport_done(sport_handle);
 }
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -326,7 +329,7 @@ static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 
 static struct platform_driver bfin_tdm_driver = {
        .driver = {
-                       .name = "bf5xx-tdm-pcm-audio",
+                       .name = "bfin-tdm-pcm-audio",
                        .owner = THIS_MODULE,
        },
 
index 5515ac9..a822d1e 100644 (file)
 #include "bf5xx-sport.h"
 #include "bf5xx-tdm.h"
 
-static struct bf5xx_tdm_port bf5xx_tdm;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-static struct sport_param sport_params[2] = {
-       {
-               .dma_rx_chan    = CH_SPORT0_RX,
-               .dma_tx_chan    = CH_SPORT0_TX,
-               .err_irq        = IRQ_SPORT0_ERROR,
-               .regs           = (struct sport_register *)SPORT0_TCR1,
-       },
-       {
-               .dma_rx_chan    = CH_SPORT1_RX,
-               .dma_tx_chan    = CH_SPORT1_TX,
-               .err_irq        = IRQ_SPORT1_ERROR,
-               .regs           = (struct sport_register *)SPORT1_TCR1,
-       }
-};
-
-/*
- * Setting the TFS pin selector for SPORT 0 based on whether the selected
- * port id F or G. If the port is F then no conflict should exist for the
- * TFS. When Port G is selected and EMAC then there is a conflict between
- * the PHY interrupt line and TFS.  Current settings prevent the conflict
- * by ignoring the TFS pin when Port G is selected. This allows both
- * codecs and EMAC using Port G concurrently.
- */
-#ifdef CONFIG_BF527_SPORT0_PORTG
-#define LOCAL_SPORT0_TFS (0)
-#else
-#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
-#endif
-
-static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-       P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
-          {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
-                  P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
-
 static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        unsigned int fmt)
 {
@@ -119,14 +82,16 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
        int ret = 0;
 
-       bf5xx_tdm.tcr2 &= ~0x1f;
-       bf5xx_tdm.rcr2 &= ~0x1f;
+       bf5xx_tdm->tcr2 &= ~0x1f;
+       bf5xx_tdm->rcr2 &= ~0x1f;
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S32_LE:
-               bf5xx_tdm.tcr2 |= 31;
-               bf5xx_tdm.rcr2 |= 31;
+               bf5xx_tdm->tcr2 |= 31;
+               bf5xx_tdm->rcr2 |= 31;
                sport_handle->wdsize = 4;
                break;
                /* at present, we only support 32bit transfer */
@@ -136,7 +101,7 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       if (!bf5xx_tdm.configured) {
+       if (!bf5xx_tdm->configured) {
                /*
                 * TX and RX are not independent,they are enabled at the
                 * same time, even if only one side is running. So, we
@@ -145,21 +110,21 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
                 *
                 * CPU DAI:slave mode.
                 */
-               ret = sport_config_rx(sport_handle, bf5xx_tdm.rcr1,
-                       bf5xx_tdm.rcr2, 0, 0);
+               ret = sport_config_rx(sport_handle, bf5xx_tdm->rcr1,
+                       bf5xx_tdm->rcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
                }
 
-               ret = sport_config_tx(sport_handle, bf5xx_tdm.tcr1,
-                       bf5xx_tdm.tcr2, 0, 0);
+               ret = sport_config_tx(sport_handle, bf5xx_tdm->tcr1,
+                       bf5xx_tdm->tcr2, 0, 0);
                if (ret) {
                        pr_err("SPORT is busy!\n");
                        return -EBUSY;
                }
 
-               bf5xx_tdm.configured = 1;
+               bf5xx_tdm->configured = 1;
        }
 
        return 0;
@@ -168,15 +133,20 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
+
        /* No active stream, SPORT is allowed to be configured again. */
        if (!dai->active)
-               bf5xx_tdm.configured = 0;
+               bf5xx_tdm->configured = 0;
 }
 
 static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
                unsigned int tx_num, unsigned int *tx_slot,
                unsigned int rx_num, unsigned int *rx_slot)
 {
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
        int i;
        unsigned int slot;
        unsigned int tx_mapped = 0, rx_mapped = 0;
@@ -189,7 +159,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
                slot = tx_slot[i];
                if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
                                (!(tx_mapped & (1 << slot)))) {
-                       bf5xx_tdm.tx_map[i] = slot;
+                       bf5xx_tdm->tx_map[i] = slot;
                        tx_mapped |= 1 << slot;
                } else
                        return -EINVAL;
@@ -198,7 +168,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
                slot = rx_slot[i];
                if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
                                (!(rx_mapped & (1 << slot)))) {
-                       bf5xx_tdm.rx_map[i] = slot;
+                       bf5xx_tdm->rx_map[i] = slot;
                        rx_mapped |= 1 << slot;
                } else
                        return -EINVAL;
@@ -212,12 +182,14 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 {
        struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
-       if (!dai->active)
-               return 0;
-       if (dai->capture_active)
-               sport_rx_stop(sport);
        if (dai->playback_active)
                sport_tx_stop(sport);
+       if (dai->capture_active)
+               sport_rx_stop(sport);
+
+       /* isolate sync/clock pins from codec while sports resume */
+       peripheral_free_list(sport->pin_req);
+
        return 0;
 }
 
@@ -226,9 +198,6 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
        int ret;
        struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
-       if (!dai->active)
-               return 0;
-
        ret = sport_set_multichannel(sport, 8, 0xFF, 1);
        if (ret) {
                pr_err("SPORT is busy!\n");
@@ -247,6 +216,8 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
                ret = -EBUSY;
        }
 
+       peripheral_request_list(sport->pin_req, "soc-audio");
+
        return 0;
 }
 
@@ -280,20 +251,14 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = {
 
 static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 {
-       int ret = 0;
-
-       if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
-               pr_err("Requesting Peripherals failed\n");
-               return -EFAULT;
-       }
+       struct sport_device *sport_handle;
+       int ret;
 
-       /* request DMA for SPORT */
-       sport_handle = sport_init(&sport_params[sport_num], 4, \
-               8 * sizeof(u32), NULL);
-       if (!sport_handle) {
-               peripheral_free_list(&sport_req[sport_num][0]);
+       /* configure SPORT for TDM */
+       sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
+               sizeof(struct bf5xx_tdm_port));
+       if (!sport_handle)
                return -ENODEV;
-       }
 
        /* SPORT works in TDM mode */
        ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1);
@@ -323,18 +288,19 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
                goto sport_config_err;
        }
 
-       sport_handle->private_data = &bf5xx_tdm;
        return 0;
 
 sport_config_err:
-       peripheral_free_list(&sport_req[sport_num][0]);
+       sport_done(sport_handle);
        return ret;
 }
 
 static int __devexit bfin_tdm_remove(struct platform_device *pdev)
 {
-       peripheral_free_list(&sport_req[sport_num][0]);
+       struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
        snd_soc_unregister_dai(&pdev->dev);
+       sport_done(sport_handle);
 
        return 0;
 }
index 6943e24..b814ed0 100644 (file)
@@ -16,8 +16,8 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AD1836 if SPI_MASTER
        select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
        select SND_SOC_AD1980 if SND_SOC_AC97_BUS
+       select SND_SOC_AD73311
        select SND_SOC_ADS117X
-       select SND_SOC_AD73311 if I2C
        select SND_SOC_AK4104 if SPI_MASTER
        select SND_SOC_AK4535 if I2C
        select SND_SOC_AK4642 if I2C
index 379bc55..49121ad 100644 (file)
@@ -69,7 +69,7 @@ snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8991-objs := wm8991.o
 snd-soc-wm8993-objs := wm8993.o
-snd-soc-wm8994-objs := wm8994.o wm8994-tables.o
+snd-soc-wm8994-objs := wm8994.o wm8994-tables.o wm8958-dsp2.o
 snd-soc-wm8995-objs := wm8995.o
 snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9705-objs := wm9705.o
index da46479..2374ca5 100644 (file)
@@ -23,8 +23,7 @@
 
 /* codec private data */
 struct ad193x_priv {
-       enum snd_soc_control_type bus_type;
-       void *control_data;
+       enum snd_soc_control_type control_type;
        int sysclk;
 };
 
@@ -354,14 +353,12 @@ static int ad193x_probe(struct snd_soc_codec *codec)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
-       codec->control_data = ad193x->control_data;
-       if (ad193x->bus_type == SND_SOC_I2C)
-               ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type);
+       if (ad193x->control_type == SND_SOC_I2C)
+               ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->control_type);
        else
-               ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type);
+               ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->control_type);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to set cache I/O: %d\n",
-                               ret);
+               dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
@@ -408,8 +405,7 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi)
                return -ENOMEM;
 
        spi_set_drvdata(spi, ad193x);
-       ad193x->control_data = spi;
-       ad193x->bus_type = SND_SOC_SPI;
+       ad193x->control_type = SND_SOC_SPI;
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_ad193x, &ad193x_dai, 1);
@@ -427,7 +423,7 @@ static int __devexit ad193x_spi_remove(struct spi_device *spi)
 
 static struct spi_driver ad193x_spi_driver = {
        .driver = {
-               .name   = "ad193x-codec",
+               .name   = "ad193x",
                .owner  = THIS_MODULE,
        },
        .probe          = ad193x_spi_probe,
@@ -454,8 +450,7 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client,
                return -ENOMEM;
 
        i2c_set_clientdata(client, ad193x);
-       ad193x->control_data = client;
-       ad193x->bus_type = SND_SOC_I2C;
+       ad193x->control_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&client->dev,
                        &soc_codec_dev_ad193x, &ad193x_dai, 1);
@@ -473,7 +468,7 @@ static int __devexit ad193x_i2c_remove(struct i2c_client *client)
 
 static struct i2c_driver ad193x_i2c_driver = {
        .driver = {
-               .name = "ad193x-codec",
+               .name = "ad193x",
        },
        .probe    = ad193x_i2c_probe,
        .remove   = __devexit_p(ad193x_i2c_remove),
index 34cb51e..923b364 100644 (file)
@@ -266,7 +266,7 @@ static int __devexit ad1980_remove(struct platform_device *pdev)
 
 static struct platform_driver ad1980_codec_driver = {
        .driver = {
-                       .name = "ad1980-codec",
+                       .name = "ad1980",
                        .owner = THIS_MODULE,
        },
 
index de799cd..8d793e9 100644 (file)
@@ -55,7 +55,7 @@ static int __devexit ad73311_remove(struct platform_device *pdev)
 
 static struct platform_driver ad73311_codec_driver = {
        .driver = {
-                       .name = "ad73311-codec",
+                       .name = "ad73311",
                        .owner = THIS_MODULE,
        },
 
index 8b38739..e1a214e 100644 (file)
@@ -230,7 +230,7 @@ static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("AIN"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route ak4535_audio_map[] = {
        /*stereo mixer */
        {"Stereo Mixer", "Playback Switch", "DAC"},
        {"Stereo Mixer", "Mic Sidetone Switch", "Mic"},
@@ -287,17 +287,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Input Mixer", "Aux Capture Switch", "Aux In"},
 };
 
-static int ak4535_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, ak4535_dapm_widgets,
-                                 ARRAY_SIZE(ak4535_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        int clk_id, unsigned int freq, int dir)
 {
@@ -457,8 +446,6 @@ static int ak4535_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, ak4535_snd_controls,
                                ARRAY_SIZE(ak4535_snd_controls));
-       ak4535_add_widgets(codec);
-
        return 0;
 }
 
@@ -480,6 +467,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
        .reg_cache_size = ARRAY_SIZE(ak4535_reg),
        .reg_word_size = sizeof(u8),
        .reg_cache_default = ak4535_reg,
+       .dapm_widgets = ak4535_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
+       .dapm_routes = ak4535_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(ak4535_audio_map),
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
index 2ec75ab..88b29f8 100644 (file)
@@ -352,7 +352,7 @@ static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route ak4671_intercon[] = {
        {"DAC Left", "NULL", "PMPLL"},
        {"DAC Right", "NULL", "PMPLL"},
        {"ADC Left", "NULL", "PMPLL"},
@@ -433,17 +433,6 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"},
 };
 
-static int ak4671_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, ak4671_dapm_widgets,
-                                 ARRAY_SIZE(ak4671_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 static int ak4671_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params,
                struct snd_soc_dai *dai)
@@ -650,7 +639,6 @@ static int ak4671_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, ak4671_snd_controls,
                             ARRAY_SIZE(ak4671_snd_controls));
-       ak4671_add_widgets(codec);
 
        ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -670,6 +658,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
        .reg_cache_size = AK4671_CACHEREGNUM,
        .reg_word_size = sizeof(u8),
        .reg_cache_default = ak4671_reg,
+       .dapm_widgets = ak4671_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets),
+       .dapm_routes = ak4671_intercon,
+       .num_dapm_routes = ARRAY_SIZE(ak4671_intercon),
 };
 
 static int __devinit ak4671_i2c_probe(struct i2c_client *client,
index 0bb424a..d68ea53 100644 (file)
@@ -86,18 +86,6 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = {
        {"ADC", NULL, "Input Mixer"},
 };
 
-static int cx20442_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, cx20442_dapm_widgets,
-                                 ARRAY_SIZE(cx20442_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, cx20442_audio_map,
-                               ARRAY_SIZE(cx20442_audio_map));
-
-       return 0;
-}
-
 static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
                                                        unsigned int reg)
 {
@@ -344,8 +332,6 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec)
                return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, cx20442);
 
-       cx20442_add_widgets(codec);
-
        cx20442->control_data = NULL;
        codec->hw_write = NULL;
        codec->card->pop_time = 0;
@@ -377,6 +363,10 @@ static struct snd_soc_codec_driver cx20442_codec_dev = {
        .reg_word_size = sizeof(u8),
        .read = cx20442_read_reg_cache,
        .write = cx20442_write,
+       .dapm_widgets = cx20442_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets),
+       .dapm_routes = cx20442_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(cx20442_audio_map),
 };
 
 static int cx20442_platform_probe(struct platform_device *pdev)
index bd0517c..bb58bdb 100644 (file)
@@ -1112,7 +1112,7 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("INB2"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route max98088_audio_map[] = {
        /* Left headphone output mixer */
        {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
        {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
@@ -1226,22 +1226,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MIC2 Input", NULL, "MIC2"},
 };
 
-static int max98088_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, max98088_dapm_widgets,
-                                 ARRAY_SIZE(max98088_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       snd_soc_add_controls(codec, max98088_snd_controls,
-                            ARRAY_SIZE(max98088_snd_controls));
-
-       snd_soc_dapm_new_widgets(dapm);
-       return 0;
-}
-
 /* codec mclk clock divider coefficients */
 static const struct {
        u32 rate;
@@ -2010,7 +1994,8 @@ static int max98088_probe(struct snd_soc_codec *codec)
 
        max98088_handle_pdata(codec);
 
-       max98088_add_widgets(codec);
+       snd_soc_add_controls(codec, max98088_snd_controls,
+                            ARRAY_SIZE(max98088_snd_controls));
 
 err_access:
        return ret;
@@ -2036,6 +2021,10 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
        .reg_word_size = sizeof(u8),
        .reg_cache_default = max98088_reg,
        .volatile_register = max98088_volatile_register,
+       .dapm_widgets = max98088_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets),
+       .dapm_routes = max98088_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(max98088_audio_map),
 };
 
 static int max98088_i2c_probe(struct i2c_client *i2c,
index 2a30eae..569555f 100644 (file)
@@ -825,8 +825,6 @@ EXPORT_SYMBOL_GPL(sn95031_jack_detection);
 /* codec registration */
 static int sn95031_codec_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-
        pr_debug("codec_probe called\n");
 
        codec->dapm.bias_level = SND_SOC_BIAS_OFF;
@@ -877,16 +875,7 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
        snd_soc_add_controls(codec, sn95031_snd_controls,
                             ARRAY_SIZE(sn95031_snd_controls));
 
-       ret = snd_soc_dapm_new_controls(&codec->dapm, sn95031_dapm_widgets,
-                               ARRAY_SIZE(sn95031_dapm_widgets));
-       if (ret)
-               pr_err("soc_dapm_new_control failed %d", ret);
-       ret = snd_soc_dapm_add_routes(&codec->dapm, sn95031_audio_map,
-                               ARRAY_SIZE(sn95031_audio_map));
-       if (ret)
-               pr_err("soc_dapm_add_routes failed %d", ret);
-
-       return ret;
+       return 0;
 }
 
 static int sn95031_codec_remove(struct snd_soc_codec *codec)
@@ -903,6 +892,10 @@ struct snd_soc_codec_driver sn95031_codec = {
        .read           = sn95031_read,
        .write          = sn95031_write,
        .set_bias_level = sn95031_set_vaud_bias,
+       .dapm_widgets   = sn95031_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(sn95031_dapm_widgets),
+       .dapm_routes    = sn95031_audio_map,
+       .num_dapm_routes        = ARRAY_SIZE(sn95031_audio_map),
 };
 
 static int __devinit sn95031_device_probe(struct platform_device *pdev)
index 2727bef..8a2b52f 100644 (file)
@@ -48,7 +48,6 @@
 struct ssm2602_priv {
        unsigned int sysclk;
        enum snd_soc_control_type control_type;
-       void *control_data;
        struct snd_pcm_substream *master_substream;
        struct snd_pcm_substream *slave_substream;
 };
@@ -65,55 +64,7 @@ static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
        0x0000, 0x0000
 };
 
-/*
- * read ssm2602 register cache
- */
-static inline unsigned int ssm2602_read_reg_cache(struct snd_soc_codec *codec,
-       unsigned int reg)
-{
-       u16 *cache = codec->reg_cache;
-       if (reg == SSM2602_RESET)
-               return 0;
-       if (reg >= SSM2602_CACHEREGNUM)
-               return -1;
-       return cache[reg];
-}
-
-/*
- * write ssm2602 register cache
- */
-static inline void ssm2602_write_reg_cache(struct snd_soc_codec *codec,
-       u16 reg, unsigned int value)
-{
-       u16 *cache = codec->reg_cache;
-       if (reg >= SSM2602_CACHEREGNUM)
-               return;
-       cache[reg] = value;
-}
-
-/*
- * write to the ssm2602 register space
- */
-static int ssm2602_write(struct snd_soc_codec *codec, unsigned int reg,
-       unsigned int value)
-{
-       u8 data[2];
-
-       /* data is
-        *   D15..D9 ssm2602 register offset
-        *   D8...D0 register data
-        */
-       data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-       data[1] = value & 0x00ff;
-
-       ssm2602_write_reg_cache(codec, reg, value);
-       if (codec->hw_write(codec->control_data, data, 2) == 2)
-               return 0;
-       else
-               return -EIO;
-}
-
-#define ssm2602_reset(c)       ssm2602_write(c, SSM2602_RESET, 0)
+#define ssm2602_reset(c)       snd_soc_write(c, SSM2602_RESET, 0)
 
 /*Appending several "None"s just for OSS mixer use*/
 static const char *ssm2602_input_select[] = {
@@ -278,12 +229,11 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_codec *codec = rtd->codec;
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = codec->control_data;
-       u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
+       u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3;
        int i = get_coeff(ssm2602->sysclk, params_rate(params));
 
        if (substream == ssm2602->slave_substream) {
-               dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
+               dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
                return 0;
        }
 
@@ -294,8 +244,8 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
        srate = (coeff_div[i].sr << 2) |
                (coeff_div[i].bosr << 1) | coeff_div[i].usb;
 
-       ssm2602_write(codec, SSM2602_ACTIVE, 0);
-       ssm2602_write(codec, SSM2602_SRATE, srate);
+       snd_soc_write(codec, SSM2602_ACTIVE, 0);
+       snd_soc_write(codec, SSM2602_SRATE, srate);
 
        /* bit size */
        switch (params_format(params)) {
@@ -311,8 +261,8 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
                iface |= 0x000c;
                break;
        }
-       ssm2602_write(codec, SSM2602_IFACE, iface);
-       ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+       snd_soc_write(codec, SSM2602_IFACE, iface);
+       snd_soc_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
        return 0;
 }
 
@@ -360,7 +310,7 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_codec *codec = rtd->codec;
        /* set active */
-       ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+       snd_soc_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
 
        return 0;
 }
@@ -374,7 +324,7 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
 
        /* deactivate */
        if (!codec->active)
-               ssm2602_write(codec, SSM2602_ACTIVE, 0);
+               snd_soc_write(codec, SSM2602_ACTIVE, 0);
 
        if (ssm2602->master_substream == substream)
                ssm2602->master_substream = ssm2602->slave_substream;
@@ -385,12 +335,12 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
 static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
-       u16 mute_reg = ssm2602_read_reg_cache(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
+       u16 mute_reg = snd_soc_read(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
        if (mute)
-               ssm2602_write(codec, SSM2602_APDIGI,
+               snd_soc_write(codec, SSM2602_APDIGI,
                                mute_reg | APDIGI_ENABLE_DAC_MUTE);
        else
-               ssm2602_write(codec, SSM2602_APDIGI, mute_reg);
+               snd_soc_write(codec, SSM2602_APDIGI, mute_reg);
        return 0;
 }
 
@@ -466,30 +416,30 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
        }
 
        /* set iface */
-       ssm2602_write(codec, SSM2602_IFACE, iface);
+       snd_soc_write(codec, SSM2602_IFACE, iface);
        return 0;
 }
 
 static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
-       u16 reg = ssm2602_read_reg_cache(codec, SSM2602_PWR) & 0xff7f;
+       u16 reg = snd_soc_read(codec, SSM2602_PWR) & 0xff7f;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
                /* vref/mid, osc on, dac unmute */
-               ssm2602_write(codec, SSM2602_PWR, reg);
+               snd_soc_write(codec, SSM2602_PWR, reg);
                break;
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
                /* everything off except vref/vmid, */
-               ssm2602_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
+               snd_soc_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
                break;
        case SND_SOC_BIAS_OFF:
                /* everything off, dac mute, inactive */
-               ssm2602_write(codec, SSM2602_ACTIVE, 0);
-               ssm2602_write(codec, SSM2602_PWR, 0xffff);
+               snd_soc_write(codec, SSM2602_ACTIVE, 0);
+               snd_soc_write(codec, SSM2602_PWR, 0xffff);
                break;
 
        }
@@ -539,17 +489,10 @@ static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int ssm2602_resume(struct snd_soc_codec *codec)
 {
-       int i;
-       u8 data[2];
-       u16 *cache = codec->reg_cache;
-
-       /* Sync reg_cache with the hardware */
-       for (i = 0; i < ARRAY_SIZE(ssm2602_reg); i++) {
-               data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-               data[1] = cache[i] & 0x00ff;
-               codec->hw_write(codec->control_data, data, 2);
-       }
+       snd_soc_cache_sync(codec);
+
        ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
        return 0;
 }
 
@@ -560,31 +503,39 @@ static int ssm2602_probe(struct snd_soc_codec *codec)
 
        pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
 
-       codec->control_data = ssm2602->control_data;
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, ssm2602->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
 
-       ssm2602_reset(codec);
+       ret = ssm2602_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               return ret;
+       }
 
        /*power on device*/
-       ssm2602_write(codec, SSM2602_ACTIVE, 0);
+       snd_soc_write(codec, SSM2602_ACTIVE, 0);
        /* set the update bits */
-       reg = ssm2602_read_reg_cache(codec, SSM2602_LINVOL);
-       ssm2602_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
-       reg = ssm2602_read_reg_cache(codec, SSM2602_RINVOL);
-       ssm2602_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
-       reg = ssm2602_read_reg_cache(codec, SSM2602_LOUT1V);
-       ssm2602_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
-       reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V);
-       ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
+       reg = snd_soc_read(codec, SSM2602_LINVOL);
+       snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
+       reg = snd_soc_read(codec, SSM2602_RINVOL);
+       snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
+       reg = snd_soc_read(codec, SSM2602_LOUT1V);
+       snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
+       reg = snd_soc_read(codec, SSM2602_ROUT1V);
+       snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
        /*select Line in as default input*/
-       ssm2602_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
+       snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
                        APANA_ENABLE_MIC_BOOST);
-       ssm2602_write(codec, SSM2602_PWR, 0);
+       snd_soc_write(codec, SSM2602_PWR, 0);
 
        snd_soc_add_controls(codec, ssm2602_snd_controls,
                                ARRAY_SIZE(ssm2602_snd_controls));
        ssm2602_add_widgets(codec);
 
-       return ret;
+       return 0;
 }
 
 /* remove everything here */
@@ -599,8 +550,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
        .remove =       ssm2602_remove,
        .suspend =      ssm2602_suspend,
        .resume =       ssm2602_resume,
-       .read = ssm2602_read_reg_cache,
-       .write = ssm2602_write,
        .set_bias_level = ssm2602_set_bias_level,
        .reg_cache_size = sizeof(ssm2602_reg),
        .reg_word_size = sizeof(u16),
@@ -625,7 +574,6 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c,
                return -ENOMEM;
 
        i2c_set_clientdata(i2c, ssm2602);
-       ssm2602->control_data = i2c;
        ssm2602->control_type = SND_SOC_I2C;
 
        ret = snd_soc_register_codec(&i2c->dev,
@@ -651,7 +599,7 @@ MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
 /* corgi i2c codec control layer */
 static struct i2c_driver ssm2602_i2c_driver = {
        .driver = {
-               .name = "ssm2602-codec",
+               .name = "ssm2602",
                .owner = THIS_MODULE,
        },
        .probe = ssm2602_i2c_probe,
index 54a30ef..33bb52f 100644 (file)
@@ -212,7 +212,7 @@ static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("MICIN"),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {
        /* Output Mixer */
        {"Output Mixer", "Line Bypass Switch", "Line Input"},
        {"Output Mixer", "Playback Switch", "DAC"},
@@ -388,18 +388,6 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
        return 0;
 }
 
-static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
-                                 ARRAY_SIZE(tlv320aic23_dapm_widgets));
-       /* set up audio path interconnects */
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
@@ -676,7 +664,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, tlv320aic23_snd_controls,
                                ARRAY_SIZE(tlv320aic23_snd_controls));
-       tlv320aic23_add_widgets(codec);
 
        return 0;
 }
@@ -698,6 +685,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
        .read = tlv320aic23_read_reg_cache,
        .write = tlv320aic23_write,
        .set_bias_level = tlv320aic23_set_bias_level,
+       .dapm_widgets = tlv320aic23_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
+       .dapm_routes = tlv320aic23_intercon,
+       .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
index 97c3038..a537e4a 100644 (file)
@@ -77,7 +77,7 @@ SND_SOC_DAPM_OUTPUT("ROUT"),
 SND_SOC_DAPM_OUTPUT("RHPOUT"),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8711_intercon[] = {
        /* output mixer */
        {"Output Mixer", "Line Bypass Switch", "Line Input"},
        {"Output Mixer", "HiFi Playback Switch", "DAC"},
@@ -89,17 +89,6 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"LOUT", NULL, "Output Mixer"},
 };
 
-static int wm8711_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8711_dapm_widgets,
-                                 ARRAY_SIZE(wm8711_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 struct _coeff_div {
        u32 mclk;
        u32 rate;
@@ -398,7 +387,6 @@ static int wm8711_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm8711_snd_controls,
                             ARRAY_SIZE(wm8711_snd_controls));
-       wm8711_add_widgets(codec);
 
        return ret;
 
@@ -420,6 +408,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
        .reg_cache_size = ARRAY_SIZE(wm8711_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8711_reg,
+       .dapm_widgets = wm8711_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8711_dapm_widgets),
+       .dapm_routes = wm8711_intercon,
+       .num_dapm_routes = ARRAY_SIZE(wm8711_intercon),
 };
 
 #if defined(CONFIG_SPI_MASTER)
index 736b035..86d4718 100644 (file)
@@ -65,22 +65,11 @@ SND_SOC_DAPM_OUTPUT("VOUTL"),
 SND_SOC_DAPM_OUTPUT("VOUTR"),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8728_intercon[] = {
        {"VOUTL", NULL, "DAC"},
        {"VOUTR", NULL, "DAC"},
 };
 
-static int wm8728_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8728_dapm_widgets,
-                                 ARRAY_SIZE(wm8728_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 static int wm8728_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
@@ -255,7 +244,6 @@ static int wm8728_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm8728_snd_controls,
                                ARRAY_SIZE(wm8728_snd_controls));
-       wm8728_add_widgets(codec);
 
        return ret;
 }
@@ -275,6 +263,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
        .reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8728_reg_defaults,
+       .dapm_widgets = wm8728_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8728_dapm_widgets),
+       .dapm_routes = wm8728_intercon,
+       .num_dapm_routes = ARRAY_SIZE(wm8728_intercon),
 };
 
 #if defined(CONFIG_SPI_MASTER)
index 0a67c31..6dec7ce 100644 (file)
@@ -201,7 +201,7 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
        return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
 }
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8731_intercon[] = {
        {"DAC", NULL, "OSC", wm8731_check_osc},
        {"ADC", NULL, "OSC", wm8731_check_osc},
 
@@ -227,17 +227,6 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Mic Bias", NULL, "MICIN"},
 };
 
-static int wm8731_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets,
-                                 ARRAY_SIZE(wm8731_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 struct _coeff_div {
        u32 mclk;
        u32 rate;
@@ -599,7 +588,6 @@ static int wm8731_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm8731_snd_controls,
                             ARRAY_SIZE(wm8731_snd_controls));
-       wm8731_add_widgets(codec);
 
        /* Regulators will have been enabled by bias management */
        regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
@@ -636,6 +624,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
        .reg_cache_size = ARRAY_SIZE(wm8731_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8731_reg,
+       .dapm_widgets = wm8731_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
+       .dapm_routes = wm8731_intercon,
+       .num_dapm_routes = ARRAY_SIZE(wm8731_intercon),
 };
 
 #if defined(CONFIG_SPI_MASTER)
@@ -667,7 +659,7 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi)
 
 static struct spi_driver wm8731_spi_driver = {
        .driver = {
-               .name   = "wm8731-codec",
+               .name   = "wm8731",
                .owner  = THIS_MODULE,
        },
        .probe          = wm8731_spi_probe,
@@ -711,7 +703,7 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
 
 static struct i2c_driver wm8731_i2c_driver = {
        .driver = {
-               .name = "wm8731-codec",
+               .name = "wm8731",
                .owner = THIS_MODULE,
        },
        .probe =    wm8731_i2c_probe,
index ae1cadf..a739e09 100644 (file)
@@ -926,7 +926,7 @@ SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8903_intercon[] = {
 
        { "CLK_DSP", NULL, "CLK_SYS" },
        { "Mic Bias", NULL, "CLK_SYS" },
@@ -1079,17 +1079,6 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "Right Line Output PGA", NULL, "Charge Pump" },
 };
 
-static int wm8903_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8903_dapm_widgets,
-                                 ARRAY_SIZE(wm8903_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 static int wm8903_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
@@ -2020,7 +2009,6 @@ static int wm8903_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm8903_snd_controls,
                                ARRAY_SIZE(wm8903_snd_controls));
-       wm8903_add_widgets(codec);
 
        wm8903_init_gpio(codec);
 
@@ -2046,6 +2034,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
        .reg_cache_default = wm8903_reg_defaults,
        .volatile_register = wm8903_volatile_register,
        .seq_notifier = wm8903_seq_notifier,
+       .dapm_widgets = wm8903_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8903_dapm_widgets),
+       .dapm_routes = wm8903_intercon,
+       .num_dapm_routes = ARRAY_SIZE(wm8903_intercon),
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
new file mode 100644 (file)
index 0000000..74983ee
--- /dev/null
@@ -0,0 +1,1028 @@
+/*
+ * wm8958-dsp2.c  --  WM8958 DSP2 support
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/mfd/wm8994/gpio.h>
+
+#include "wm8994.h"
+
+#define WM_FW_BLOCK_INFO 0xff
+#define WM_FW_BLOCK_PM   0x00
+#define WM_FW_BLOCK_X    0x01
+#define WM_FW_BLOCK_Y    0x02
+#define WM_FW_BLOCK_Z    0x03
+#define WM_FW_BLOCK_I    0x06
+#define WM_FW_BLOCK_A    0x08
+#define WM_FW_BLOCK_C    0x0c
+
+static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
+                         const struct firmware *fw, bool check)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       u64 data64;
+       u32 data32;
+       const u8 *data;
+       char *str;
+       size_t block_len, len;
+       int ret = 0;
+
+       /* Suppress unneeded downloads */
+       if (wm8994->cur_fw == fw)
+               return 0;
+
+       if (fw->size < 32) {
+               dev_err(codec->dev, "%s: firmware too short\n", name);
+               goto err;
+       }
+
+       if (memcmp(fw->data, "WMFW", 4) != 0) {
+               dev_err(codec->dev, "%s: firmware has bad file magic %08x\n",
+                       name, data32);
+               goto err;
+       }
+
+       memcpy(&data32, fw->data + 4, sizeof(data32));
+       len = be32_to_cpu(data32);
+
+       memcpy(&data32, fw->data + 8, sizeof(data32));
+       data32 = be32_to_cpu(data32);
+       if ((data32 >> 24) & 0xff) {
+               dev_err(codec->dev, "%s: unsupported firmware version %d\n",
+                       name, (data32 >> 24) & 0xff);
+               goto err;
+       }
+       if ((data32 & 0xffff) != 8958) {
+               dev_err(codec->dev, "%s: unsupported target device %d\n",
+                       name, data32 & 0xffff);
+               goto err;
+       }
+       if (((data32 >> 16) & 0xff) != 0xc) {
+               dev_err(codec->dev, "%s: unsupported target core %d\n",
+                       name, (data32 >> 16) & 0xff);
+               goto err;
+       }
+
+       if (check) {
+               memcpy(&data64, fw->data + 24, sizeof(u64));
+               dev_info(codec->dev, "%s timestamp %llx\n",
+                        name, be64_to_cpu(data64));
+       } else {
+               snd_soc_write(codec, 0x102, 0x2);
+               snd_soc_write(codec, 0x900, 0x2);
+       }
+
+       data = fw->data + len;
+       len = fw->size - len;
+       while (len) {
+               if (len < 12) {
+                       dev_err(codec->dev, "%s short data block of %d\n",
+                               name, len);
+                       goto err;
+               }
+
+               memcpy(&data32, data + 4, sizeof(data32));
+               block_len = be32_to_cpu(data32);
+               if (block_len + 8 > len) {
+                       dev_err(codec->dev, "%d byte block longer than file\n",
+                               block_len);
+                       goto err;
+               }
+               if (block_len == 0) {
+                       dev_err(codec->dev, "Zero length block\n");
+                       goto err;
+               }
+
+               memcpy(&data32, data, sizeof(data32));
+               data32 = be32_to_cpu(data32);
+
+               switch ((data32 >> 24) & 0xff) {
+               case WM_FW_BLOCK_INFO:
+                       /* Informational text */
+                       if (!check)
+                               break;
+
+                       str = kzalloc(block_len + 1, GFP_KERNEL);
+                       if (str) {
+                               memcpy(str, data + 8, block_len);
+                               dev_info(codec->dev, "%s: %s\n", name, str);
+                               kfree(str);
+                       } else {
+                               dev_err(codec->dev, "Out of memory\n");
+                       }
+                       break;
+               case WM_FW_BLOCK_PM:
+               case WM_FW_BLOCK_X:
+               case WM_FW_BLOCK_Y:
+               case WM_FW_BLOCK_Z:
+               case WM_FW_BLOCK_I:
+               case WM_FW_BLOCK_A:
+               case WM_FW_BLOCK_C:
+                       dev_dbg(codec->dev, "%s: %d bytes of %x@%x\n", name,
+                               block_len, (data32 >> 24) & 0xff,
+                               data32 & 0xffffff);
+
+                       if (check)
+                               break;
+
+                       data32 &= 0xffffff;
+
+                       wm8994_bulk_write(codec->control_data,
+                                         data32 & 0xffffff,
+                                         block_len / 2,
+                                         (void *)(data + 8));
+
+                       break;
+               default:
+                       dev_warn(codec->dev, "%s: unknown block type %d\n",
+                                name, (data32 >> 24) & 0xff);
+                       break;
+               }
+
+               /* Round up to the next 32 bit word */
+               block_len += block_len % 4;
+
+               data += block_len + 8;
+               len -= block_len + 8;
+       }
+
+       if (!check) {
+               dev_dbg(codec->dev, "%s: download done\n", name);
+               wm8994->cur_fw = fw;
+       } else {
+               dev_info(codec->dev, "%s: got firmware\n", name);
+       }
+
+       goto ok;
+
+err:
+       ret = -EINVAL;
+ok:
+       if (!check) {
+               snd_soc_write(codec, 0x900, 0x0);
+               snd_soc_write(codec, 0x102, 0x0);
+       }
+
+       return ret;
+}
+
+static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int i;
+
+       /* If the DSP is already running then noop */
+       if (snd_soc_read(codec, WM8958_DSP2_PROGRAM) & WM8958_DSP2_ENA)
+               return;
+
+       /* If we have MBC firmware download it */
+       if (wm8994->mbc)
+               wm8958_dsp2_fw(codec, "MBC", wm8994->mbc, false);
+
+       snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+                           WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+       /* If we've got user supplied MBC settings use them */
+       if (pdata && pdata->num_mbc_cfgs) {
+               struct wm8958_mbc_cfg *cfg
+                       = &pdata->mbc_cfgs[wm8994->mbc_cfg];
+
+               for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
+                       snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
+                                     cfg->coeff_regs[i]);
+
+               for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
+                       snd_soc_write(codec,
+                                     i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
+                                     cfg->cutoff_regs[i]);
+       }
+
+       /* Run the DSP */
+       snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+                     WM8958_DSP2_RUNR);
+
+       /* And we're off! */
+       snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+                           WM8958_MBC_ENA |
+                           WM8958_MBC_SEL_MASK,
+                           path << WM8958_MBC_SEL_SHIFT |
+                           WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int i, ena;
+
+       if (wm8994->mbc_vss)
+               wm8958_dsp2_fw(codec, "MBC+VSS", wm8994->mbc_vss, false);
+
+       snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+                           WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+       /* If we've got user supplied settings use them */
+       if (pdata && pdata->num_mbc_cfgs) {
+               struct wm8958_mbc_cfg *cfg
+                       = &pdata->mbc_cfgs[wm8994->mbc_cfg];
+
+               for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++)
+                       snd_soc_write(codec, i + 0x2800,
+                                     cfg->combined_regs[i]);
+       }
+
+       if (pdata && pdata->num_vss_cfgs) {
+               struct wm8958_vss_cfg *cfg
+                       = &pdata->vss_cfgs[wm8994->vss_cfg];
+
+               for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+                       snd_soc_write(codec, i + 0x2600, cfg->regs[i]);
+       }
+
+       if (pdata && pdata->num_vss_hpf_cfgs) {
+               struct wm8958_vss_hpf_cfg *cfg
+                       = &pdata->vss_hpf_cfgs[wm8994->vss_hpf_cfg];
+
+               for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+                       snd_soc_write(codec, i + 0x2400, cfg->regs[i]);
+       }
+
+       /* Run the DSP */
+       snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+                     WM8958_DSP2_RUNR);
+
+       /* Enable the algorithms we've selected */
+       ena = 0;
+       if (wm8994->mbc_ena[path])
+               ena |= 0x8;
+       if (wm8994->hpf2_ena[path])
+               ena |= 0x4;
+       if (wm8994->hpf1_ena[path])
+               ena |= 0x2;
+       if (wm8994->vss_ena[path])
+               ena |= 0x1;
+
+       snd_soc_write(codec, 0x2201, ena);
+
+       /* Switch the DSP into the data path */
+       snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+                           WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
+                           path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int i;
+
+       wm8958_dsp2_fw(codec, "ENH_EQ", wm8994->enh_eq, false);
+
+       snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+                           WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+       /* If we've got user supplied settings use them */
+       if (pdata && pdata->num_enh_eq_cfgs) {
+               struct wm8958_enh_eq_cfg *cfg
+                       = &pdata->enh_eq_cfgs[wm8994->enh_eq_cfg];
+
+               for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+                       snd_soc_write(codec, i + 0x2200,
+                                     cfg->regs[i]);
+       }
+
+       /* Run the DSP */
+       snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+                     WM8958_DSP2_RUNR);
+
+       /* Switch the DSP into the data path */
+       snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+                           WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
+                           path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
+       int ena, reg, aif;
+
+       switch (path) {
+       case 0:
+               pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
+               aif = 0;
+               break;
+       case 1:
+               pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
+               aif = 0;
+               break;
+       case 2:
+               pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
+               aif = 1;
+               break;
+       default:
+               BUG();
+               return;
+       }
+
+       /* Do we have both an active AIF and an active algorithm? */
+       ena = wm8994->mbc_ena[path] || wm8994->vss_ena[path] ||
+               wm8994->hpf1_ena[path] || wm8994->hpf2_ena[path] ||
+               wm8994->enh_eq_ena[path];
+       if (!pwr_reg)
+               ena = 0;
+
+       reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
+
+       dev_dbg(codec->dev, "DSP path %d %d startup: %d, power: %x, DSP: %x\n",
+               path, wm8994->dsp_active, start, pwr_reg, reg);
+
+       if (start && ena) {
+               /* If either AIFnCLK is not yet enabled postpone */
+               if (!(snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
+                     & WM8994_AIF1CLK_ENA_MASK) &&
+                   !(snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
+                     & WM8994_AIF2CLK_ENA_MASK))
+                       return;
+
+               /* Switch the clock over to the appropriate AIF */
+               snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+                                   WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
+                                   aif << WM8958_DSP2CLK_SRC_SHIFT |
+                                   WM8958_DSP2CLK_ENA);
+
+               if (wm8994->enh_eq_ena[path])
+                       wm8958_dsp_start_enh_eq(codec, path);
+               else if (wm8994->vss_ena[path] || wm8994->hpf1_ena[path] ||
+                   wm8994->hpf2_ena[path])
+                       wm8958_dsp_start_vss(codec, path);
+               else if (wm8994->mbc_ena[path])
+                       wm8958_dsp_start_mbc(codec, path);
+
+               wm8994->dsp_active = path;
+
+               dev_dbg(codec->dev, "DSP running in path %d\n", path);
+       }
+
+       if (!start && wm8994->dsp_active == path) {
+               /* If the DSP is already stopped then noop */
+               if (!(reg & WM8958_DSP2_ENA))
+                       return;
+
+               snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+                                   WM8958_MBC_ENA, 0); 
+               snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+                             WM8958_DSP2_STOP);
+               snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+                                   WM8958_DSP2_ENA, 0);
+               snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+                                   WM8958_DSP2CLK_ENA, 0);
+
+               wm8994->dsp_active = -1;
+
+               dev_dbg(codec->dev, "DSP stopped\n");
+       }
+}
+
+int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
+                 struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       int i;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+       case SND_SOC_DAPM_PRE_PMU:
+               for (i = 0; i < 3; i++)
+                       wm8958_dsp_apply(codec, i, 1);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+       case SND_SOC_DAPM_PRE_PMD:
+               for (i = 0; i < 3; i++)
+                       wm8958_dsp_apply(codec, i, 0);
+               break;
+       }
+
+       return 0;
+}
+
+/* Check if DSP2 is in use on another AIF */
+static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
+               if (i == aif)
+                       continue;
+               if (wm8994->mbc_ena[i] || wm8994->vss_ena[i] ||
+                   wm8994->hpf1_ena[i] || wm8994->hpf2_ena[i])
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int value = ucontrol->value.integer.value[0];
+       int reg;
+
+       /* Don't allow on the fly reconfiguration */
+       reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+       if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+               return -EBUSY;
+
+       if (value >= pdata->num_mbc_cfgs)
+               return -EINVAL;
+
+       wm8994->mbc_cfg = value;
+
+       return 0;
+}
+
+static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
+
+       return 0;
+}
+
+static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int mbc = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
+
+       return 0;
+}
+
+static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int mbc = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (ucontrol->value.integer.value[0] > 1)
+               return -EINVAL;
+
+       if (wm8958_dsp2_busy(wm8994, mbc)) {
+               dev_dbg(codec->dev, "DSP2 active on %d already\n", mbc);
+               return -EBUSY;
+       }
+
+       if (wm8994->enh_eq_ena[mbc])
+               return -EBUSY;
+
+       wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
+
+       wm8958_dsp_apply(codec, mbc, wm8994->mbc_ena[mbc]);
+
+       return 0;
+}
+
+#define WM8958_MBC_SWITCH(xname, xval) {\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .info = wm8958_mbc_info, \
+       .get = wm8958_mbc_get, .put = wm8958_mbc_put, \
+       .private_value = xval }
+
+static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int value = ucontrol->value.integer.value[0];
+       int reg;
+
+       /* Don't allow on the fly reconfiguration */
+       reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+       if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+               return -EBUSY;
+
+       if (value >= pdata->num_vss_cfgs)
+               return -EINVAL;
+
+       wm8994->vss_cfg = value;
+
+       return 0;
+}
+
+static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = wm8994->vss_cfg;
+
+       return 0;
+}
+
+static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int value = ucontrol->value.integer.value[0];
+       int reg;
+
+       /* Don't allow on the fly reconfiguration */
+       reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+       if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+               return -EBUSY;
+
+       if (value >= pdata->num_vss_hpf_cfgs)
+               return -EINVAL;
+
+       wm8994->vss_hpf_cfg = value;
+
+       return 0;
+}
+
+static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg;
+
+       return 0;
+}
+
+static int wm8958_vss_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int wm8958_vss_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int vss = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = wm8994->vss_ena[vss];
+
+       return 0;
+}
+
+static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int vss = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (ucontrol->value.integer.value[0] > 1)
+               return -EINVAL;
+
+       if (!wm8994->mbc_vss)
+               return -ENODEV;
+
+       if (wm8958_dsp2_busy(wm8994, vss)) {
+               dev_dbg(codec->dev, "DSP2 active on %d already\n", vss);
+               return -EBUSY;
+       }
+
+       if (wm8994->enh_eq_ena[vss])
+               return -EBUSY;
+
+       wm8994->vss_ena[vss] = ucontrol->value.integer.value[0];
+
+       wm8958_dsp_apply(codec, vss, wm8994->vss_ena[vss]);
+
+       return 0;
+}
+
+
+#define WM8958_VSS_SWITCH(xname, xval) {\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .info = wm8958_vss_info, \
+       .get = wm8958_vss_get, .put = wm8958_vss_put, \
+       .private_value = xval }
+
+static int wm8958_hpf_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int hpf = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (hpf < 3)
+               ucontrol->value.integer.value[0] = wm8994->hpf1_ena[hpf % 3];
+       else
+               ucontrol->value.integer.value[0] = wm8994->hpf2_ena[hpf % 3];
+
+       return 0;
+}
+
+static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int hpf = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (ucontrol->value.integer.value[0] > 1)
+               return -EINVAL;
+
+       if (!wm8994->mbc_vss)
+               return -ENODEV;
+
+       if (wm8958_dsp2_busy(wm8994, hpf % 3)) {
+               dev_dbg(codec->dev, "DSP2 active on %d already\n", hpf);
+               return -EBUSY;
+       }
+
+       if (wm8994->enh_eq_ena[hpf % 3])
+               return -EBUSY;
+
+       if (hpf < 3)
+               wm8994->hpf1_ena[hpf % 3] = ucontrol->value.integer.value[0];
+       else
+               wm8994->hpf2_ena[hpf % 3] = ucontrol->value.integer.value[0];
+
+       wm8958_dsp_apply(codec, hpf % 3, ucontrol->value.integer.value[0]);
+
+       return 0;
+}
+
+#define WM8958_HPF_SWITCH(xname, xval) {\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .info = wm8958_hpf_info, \
+       .get = wm8958_hpf_get, .put = wm8958_hpf_put, \
+       .private_value = xval }
+
+static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int value = ucontrol->value.integer.value[0];
+       int reg;
+
+       /* Don't allow on the fly reconfiguration */
+       reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+       if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+               return -EBUSY;
+
+       if (value >= pdata->num_enh_eq_cfgs)
+               return -EINVAL;
+
+       wm8994->enh_eq_cfg = value;
+
+       return 0;
+}
+
+static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg;
+
+       return 0;
+}
+
+static int wm8958_enh_eq_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int eq = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq];
+
+       return 0;
+}
+
+static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int eq = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (ucontrol->value.integer.value[0] > 1)
+               return -EINVAL;
+
+       if (!wm8994->enh_eq)
+               return -ENODEV;
+
+       if (wm8958_dsp2_busy(wm8994, eq)) {
+               dev_dbg(codec->dev, "DSP2 active on %d already\n", eq);
+               return -EBUSY;
+       }
+
+       if (wm8994->mbc_ena[eq] || wm8994->vss_ena[eq] ||
+           wm8994->hpf1_ena[eq] || wm8994->hpf2_ena[eq])
+               return -EBUSY;
+
+       wm8994->enh_eq_ena[eq] = ucontrol->value.integer.value[0];
+
+       wm8958_dsp_apply(codec, eq, ucontrol->value.integer.value[0]);
+
+       return 0;
+}
+
+#define WM8958_ENH_EQ_SWITCH(xname, xval) {\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .info = wm8958_enh_eq_info, \
+       .get = wm8958_enh_eq_get, .put = wm8958_enh_eq_put, \
+       .private_value = xval }
+
+static const struct snd_kcontrol_new wm8958_mbc_snd_controls[] = {
+WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
+WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
+WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
+};
+
+static const struct snd_kcontrol_new wm8958_vss_snd_controls[] = {
+WM8958_VSS_SWITCH("AIF1DAC1 VSS Switch", 0),
+WM8958_VSS_SWITCH("AIF1DAC2 VSS Switch", 1),
+WM8958_VSS_SWITCH("AIF2DAC VSS Switch", 2),
+WM8958_HPF_SWITCH("AIF1DAC1 HPF1 Switch", 0),
+WM8958_HPF_SWITCH("AIF1DAC2 HPF1 Switch", 1),
+WM8958_HPF_SWITCH("AIF2DAC HPF1 Switch", 2),
+WM8958_HPF_SWITCH("AIF1DAC1 HPF2 Switch", 3),
+WM8958_HPF_SWITCH("AIF1DAC2 HPF2 Switch", 4),
+WM8958_HPF_SWITCH("AIF2DAC HPF2 Switch", 5),
+};
+
+static const struct snd_kcontrol_new wm8958_enh_eq_snd_controls[] = {
+WM8958_ENH_EQ_SWITCH("AIF1DAC1 Enhanced EQ Switch", 0),
+WM8958_ENH_EQ_SWITCH("AIF1DAC2 Enhanced EQ Switch", 1),
+WM8958_ENH_EQ_SWITCH("AIF2DAC Enhanced EQ Switch", 2),
+};
+
+static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
+{
+       struct snd_soc_codec *codec = context;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) {
+               mutex_lock(&codec->mutex);
+               wm8994->enh_eq = fw;
+               mutex_unlock(&codec->mutex);
+       }
+}
+
+static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
+{
+       struct snd_soc_codec *codec = context;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) {
+               mutex_lock(&codec->mutex);
+               wm8994->mbc_vss = fw;
+               mutex_unlock(&codec->mutex);
+       }
+
+       /* We can't have more than one request outstanding at once so
+        * we daisy chain.
+        */
+       request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+                               "wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL,
+                               codec, wm8958_enh_eq_loaded);
+}
+
+static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
+{
+       struct snd_soc_codec *codec = context;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (wm8958_dsp2_fw(codec, "MBC", fw, true) != 0)
+               return;
+
+       mutex_lock(&codec->mutex);
+       wm8994->mbc = fw;
+       mutex_unlock(&codec->mutex);
+
+       /* We can't have more than one request outstanding at once so
+        * we daisy chain.
+        */
+       request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+                               "wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL,
+                               codec, wm8958_mbc_vss_loaded);
+}
+
+void wm8958_dsp2_init(struct snd_soc_codec *codec)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int ret, i;
+
+       wm8994->dsp_active = -1;
+
+       snd_soc_add_controls(codec, wm8958_mbc_snd_controls,
+                            ARRAY_SIZE(wm8958_mbc_snd_controls));
+       snd_soc_add_controls(codec, wm8958_vss_snd_controls,
+                            ARRAY_SIZE(wm8958_vss_snd_controls));
+       snd_soc_add_controls(codec, wm8958_enh_eq_snd_controls,
+                            ARRAY_SIZE(wm8958_enh_eq_snd_controls));
+
+
+       /* We don't *require* firmware and don't want to delay boot */
+       request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+                               "wm8958_mbc.wfw", codec->dev, GFP_KERNEL,
+                               codec, wm8958_mbc_loaded);
+
+       if (!pdata)
+               return;
+
+       if (pdata->num_mbc_cfgs) {
+               struct snd_kcontrol_new control[] = {
+                       SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
+                                    wm8958_get_mbc_enum, wm8958_put_mbc_enum),
+               };
+
+               /* We need an array of texts for the enum API */
+               wm8994->mbc_texts = kmalloc(sizeof(char *)
+                                           * pdata->num_mbc_cfgs, GFP_KERNEL);
+               if (!wm8994->mbc_texts) {
+                       dev_err(wm8994->codec->dev,
+                               "Failed to allocate %d MBC config texts\n",
+                               pdata->num_mbc_cfgs);
+                       return;
+               }
+
+               for (i = 0; i < pdata->num_mbc_cfgs; i++)
+                       wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
+
+               wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
+               wm8994->mbc_enum.texts = wm8994->mbc_texts;
+
+               ret = snd_soc_add_controls(wm8994->codec, control, 1);
+               if (ret != 0)
+                       dev_err(wm8994->codec->dev,
+                               "Failed to add MBC mode controls: %d\n", ret);
+       }
+
+       if (pdata->num_vss_cfgs) {
+               struct snd_kcontrol_new control[] = {
+                       SOC_ENUM_EXT("VSS Mode", wm8994->vss_enum,
+                                    wm8958_get_vss_enum, wm8958_put_vss_enum),
+               };
+
+               /* We need an array of texts for the enum API */
+               wm8994->vss_texts = kmalloc(sizeof(char *)
+                                           * pdata->num_vss_cfgs, GFP_KERNEL);
+               if (!wm8994->vss_texts) {
+                       dev_err(wm8994->codec->dev,
+                               "Failed to allocate %d VSS config texts\n",
+                               pdata->num_vss_cfgs);
+                       return;
+               }
+
+               for (i = 0; i < pdata->num_vss_cfgs; i++)
+                       wm8994->vss_texts[i] = pdata->vss_cfgs[i].name;
+
+               wm8994->vss_enum.max = pdata->num_vss_cfgs;
+               wm8994->vss_enum.texts = wm8994->vss_texts;
+
+               ret = snd_soc_add_controls(wm8994->codec, control, 1);
+               if (ret != 0)
+                       dev_err(wm8994->codec->dev,
+                               "Failed to add VSS mode controls: %d\n", ret);
+       }
+
+       if (pdata->num_vss_hpf_cfgs) {
+               struct snd_kcontrol_new control[] = {
+                       SOC_ENUM_EXT("VSS HPF Mode", wm8994->vss_hpf_enum,
+                                    wm8958_get_vss_hpf_enum,
+                                    wm8958_put_vss_hpf_enum),
+               };
+
+               /* We need an array of texts for the enum API */
+               wm8994->vss_hpf_texts = kmalloc(sizeof(char *)
+                                               * pdata->num_vss_hpf_cfgs, GFP_KERNEL);
+               if (!wm8994->vss_hpf_texts) {
+                       dev_err(wm8994->codec->dev,
+                               "Failed to allocate %d VSS HPF config texts\n",
+                               pdata->num_vss_hpf_cfgs);
+                       return;
+               }
+
+               for (i = 0; i < pdata->num_vss_hpf_cfgs; i++)
+                       wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name;
+
+               wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;
+               wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
+
+               ret = snd_soc_add_controls(wm8994->codec, control, 1);
+               if (ret != 0)
+                       dev_err(wm8994->codec->dev,
+                               "Failed to add VSS HPFmode controls: %d\n",
+                               ret);
+       }
+
+       if (pdata->num_enh_eq_cfgs) {
+               struct snd_kcontrol_new control[] = {
+                       SOC_ENUM_EXT("Enhanced EQ Mode", wm8994->enh_eq_enum,
+                                    wm8958_get_enh_eq_enum,
+                                    wm8958_put_enh_eq_enum),
+               };
+
+               /* We need an array of texts for the enum API */
+               wm8994->enh_eq_texts = kmalloc(sizeof(char *)
+                                               * pdata->num_enh_eq_cfgs, GFP_KERNEL);
+               if (!wm8994->enh_eq_texts) {
+                       dev_err(wm8994->codec->dev,
+                               "Failed to allocate %d enhanced EQ config texts\n",
+                               pdata->num_enh_eq_cfgs);
+                       return;
+               }
+
+               for (i = 0; i < pdata->num_enh_eq_cfgs; i++)
+                       wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name;
+
+               wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;
+               wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
+
+               ret = snd_soc_add_controls(wm8994->codec, control, 1);
+               if (ret != 0)
+                       dev_err(wm8994->codec->dev,
+                               "Failed to add enhanced EQ controls: %d\n",
+                               ret);
+       }
+}
index 3dc64c8..03ef624 100644 (file)
 #include "wm8994.h"
 #include "wm_hubs.h"
 
-struct fll_config {
-       int src;
-       int in;
-       int out;
-};
-
 #define WM8994_NUM_DRC 3
 #define WM8994_NUM_EQ  3
 
@@ -59,63 +53,11 @@ static int wm8994_retune_mobile_base[] = {
        WM8994_AIF2_EQ_GAINS_1,
 };
 
-struct wm8994_micdet {
-       struct snd_soc_jack *jack;
-       int det;
-       int shrt;
-};
-
-/* codec private data */
-struct wm8994_priv {
-       struct wm_hubs_data hubs;
-       enum snd_soc_control_type control_type;
-       void *control_data;
-       struct snd_soc_codec *codec;
-       int sysclk[2];
-       int sysclk_rate[2];
-       int mclk[2];
-       int aifclk[2];
-       struct fll_config fll[2], fll_suspend[2];
-
-       int dac_rates[2];
-       int lrclk_shared[2];
-
-       int mbc_ena[3];
-
-       /* Platform dependant DRC configuration */
-       const char **drc_texts;
-       int drc_cfg[WM8994_NUM_DRC];
-       struct soc_enum drc_enum;
-
-       /* Platform dependant ReTune mobile configuration */
-       int num_retune_mobile_texts;
-       const char **retune_mobile_texts;
-       int retune_mobile_cfg[WM8994_NUM_EQ];
-       struct soc_enum retune_mobile_enum;
-
-       /* Platform dependant MBC configuration */
-       int mbc_cfg;
-       const char **mbc_texts;
-       struct soc_enum mbc_enum;
-
-       struct wm8994_micdet micdet[2];
-
-       wm8958_micdet_cb jack_cb;
-       void *jack_cb_data;
-       int micdet_irq;
-
-       int revision;
-       struct wm8994_pdata *pdata;
-
-       unsigned int aif1clk_enable:1;
-       unsigned int aif2clk_enable:1;
-
-       unsigned int aif1clk_disable:1;
-       unsigned int aif2clk_disable:1;
-};
-
 static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
 {
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994 *control = wm8994->control_data;
+
        switch (reg) {
        case WM8994_GPIO_1:
        case WM8994_GPIO_2:
@@ -132,6 +74,15 @@ static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
        case WM8994_INTERRUPT_STATUS_2:
        case WM8994_INTERRUPT_RAW_STATUS_2:
                return 1;
+
+       case WM8958_DSP2_PROGRAM:
+       case WM8958_DSP2_CONFIG:
+       case WM8958_DSP2_EXECCONTROL:
+               if (control->type == WM8958)
+                       return 1;
+               else
+                       return 0;
+
        default:
                break;
        }
@@ -574,215 +525,6 @@ static const struct soc_enum dac_osr =
 static const struct soc_enum adc_osr =
        SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text);
 
-static void wm8958_mbc_apply(struct snd_soc_codec *codec, int mbc, int start)
-{
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994_pdata *pdata = wm8994->pdata;
-       int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
-       int ena, reg, aif, i;
-
-       switch (mbc) {
-       case 0:
-               pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
-               aif = 0;
-               break;
-       case 1:
-               pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
-               aif = 0;
-               break;
-       case 2:
-               pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
-               aif = 1;
-               break;
-       default:
-               BUG();
-               return;
-       }
-
-       /* We can only enable the MBC if the AIF is enabled and we
-        * want it to be enabled. */
-       ena = pwr_reg && wm8994->mbc_ena[mbc];
-
-       reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
-
-       dev_dbg(codec->dev, "MBC %d startup: %d, power: %x, DSP: %x\n",
-               mbc, start, pwr_reg, reg);
-
-       if (start && ena) {
-               /* If the DSP is already running then noop */
-               if (reg & WM8958_DSP2_ENA)
-                       return;
-
-               /* Switch the clock over to the appropriate AIF */
-               snd_soc_update_bits(codec, WM8994_CLOCKING_1,
-                                   WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
-                                   aif << WM8958_DSP2CLK_SRC_SHIFT |
-                                   WM8958_DSP2CLK_ENA);
-
-               snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
-                                   WM8958_DSP2_ENA, WM8958_DSP2_ENA);
-
-               /* If we've got user supplied MBC settings use them */
-               if (pdata && pdata->num_mbc_cfgs) {
-                       struct wm8958_mbc_cfg *cfg
-                               = &pdata->mbc_cfgs[wm8994->mbc_cfg];
-
-                       for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
-                               snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
-                                             cfg->coeff_regs[i]);
-
-                       for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
-                               snd_soc_write(codec,
-                                             i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
-                                             cfg->cutoff_regs[i]);
-               }
-
-               /* Run the DSP */
-               snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
-                             WM8958_DSP2_RUNR);
-
-               /* And we're off! */
-               snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
-                                   WM8958_MBC_ENA | WM8958_MBC_SEL_MASK,
-                                   mbc << WM8958_MBC_SEL_SHIFT |
-                                   WM8958_MBC_ENA);
-       } else {
-               /* If the DSP is already stopped then noop */
-               if (!(reg & WM8958_DSP2_ENA))
-                       return;
-
-               snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
-                                   WM8958_MBC_ENA, 0); 
-               snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
-                                   WM8958_DSP2_ENA, 0);
-               snd_soc_update_bits(codec, WM8994_CLOCKING_1,
-                                   WM8958_DSP2CLK_ENA, 0);
-       }
-}
-
-static int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
-                   struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = w->codec;
-       int mbc;
-
-       switch (w->shift) {
-       case 13:
-       case 12:
-               mbc = 2;
-               break;
-       case 11:
-       case 10:
-               mbc = 1;
-               break;
-       case 9:
-       case 8:
-               mbc = 0;
-               break;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               wm8958_mbc_apply(codec, mbc, 1);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               wm8958_mbc_apply(codec, mbc, 0);
-               break;
-       }
-
-       return 0;
-}
-
-static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994_pdata *pdata = wm8994->pdata;
-       int value = ucontrol->value.integer.value[0];
-       int reg;
-
-       /* Don't allow on the fly reconfiguration */
-       reg = snd_soc_read(codec, WM8994_CLOCKING_1);
-       if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
-               return -EBUSY;
-
-       if (value >= pdata->num_mbc_cfgs)
-               return -EINVAL;
-
-       wm8994->mbc_cfg = value;
-
-       return 0;
-}
-
-static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-
-       ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
-
-       return 0;
-}
-
-static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 1;
-       return 0;
-}
-
-static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
-{
-       int mbc = kcontrol->private_value;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-
-       ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
-
-       return 0;
-}
-
-static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
-{
-       int mbc = kcontrol->private_value;
-       int i;
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-
-       if (ucontrol->value.integer.value[0] > 1)
-               return -EINVAL;
-
-       for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
-               if (mbc != i && wm8994->mbc_ena[i]) {
-                       dev_dbg(codec->dev, "MBC %d active already\n", mbc);
-                       return -EBUSY;
-               }
-       }
-
-       wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
-
-       wm8958_mbc_apply(codec, mbc, wm8994->mbc_ena[mbc]);
-
-       return 0;
-}
-
-#define WM8958_MBC_SWITCH(xname, xval) {\
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
-       .info = wm8958_mbc_info, \
-       .get = wm8958_mbc_get, .put = wm8958_mbc_put, \
-       .private_value = xval }
-
 static const struct snd_kcontrol_new wm8994_snd_controls[] = {
 SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
                 WM8994_AIF1_ADC1_RIGHT_VOLUME,
@@ -924,9 +666,6 @@ SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0,
 
 static const struct snd_kcontrol_new wm8958_snd_controls[] = {
 SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),
-WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
-WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
-WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
 };
 
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
@@ -1032,6 +771,9 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w,
                break;
        }
 
+       /* We may also have postponed startup of DSP, handle that. */
+       wm8958_aif_ev(w, kcontrol, event);
+
        return 0;
 }
 
@@ -2180,6 +1922,8 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                                            WM8994_VMID_BUF_ENA |
                                            WM8994_VMID_RAMP_MASK, 0);
 
+                       wm8994->cur_fw = NULL;
+
                        pm_runtime_put(codec->dev);
                }
                break;
@@ -2676,7 +2420,7 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
        for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
                memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
-                      sizeof(struct fll_config));
+                      sizeof(struct wm8994_fll_config));
                ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0);
                if (ret < 0)
                        dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
@@ -2862,34 +2606,6 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
        dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
                pdata->num_retune_mobile_cfgs);
 
-       if (pdata->num_mbc_cfgs) {
-               struct snd_kcontrol_new control[] = {
-                       SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
-                                    wm8958_get_mbc_enum, wm8958_put_mbc_enum),
-               };
-
-               /* We need an array of texts for the enum API */
-               wm8994->mbc_texts = kmalloc(sizeof(char *)
-                                           * pdata->num_mbc_cfgs, GFP_KERNEL);
-               if (!wm8994->mbc_texts) {
-                       dev_err(wm8994->codec->dev,
-                               "Failed to allocate %d MBC config texts\n",
-                               pdata->num_mbc_cfgs);
-                       return;
-               }
-
-               for (i = 0; i < pdata->num_mbc_cfgs; i++)
-                       wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
-
-               wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
-               wm8994->mbc_enum.texts = wm8994->mbc_texts;
-
-               ret = snd_soc_add_controls(wm8994->codec, control, 1);
-               if (ret != 0)
-                       dev_err(wm8994->codec->dev,
-                               "Failed to add MBC mode controls: %d\n", ret);
-       }
-
        if (pdata->num_retune_mobile_cfgs)
                wm8994_handle_retune_mobile_pdata(wm8994);
        else
@@ -3327,14 +3043,23 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        case WM8958:
                snd_soc_add_controls(codec, wm8958_snd_controls,
                                     ARRAY_SIZE(wm8958_snd_controls));
-               snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
-                                         ARRAY_SIZE(wm8994_lateclk_widgets));
-               snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
-                                         ARRAY_SIZE(wm8994_adc_widgets));
-               snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
-                                         ARRAY_SIZE(wm8994_dac_widgets));
                snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
                                          ARRAY_SIZE(wm8958_dapm_widgets));
+               if (wm8994->revision < 1) {
+                       snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
+                                                 ARRAY_SIZE(wm8994_lateclk_revd_widgets));
+                       snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
+                                                 ARRAY_SIZE(wm8994_adc_revd_widgets));
+                       snd_soc_dapm_new_controls(dapm, wm8994_dac_revd_widgets,
+                                                 ARRAY_SIZE(wm8994_dac_revd_widgets));
+               } else {
+                       snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
+                                                 ARRAY_SIZE(wm8994_lateclk_widgets));
+                       snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
+                                                 ARRAY_SIZE(wm8994_adc_widgets));
+                       snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
+                                                 ARRAY_SIZE(wm8994_dac_widgets));
+               }
                break;
        }
                
@@ -3358,10 +3083,19 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                }
                break;
        case WM8958:
-               snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
-                                       ARRAY_SIZE(wm8994_lateclk_intercon));
-               snd_soc_dapm_add_routes(dapm, wm8958_intercon,
-                                       ARRAY_SIZE(wm8958_intercon));
+               if (wm8994->revision < 1) {
+                       snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
+                                               ARRAY_SIZE(wm8994_revd_intercon));
+                       snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
+                                               ARRAY_SIZE(wm8994_lateclk_revd_intercon));
+               } else {
+                       snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
+                                               ARRAY_SIZE(wm8994_lateclk_intercon));
+                       snd_soc_dapm_add_routes(dapm, wm8958_intercon,
+                                               ARRAY_SIZE(wm8958_intercon));
+               }
+
+               wm8958_dsp2_init(codec);
                break;
        }
 
@@ -3404,6 +3138,12 @@ static int  wm8994_codec_remove(struct snd_soc_codec *codec)
                        free_irq(wm8994->micdet_irq, wm8994);
                break;
        }
+       if (wm8994->mbc)
+               release_firmware(wm8994->mbc);
+       if (wm8994->mbc_vss)
+               release_firmware(wm8994->mbc_vss);
+       if (wm8994->enh_eq)
+               release_firmware(wm8994->enh_eq);
        kfree(wm8994->retune_mobile_texts);
        kfree(wm8994->drc_texts);
        kfree(wm8994);
index 999b885..0a1db04 100644 (file)
@@ -10,6 +10,9 @@
 #define _WM8994_H
 
 #include <sound/soc.h>
+#include <linux/firmware.h>
+
+#include "wm_hubs.h"
 
 /* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
 #define WM8994_SYSCLK_MCLK1 1
@@ -45,4 +48,98 @@ struct wm8994_access_mask {
 extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE];
 extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE];
 
+int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
+                 struct snd_kcontrol *kcontrol, int event);
+
+void wm8958_dsp2_init(struct snd_soc_codec *codec);
+
+struct wm8994_micdet {
+       struct snd_soc_jack *jack;
+       int det;
+       int shrt;
+};
+
+/* codec private data */
+struct wm8994_fll_config {
+       int src;
+       int in;
+       int out;
+};
+
+#define WM8994_NUM_DRC 3
+#define WM8994_NUM_EQ  3
+
+struct wm8994_priv {
+       struct wm_hubs_data hubs;
+       enum snd_soc_control_type control_type;
+       void *control_data;
+       struct snd_soc_codec *codec;
+       int sysclk[2];
+       int sysclk_rate[2];
+       int mclk[2];
+       int aifclk[2];
+       struct wm8994_fll_config fll[2], fll_suspend[2];
+
+       int dac_rates[2];
+       int lrclk_shared[2];
+
+       int mbc_ena[3];
+       int hpf1_ena[3];
+       int hpf2_ena[3];
+       int vss_ena[3];
+       int enh_eq_ena[3];
+
+       /* Platform dependant DRC configuration */
+       const char **drc_texts;
+       int drc_cfg[WM8994_NUM_DRC];
+       struct soc_enum drc_enum;
+
+       /* Platform dependant ReTune mobile configuration */
+       int num_retune_mobile_texts;
+       const char **retune_mobile_texts;
+       int retune_mobile_cfg[WM8994_NUM_EQ];
+       struct soc_enum retune_mobile_enum;
+
+       /* Platform dependant MBC configuration */
+       int mbc_cfg;
+       const char **mbc_texts;
+       struct soc_enum mbc_enum;
+
+       /* Platform dependant VSS configuration */
+       int vss_cfg;
+       const char **vss_texts;
+       struct soc_enum vss_enum;
+
+       /* Platform dependant VSS HPF configuration */
+       int vss_hpf_cfg;
+       const char **vss_hpf_texts;
+       struct soc_enum vss_hpf_enum;
+
+       /* Platform dependant enhanced EQ configuration */
+       int enh_eq_cfg;
+       const char **enh_eq_texts;
+       struct soc_enum enh_eq_enum;
+
+       struct wm8994_micdet micdet[2];
+
+       wm8958_micdet_cb jack_cb;
+       void *jack_cb_data;
+       int micdet_irq;
+
+       int revision;
+       struct wm8994_pdata *pdata;
+
+       unsigned int aif1clk_enable:1;
+       unsigned int aif2clk_enable:1;
+
+       unsigned int aif1clk_disable:1;
+       unsigned int aif2clk_disable:1;
+
+       int dsp_active;
+       const struct firmware *cur_fw;
+       const struct firmware *mbc;
+       const struct firmware *mbc_vss;
+       const struct firmware *enh_eq;
+};
+
 #endif
index 47b357a..646b58d 100644 (file)
@@ -142,7 +142,7 @@ static const struct snd_soc_dapm_widget wm9705_dapm_widgets[] = {
  * constantly enabled, we use the mutes on those inputs to simulate such
  * controls.
  */
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm9705_audio_map[] = {
        /* HP mixer */
        {"HP Mixer", "PCBeep Playback Switch", "PCBEEP PGA"},
        {"HP Mixer", "CD Playback Switch", "CD PGA"},
@@ -200,17 +200,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Right ADC", NULL, "ADC PGA"},
 };
 
-static int wm9705_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm9705_dapm_widgets,
-                                       ARRAY_SIZE(wm9705_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 /* We use a register cache to enhance read performance. */
 static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
 {
@@ -364,7 +353,6 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm9705_snd_ac97_controls,
                                ARRAY_SIZE(wm9705_snd_ac97_controls));
-       wm9705_add_widgets(codec);
 
        return 0;
 
@@ -390,6 +378,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
        .reg_word_size = sizeof(u16),
        .reg_cache_step = 2,
        .reg_cache_default = wm9705_reg,
+       .dapm_widgets = wm9705_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets),
+       .dapm_routes = wm9705_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(wm9705_audio_map),
 };
 
 static __devinit int wm9705_probe(struct platform_device *pdev)
index bf5d4ef..90117f8 100644 (file)
@@ -332,7 +332,7 @@ SND_SOC_DAPM_INPUT("MIC1"),
 SND_SOC_DAPM_INPUT("MIC2"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm9712_audio_map[] = {
        /* virtual mixer - mixes left & right channels for spk and mono */
        {"AC97 Mixer", NULL, "Left DAC"},
        {"AC97 Mixer", NULL, "Right DAC"},
@@ -429,17 +429,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"ROUT2", NULL, "Speaker PGA"},
 };
 
-static int wm9712_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm9712_dapm_widgets,
-                                 ARRAY_SIZE(wm9712_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 static unsigned int ac97_read(struct snd_soc_codec *codec,
        unsigned int reg)
 {
@@ -651,7 +640,6 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
        wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        snd_soc_add_controls(codec, wm9712_snd_ac97_controls,
                                ARRAY_SIZE(wm9712_snd_ac97_controls));
-       wm9712_add_widgets(codec);
 
        return 0;
 
@@ -678,6 +666,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
        .reg_word_size = sizeof(u16),
        .reg_cache_step = 2,
        .reg_cache_default = wm9712_reg,
+       .dapm_widgets = wm9712_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets),
+       .dapm_routes = wm9712_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(wm9712_audio_map),
 };
 
 static __devinit int wm9712_probe(struct platform_device *pdev)
index 38ed985..7167cb6 100644 (file)
@@ -487,7 +487,7 @@ SND_SOC_DAPM_INPUT("MIC2B"),
 SND_SOC_DAPM_VMID("VMID"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm9713_audio_map[] = {
        /* left HP mixer */
        {"Left HP Mixer", "Beep Playback Switch",    "PCBEEP"},
        {"Left HP Mixer", "Voice Playback Switch",   "Voice DAC"},
@@ -644,18 +644,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Capture Mono Mux", "Right", "Right Capture Source"},
 };
 
-static int wm9713_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm9713_dapm_widgets,
-                                 ARRAY_SIZE(wm9713_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 static unsigned int ac97_read(struct snd_soc_codec *codec,
        unsigned int reg)
 {
@@ -1231,7 +1219,6 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm9713_snd_ac97_controls,
                                ARRAY_SIZE(wm9713_snd_ac97_controls));
-       wm9713_add_widgets(codec);
 
        return 0;
 
@@ -1262,6 +1249,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
        .reg_word_size = sizeof(u16),
        .reg_cache_step = 2,
        .reg_cache_default = wm9713_reg,
+       .dapm_widgets = wm9713_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets),
+       .dapm_routes = wm9713_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(wm9713_audio_map),
 };
 
 static __devinit int wm9713_probe(struct platform_device *pdev)
index bc92ec6..c331d65 100644 (file)
@@ -667,12 +667,6 @@ static int imx_ssi_probe(struct platform_device *pdev)
        if (res)
                ssi->dma_params_rx.dma = res->start;
 
-       if ((cpu_is_mx27() || cpu_is_mx21()) &&
-                       !(ssi->flags & IMX_SSI_USE_AC97) &&
-                       (ssi->flags & IMX_SSI_DMA)) {
-               ssi->flags |= IMX_SSI_DMA;
-       }
-
        platform_set_drvdata(pdev, ssi);
 
        ret = snd_soc_register_dai(&pdev->dev, dai);
index 9027da4..28757fb 100644 (file)
@@ -310,7 +310,7 @@ static struct snd_soc_dai_link corgi_dai = {
        .cpu_dai_name = "pxa2xx-i2s",
        .codec_dai_name = "wm8731-hifi",
        .platform_name = "pxa-pcm-audio",
-       .codec_name = "wm8731-codec.0-001b",
+       .codec_name = "wm8731.0-001b",
        .init = corgi_wm8731_init,
        .ops = &corgi_ops,
 };
index a7d4999..da3ae43 100644 (file)
@@ -276,7 +276,7 @@ static struct snd_soc_dai_link poodle_dai = {
        .cpu_dai_name = "pxa2xx-i2s",
        .codec_dai_name = "wm8731-hifi",
        .platform_name = "pxa-pcm-audio",
-       .codec_name = "wm8731-codec.0-001b",
+       .codec_name = "wm8731.0-001b",
        .init = poodle_wm8731_init,
        .ops = &poodle_ops,
 };
index 5d76da4..22b0990 100644 (file)
 
 #include <trace/events/asoc.h>
 
-static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
-                                    unsigned int reg)
+#if defined(CONFIG_SPI_MASTER)
+static int do_spi_write(void *control_data, const void *msg,
+                       int len)
 {
-       int ret;
-       unsigned int val;
+       struct spi_device *spi = control_data;
+       struct spi_transfer t;
+       struct spi_message m;
 
-       if (reg >= codec->driver->reg_cache_size ||
-               snd_soc_codec_volatile_register(codec, reg) ||
-               codec->cache_bypass) {
-                       if (codec->cache_only)
-                               return -1;
+       if (len <= 0)
+               return 0;
 
-                       BUG_ON(!codec->hw_read);
-                       return codec->hw_read(codec, reg);
-       }
+       spi_message_init(&m);
+       memset(&t, 0, sizeof t);
 
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret < 0)
-               return -1;
-       return val;
+       t.tx_buf = msg;
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
 }
+#endif
 
-static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
-                            unsigned int value)
+static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
+                      unsigned int value, const void *data, int len)
 {
-       u8 data[2];
        int ret;
 
-       data[0] = (reg << 4) | ((value >> 8) & 0x000f);
-       data[1] = value & 0x00ff;
-
        if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size &&
-               !codec->cache_bypass) {
+           reg < codec->driver->reg_cache_size &&
+           !codec->cache_bypass) {
                ret = snd_soc_cache_write(codec, reg, value);
                if (ret < 0)
                        return -1;
@@ -64,8 +62,8 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
                return 0;
        }
 
-       ret = codec->hw_write(codec->control_data, data, 2);
-       if (ret == 2)
+       ret = codec->hw_write(codec->control_data, data, len);
+       if (ret == len)
                return 0;
        if (ret < 0)
                return ret;
@@ -73,31 +71,54 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
                return -EIO;
 }
 
+static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+       int ret;
+       unsigned int val;
+
+       if (reg >= codec->driver->reg_cache_size ||
+           snd_soc_codec_volatile_register(codec, reg) ||
+           codec->cache_bypass) {
+               if (codec->cache_only)
+                       return -1;
+
+               BUG_ON(!codec->hw_read);
+               return codec->hw_read(codec, reg);
+       }
+
+       ret = snd_soc_cache_read(codec, reg, &val);
+       if (ret < 0)
+               return -1;
+       return val;
+}
+
+static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
+                                     unsigned int reg)
+{
+       return do_hw_read(codec, reg);
+}
+
+static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
+                             unsigned int value)
+{
+       u8 data[2];
+
+       data[0] = (reg << 4) | ((value >> 8) & 0x000f);
+       data[1] = value & 0x00ff;
+
+       return do_hw_write(codec, reg, value, data, 2);
+}
+
 #if defined(CONFIG_SPI_MASTER)
 static int snd_soc_4_12_spi_write(void *control_data, const char *data,
-                                int len)
+                                 int len)
 {
-       struct spi_device *spi = control_data;
-       struct spi_transfer t;
-       struct spi_message m;
        u8 msg[2];
 
-       if (len <= 0)
-               return 0;
-
        msg[0] = data[1];
        msg[1] = data[0];
 
-       spi_message_init(&m);
-       memset(&t, 0, sizeof t);
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
+       return do_spi_write(control_data, msg, len);
 }
 #else
 #define snd_soc_4_12_spi_write NULL
@@ -106,81 +127,30 @@ static int snd_soc_4_12_spi_write(void *control_data, const char *data,
 static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
-       int ret;
-       unsigned int val;
-
-       if (reg >= codec->driver->reg_cache_size ||
-               snd_soc_codec_volatile_register(codec, reg) ||
-               codec->cache_bypass) {
-                       if (codec->cache_only)
-                               return -1;
-
-                       BUG_ON(!codec->hw_read);
-                       return codec->hw_read(codec, reg);
-       }
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret < 0)
-               return -1;
-       return val;
+       return do_hw_read(codec, reg);
 }
 
 static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
                             unsigned int value)
 {
        u8 data[2];
-       int ret;
 
        data[0] = (reg << 1) | ((value >> 8) & 0x0001);
        data[1] = value & 0x00ff;
 
-       if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size &&
-               !codec->cache_bypass) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret < 0)
-                       return -1;
-       }
-
-       if (codec->cache_only) {
-               codec->cache_sync = 1;
-               return 0;
-       }
-
-       ret = codec->hw_write(codec->control_data, data, 2);
-       if (ret == 2)
-               return 0;
-       if (ret < 0)
-               return ret;
-       else
-               return -EIO;
+       return do_hw_write(codec, reg, value, data, 2);
 }
 
 #if defined(CONFIG_SPI_MASTER)
 static int snd_soc_7_9_spi_write(void *control_data, const char *data,
                                 int len)
 {
-       struct spi_device *spi = control_data;
-       struct spi_transfer t;
-       struct spi_message m;
        u8 msg[2];
 
-       if (len <= 0)
-               return 0;
-
        msg[0] = data[0];
        msg[1] = data[1];
 
-       spi_message_init(&m);
-       memset(&t, 0, sizeof t);
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
+       return do_spi_write(control_data, msg, len);
 }
 #else
 #define snd_soc_7_9_spi_write NULL
@@ -190,79 +160,30 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
                             unsigned int value)
 {
        u8 data[2];
-       int ret;
 
        reg &= 0xff;
        data[0] = reg;
        data[1] = value & 0xff;
 
-       if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size &&
-               !codec->cache_bypass) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret < 0)
-                       return -1;
-       }
-
-       if (codec->cache_only) {
-               codec->cache_sync = 1;
-               return 0;
-       }
-
-       if (codec->hw_write(codec->control_data, data, 2) == 2)
-               return 0;
-       else
-               return -EIO;
+       return do_hw_write(codec, reg, value, data, 2);
 }
 
 static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
-       int ret;
-       unsigned int val;
-
-       reg &= 0xff;
-       if (reg >= codec->driver->reg_cache_size ||
-               snd_soc_codec_volatile_register(codec, reg) ||
-               codec->cache_bypass) {
-                       if (codec->cache_only)
-                               return -1;
-
-                       BUG_ON(!codec->hw_read);
-                       return codec->hw_read(codec, reg);
-       }
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret < 0)
-               return -1;
-       return val;
+       return do_hw_read(codec, reg);
 }
 
 #if defined(CONFIG_SPI_MASTER)
 static int snd_soc_8_8_spi_write(void *control_data, const char *data,
                                 int len)
 {
-       struct spi_device *spi = control_data;
-       struct spi_transfer t;
-       struct spi_message m;
        u8 msg[2];
 
-       if (len <= 0)
-               return 0;
-
        msg[0] = data[0];
        msg[1] = data[1];
 
-       spi_message_init(&m);
-       memset(&t, 0, sizeof t);
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
+       return do_spi_write(control_data, msg, len);
 }
 #else
 #define snd_soc_8_8_spi_write NULL
@@ -272,112 +193,79 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
                              unsigned int value)
 {
        u8 data[3];
-       int ret;
 
        data[0] = reg;
        data[1] = (value >> 8) & 0xff;
        data[2] = value & 0xff;
 
-       if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size &&
-               !codec->cache_bypass) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret < 0)
-                       return -1;
-       }
-
-       if (codec->cache_only) {
-               codec->cache_sync = 1;
-               return 0;
-       }
-
-       if (codec->hw_write(codec->control_data, data, 3) == 3)
-               return 0;
-       else
-               return -EIO;
+       return do_hw_write(codec, reg, value, data, 3);
 }
 
 static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
                                      unsigned int reg)
 {
-       int ret;
-       unsigned int val;
-
-       if (reg >= codec->driver->reg_cache_size ||
-           snd_soc_codec_volatile_register(codec, reg) ||
-           codec->cache_bypass) {
-               if (codec->cache_only)
-                       return -1;
-
-               BUG_ON(!codec->hw_read);
-               return codec->hw_read(codec, reg);
-       }
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret < 0)
-               return -1;
-       return val;
+       return do_hw_read(codec, reg);
 }
 
 #if defined(CONFIG_SPI_MASTER)
 static int snd_soc_8_16_spi_write(void *control_data, const char *data,
-                                int len)
+                                 int len)
 {
-       struct spi_device *spi = control_data;
-       struct spi_transfer t;
-       struct spi_message m;
        u8 msg[3];
 
-       if (len <= 0)
-               return 0;
-
        msg[0] = data[0];
        msg[1] = data[1];
        msg[2] = data[2];
 
-       spi_message_init(&m);
-       memset(&t, 0, sizeof t);
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
+       return do_spi_write(control_data, msg, len);
 }
 #else
 #define snd_soc_8_16_spi_write NULL
 #endif
 
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
-                                         unsigned int r)
+static unsigned int do_i2c_read(struct snd_soc_codec *codec,
+                               void *reg, int reglen,
+                               void *data, int datalen)
 {
        struct i2c_msg xfer[2];
-       u8 reg = r;
-       u8 data;
        int ret;
        struct i2c_client *client = codec->control_data;
 
        /* Write register */
        xfer[0].addr = client->addr;
        xfer[0].flags = 0;
-       xfer[0].len = 1;
-       xfer[0].buf = &reg;
+       xfer[0].len = reglen;
+       xfer[0].buf = reg;
 
        /* Read data */
        xfer[1].addr = client->addr;
        xfer[1].flags = I2C_M_RD;
-       xfer[1].len = 1;
-       xfer[1].buf = &data;
+       xfer[1].len = datalen;
+       xfer[1].buf = data;
 
        ret = i2c_transfer(client->adapter, xfer, 2);
-       if (ret != 2) {
-               dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+       dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+       if (ret == 2)
                return 0;
-       }
+       else if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+#endif
+
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
+                                        unsigned int r)
+{
+       u8 reg = r;
+       u8 data;
+       int ret;
 
+       ret = do_i2c_read(codec, &reg, 1, &data, 1);
+       if (ret < 0)
+               return 0;
        return data;
 }
 #else
@@ -388,30 +276,13 @@ static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
                                          unsigned int r)
 {
-       struct i2c_msg xfer[2];
        u8 reg = r;
        u16 data;
        int ret;
-       struct i2c_client *client = codec->control_data;
-
-       /* Write register */
-       xfer[0].addr = client->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = 1;
-       xfer[0].buf = &reg;
-
-       /* Read data */
-       xfer[1].addr = client->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = 2;
-       xfer[1].buf = (u8 *)&data;
 
-       ret = i2c_transfer(client->adapter, xfer, 2);
-       if (ret != 2) {
-               dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+       ret = do_i2c_read(codec, &reg, 1, &data, 2);
+       if (ret < 0)
                return 0;
-       }
-
        return (data >> 8) | ((data & 0xff) << 8);
 }
 #else
@@ -422,30 +293,13 @@ static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
                                          unsigned int r)
 {
-       struct i2c_msg xfer[2];
        u16 reg = r;
        u8 data;
        int ret;
-       struct i2c_client *client = codec->control_data;
 
-       /* Write register */
-       xfer[0].addr = client->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = 2;
-       xfer[0].buf = (u8 *)&reg;
-
-       /* Read data */
-       xfer[1].addr = client->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = 1;
-       xfer[1].buf = &data;
-
-       ret = i2c_transfer(client->adapter, xfer, 2);
-       if (ret != 2) {
-               dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+       ret = do_i2c_read(codec, &reg, 2, &data, 1);
+       if (ret < 0)
                return 0;
-       }
-
        return data;
 }
 #else
@@ -453,87 +307,35 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
 #endif
 
 static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
-                                    unsigned int reg)
+                                     unsigned int reg)
 {
-       int ret;
-       unsigned int val;
-
-       reg &= 0xff;
-       if (reg >= codec->driver->reg_cache_size ||
-               snd_soc_codec_volatile_register(codec, reg) ||
-               codec->cache_bypass) {
-                       if (codec->cache_only)
-                               return -1;
-
-                       BUG_ON(!codec->hw_read);
-                       return codec->hw_read(codec, reg);
-       }
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret < 0)
-               return -1;
-       return val;
+       return do_hw_read(codec, reg);
 }
 
 static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
-                            unsigned int value)
+                             unsigned int value)
 {
        u8 data[3];
-       int ret;
 
        data[0] = (reg >> 8) & 0xff;
        data[1] = reg & 0xff;
        data[2] = value;
-
        reg &= 0xff;
-       if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size &&
-               !codec->cache_bypass) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret < 0)
-                       return -1;
-       }
 
-       if (codec->cache_only) {
-               codec->cache_sync = 1;
-               return 0;
-       }
-
-       ret = codec->hw_write(codec->control_data, data, 3);
-       if (ret == 3)
-               return 0;
-       if (ret < 0)
-               return ret;
-       else
-               return -EIO;
+       return do_hw_write(codec, reg, value, data, 3);
 }
 
 #if defined(CONFIG_SPI_MASTER)
 static int snd_soc_16_8_spi_write(void *control_data, const char *data,
-                                int len)
+                                 int len)
 {
-       struct spi_device *spi = control_data;
-       struct spi_transfer t;
-       struct spi_message m;
        u8 msg[3];
 
-       if (len <= 0)
-               return 0;
-
        msg[0] = data[0];
        msg[1] = data[1];
        msg[2] = data[2];
 
-       spi_message_init(&m);
-       memset(&t, 0, sizeof t);
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
+       return do_spi_write(control_data, msg, len);
 }
 #else
 #define snd_soc_16_8_spi_write NULL
@@ -543,30 +345,13 @@ static int snd_soc_16_8_spi_write(void *control_data, const char *data,
 static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
                                           unsigned int r)
 {
-       struct i2c_msg xfer[2];
        u16 reg = cpu_to_be16(r);
        u16 data;
        int ret;
-       struct i2c_client *client = codec->control_data;
-
-       /* Write register */
-       xfer[0].addr = client->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = 2;
-       xfer[0].buf = (u8 *)&reg;
-
-       /* Read data */
-       xfer[1].addr = client->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = 2;
-       xfer[1].buf = (u8 *)&data;
 
-       ret = i2c_transfer(client->adapter, xfer, 2);
-       if (ret != 2) {
-               dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+       ret = do_i2c_read(codec, &reg, 2, &data, 2);
+       if (ret < 0)
                return 0;
-       }
-
        return be16_to_cpu(data);
 }
 #else
@@ -576,91 +361,77 @@ static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
                                       unsigned int reg)
 {
-       int ret;
-       unsigned int val;
-
-       if (reg >= codec->driver->reg_cache_size ||
-           snd_soc_codec_volatile_register(codec, reg) ||
-           codec->cache_bypass) {
-               if (codec->cache_only)
-                       return -1;
-
-               BUG_ON(!codec->hw_read);
-               return codec->hw_read(codec, reg);
-       }
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret < 0)
-               return -1;
-
-       return val;
+       return do_hw_read(codec, reg);
 }
 
 static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
                               unsigned int value)
 {
        u8 data[4];
-       int ret;
 
        data[0] = (reg >> 8) & 0xff;
        data[1] = reg & 0xff;
        data[2] = (value >> 8) & 0xff;
        data[3] = value & 0xff;
 
-       if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size &&
-               !codec->cache_bypass) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret < 0)
-                       return -1;
-       }
-
-       if (codec->cache_only) {
-               codec->cache_sync = 1;
-               return 0;
-       }
-
-       ret = codec->hw_write(codec->control_data, data, 4);
-       if (ret == 4)
-               return 0;
-       if (ret < 0)
-               return ret;
-       else
-               return -EIO;
+       return do_hw_write(codec, reg, value, data, 4);
 }
 
 #if defined(CONFIG_SPI_MASTER)
 static int snd_soc_16_16_spi_write(void *control_data, const char *data,
-                                int len)
+                                  int len)
 {
-       struct spi_device *spi = control_data;
-       struct spi_transfer t;
-       struct spi_message m;
        u8 msg[4];
 
-       if (len <= 0)
-               return 0;
-
        msg[0] = data[0];
        msg[1] = data[1];
        msg[2] = data[2];
        msg[3] = data[3];
 
-       spi_message_init(&m);
-       memset(&t, 0, sizeof t);
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
+       return do_spi_write(control_data, msg, len);
 }
 #else
 #define snd_soc_16_16_spi_write NULL
 #endif
 
+/* Primitive bulk write support for soc-cache.  The data pointed to by `data' needs
+ * to already be in the form the hardware expects including any leading register specific
+ * data.  Any data written through this function will not go through the cache as it
+ * only handles writing to volatile or out of bounds registers.
+ */
+static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
+                                    const void *data, size_t len)
+{
+       int ret;
+
+       /* Ensure that the base register is volatile.  Subsequently
+        * any other register that is touched by this routine should be
+        * volatile as well to ensure that we don't get out of sync with
+        * the cache.
+        */
+       if (!snd_soc_codec_volatile_register(codec, reg)
+           && reg < codec->driver->reg_cache_size)
+               return -EINVAL;
+
+       switch (codec->control_type) {
+       case SND_SOC_I2C:
+               ret = i2c_master_send(codec->control_data, data, len);
+               break;
+       case SND_SOC_SPI:
+               ret = do_spi_write(codec->control_data, data, len);
+               break;
+       default:
+               BUG();
+       }
+
+       if (ret == len)
+               return 0;
+       if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+
 static struct {
        int addr_bits;
        int data_bits;
@@ -744,6 +515,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 
        codec->write = io_types[i].write;
        codec->read = io_types[i].read;
+       codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
 
        switch (control) {
        case SND_SOC_CUSTOM:
@@ -889,6 +661,8 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
                rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
                if (rbnode->value == rbnode->defval)
                        continue;
+               WARN_ON(codec->writable_register &&
+                       codec->writable_register(codec, rbnode->reg));
                ret = snd_soc_cache_read(codec, rbnode->reg, &val);
                if (ret)
                        return ret;
@@ -1149,6 +923,8 @@ static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
 
        lzo_blocks = codec->reg_cache;
        for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
+               WARN_ON(codec->writable_register &&
+                       codec->writable_register(codec, i));
                ret = snd_soc_cache_read(codec, i, &val);
                if (ret)
                        return ret;
@@ -1407,6 +1183,8 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
 
        codec_drv = codec->driver;
        for (i = 0; i < codec_drv->reg_cache_size; ++i) {
+               WARN_ON(codec->writable_register &&
+                       codec->writable_register(codec, i));
                ret = snd_soc_cache_read(codec, i, &val);
                if (ret)
                        return ret;
@@ -1523,7 +1301,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec)
                                codec->cache_ops->name, codec->name);
                return codec->cache_ops->init(codec);
        }
-       return -EINVAL;
+       return -ENOSYS;
 }
 
 /*
@@ -1538,7 +1316,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec)
                                codec->cache_ops->name, codec->name);
                return codec->cache_ops->exit(codec);
        }
-       return -EINVAL;
+       return -ENOSYS;
 }
 
 /**
@@ -1562,7 +1340,7 @@ int snd_soc_cache_read(struct snd_soc_codec *codec,
        }
 
        mutex_unlock(&codec->cache_rw_mutex);
-       return -EINVAL;
+       return -ENOSYS;
 }
 EXPORT_SYMBOL_GPL(snd_soc_cache_read);
 
@@ -1587,7 +1365,7 @@ int snd_soc_cache_write(struct snd_soc_codec *codec,
        }
 
        mutex_unlock(&codec->cache_rw_mutex);
-       return -EINVAL;
+       return -ENOSYS;
 }
 EXPORT_SYMBOL_GPL(snd_soc_cache_write);
 
@@ -1610,7 +1388,7 @@ int snd_soc_cache_sync(struct snd_soc_codec *codec)
        }
 
        if (!codec->cache_ops || !codec->cache_ops->sync)
-               return -EINVAL;
+               return -ENOSYS;
 
        if (codec->cache_ops->name)
                name = codec->cache_ops->name;
@@ -1677,3 +1455,17 @@ int snd_soc_default_readable_register(struct snd_soc_codec *codec,
        return codec->driver->reg_access_default[index].read;
 }
 EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
+
+int snd_soc_default_writable_register(struct snd_soc_codec *codec,
+                                     unsigned int reg)
+{
+       int index;
+
+       if (reg >= codec->driver->reg_cache_size)
+               return 1;
+       index = snd_soc_get_reg_access_index(codec, reg);
+       if (index < 0)
+               return 0;
+       return codec->driver->reg_access_default[index].write;
+}
+EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);
index 4dda589..5ae70a1 100644 (file)
@@ -2146,6 +2146,42 @@ int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register);
 
+/**
+ * snd_soc_codec_readable_register: Report if a register is readable.
+ *
+ * @codec: CODEC to query.
+ * @reg: Register to query.
+ *
+ * Boolean function indicating if a CODEC register is readable.
+ */
+int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
+                                   unsigned int reg)
+{
+       if (codec->readable_register)
+               return codec->readable_register(codec, reg);
+       else
+               return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_codec_readable_register);
+
+/**
+ * snd_soc_codec_writable_register: Report if a register is writable.
+ *
+ * @codec: CODEC to query.
+ * @reg: Register to query.
+ *
+ * Boolean function indicating if a CODEC register is writable.
+ */
+int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
+                                   unsigned int reg)
+{
+       if (codec->writable_register)
+               return codec->writable_register(codec, reg);
+       else
+               return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register);
+
 /**
  * snd_soc_new_ac97_codec - initailise AC97 device
  * @codec: audio codec
@@ -2228,6 +2264,13 @@ unsigned int snd_soc_write(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_write);
 
+unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec,
+                                   unsigned int reg, const void *data, size_t len)
+{
+       return codec->bulk_write_raw(codec, reg, data, len);
+}
+EXPORT_SYMBOL_GPL(snd_soc_bulk_write_raw);
+
 /**
  * snd_soc_update_bits - update codec register bits
  * @codec: audio codec
@@ -3666,6 +3709,7 @@ int snd_soc_register_codec(struct device *dev,
        codec->read = codec_drv->read;
        codec->volatile_register = codec_drv->volatile_register;
        codec->readable_register = codec_drv->readable_register;
+       codec->writable_register = codec_drv->writable_register;
        codec->dapm.bias_level = SND_SOC_BIAS_OFF;
        codec->dapm.dev = dev;
        codec->dapm.codec = codec;
@@ -3700,6 +3744,8 @@ int snd_soc_register_codec(struct device *dev,
                        codec->volatile_register = snd_soc_default_volatile_register;
                if (!codec->readable_register)
                        codec->readable_register = snd_soc_default_readable_register;
+               if (!codec->writable_register)
+                       codec->writable_register = snd_soc_default_writable_register;
        }
 
        for (i = 0; i < num_dai; i++) {